/// <summary> /// VMP message to 'matrixMultiply' /// </summary> /// <param name="A">Incoming message from 'A'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="B">Incoming message from 'B'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="result">Modified to contain the outgoing message</param> /// <returns><paramref name="result"/></returns> /// <remarks><para> /// The outgoing message is a distribution matching the moments of 'matrixMultiply' as the random arguments are varied. /// The formula is <c>proj[sum_(A,B) p(A,B) factor(matrixMultiply,A,B)]</c>. /// </para></remarks> /// <exception cref="ImproperMessageException"><paramref name="A"/> is not a proper distribution</exception> /// <exception cref="ImproperMessageException"><paramref name="B"/> is not a proper distribution</exception> public static GaussianArray2D MatrixMultiplyAverageLogarithm([SkipIfUniform] DistributionArray2D<Gaussian> A, [SkipIfUniform] DistributionArray2D<Gaussian> B, GaussianArray2D result) { if (result == null) result = new DistributionStructArray2D<Gaussian, double>(A.GetLength(0), B.GetLength(1)); // x[i,j] = sum_k a[i,k]*b[k,j] // E(x[i,j]) = sum_k E(a[i,k])*E(b[k,j]) // var(x[i,j]) = sum_k E(a[i,k])^2*var(b[k,j]) + var(a[i,k])*E(b[k,j])^2 + var(a[i,k])*var(b[k,j]) int rows = result.GetLength(0); int cols = result.GetLength(1); int inner = A.GetLength(1); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { double mean = 0; double var = 0; for (int k = 0; k < inner; k++) { double Am, Av, Bm, Bv; A[i, k].GetMeanAndVariance(out Am, out Av); B[k, j].GetMeanAndVariance(out Bm, out Bv); mean += Am * Bm; var += Av * Bm * Bm + Bv * Am * Am + Av * Bv; } Gaussian rij = result[i, j]; rij.SetMeanAndVariance(mean, var); result[i, j] = rij; } } return result; }
/// <summary> /// VMP message to 'matrixMultiply' /// </summary> /// <param name="A">Incoming message from 'A'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="B">Incoming message from 'B'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="result">Modified to contain the outgoing message</param> /// <returns><paramref name="result"/></returns> /// <remarks><para> /// The outgoing message is a distribution matching the moments of 'matrixMultiply' as the random arguments are varied. /// The formula is <c>proj[sum_(A,B) p(A,B) factor(matrixMultiply,A,B)]</c>. /// </para></remarks> /// <exception cref="ImproperMessageException"><paramref name="A"/> is not a proper distribution</exception> /// <exception cref="ImproperMessageException"><paramref name="B"/> is not a proper distribution</exception> public static GaussianArray2D MatrixMultiplyAverageLogarithm([SkipIfUniform] DistributionArray2D <Gaussian> A, [SkipIfUniform] DistributionArray2D <Gaussian> B, GaussianArray2D result) { if (result == null) { result = new DistributionStructArray2D <Gaussian, double>(A.GetLength(0), B.GetLength(1)); } // x[i,j] = sum_k a[i,k]*b[k,j] // E(x[i,j]) = sum_k E(a[i,k])*E(b[k,j]) // var(x[i,j]) = sum_k E(a[i,k])^2*var(b[k,j]) + var(a[i,k])*E(b[k,j])^2 + var(a[i,k])*var(b[k,j]) int rows = result.GetLength(0); int cols = result.GetLength(1); int inner = A.GetLength(1); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { double mean = 0; double var = 0; for (int k = 0; k < inner; k++) { double Am, Av, Bm, Bv; A[i, k].GetMeanAndVariance(out Am, out Av); B[k, j].GetMeanAndVariance(out Bm, out Bv); mean += Am * Bm; var += Av * Bm * Bm + Bv * Am * Am + Av * Bv; } Gaussian rij = result[i, j]; rij.SetMeanAndVariance(mean, var); result[i, j] = rij; } } return(result); }
/// <summary> /// VMP message to 'A' /// </summary> /// <param name="matrixMultiply">Incoming message from 'matrixMultiply'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="A">Incoming message from 'A'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="B">Constant value for 'B'.</param> /// <param name="to_A">Previous outgoing message to 'A'.</param> /// <returns>The outgoing VMP message to the 'A' argument</returns> /// <remarks><para> /// The outgoing message is the factor viewed as a function of 'A' with 'matrixMultiply' integrated out. /// The formula is <c>sum_matrixMultiply p(matrixMultiply) factor(matrixMultiply,A,B)</c>. /// </para></remarks> /// <exception cref="ImproperMessageException"><paramref name="matrixMultiply"/> is not a proper distribution</exception> /// <exception cref="ImproperMessageException"><paramref name="A"/> is not a proper distribution</exception> public static GaussianArray2D AAverageLogarithm([SkipIfUniform] GaussianArray2D matrixMultiply, [Proper, Stochastic] GaussianArray2D A, double[,] B, GaussianArray2D to_A) { GaussianArray2D result = to_A; if (result == null) { result = new DistributionStructArray2D <Gaussian, double>(A.GetLength(0), A.GetLength(1)); } int rows = matrixMultiply.GetLength(0); int cols = matrixMultiply.GetLength(1); int inner = A.GetLength(1); double[] ab = new double[cols]; //Gaussian temp = new Gaussian(); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { double sum = 0.0; for (int k = 0; k < inner; k++) { sum += A[i, k].GetMean() * B[k, j]; } ab[j] = sum; } for (int k = 0; k < inner; k++) { double prec = 0.0; double pm = 0.0; double Am = A[i, k].GetMean(); for (int j = 0; j < cols; j++) { double Bm = B[k, j]; Gaussian x = matrixMultiply[i, j]; prec += (Bm * Bm) * x.Precision; //pm += Bm * (x.MeanTimesPrecision - x.Precision * (ab[j] - Am * Bm)); //Replace previous line with: ab[j] -= Am * Bm; pm += Bm * (x.MeanTimesPrecision - x.Precision * ab[j]); } Gaussian old_result = (Gaussian)result[i, k].Clone(); Gaussian rik = result[i, k]; rik.Precision = prec; rik.MeanTimesPrecision = pm; result[i, k] = rik; Gaussian partial = A[i, k] / old_result; Gaussian newPosterior = partial * rik; Am = newPosterior.GetMean(); for (int j = 0; j < cols; j++) { ab[j] += Am * B[k, j]; } } } return(result); }
/// <summary> /// VMP message to 'X'. /// </summary> /// <param name="A">Incoming message from 'a'. Must be a proper distribution. If uniform, the result will be uniform.</param> /// <param name="B">Incoming message from 'b'. Must be a proper distribution. If uniform, the result will be uniform.</param> /// <returns>The outgoing VMP message to the 'X' argument.</returns> /// <remarks><para> /// The outgoing message is the exponential of the integral of the log-factor times incoming messages, over all arguments except 'innerProduct'. /// The formula is <c>int log(f(innerProduct,x)) q(x) dx</c> where <c>x = (a,b)</c>. /// </para></remarks> /// <exception cref="ImproperMessageException"><paramref name="A"/> is not a proper distribution</exception> /// <exception cref="ImproperMessageException"><paramref name="A"/> is not a proper distribution</exception> public static GaussianArray2D XAverageLogarithm([SkipIfAllUniform] VectorGaussianArray A, [SkipIfAllUniform] VectorGaussianArray B, GaussianArray2D result) { int I = A.GetLength(0), J = B.Count, K = A[0].Dimension; if (result == null) { result = new DistributionStructArray2D <Gaussian, double>(I, J); } // p(x|a,b) = N(E[a]'*E[b], E[b]'*var(a)*E[b] + E[a]'*var(b)*E[a] + trace(var(a)*var(b))) var ma = new Vector[I]; var mb = new Vector[J]; var va = new PositiveDefiniteMatrix[I]; var vb = new PositiveDefiniteMatrix[J]; for (int i = 0; i < I; i++) { ma[i] = Vector.Zero(K); va[i] = new PositiveDefiniteMatrix(K, K); A[i].GetMeanAndVariance(ma[i], va[i]); } for (int j = 0; j < J; j++) { mb[j] = Vector.Zero(K); vb[j] = new PositiveDefiniteMatrix(K, K); B[j].GetMeanAndVariance(mb[j], vb[j]); } // Uses John Winn's rule for deterministic factors. // Strict variational inference would set the variance to 0. for (int i = 0; i < I; i++) { for (int j = 0; j < J; j++) { var rij = result[i, j]; rij.SetMeanAndVariance(ma[i].Inner(mb[j]), va[i].QuadraticForm(mb[j]) + vb[j].QuadraticForm(ma[i]) + va[i].Inner(vb[j])); result[i, j] = rij; } } return(result); }
/// <summary> /// VMP message to 'A' /// </summary> /// <param name="matrixMultiply">Incoming message from 'matrixMultiply'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="A">Incoming message from 'A'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="B">Constant value for 'B'.</param> /// <param name="to_A">Previous outgoing message to 'A'.</param> /// <returns>The outgoing VMP message to the 'A' argument</returns> /// <remarks><para> /// The outgoing message is the factor viewed as a function of 'A' with 'matrixMultiply' integrated out. /// The formula is <c>sum_matrixMultiply p(matrixMultiply) factor(matrixMultiply,A,B)</c>. /// </para></remarks> /// <exception cref="ImproperMessageException"><paramref name="matrixMultiply"/> is not a proper distribution</exception> /// <exception cref="ImproperMessageException"><paramref name="A"/> is not a proper distribution</exception> public static GaussianArray2D AAverageLogarithm([SkipIfUniform] GaussianArray2D matrixMultiply, [Proper, Stochastic] GaussianArray2D A, double[,] B, GaussianArray2D to_A) { GaussianArray2D result = to_A; if (result == null) result = new DistributionStructArray2D<Gaussian, double>(A.GetLength(0), A.GetLength(1)); int rows = matrixMultiply.GetLength(0); int cols = matrixMultiply.GetLength(1); int inner = A.GetLength(1); double[] ab = new double[cols]; //Gaussian temp = new Gaussian(); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { double sum = 0.0; for (int k = 0; k < inner; k++) { sum += A[i, k].GetMean() * B[k, j]; } ab[j] = sum; } for (int k = 0; k < inner; k++) { double prec = 0.0; double pm = 0.0; double Am = A[i, k].GetMean(); for (int j = 0; j < cols; j++) { double Bm = B[k, j]; Gaussian x = matrixMultiply[i, j]; prec += (Bm * Bm) * x.Precision; //pm += Bm * (x.MeanTimesPrecision - x.Precision * (ab[j] - Am * Bm)); //Replace previous line with: ab[j] -= Am * Bm; pm += Bm * (x.MeanTimesPrecision - x.Precision * ab[j]); } Gaussian old_result = (Gaussian)result[i, k].Clone(); Gaussian rik = result[i, k]; rik.Precision = prec; rik.MeanTimesPrecision = pm; result[i, k] = rik; Gaussian partial = A[i, k] / old_result; Gaussian newPosterior = partial * rik; Am = newPosterior.GetMean(); for (int j = 0; j < cols; j++) ab[j] += Am * B[k, j]; } } return result; }
/// <summary> /// VMP message to 'A' /// </summary> /// <param name="matrixMultiply">Incoming message from 'matrixMultiply'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="A">Incoming message from 'A'.</param> /// <param name="B">Incoming message from 'B'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="to_A">Previous outgoing message to 'A'.</param> /// <returns>The outgoing VMP message to the 'A' argument</returns> /// <remarks><para> /// The outgoing message is the exponential of the average log-factor value, where the average is over all arguments except 'A'. /// Because the factor is deterministic, 'matrixMultiply' is integrated out before taking the logarithm. /// The formula is <c>exp(sum_(B) p(B) log(sum_matrixMultiply p(matrixMultiply) factor(matrixMultiply,A,B)))</c>. /// </para></remarks> /// <exception cref="ImproperMessageException"><paramref name="matrixMultiply"/> is not a proper distribution</exception> /// <exception cref="ImproperMessageException"><paramref name="B"/> is not a proper distribution</exception> public static GaussianArray2D AAverageLogarithm([SkipIfUniform] GaussianArray2D matrixMultiply, [Stochastic] GaussianArray2D A, [SkipIfUniform] GaussianArray2D B, GaussianArray2D to_A) { GaussianArray2D result = to_A; if (result == null) result = new DistributionStructArray2D<Gaussian, double>(A.GetLength(0), A.GetLength(1)); // E[log N(x[i,j]; a[i,:]*b[:,j], 0)] = -0.5 E[(x[i,j]- sum_k a[i,k]*b[k,j])^2]/0 // = -0.5 (E[x[i,j]^2] - 2 E[x[i,j]] a[i,k] E[b[k,j]] + a[i,k] a[i,k2] E(b[k,j] b[k2,j]))/0 // a[i,k] * (-2 E[x[i,j]] E[b[k,j]] + sum_{k2 not k} E[a[i,k2]] E(b[k,j] b[k2,j])) // a[i,k]^2 * E(b[k,j]^2) // message to a[i,k] = N(a; inv(prec[i,k])*(sum_j E[b[k,j]]*res[i,j,k]/var(x[i,j])), inv(prec[i,k])) // where res[i,j,k] = E[x[i,j]] - sum_{k2 not k} E[a[i,k2]] E[b[k2,j]] // prec[i,k] = sum_j E(b[k,j]^2)/var(x[i,j]) // result.Precision = prec[i,k] // result.MeanTimesPrecision = sum_j E[b[k,j]]*res[i,j,k]/var(x[i,j]) // = sum_j E[b[k,j]]*(X.MeanTimesPrecision - X.precision*(sum_{k2 not k})) int rows = matrixMultiply.GetLength(0); int cols = matrixMultiply.GetLength(1); int inner = A.GetLength(1); double[] ab = new double[cols]; //Gaussian temp = new Gaussian(); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { double sum = 0.0; for (int k = 0; k < inner; k++) { sum += A[i, k].GetMean() * B[k, j].GetMean(); } ab[j] = sum; } for (int k = 0; k < inner; k++) { double prec = 0.0; double pm = 0.0; double Am = A[i, k].GetMean(); for (int j = 0; j < cols; j++) { double Bm, Bv; B[k, j].GetMeanAndVariance(out Bm, out Bv); Gaussian x = matrixMultiply[i, j]; prec += (Bv + Bm * Bm) * x.Precision; //pm += Bm * (x.MeanTimesPrecision - x.Precision * (ab[j] - Am * Bm)); //Replace previous line with: ab[j] -= Am * Bm; pm += Bm * (x.MeanTimesPrecision - x.Precision * ab[j]); } Gaussian old_result = (Gaussian)result[i, k].Clone(); Gaussian rik = result[i, k]; rik.Precision = prec; rik.MeanTimesPrecision = pm; result[i, k] = rik; Gaussian partial = A[i, k] / old_result; Gaussian newPosterior = partial * rik; Am = newPosterior.GetMean(); for (int j = 0; j < cols; j++) ab[j] += Am * B[k, j].GetMean(); } } return result; }
/// <summary> /// VMP message to 'X'. /// </summary> /// <param name="A">Incoming message from 'a'. Must be a proper distribution. If uniform, the result will be uniform.</param> /// <param name="B">Incoming message from 'b'. Must be a proper distribution. If uniform, the result will be uniform.</param> /// <returns>The outgoing VMP message to the 'X' argument.</returns> /// <remarks><para> /// The outgoing message is the exponential of the integral of the log-factor times incoming messages, over all arguments except 'innerProduct'. /// The formula is <c>int log(f(innerProduct,x)) q(x) dx</c> where <c>x = (a,b)</c>. /// </para></remarks> /// <exception cref="ImproperMessageException"><paramref name="A"/> is not a proper distribution</exception> /// <exception cref="ImproperMessageException"><paramref name="A"/> is not a proper distribution</exception> public static GaussianArray2D XAverageLogarithm([SkipIfAllUniform] VectorGaussianArray A, [SkipIfAllUniform] VectorGaussianArray B, GaussianArray2D result) { int I = A.GetLength(0), J = B.Count, K = A[0].Dimension; if (result == null) result = new DistributionStructArray2D<Gaussian, double>(I, J); // p(x|a,b) = N(E[a]'*E[b], E[b]'*var(a)*E[b] + E[a]'*var(b)*E[a] + trace(var(a)*var(b))) var ma = new Vector[I]; var mb = new Vector[J]; var va = new PositiveDefiniteMatrix[I]; var vb = new PositiveDefiniteMatrix[J]; for (int i = 0; i < I; i++) { ma[i] = Vector.Zero(K); va[i] = new PositiveDefiniteMatrix(K, K); A[i].GetMeanAndVariance(ma[i], va[i]); } for (int j = 0; j < J; j++) { mb[j] = Vector.Zero(K); vb[j] = new PositiveDefiniteMatrix(K, K); B[j].GetMeanAndVariance(mb[j], vb[j]); } // Uses John Winn's rule for deterministic factors. // Strict variational inference would set the variance to 0. for (int i = 0; i < I; i++) for (int j = 0; j < J; j++) { var rij = result[i, j]; rij.SetMeanAndVariance(ma[i].Inner(mb[j]), va[i].QuadraticForm(mb[j]) + vb[j].QuadraticForm(ma[i]) + va[i].Inner(vb[j])); result[i, j] = rij; } 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); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="MatrixMultiplyOp"]/message_doc[@name="AAverageLogarithm(DistributionStructArray2D{Gaussian, double}, DistributionStructArray2D{Gaussian, double}, double[,], DistributionStructArray2D{Gaussian, double})"]/*'/> public static GaussianArray2D AAverageLogarithm( [SkipIfUniform] GaussianArray2D matrixMultiply, [Proper, Stochastic] GaussianArray2D A, double[,] B, GaussianArray2D to_A) { GaussianArray2D result = to_A; if (result == null) { result = new DistributionStructArray2D <Gaussian, double>(A.GetLength(0), A.GetLength(1)); } int rows = matrixMultiply.GetLength(0); int cols = matrixMultiply.GetLength(1); int inner = A.GetLength(1); double[] ab = new double[cols]; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { double sum = 0.0; for (int k = 0; k < inner; k++) { sum += A[i, k].GetMean() * B[k, j]; } ab[j] = sum; } for (int k = 0; k < inner; k++) { Gaussian old_result = result[i, k]; Gaussian rik = Gaussian.Uniform(); double Am = A[i, k].GetMean(); for (int j = 0; j < cols; j++) { double Bm = B[k, j]; if (Bm == 0) { continue; } Gaussian x = matrixMultiply[i, j]; ab[j] -= Am * Bm; Gaussian msg; if (x.IsPointMass) { msg = Gaussian.PointMass(x.Point / Bm); } else { double prec = (Bm * Bm) * x.Precision; //pm += Bm * (x.MeanTimesPrecision - x.Precision * (ab[j] - Am * Bm)); //Replace previous line with: double pm = Bm * (x.MeanTimesPrecision - x.Precision * ab[j]); msg = Gaussian.FromNatural(pm, prec); } rik.SetToProduct(rik, msg); } result[i, k] = rik; Gaussian partial = A[i, k] / old_result; Gaussian newPosterior = partial * rik; Am = newPosterior.GetMean(); for (int j = 0; j < cols; j++) { ab[j] += Am * B[k, j]; } } } return(result); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="MatrixMultiplyOp"]/message_doc[@name="AAverageLogarithm(DistributionStructArray2D{Gaussian, double}, DistributionStructArray2D{Gaussian, double}, DistributionStructArray2D{Gaussian, double}, DistributionStructArray2D{Gaussian, double})"]/*'/> public static GaussianArray2D AAverageLogarithm( [SkipIfUniform] GaussianArray2D matrixMultiply, [Stochastic] GaussianArray2D A, [SkipIfUniform] GaussianArray2D B, GaussianArray2D to_A) { GaussianArray2D result = to_A; if (result == null) { result = new DistributionStructArray2D <Gaussian, double>(A.GetLength(0), A.GetLength(1)); } // E[log N(x[i,j]; a[i,:]*b[:,j], 0)] = -0.5 E[(x[i,j]- sum_k a[i,k]*b[k,j])^2]/0 // = -0.5 (E[x[i,j]^2] - 2 E[x[i,j]] a[i,k] E[b[k,j]] + a[i,k] a[i,k2] E(b[k,j] b[k2,j]))/0 // a[i,k] * (-2 E[x[i,j]] E[b[k,j]] + sum_{k2 not k} E[a[i,k2]] E(b[k,j] b[k2,j])) // a[i,k]^2 * E(b[k,j]^2) // message to a[i,k] = N(a; inv(prec[i,k])*(sum_j E[b[k,j]]*res[i,j,k]/var(x[i,j])), inv(prec[i,k])) // where res[i,j,k] = E[x[i,j]] - sum_{k2 not k} E[a[i,k2]] E[b[k2,j]] // prec[i,k] = sum_j E(b[k,j]^2)/var(x[i,j]) // result.Precision = prec[i,k] // result.MeanTimesPrecision = sum_j E[b[k,j]]*res[i,j,k]/var(x[i,j]) // = sum_j E[b[k,j]]*(X.MeanTimesPrecision - X.precision*(sum_{k2 not k})) int rows = matrixMultiply.GetLength(0); int cols = matrixMultiply.GetLength(1); int inner = A.GetLength(1); double[] ab = new double[cols]; //Gaussian temp = new Gaussian(); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { double sum = 0.0; for (int k = 0; k < inner; k++) { sum += A[i, k].GetMean() * B[k, j].GetMean(); } ab[j] = sum; } for (int k = 0; k < inner; k++) { Gaussian old_result = result[i, k]; Gaussian rik = Gaussian.Uniform(); double Am = A[i, k].GetMean(); for (int j = 0; j < cols; j++) { double Bm, Bv; B[k, j].GetMeanAndVariance(out Bm, out Bv); if (Bm == 0) { continue; } Gaussian x = matrixMultiply[i, j]; ab[j] -= Am * Bm; Gaussian msg; if (x.IsPointMass) { msg = Gaussian.PointMass((x.Point * Bm) / (Bv + Bm * Bm)); } else { double prec = (Bv + Bm * Bm) * x.Precision; //pm += Bm * (x.MeanTimesPrecision - x.Precision * (ab[j] - Am * Bm)); //Replace previous line with: double pm = Bm * (x.MeanTimesPrecision - x.Precision * ab[j]); msg = Gaussian.FromNatural(pm, prec); } rik.SetToProduct(rik, msg); } result[i, k] = rik; Gaussian partial = A[i, k] / old_result; Gaussian newPosterior = partial * rik; Am = newPosterior.GetMean(); for (int j = 0; j < cols; j++) { ab[j] += Am * B[k, j].GetMean(); } } } return(result); }