public static Gaussian BAverageConditional([SkipIfUniform] VectorGaussian product, [SkipIfUniform] VectorGaussian a, Gaussian b) { if (!b.IsPointMass) { throw new ArgumentException("b is not a point mass", nameof(b)); } double bPoint = b.Point; Vector productMean = Vector.Zero(product.Dimension); PositiveDefiniteMatrix productVariance = new PositiveDefiniteMatrix(product.Dimension, product.Dimension); product.GetMeanAndVariance(productMean, productVariance); Vector aMean = Vector.Zero(product.Dimension); PositiveDefiniteMatrix aVariance = new PositiveDefiniteMatrix(product.Dimension, product.Dimension); a.GetMeanAndVariance(aMean, aVariance); PositiveDefiniteMatrix variance = new PositiveDefiniteMatrix(product.Dimension, product.Dimension); variance.SetToSum(1, productVariance, bPoint * bPoint, aVariance); // variance = productVariance + aVariance * b^2 PositiveDefiniteMatrix precision = variance.Inverse(); Vector diff = aMean * bPoint; diff.SetToDifference(productMean, diff); // diff = productMean - aMean * b var precisionDiff = precision * diff; double dlogf = aMean.Inner(precisionDiff) + bPoint * (precisionDiff.Inner(aVariance * precisionDiff) - Matrix.TraceOfProduct(precision, aVariance)); double ddlogf = -1; return(Gaussian.FromDerivatives(bPoint, dlogf, ddlogf, GaussianProductOp.ForceProper)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="IntegralOp"]/message_doc[@name="UpperBoundAverageConditional(Gaussian, double, Func{double,double}, ITruncatableDistribution{double})"]/*'/> public static Gaussian UpperBoundAverageConditional(Gaussian integral, double upperBound, Func <double, double> func, ITruncatableDistribution <double> distribution) { CanGetLogProb <double> canGetLogProb = (CanGetLogProb <double>)distribution; double dlogf = integral.MeanTimesPrecision * func(upperBound) * Math.Exp(canGetLogProb.GetLogProb(upperBound)); double ddlogf = 0; // approximation ignoring integral.Precision return(Gaussian.FromDerivatives(upperBound, dlogf, ddlogf, false)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="RatioGaussianOp"]/message_doc[@name="ProbabilityAverageConditional(Gaussian, CanGetQuantile{double}, double)"]/*'/> public static Gaussian ProbabilityAverageConditional(Gaussian quantile, CanGetQuantile <double> canGetQuantile, double probability) { // The quantile function is the inverse function of the cdf. // The derivative of the quantile function is the reciprocal of the pdf. double x = canGetQuantile.GetQuantile(probability); CanGetLogProb <double> canGetLogProb = (CanGetLogProb <double>)canGetQuantile; double dlogp = quantile.MeanTimesPrecision / Math.Exp(canGetLogProb.GetLogProb(x)); double ddlogp = 0; // approximation ignoring quantile.Precision return(Gaussian.FromDerivatives(probability, dlogp, ddlogp, false)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="ProbBetweenOp"]/message_doc[@name="LowerBoundAverageConditional(Gaussian, CanGetProbLessThan{double}, double)"]/*'/> public static Gaussian LowerBoundAverageConditional(Gaussian probBetween, CanGetProbLessThan <double> canGetProbLessThan, double lowerBound) { CanGetLogProb <double> canGetLogProb = (CanGetLogProb <double>)canGetProbLessThan; // factor is N(ProbBetween(left, right); m, v) // logp = -(m - ProbBetween(left, right))^2/(2v) // dlogp = (m - ProbBetween(left, right))/v * dProbBetween(left, right) // dProbBetween(left, right)/dleft = -p(left) // ddlogp = (m - ProbBetween(left, right))/v * ddProbBetween(left, right) - dProbBetween(left, right)/v * dProbBetween(left, right) // (m - ProbBetween(left, right))/v -> m/v double dlogp = -Math.Exp(canGetLogProb.GetLogProb(lowerBound)) * probBetween.MeanTimesPrecision; double ddlogp = 0; // approximation ignoring probBetween.Precision return(Gaussian.FromDerivatives(lowerBound, dlogp, ddlogp, false)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="RatioGaussianOp"]/message_doc[@name="AAverageConditional(Gaussian, Gaussian, Gaussian)"]/*'/> public static Gaussian BAverageConditional([SkipIfUniform] Gaussian ratio, [SkipIfUniform] Gaussian a, Gaussian b) { //if (string.Empty.Length == 0) return GaussianProductOp.BAverageConditional(Gaussian.FromNatural(a.MeanTimesPrecision, Math.Min(a.Precision, 1e16)), Gaussian.FromNatural(ratio.MeanTimesPrecision, ratio.Precision + 1e-16), b); if (b.IsPointMass && ratio.Precision == 0) { // f(b) = int_a N(m; a/b, v) p(a) da // = N(m; ma/b, v + va/b^2) // logf = -0.5*log(v + va/b^2) -0.5*(m - ma/b)^2/(v + va/b^2) // dlogf = va/b^3/(v + va/b^2) -(m - ma/b)/(v + va/b^2)*(ma/b^2) + (m - ma/b)^2/(v + va/b^2)^2*(va/b^3) // -> -(m - ma/b)/v * (ma/b^2) double dlogp = -a.GetMean() / (b.Point * b.Point) * ratio.MeanTimesPrecision; double ddlogp = 0; return(Gaussian.FromDerivatives(b.Point, dlogp, ddlogp, false)); } else { throw new NotSupportedException(); } }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="ProbBetweenOp"]/message_doc[@name="UpperBoundAverageConditional(Gaussian, CanGetProbLessThan{double}, Gaussian)"]/*'/> public static Gaussian UpperBoundAverageConditional(Gaussian probBetween, CanGetProbLessThan <double> canGetProbLessThan, [RequiredArgument] Gaussian upperBound) { CanGetLogProb <double> canGetLogProb = (CanGetLogProb <double>)canGetProbLessThan; // factor is N(ProbBetween(left, right); m, v) if (upperBound.IsPointMass) { // logp = -(m - ProbBetween(left, right))^2/(2v) // dlogp = (m - ProbBetween(left, right))/v * dProbBetween(left, right) // dProbBetween(left, right)/dright = p(right) // ddlogp = (m - ProbBetween(left, right))/v * ddProbBetween(left, right) - dProbBetween(left, right)/v * dProbBetween(left, right) double dlogp = Math.Exp(canGetLogProb.GetLogProb(upperBound.Point)) * probBetween.MeanTimesPrecision; double ddlogp = 0; // approximation ignoring probBetween.Precision return(Gaussian.FromDerivatives(upperBound.Point, dlogp, ddlogp, false)); } else { throw new NotSupportedException(); } }
/// <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); } }
/// <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); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="MatrixVectorProductOp"]/message_doc[@name="AAverageConditional(VectorGaussian, DistributionArray2D{Gaussian, double}, Vector, PositiveDefiniteMatrix, DistributionStructArray2D{Gaussian, double})"]/*'/> public static DistributionStructArray2D <Gaussian, double> AAverageConditional([SkipIfUniform] VectorGaussian product, DistributionArray2D <Gaussian, double> A, Vector BMean, PositiveDefiniteMatrix BVariance, DistributionStructArray2D <Gaussian, double> result) { if (product.IsUniform()) { result.SetToUniform(); return(result); } if (!A.IsPointMass) { throw new ArgumentException("A is not a point mass"); } // logZ = log N(mProduct; A*BMean, vProduct + A*BVariance*A') // = -0.5 (mProduct - A*BMean)' inv(vProduct + A*BVariance*A') (mProduct - A*BMean) - 0.5 logdet(vProduct + A*BVariance*A') // = -0.5 (mProduct - A*BMean)' pPrec inv(pProduct + pProduct*A*BVariance*A'*pProduct) pProduct (mProduct - A*BMean) // - 0.5 logdet(pProduct + pProduct*A*BVariance*A'*pProduct) + logdet(pProduct) // dlogZ = 0.5 (dA*BMean)' pProduct inv(pProduct + pProduct*A*BVariance*A'*pProduct) pProduct (mProduct - A*BMean) // +0.5 (mProduct - A*BMean)' pProduct inv(pProduct + pProduct*A*BVariance*A'*pProduct) pProduct (dA*BMean) // +0.5 (mProduct - A*BMean)' pProduct inv(pProduct + pProduct*A*BVariance*A'*pProduct) (pProduct*dA*BVariance*A'*pProduct + pProduct*A*BVariance*dA'*pProduct) inv(pProduct + pProduct*A*BVariance*A'*pProduct) pProduct (mProduct - A*BMean) // - 0.5 tr(inv(pProduct + pProduct*A*BVariance*A'*pProduct) (pProduct*dA*BVariance*A'*pProduct + pProduct*A*BVariance*dA'*pProduct)) // dlogZ/dA = pProduct inv(pProduct + pProduct*A*BVariance*A'*pProduct) pProduct (mProduct - A*BMean) BMean' // + pProduct inv(pProduct + pProduct*A*BVariance*A'*pProduct) pProduct (mProduct - A*BMean) (mProduct - A*BMean)' pProduct inv(pProduct + pProduct*A*BVariance*A'*pProduct) pProduct*A*BVariance // - pProduct inv(pProduct + pProduct*A*BVariance*A'*pProduct) pProduct A*BVariance var Amatrix = new Matrix(A.Point); var pProductA = product.Precision * Amatrix; var pProductABV = pProductA * BVariance; PositiveDefiniteMatrix prec = new PositiveDefiniteMatrix(product.Dimension, product.Dimension); prec.SetToSum(product.Precision, pProductABV * pProductA.Transpose()); // pProductA is now free for (int i = 0; i < prec.Rows; i++) { if (prec[i, i] == 0) { prec[i, i] = 1; } } var v = prec.Inverse(); var ABM = Amatrix * BMean; var pProductABM = product.Precision * ABM; var diff = pProductABM; diff.SetToDifference(product.MeanTimesPrecision, pProductABM); // ABM is now free var pProductV = product.Precision * v; var pProductVdiff = ABM; pProductVdiff.SetToProduct(pProductV, diff); var Vdiff = v * diff; pProductV.Scale(-1); pProductV.SetToSumWithOuter(pProductV, 1, pProductVdiff, Vdiff); Matrix dlogZ = pProductA; dlogZ.SetToProduct(pProductV, pProductABV); dlogZ.SetToSumWithOuter(dlogZ, 1, pProductVdiff, BMean); int rows = A.GetLength(0); int cols = A.GetLength(1); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { double dlogp = dlogZ[i, j]; // for now, we don't compute the second derivative. double ddlogp = -1; result[i, j] = Gaussian.FromDerivatives(A[i, j].Point, dlogp, ddlogp, false); } } return(result); }
public static Gaussian DAverageConditional([SkipIfUniform] Gamma exp, [Proper] Gaussian d) { // as a function of d, the factor is Ga(exp(d); shape, rate) = exp(d*(shape-1) -rate*exp(d)) if (exp.IsUniform()) { return(Gaussian.Uniform()); } if (exp.IsPointMass) { return(ExpOp.DAverageConditional(exp.Point)); } if (exp.Rate < 0) { throw new ImproperMessageException(exp); } if (exp.Rate == 0) { return(Gaussian.FromNatural(exp.Shape - 1, 0)); } if (d.IsUniform()) { if (exp.Shape <= 1) { throw new ArgumentException("The posterior has infinite variance due to input of Exp distributed as " + d + " and output of Exp distributed as " + exp + " (shape <= 1)"); } // posterior for d is a shifted log-Gamma distribution: // exp((a-1)*d - b*exp(d)) =propto exp(a*(d+log(b)) - exp(d+log(b))) // we find the Gaussian with same moments. // u = d+log(b) // E[u] = digamma(a-1) // E[d] = E[u]-log(b) = digamma(a-1)-log(b) // var(d) = var(u) = trigamma(a-1) double lnRate = Math.Log(exp.Rate); return(new Gaussian(MMath.Digamma(exp.Shape - 1) - lnRate, MMath.Trigamma(exp.Shape - 1))); } double aMinus1 = exp.Shape - 1; double b = exp.Rate; if (d.IsPointMass) { double x = d.Point; double expx = Math.Exp(x); double dlogf = aMinus1 - b * expx; double ddlogf = -b * expx; return(Gaussian.FromDerivatives(x, dlogf, ddlogf, true)); } double dmode, dmin, dmax; GetIntegrationBounds(exp, d, out dmode, out dmin, out dmax); double expmode = Math.Exp(dmode); int n = QuadratureNodeCount; double inc = (dmax - dmin) / (n - 1); MeanVarianceAccumulator mva = new MeanVarianceAccumulator(); for (int i = 0; i < n; i++) { double x = dmin + i * inc; double xMinusMode = x - dmode; double diff = aMinus1 * xMinusMode - b * (Math.Exp(x) - expmode) - 0.5 * ((x * x - dmode * dmode) * d.Precision - 2 * xMinusMode * d.MeanTimesPrecision); double p = Math.Exp(diff); mva.Add(x, p); if (double.IsNaN(mva.Variance)) { throw new Exception(); } } double dMean = mva.Mean; double dVariance = mva.Variance; Gaussian result = Gaussian.FromMeanAndVariance(dMean, dVariance); result.SetToRatio(result, d, true); return(result); }