Esempio n. 1
0
        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));
        }
Esempio n. 2
0
        /// <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);
        }
Esempio n. 3
0
        /// <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);
        }
Esempio n. 4
0
        /// <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);
        }
Esempio n. 5
0
        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;
		}
Esempio n. 11
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);
        }