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="MatrixMultiplyOp"]/message_doc[@name="AAverageConditional(DistributionStructArray2D{Gaussian, double}, DistributionStructArray2D{Gaussian, double}, double[,], DistributionStructArray2D{Gaussian, double})"]/*'/> public static GaussianArray2D AAverageConditional( [SkipIfUniform] GaussianArray2D matrixMultiply, [SkipIfUniform] GaussianArray2D A, double[,] B, GaussianArray2D result) { int rows = matrixMultiply.GetLength(0); int cols = matrixMultiply.GetLength(1); int inner = B.GetLength(0); if (result == null) { result = new GaussianArray2D(rows, inner); } // sum_{i,j} (m[i,j] - a[i,:]*b[:,j])^2/v[i,j] = // sum_{i,j} (m[i,j]^2 - 2m[i,j]a[i,:]*b[:,j] + a[i,:]*(b[:,j] b[:,j]')*a[i,:]')/v[i,j] // meanTimesPrec(a[i,:]) = sum_j (m[i,j]/v[i,j]) b[:,j] // prec(a[i,:]) = sum_j b[:,j]*b[:,j]'/v[i,j] Vector bj = Vector.Zero(inner); Vector mean = Vector.Zero(inner); VectorGaussian ai = new VectorGaussian(inner); PositiveDefiniteMatrix variance = new PositiveDefiniteMatrix(inner, inner); for (int i = 0; i < rows; i++) { ai.Precision.SetAllElementsTo(0.0); ai.MeanTimesPrecision.SetAllElementsTo(0.0); // we are projecting from family of full covariance Gaussians to diagonal // covariance, so we should include the context for (int c = 0; c < inner; c++) { ai.Precision[c, c] = A[i, c].Precision; ai.MeanTimesPrecision[c] = A[i, c].MeanTimesPrecision; } for (int j = 0; j < cols; j++) { Gaussian xij = matrixMultiply[i, j]; for (int k = 0; k < inner; k++) { bj[k] = B[k, j]; } if (xij.IsPointMass) { throw new NotImplementedException(LowRankNotSupportedMessage); } ai.Precision.SetToSumWithOuter(ai.Precision, xij.Precision, bj, bj); ai.MeanTimesPrecision.SetToSum(1.0, ai.MeanTimesPrecision, xij.MeanTimesPrecision, bj); } ai.GetMeanAndVariance(mean, variance); for (int k = 0; k < inner; k++) { Gaussian rik = result[i, k]; rik.SetMeanAndVariance(mean[k], variance[k, k]); result[i, k] = rik / A[i, k]; } } return(result); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="MatrixMultiplyOp"]/message_doc[@name="BAverageConditional(DistributionStructArray2D{Gaussian, double}, double[,], DistributionStructArray2D{Gaussian, double}, DistributionStructArray2D{Gaussian, double})"]/*'/> public static GaussianArray2D BAverageConditional( [SkipIfUniform] GaussianArray2D matrixMultiply, double[,] A, [SkipIfUniform] GaussianArray2D B, GaussianArray2D result) { int rows = matrixMultiply.GetLength(0); int cols = matrixMultiply.GetLength(1); int inner = A.GetLength(1); if (result == null) { result = new GaussianArray2D(inner, cols); } var ai = DenseVector.Zero(inner); var mean = DenseVector.Zero(inner); PositiveDefiniteMatrix variance = new PositiveDefiniteMatrix(inner, inner); var bj = new VectorGaussian(inner); for (int j = 0; j < cols; j++) { bj.Precision.SetAllElementsTo(0); bj.MeanTimesPrecision.SetAllElementsTo(0); // we are projecting from family of full covariance Gaussians to diagonal // covariance, so we should include the context for (int c = 0; c < inner; c++) { bj.Precision[c, c] = B[c, j].Precision; bj.MeanTimesPrecision[c] = B[c, j].MeanTimesPrecision; } for (int i = 0; i < rows; i++) { Gaussian xij = matrixMultiply[i, j]; for (int k = 0; k < inner; k++) { ai[k] = A[i, k]; } if (xij.IsPointMass) { throw new NotImplementedException(LowRankNotSupportedMessage); } bj.Precision.SetToSumWithOuter(bj.Precision, xij.Precision, ai, ai); bj.MeanTimesPrecision.SetToSum(1.0, bj.MeanTimesPrecision, xij.MeanTimesPrecision, ai); } bj.GetMeanAndVariance(mean, variance); for (int k = 0; k < inner; k++) { Gaussian rkj = result[k, j]; rkj.SetMeanAndVariance(mean[k], variance[k, k]); result[k, j] = rkj / B[k, j]; } } return(result); }
/// <summary>VMP message to <c>array</c>.</summary> /// <param name="vector">Incoming message from <c>vector</c>. 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 <c>array</c> as the random arguments are varied. The formula is <c>proj[sum_(vector) p(vector) factor(array,vector)]</c>.</para> /// </remarks> /// <exception cref="ImproperMessageException"> /// <paramref name="vector" /> is not a proper distribution.</exception> /// <typeparam name="GaussianList">The type of the resulting array.</typeparam> public static GaussianList ArrayAverageLogarithm <GaussianList>([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; Vector mean = Vector.Zero(length); PositiveDefiniteMatrix variance = new PositiveDefiniteMatrix(length, length); vector.GetMeanAndVariance(mean, variance); for (int i = 0; i < length; i++) { result[i] = Gaussian.FromMeanAndVariance(mean[i], variance[i, i]); } return(result); }
public static double LogAverageFactor([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 return(VectorGaussian.GetLogProb(productMean, aMean * bPoint, variance)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="SumVectorGaussianOp"]/message_doc[@name="ArrayAverageLogarithm1{TVectorGaussianList}(VectorGaussian, IList{VectorGaussian}, TVectorGaussianList)"]/*'/> /// <typeparam name="TVectorGaussianList">A list of <see cref="VectorGaussian"/> distributions.</typeparam> public static TVectorGaussianList ArrayAverageLogarithm1 <TVectorGaussianList>( [SkipIfUniform] VectorGaussian sum, [Stochastic, Proper] IList <VectorGaussian> array, TVectorGaussianList to_array) where TVectorGaussianList : IList <VectorGaussian> { // Check inputs for consistency int dimension = CheckArgumentConsistency(sum, sum, array, to_array); TVectorGaussianList result = to_array; var sumMean = Vector.Zero(dimension); var sumVariance = PositiveDefiniteMatrix.Identity(dimension); sum.GetMeanAndVariance(sumMean, sumVariance); // This version does one update of q(array[i]) for each array element in turn. Vector arraySumOfMean = Vector.Zero(dimension); foreach (VectorGaussian element in array) { arraySumOfMean.SetToSum(arraySumOfMean, element.GetMean()); } for (int i = 0; i < result.Count; i++) { arraySumOfMean.SetToDifference(arraySumOfMean, array[i].GetMean()); VectorGaussian oldResult = result[i]; result[i] = new VectorGaussian(sumMean - arraySumOfMean, sumVariance); oldResult.SetToRatio(result[i], oldResult); oldResult.SetToProduct(array[i], oldResult); arraySumOfMean.SetToSum(arraySumOfMean, oldResult.GetMean()); } return(result); }
/// <summary> /// EP message to 'array' /// </summary> /// <param name="array">Incoming message from 'array'.</param> /// <param name="vector">Incoming message from 'vector'. Must be a proper distribution. If any element is uniform, the result will be uniform.</param> /// <param name="to_vector">Outgoing message to 'vector'.</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 'array' as the random arguments are varied. /// The formula is <c>proj[p(array) sum_(vector) p(vector) factor(array,vector)]/p(array)</c>. /// </para></remarks> /// <exception cref="ImproperMessageException"><paramref name="vector"/> is not a proper distribution</exception> public static GaussianList ArrayAverageConditional <GaussianList>(IList <Gaussian> array, [SkipIfUniform] VectorGaussian vector, [Fresh] VectorGaussian to_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; VectorGaussian vectorTimesArray = new VectorGaussian(vector.Dimension); vectorTimesArray.SetToProduct(vector, to_vector); Vector mean = Vector.Zero(length); PositiveDefiniteMatrix variance = new PositiveDefiniteMatrix(length, length); vectorTimesArray.GetMeanAndVariance(mean, variance); for (int i = 0; i < length; i++) { Gaussian marginal = Gaussian.FromMeanAndVariance(mean[i], variance[i, i]); marginal.SetToRatio(marginal, array[i]); result[i] = marginal; } return(result); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="SumVectorGaussianOp"]/message_doc[@name="ArrayAverageConditional{TVectorGaussianList}(VectorGaussian, VectorGaussian, IList{VectorGaussian}, TVectorGaussianList)"]/*'/> public static TVectorGaussianList ArrayAverageConditional <TVectorGaussianList>( [SkipIfUniform] VectorGaussian sum, [Fresh] VectorGaussian to_sum, IList <VectorGaussian> array, TVectorGaussianList result) where TVectorGaussianList : IList <VectorGaussian>, SettableToUniform { // Check inputs for consistency int dimension = CheckArgumentConsistency(sum, to_sum, array, result); if (array.Count == 0) { return(result); } // It is tempting to put SkipIfAllUniform on array but this isn't correct if the array has one element if (array.Count == 1) { result[0].SetTo(sum); return(result); } if (!sum.IsProper()) { foreach (VectorGaussian element in result) { element.SetTo(sum); } return(result); } var elementMean = Vector.Zero(dimension); var elementVariance = PositiveDefiniteMatrix.Identity(dimension); // Check if an element of the array is uniform int indexOfUniform = -1; for (int i = 0; i < array.Count; i++) { array[i].GetMeanAndVariance(elementMean, elementVariance); // Instead of testing IsUniform, we need to test the more strict requirement that all diagonal // elements of variance are infinite due to the way we are doing the computations if (IsUniform(elementVariance)) { if (indexOfUniform >= 0) { // More than one element of array is uniform result.SetToUniform(); return(result); } indexOfUniform = i; } } Vector sumMean = Vector.Zero(dimension); PositiveDefiniteMatrix sumVariance = PositiveDefiniteMatrix.Identity(dimension); sum.GetMeanAndVariance(sumMean, sumVariance); Vector totalMean = Vector.Zero(sum.Dimension); PositiveDefiniteMatrix totalVariance = PositiveDefiniteMatrix.IdentityScaledBy(sum.Dimension, 0.0); if (indexOfUniform >= 0) { // Exactly one element of array is uniform for (int i = 0; i < array.Count; i++) { if (i == indexOfUniform) { continue; } array[i].GetMeanAndVariance(elementMean, elementVariance); totalMean.SetToSum(totalMean, elementMean); totalVariance.SetToSum(totalVariance, elementVariance); result[i].SetToUniform(); } // totalMean = sum_{i except indexOfUniform} array[i].GetMean() // totalVariance = sum_{i except indexOfUniform} array[i].GetVariance() totalMean.SetToDifference(sumMean, totalMean); totalVariance.SetToSum(sumVariance, totalVariance); result[indexOfUniform].SetMeanAndVariance(totalMean, totalVariance); return(result); } // At this point, the array has no uniform elements // Get the mean and variance of sum of all Gaussians to_sum.GetMeanAndVariance(totalMean, totalVariance); // Subtract it off from the mean and variance of the incoming Gaussian from Sum totalMean.SetToDifference(sumMean, totalMean); totalVariance.SetToSum(totalVariance, sumVariance); for (int i = 0; i < array.Count; i++) { array[i].GetMeanAndVariance(elementMean, elementVariance); elementMean.SetToSum(elementMean, totalMean); elementVariance.SetToDifference(totalVariance, elementVariance); result[i].SetMeanAndVariance(elementMean, elementVariance); } return(result); }
/// <summary> /// EP message to 'B' /// </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">Constant value for '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="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 'B' as the random arguments are varied. /// The formula is <c>proj[p(B) sum_(matrixMultiply) p(matrixMultiply) factor(matrixMultiply,A,B)]/p(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 BAverageConditional([SkipIfUniform] GaussianArray2D matrixMultiply, double[,] A, [SkipIfUniform] GaussianArray2D B, GaussianArray2D result) { int rows = matrixMultiply.GetLength(0); int cols = matrixMultiply.GetLength(1); int inner = A.GetLength(1); if (result == null) result = new GaussianArray2D(inner, cols); var ai = DenseVector.Zero(inner); var mean = DenseVector.Zero(inner); PositiveDefiniteMatrix variance = new PositiveDefiniteMatrix(inner, inner); var bj = new VectorGaussian(inner); for (int j = 0; j < cols; j++) { bj.Precision.SetAllElementsTo(0); bj.MeanTimesPrecision.SetAllElementsTo(0); // we are projecting from family of full covariance Gaussians to diagonal // covariance, so we should include the context for (int c = 0; c < inner; c++) { bj.Precision[c, c] = B[c, j].Precision; bj.MeanTimesPrecision[c] = B[c, j].MeanTimesPrecision; } for (int i = 0; i < rows; i++) { Gaussian xij = matrixMultiply[i, j]; for (int k = 0; k < inner; k++) { ai[k] = A[i, k]; } if (xij.IsPointMass) throw new NotImplementedException(LowRankNotSupportedMessage); bj.Precision.SetToSumWithOuter(bj.Precision, xij.Precision, ai, ai); bj.MeanTimesPrecision.SetToSum(1.0, bj.MeanTimesPrecision, xij.MeanTimesPrecision, ai); } bj.GetMeanAndVariance(mean, variance); for (int k = 0; k < inner; k++) { Gaussian rkj = result[k, j]; rkj.SetMeanAndVariance(mean[k], variance[k, k]); result[k, j] = rkj / B[k, j]; } } return result; }
/// <summary> /// EP 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="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 'A' as the random arguments are varied. /// The formula is <c>proj[p(A) sum_(matrixMultiply) p(matrixMultiply) factor(matrixMultiply,A,B)]/p(A)</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 AAverageConditional([SkipIfUniform] GaussianArray2D matrixMultiply, [SkipIfUniform] GaussianArray2D A, double[,] B, GaussianArray2D result) { int rows = matrixMultiply.GetLength(0); int cols = matrixMultiply.GetLength(1); int inner = B.GetLength(0); if (result == null) result = new GaussianArray2D(rows, inner); // sum_{i,j} (m[i,j] - a[i,:]*b[:,j])^2/v[i,j] = // sum_{i,j} (m[i,j]^2 - 2m[i,j]a[i,:]*b[:,j] + a[i,:]*(b[:,j] b[:,j]')*a[i,:]')/v[i,j] // meanTimesPrec(a[i,:]) = sum_j (m[i,j]/v[i,j]) b[:,j] // prec(a[i,:]) = sum_j b[:,j]*b[:,j]'/v[i,j] Vector bj = Vector.Zero(inner); Vector mean = Vector.Zero(inner); VectorGaussian ai = new VectorGaussian(inner); PositiveDefiniteMatrix variance = new PositiveDefiniteMatrix(inner, inner); for (int i = 0; i < rows; i++) { ai.Precision.SetAllElementsTo(0.0); ai.MeanTimesPrecision.SetAllElementsTo(0.0); // we are projecting from family of full covariance Gaussians to diagonal // covariance, so we should include the context for (int c = 0; c < inner; c++) { ai.Precision[c, c] = A[i, c].Precision; ai.MeanTimesPrecision[c] = A[i, c].MeanTimesPrecision; } for (int j = 0; j < cols; j++) { Gaussian xij = matrixMultiply[i, j]; for (int k = 0; k < inner; k++) { bj[k] = B[k, j]; } if (xij.IsPointMass) throw new NotImplementedException(LowRankNotSupportedMessage); ai.Precision.SetToSumWithOuter(ai.Precision, xij.Precision, bj, bj); ai.MeanTimesPrecision.SetToSum(1.0, ai.MeanTimesPrecision, xij.MeanTimesPrecision, bj); } ai.GetMeanAndVariance(mean, variance); for (int k = 0; k < inner; k++) { Gaussian rik = result[i, k]; rik.SetMeanAndVariance(mean[k], variance[k, k]); result[i, k] = rik / A[i, k]; } } 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); }