Пример #1
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="MaxGaussianOp"]/message_doc[@name="AAverageConditional(Gaussian, Gaussian, Gaussian)"]/*'/>
        public static Gaussian AAverageConditional([SkipIfUniform] Gaussian max, [Proper] Gaussian a, [Proper] Gaussian b)
        {
            if (max.IsUniform())
            {
                return(Gaussian.Uniform());
            }
            if (!b.IsProper())
            {
                throw new ImproperMessageException(b);
            }

            double logw1, alpha1, vx1, mx1;
            double logw2, alpha2, vx2, mx2;
            double logz;

            ComputeStats(max, a, b, out logz, out logw1, out alpha1, out vx1, out mx1,
                         out logw2, out alpha2, out vx2, out mx2);
            double w1 = Math.Exp(logw1 - logz);
            double w2 = Math.Exp(logw2 - logz);
            bool   checkDerivatives = false;

            if (a.IsPointMass)
            {
                // f(a) = int p(x = max(a,b)) p(b) db
                // f(a) = p(x = a) p(a >= b) + p(x = b) p(a < b | x = b)
                // f(a) = N(a; mx, vx) phi((a - m2)/sqrt(v2)) + N(m2; mx, vx + v2) phi((mx2 - a)/sqrt(vx2))
                // f'(a) = (mx-a)/vx N(a; mx, vx) phi((a - m2)/sqrt(v2)) + N(a; mx, vx) N(a; m2, v2) - N(m2; mx, vx + v2) N(a; mx2, vx2)
                //       = (mx-a)/vx N(a; mx, vx) phi((a - m2)/sqrt(v2))
                // f''(a) = -1/vx N(a; mx, vx) phi((a - m2)/sqrt(v2)) + (mx-a)^2/vx^2 N(a; mx, vx) phi((a - m2)/sqrt(v2)) + (mx-a)/vx N(a; mx, vx) N(a; m2, v2)
                // ddlogf = f''(a)/f(a) - (f'(a)/f(a))^2 = (f''(a) f(a) - f'(a)^2)/f(a)^2
                double aPoint = a.Point;
                if (max.IsPointMass)
                {
                    return(max);
                }
                double z     = max.MeanTimesPrecision - aPoint * max.Precision;
                double alpha = z * w1;
                double beta  = (z * alpha1 - max.Precision + z * z) * w1 - alpha * alpha;
                if (b.IsPointMass && b.Point != aPoint)
                {
                    beta -= max.Precision * w2 * alpha2 * (b.Point - aPoint);
                }
                if (checkDerivatives)
                {
                    double m1 = a.GetMean();
                    double delta = m1 * 1e-6;
                    double logzd, logw1d, alpha1d, vx1d, mx1d, logw2d, alpha2d, vx2d, mx2d;
                    ComputeStats(max, Gaussian.FromMeanAndPrecision(m1 + delta, a.Precision), b, out logzd, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d);
                    double logzd2;
                    ComputeStats(max, Gaussian.FromMeanAndPrecision(m1 - delta, a.Precision), b, out logzd2, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d);
                    double alphaCheck = (logzd - logzd2) / (2 * delta);
                    double alphaError = Math.Abs(alpha - alphaCheck);
                    double betaCheck  = (logzd + logzd2 - 2 * logz) / (delta * delta);
                    double betaError  = Math.Abs(beta - betaCheck);
                    Console.WriteLine($"alpha={alpha} check={alphaCheck} error={alphaError} beta={beta} check={betaCheck} error={betaError}");
                }
                return(Gaussian.FromDerivatives(aPoint, alpha, beta, ForceProper));
            }
            bool useMessage = (w1 > 0) || (logw2 > -100);

            if (useMessage)
            {
                // vx1 = 1/(1/vx + 1/v1) = vx*v1/(vx + v1)
                double z, alpha, beta;
                if (max.IsPointMass)
                {
                    if (w2 == 0)
                    {
                        return(max);
                    }
                    z     = max.Point * a.Precision - a.MeanTimesPrecision;
                    alpha = z * w1 - w2 * alpha2;
                    beta  = (z * z - a.Precision) * w1 - z * alpha2 * w2 - alpha * alpha;
                }
                else
                {
                    //z = vx1 * (max.MeanTimesPrecision * a.Precision - a.MeanTimesPrecision * max.Precision);
                    z     = (max.MeanTimesPrecision - a.GetMean() * max.Precision) / (max.Precision / a.Precision + 1);
                    alpha = z * w1 - vx1 * max.Precision * w2 * alpha2;
                    if (w2 == 0)
                    {
                        //beta = (z * alpha1 - max.Precision) / (max.Precision / a.Precision + 1);
                        //double resultPrecision = a.Precision * beta / (-a.Precision - beta);
                        //resultPrecision = beta / (-1 - beta/a.Precision);
                        //resultPrecision = 1 / (-1/beta - 1 / a.Precision);
                        //resultPrecision = a.Precision / (-a.Precision / beta - 1);
                        //resultPrecision = a.Precision / (-(a.Precision + max.Precision) / (z * alpha1 - max.Precision) - 1);
                        //resultPrecision = -a.Precision / ((a.Precision + z*alpha1) / (z * alpha1 - max.Precision));
                        double zalpha1         = z * alpha1;
                        double denom           = (1 + zalpha1 / a.Precision);
                        double resultPrecision = (max.Precision - zalpha1) / denom;
                        //double weight = (max.Precision - z * alpha1) / (a.Precision + z * alpha1);
                        //double weightPlus1 = (max.Precision + a.Precision) / (a.Precision + z * alpha1);
                        //double resultMeanTimesPrecision = weight * (a.MeanTimesPrecision + alpha) + alpha;
                        //resultMeanTimesPrecision = weight * a.MeanTimesPrecision + weightPlus1 * alpha;
                        //double resultMeanTimesPrecision = (a.Precision * max.MeanTimesPrecision - z * alpha1 * a.MeanTimesPrecision) / (a.Precision + z * alpha1);
                        double resultMeanTimesPrecision = (max.MeanTimesPrecision - zalpha1 * a.GetMean()) / denom;
                        return(Gaussian.FromNatural(resultMeanTimesPrecision, resultPrecision));
                    }
                    else
                    {
                        beta = ((z * alpha1 - max.Precision) * vx1 * a.Precision + z * z) * w1
                               - max.Precision * vx1 * w2 * alpha2 * (mx2 * a.Precision - a.MeanTimesPrecision) / (vx2 * a.Precision + 1) - alpha * alpha;
                    }
                }
                //Console.WriteLine($"z={z} w1={w1:r} w2={w2:r} logw2={logw2} alpha1={alpha1} alpha2={alpha2} alpha={alpha:r} beta={beta:r}");
                if (checkDerivatives)
                {
                    double m1 = a.GetMean();
                    double delta = m1 * 1e-6;
                    double logzd, logw1d, alpha1d, vx1d, mx1d, logw2d, alpha2d, vx2d, mx2d;
                    ComputeStats(max, Gaussian.FromMeanAndPrecision(m1 + delta, a.Precision), b, out logzd, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d);
                    double logzd2;
                    ComputeStats(max, Gaussian.FromMeanAndPrecision(m1 - delta, a.Precision), b, out logzd2, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d);
                    double alphaCheck = (logzd - logzd2) / (2 * delta);
                    double alphaError = Math.Abs(alpha - alphaCheck);
                    double betaCheck  = (logzd + logzd2 - 2 * logz) / (delta * delta);
                    double betaError  = Math.Abs(beta - betaCheck);
                    Console.WriteLine($"alpha={alpha} check={alphaCheck} error={alphaError} beta={beta} check={betaCheck} error={betaError}");
                }
                return(GaussianOp.GaussianFromAlphaBeta(a, alpha, -beta, ForceProper));
            }
            else
            {
                double m1, v1, m2, v2;
                a.GetMeanAndVariance(out m1, out v1);
                b.GetMeanAndVariance(out m2, out v2);
                // the posterior is a mixture model with weights exp(logw1-logz), exp(logw2-logz) and distributions
                // N(a; mx1, vx1) phi((a - m2)/sqrt(v2)) / phi((mx1 - m2)/sqrt(vx1 + v2))
                // N(a; m1, v1) phi((mx2 - a)/sqrt(vx2)) / phi((mx2 - m1)/sqrt(vx2 + v1))
                // the moments of the posterior are computed via the moments of these two components.
                if (vx1 == 0)
                {
                    alpha1 = 0;
                }
                if (vx2 == 0)
                {
                    alpha2 = 0;
                }
                double mc1 = mx1;
                if (alpha1 != 0) // avoid 0*infinity
                {
                    mc1 += alpha1 * vx1;
                }
                alpha2 = -alpha2;
                double mc2 = m1;
                if (alpha2 != 0) // avoid 0*infinity
                {
                    mc2 += alpha2 * v1;
                }
                // z2 = (mx2 - m1) / Math.Sqrt(vx2 + v1)
                // logw2 = MMath.NormalCdfLn(z2);
                // alpha2 = -Math.Exp(Gaussian.GetLogProb(mx2, m1, vx2 + v1) - logw2);
                //        = -1/sqrt(vx2+v1)/NormalCdfRatio(z2)
                // m1 + alpha2*v1 = sqrt(vx2+v1)*(m1/sqrt(vx2+v1) - v1/(vx2+v1)/NormalCdfRatio(z2))
                //                = sqrt(vx2+v1)*(mx2/sqrt(vx2+v1) - z2 - v1/(vx2+v1)/NormalCdfRatio(z2))
                //                = sqrt(vx2+v1)*(mx2/sqrt(vx2+v1) - dY/Y)  if vx2=0
                double       z2 = 0, Y = 0, dY = 0;
                const double z2small = 0;
                if (vx2 == 0)
                {
                    z2 = (mx2 - m1) / Math.Sqrt(vx2 + v1);
                    if (z2 < z2small)
                    {
                        Y   = MMath.NormalCdfRatio(z2);
                        dY  = MMath.NormalCdfMomentRatio(1, z2);
                        mc2 = mx2 - Math.Sqrt(v1) * dY / Y;
                    }
                }
                double m = w1 * mc1 + w2 * mc2;
                double beta1;
                if (alpha1 == 0)
                {
                    beta1 = 0;  // avoid 0*infinity
                }
                else
                {
                    double r1 = (mx1 - m2) / (vx1 + v2);
                    beta1 = alpha1 * (alpha1 + r1);
                }
                double beta2;
                if (alpha2 == 0)
                {
                    beta2 = 0;  // avoid 0*infinity
                }
                else
                {
                    double r2 = (mx2 - m1) / (vx2 + v1);
                    beta2 = alpha2 * (alpha2 - r2);
                }
                double vc1 = vx1 * (1 - vx1 * beta1);
                double vc2;
                if (vx2 == 0 && z2 < z2small)
                {
                    // beta2 = alpha2 * (alpha2 - z2/sqrt(v1))
                    // vc2 = v1 - v1^2 * alpha2 * (alpha2 - z2/sqrt(v1))
                    //     = v1 - v1*dY/Y^2
                    //     =approx v1/z2^2
                    // posterior E[x^2] = v - v*dY/Y^2 + v*dY^2/Y^2 = v - v*dY/Y^2*(1 - dY) = v + v*z*dY/Y = v*d2Y/Y
                    //vc2 = v1 * (1 - dY / (Y * Y));
                    double d2Y  = 2 * MMath.NormalCdfMomentRatio(2, z2);
                    double dYiY = dY / Y;
                    vc2 = v1 * (d2Y / Y - dYiY * dYiY);
                }
                else if (beta2 == 0)
                {
                    vc2 = v1;
                }
                else
                {
                    vc2 = v1 * (1 - v1 * beta2);
                }
                double   diff   = mc1 - mc2;
                double   v      = w1 * vc1 + w2 * vc2 + w1 * w2 * diff * diff;
                Gaussian result = new Gaussian(m, v);
                //Console.WriteLine($"z2={z2} m={m} v={v} vc2={vc2} diff={diff}");
                result.SetToRatio(result, a, ForceProper);
                if (Double.IsNaN(result.Precision) || Double.IsNaN(result.MeanTimesPrecision))
                {
                    throw new InferRuntimeException($"result is NaN.  max={max}, a={a}, b={b}");
                }
                return(result);
            }
        }
Пример #2
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="MaxGaussianOp"]/message_doc[@name="MaxAverageConditional(Gaussian, Gaussian, Gaussian)"]/*'/>
        public static Gaussian MaxAverageConditional(Gaussian max, [Proper] Gaussian a, [Proper] Gaussian b)
        {
            // the following code works correctly even if max is uniform or improper.
            if (!a.IsProper())
            {
                throw new ImproperMessageException(a);
            }
            if (!b.IsProper())
            {
                throw new ImproperMessageException(b);
            }
            double m1, v1, m2, v2;

            a.GetMeanAndVariance(out m1, out v1);
            b.GetMeanAndVariance(out m2, out v2);

            double logw1, alpha1, vx1, mx1;
            double logw2, alpha2, vx2, mx2;
            double logz;

            ComputeStats(max, a, b, out logz, out logw1, out alpha1, out vx1, out mx1,
                         out logw2, out alpha2, out vx2, out mx2);
            double w1 = Math.Exp(logw1 - logz);
            double w2 = Math.Exp(logw2 - logz);

            if (max.IsPointMass)
            {
                double z1 = a.MeanTimesPrecision - max.Point * a.Precision;
                double z2 = b.MeanTimesPrecision - max.Point * b.Precision;
                if (a.IsPointMass)
                {
                    if (max.Point == a.Point)
                    {
                        return(Gaussian.PointMass(a.Point));
                    }
                    else
                    {
                        z1 = 0;
                    }
                }
                if (b.IsPointMass)
                {
                    if (max.Point == b.Point)
                    {
                        return(Gaussian.PointMass(b.Point));
                    }
                    else
                    {
                        z2 = 0;
                    }
                }
                double alpha = (z1 + alpha1) * w1 + (z2 + alpha2) * w2;
                double beta  = -alpha * alpha;
                if (w1 > 0)
                {
                    beta += (z1 * z1 - a.Precision + (2 * z1 + z2) * alpha1) * w1;
                }
                if (w2 > 0)
                {
                    beta += (z2 * z2 - b.Precision + (2 * z2 + z1) * alpha2) * w2;
                }
                //Console.WriteLine($"z1={z1} w1={w1} alpha1={alpha1} z2={z2} w2={w2} alpha2={alpha2} alpha={alpha} beta={beta:r}");
                return(GaussianOp.GaussianFromAlphaBeta(max, alpha, -beta, ForceProper));
            }
            bool useMessage = max.Precision > 10;

            if (useMessage)
            {
                // We want to avoid computing 1/max.Precision or max.MeanTimesPrecision/max.Precision, since these lead to roundoff errors.
                double z1    = (m1 * max.Precision - max.MeanTimesPrecision) / (v1 * max.Precision + 1);
                double z2    = (m2 * max.Precision - max.MeanTimesPrecision) / (v2 * max.Precision + 1);
                double alpha = 0;
                if (w1 > 0)
                {
                    alpha += (z1 + vx1 * max.Precision * alpha1) * w1;
                }
                if (w2 > 0)
                {
                    alpha += (z2 + vx2 * max.Precision * alpha2) * w2;
                }
                double beta = -alpha * alpha;
                if (w1 > 0)
                {
                    double diff;
                    // compute diff to avoid roundoff errors
                    if (a.IsPointMass)
                    {
                        diff = m2 - mx1;
                    }
                    else
                    {
                        diff = (m2 * (max.Precision + a.Precision) - (max.MeanTimesPrecision + a.MeanTimesPrecision)) * vx1;
                    }
                    if (!b.IsPointMass)
                    {
                        diff *= vx1 / (v2 + vx1);
                    }
                    beta += (z1 * z1 - max.Precision / (v1 * max.Precision + 1) + (2 * z1 + diff * max.Precision) * vx1 * max.Precision * alpha1) * w1;
                }
                if (w2 > 0)
                {
                    double diff;
                    if (b.IsPointMass)
                    {
                        diff = m1 - mx2;
                    }
                    else
                    {
                        diff = (m1 * (max.Precision + b.Precision) - (max.MeanTimesPrecision + b.MeanTimesPrecision)) * vx2;
                    }
                    if (!a.IsPointMass)
                    {
                        diff *= vx2 / (v1 + vx2);
                    }
                    beta += (z2 * z2 - max.Precision / (v2 * max.Precision + 1) + (2 * z2 + diff * max.Precision) * vx2 * max.Precision * alpha2) * w2;
                }
                bool check = false;
                if (check)
                {
                    double mx = max.GetMean();
                    double delta = mx * 1e-4;
                    double logzd, logw1d, alpha1d, vx1d, mx1d, logw2d, alpha2d, vx2d, mx2d;
                    ComputeStats(Gaussian.FromMeanAndPrecision(mx + delta, max.Precision), a, b, out logzd, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d);
                    double logzd2;
                    ComputeStats(Gaussian.FromMeanAndPrecision(mx - delta, max.Precision), a, b, out logzd2, out logw1d, out alpha1d, out vx1d, out mx1d, out logw2d, out alpha2d, out vx2d, out mx2d);
                    double alphaCheck = (logzd - logzd2) / (2 * delta);
                    double alphaError = Math.Abs(alpha - alphaCheck);
                    double betaCheck  = (logzd + logzd2 - 2 * logz) / (delta * delta);
                    double betaError  = Math.Abs(beta - betaCheck);
                    Console.WriteLine($"alpha={alpha} check={alphaCheck} error={alphaError} beta={beta} check={betaCheck} error={betaError}");
                }
                //Console.WriteLine($"z1={z1} w1={w1} vx1={vx1} alpha1={alpha1} z2={z2} w2={w2} vx2={vx2} alpha2={alpha2} alpha={alpha} beta={beta:r} {max.Precision:r}");
                return(GaussianOp.GaussianFromAlphaBeta(max, alpha, -beta, ForceProper));
            }
            // the posterior is a mixture model with weights exp(logw1-logz), exp(logw2-logz) and distributions
            // N(x; mx1, vx1) phi((x - m2)/sqrt(v2)) / phi((mx1 - m2)/sqrt(vx1 + v2))
            // the moments of the posterior are computed via the moments of these two components.
            if (vx1 == 0)
            {
                alpha1 = 0;
            }
            if (vx2 == 0)
            {
                alpha2 = 0;
            }
            double mc1 = mx1 + alpha1 * vx1;
            double mc2 = mx2 + alpha2 * vx2;
            double m, v;

            if (w1 == 0)
            {
                // avoid dealing with infinities.
                m = mx2;
                v = vx2;
            }
            else if (w2 == 0)
            {
                // avoid dealing with infinities.
                m = mx1;
                v = vx1;
            }
            else
            {
                m = w1 * mc1 + w2 * mc2;
                double beta1;
                if (alpha1 == 0)
                {
                    beta1 = 0;
                }
                else
                {
                    double r1 = (mx1 - m2) / (vx1 + v2);
                    beta1 = alpha1 * (alpha1 + r1);
                }
                double vc1 = vx1 * (1 - vx1 * beta1);
                double beta2;
                if (alpha2 == 0)
                {
                    beta2 = 0;
                }
                else
                {
                    double r2 = (mx2 - m1) / (vx2 + v1);
                    beta2 = alpha2 * (alpha2 + r2);
                }
                double vc2  = vx2 * (1 - vx2 * beta2);
                double diff = mc1 - mc2;
                v = w1 * vc1 + w2 * vc2 + w1 * w2 * diff * diff;
            }
            Gaussian result = new Gaussian(m, v);

            result.SetToRatio(result, max, ForceProper);
            if (Double.IsNaN(result.Precision) || Double.IsNaN(result.MeanTimesPrecision))
            {
                throw new InferRuntimeException($"result is NaN.  max={max}, a={a}, b={b}");
            }
            return(result);
        }
Пример #3
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="ArrayFromVectorOp"]/message_doc[@name="ArrayAverageConditional{GaussianList}(IList{Gaussian}, VectorGaussian, GaussianList)"]/*'/>
        /// <typeparam name="GaussianList">The type of the resulting array.</typeparam>
        public static GaussianList ArrayAverageConditional <GaussianList>(
            [NoInit] IList <Gaussian> array, [SkipIfUniform] VectorGaussian vector, GaussianList result)
            where GaussianList : IList <Gaussian>
        {
            if (result.Count != vector.Dimension)
            {
                throw new ArgumentException("vector.Dimension (" + vector.Dimension + ") != result.Count (" + result.Count + ")");
            }
            int  length       = result.Count;
            bool allPointMass = array.All(g => g.IsPointMass);

            if (allPointMass)
            {
                // efficient special case
                for (int i = 0; i < length; i++)
                {
                    double x = array[i].Point;
                    // -prec*(x-m) = -prec*x + prec*m
                    double dlogp = vector.MeanTimesPrecision[i];
                    for (int j = 0; j < length; j++)
                    {
                        dlogp -= vector.Precision[i, j] * array[j].Point;
                    }
                    double ddlogp = -vector.Precision[i, i];
                    result[i] = Gaussian.FromDerivatives(x, dlogp, ddlogp, false);
                }
            }
            else if (vector.IsPointMass)
            {
                // efficient special case
                Vector mean = vector.Point;
                for (int i = 0; i < length; i++)
                {
                    result[i] = Gaussian.PointMass(mean[i]);
                }
            }
            else if (vector.IsUniform())
            {
                for (int i = 0; i < length; i++)
                {
                    result[i] = Gaussian.Uniform();
                }
            }
            else if (array.Any(g => g.IsPointMass))
            {
                // Z = N(m1; m2, V1+V2)
                // logZ = -0.5 (m1-m2)'inv(V1+V2)(m1-m2)
                // dlogZ = (m1-m2)'inv(V1+V2) dm2
                // ddlogZ = -dm2'inv(V1+V2) dm2
                Vector mean = Vector.Zero(length);
                PositiveDefiniteMatrix variance = new PositiveDefiniteMatrix(length, length);
                vector.GetMeanAndVariance(mean, variance);
                for (int i = 0; i < length; i++)
                {
                    if (array[i].IsUniform())
                    {
                        continue;
                    }
                    double m, v;
                    array[i].GetMeanAndVariance(out m, out v);
                    variance[i, i] += v;
                    mean[i]        -= m;
                }
                PositiveDefiniteMatrix precision = variance.Inverse();
                Vector meanTimesPrecision        = precision * mean;
                for (int i = 0; i < length; i++)
                {
                    if (array[i].IsUniform())
                    {
                        result[i] = Gaussian.FromMeanAndVariance(mean[i], variance[i, i]);
                    }
                    else
                    {
                        double alpha = meanTimesPrecision[i];
                        double beta  = precision[i, i];
                        result[i] = GaussianOp.GaussianFromAlphaBeta(array[i], alpha, beta, false);
                    }
                }
            }
            else
            {
                // Compute inv(V1+V2)*(m1-m2) as inv(V2)*inv(inv(V1) + inv(V2))*(inv(V1)*m1 + inv(V2)*m2) - inv(V2)*m2 = inv(V2)*(m - m2)
                // Compute inv(V1+V2) as inv(V2)*inv(inv(V1) + inv(V2))*inv(V2) - inv(V2)
                PositiveDefiniteMatrix precision = (PositiveDefiniteMatrix)vector.Precision.Clone();
                Vector meanTimesPrecision        = vector.MeanTimesPrecision.Clone();
                for (int i = 0; i < length; i++)
                {
                    Gaussian g = array[i];
                    precision[i, i]       += g.Precision;
                    meanTimesPrecision[i] += g.MeanTimesPrecision;
                }
                bool fastMethod = true;
                if (fastMethod)
                {
                    bool isPosDef;
                    // this destroys precision
                    LowerTriangularMatrix precisionChol = precision.CholeskyInPlace(out isPosDef);
                    if (!isPosDef)
                    {
                        throw new PositiveDefiniteMatrixException();
                    }
                    // variance = inv(precisionChol*precisionChol') = inv(precisionChol)'*inv(precisionChol) = varianceChol*varianceChol'
                    // this destroys meanTimesPrecision
                    var mean = meanTimesPrecision.PredivideBy(precisionChol);
                    mean = mean.PredivideByTranspose(precisionChol);
                    var varianceCholTranspose = precisionChol;
                    // this destroys precisionChol
                    varianceCholTranspose.SetToInverse(precisionChol);
                    for (int i = 0; i < length; i++)
                    {
                        Gaussian g           = array[i];
                        double   variance_ii = GetSquaredLengthOfColumn(varianceCholTranspose, i);
                        // works when g is uniform, but not when g is point mass
                        result[i] = Gaussian.FromMeanAndVariance(mean[i], variance_ii) / g;
                    }
                }
                else
                {
                    // equivalent to above, but slower
                    PositiveDefiniteMatrix variance = precision.Inverse();
                    var mean = variance * meanTimesPrecision;
                    for (int i = 0; i < length; i++)
                    {
                        Gaussian g = array[i];
                        // works when g is uniform, but not when g is point mass
                        result[i] = Gaussian.FromMeanAndVariance(mean[i], variance[i, i]) / g;
                    }
                }
            }
            return(result);
        }
Пример #4
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="ArrayFromVectorOp"]/message_doc[@name="ArrayAverageConditional{GaussianList}(IList{Gaussian}, VectorGaussianMoments, GaussianList)"]/*'/>
        /// <typeparam name="GaussianList">The type of the resulting array.</typeparam>
        public static GaussianList ArrayAverageConditional <GaussianList>(
            [NoInit] IList <Gaussian> array, [SkipIfUniform] VectorGaussianMoments vector, GaussianList result)
            where GaussianList : IList <Gaussian>
        {
            if (result.Count != vector.Dimension)
            {
                throw new ArgumentException("vector.Dimension (" + vector.Dimension + ") != result.Count (" + result.Count + ")");
            }
            int length = result.Count;

            if (array.All(g => g.IsUniform()) || vector.IsUniform() || vector.IsPointMass)
            {
                for (int i = 0; i < length; i++)
                {
                    result[i] = Gaussian.FromMeanAndVariance(vector.Mean[i], vector.Variance[i, i]);
                }
            }
            else
            {
                // Z = N(m1; m2, V1+V2)
                // logZ = -0.5 (m1-m2)'inv(V1+V2)(m1-m2)
                // dlogZ = (m1-m2)'inv(V1+V2) dm2
                // ddlogZ = -dm2'inv(V1+V2) dm2
                VectorGaussianMoments product = new VectorGaussianMoments(length);
                Vector mean = product.Mean;
                PositiveDefiniteMatrix variance = product.Variance;
                vector.GetMeanAndVariance(mean, variance);
                for (int i = 0; i < length; i++)
                {
                    double m, v;
                    array[i].GetMeanAndVariance(out m, out v);
                    variance[i, i] += v;
                    mean[i]        -= m;
                }
                double offset = 1e-10;
                for (int i = 0; i < length; i++)
                {
                    variance[i, i] += offset;
                }
                PositiveDefiniteMatrix precision = variance.Inverse();
                Vector meanTimesPrecision        = precision * mean;
                double precisionThreshold        = 1;
                if (array.Any(g => g.Precision <= precisionThreshold))
                {
                    // compute the posterior mean and variance
                    product.SetToProduct(vector, array);
                    mean     = product.Mean;
                    variance = product.Variance;
                }
                for (int i = 0; i < length; i++)
                {
                    if (array[i].Precision <= precisionThreshold)
                    {
                        result[i] = Gaussian.FromMeanAndVariance(mean[i], variance[i, i]) / array[i];
                    }
                    else
                    {
                        double alpha = meanTimesPrecision[i];
                        double beta  = precision[i, i];
                        if (double.IsNaN(alpha))
                        {
                            throw new Exception("alpha is NaN");
                        }
                        if (double.IsNaN(beta))
                        {
                            throw new Exception("beta is NaN");
                        }
                        result[i] = GaussianOp.GaussianFromAlphaBeta(array[i], alpha, beta, false);
                        if (double.IsNaN(result[i].MeanTimesPrecision))
                        {
                            throw new Exception("result is NaN");
                        }
                        if (result[i].Precision < 0)
                        {
                            throw new Exception("result is improper");
                        }
                    }
                }
            }
            return(result);
        }
Пример #5
0
        /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="BernoulliFromLogOddsOp"]/message_doc[@name="LogOddsAverageConditional(bool, Gaussian)"]/*'/>
        public static Gaussian LogOddsAverageConditional(bool sample, [SkipIfUniform] Gaussian logOdds)
        {
            double m, v;

            logOdds.GetMeanAndVariance(out m, out v);
            double s = sample ? 1 : -1;

            m *= s;
            // catch cases when sigma0 would evaluate to 0
            if (m + 1.5 * v < -38)  // this check catches sigma0=0 when v <= 200
            {
                double beta2 = Math.Exp(m + 1.5 * v);
                return(Gaussian.FromMeanAndVariance(s * (m + v), v * (1 - v * beta2)) / logOdds);
            }
            else if (m + v < 0)
            {
                // Factor out exp(m+v/2) in the following formulas:
                // sigma(m,v) = exp(m+v/2)(1-sigma(m+v,v))
                // sigma'(m,v) = d/dm sigma(m,v) = exp(m+v/2)(1-sigma(m+v,v) - sigma'(m+v,v))
                // sigma''(m,v) = d/dm sigma'(m,v) = exp(m+v/2)(1-sigma(m+v,v) - 2 sigma'(m+v,v) - sigma''(m+v,v))
                // This approach is always safe if sigma(-m-v,v)>0, which is guaranteed by m+v<0
                double sigma0 = MMath.LogisticGaussian(-m - v, v);
                double sd     = MMath.LogisticGaussianDerivative(m + v, v);
                double sigma1 = sigma0 - sd;
                double sigma2 = sigma1 - sd - MMath.LogisticGaussianDerivative2(m + v, v);
                double alpha  = sigma1 / sigma0; // 1 - sd/sigma0
                if (Double.IsNaN(alpha))
                {
                    throw new Exception("alpha is NaN");
                }
                double beta = alpha * alpha - sigma2 / sigma0;
                if (Double.IsNaN(beta))
                {
                    throw new Exception("beta is NaN");
                }
                return(GaussianOp.GaussianFromAlphaBeta(logOdds, s * alpha, beta, ForceProper));
            }
            else if (v > 1488 && m < 0)
            {
                double sigma0 = MMath.LogisticGaussianRatio(m, v, 0);
                double sigma1 = MMath.LogisticGaussianRatio(m, v, 1);
                double sigma2 = MMath.LogisticGaussianRatio(m, v, 2);
                double alpha, beta;
                alpha = sigma1 / sigma0;
                if (Double.IsNaN(alpha))
                {
                    throw new Exception("alpha is NaN");
                }
                beta = alpha * alpha - sigma2 / sigma0;
                if (Double.IsNaN(beta))
                {
                    throw new Exception("beta is NaN");
                }
                return(GaussianOp.GaussianFromAlphaBeta(logOdds, s * alpha, beta, ForceProper));
            }
            else
            {
                // the following code only works when sigma0 > 0
                // sigm0=0 can only happen here if v > 1488
                double sigma0 = MMath.LogisticGaussian(m, v);
                double sigma1 = MMath.LogisticGaussianDerivative(m, v);
                double sigma2 = MMath.LogisticGaussianDerivative2(m, v);
                double alpha, beta;
                alpha = sigma1 / sigma0;
                if (Double.IsNaN(alpha))
                {
                    throw new Exception("alpha is NaN");
                }
                if (m + 2 * v < -19)
                {
                    beta = Math.Exp(3 * m + 2.5 * v) / (sigma0 * sigma0);
                }
                else
                {
                    //beta = (sigma1*sigma1 - sigma2*sigma0)/(sigma0*sigma0);
                    beta = alpha * alpha - sigma2 / sigma0;
                }
                if (Double.IsNaN(beta))
                {
                    throw new Exception("beta is NaN");
                }
                return(GaussianOp.GaussianFromAlphaBeta(logOdds, s * alpha, beta, ForceProper));
            }
        }