Пример #1
0
        /// <summary>
        ///   Fits the underlying distribution to a given set of observations.
        /// </summary>
        ///
        /// <param name="observations">The array of observations to fit the model against. The array
        ///   elements can be either of type double (for univariate data) or
        ///   type double[] (for multivariate data).</param>
        /// <param name="weights">The weight vector containing the weight for each of the samples.</param>
        /// <param name="options">Optional arguments which may be used during fitting, such
        ///   as regularization constants and additional parameters.</param>
        ///
        /// <example>
        ///   Please see <see cref="MultivariateNormalDistribution"/>.
        /// </example>
        ///
        public void Fit(double[][] observations, double[] weights, NormalOptions options)
        {
            double[] means;
            double[,] cov;


            if (weights != null)
            {
#if DEBUG
                for (int i = 0; i < weights.Length; i++)
                {
                    if (Double.IsNaN(weights[i]) || Double.IsInfinity(weights[i]))
                    {
                        throw new ArgumentException("Invalid numbers in the weight vector.", "weights");
                    }
                }
#endif
                // Compute weighted mean vector
                means = Statistics.Tools.WeightedMean(observations, weights);

                // Compute weighted covariance matrix
                if (options != null && options.Diagonal)
                {
                    cov = Matrix.Diagonal(Statistics.Tools.WeightedVariance(observations, weights, means));
                }
                else
                {
                    cov = Statistics.Tools.WeightedCovariance(observations, weights, means);
                }
            }
            else
            {
                // Compute mean vector
                means = Statistics.Tools.Mean(observations);

                // Compute covariance matrix
                if (options != null && options.Diagonal)
                {
                    cov = Matrix.Diagonal(Statistics.Tools.Variance(observations, means));
                }
                cov = Statistics.Tools.Covariance(observations, means);
            }


            CholeskyDecomposition      chol = null;
            SingularValueDecomposition svd  = null;

            if (options == null)
            {
                // We don't have further options. Just attempt a standard
                // fitting. If the matrix is not positive semi-definite,
                // throw an exception.

                chol = new CholeskyDecomposition(cov,
                                                 robust: false, lowerTriangular: true);

                if (!chol.PositiveDefinite)
                {
                    throw new NonPositiveDefiniteMatrixException("Covariance matrix is not positive "
                                                                 + "definite. Try specifying a regularization constant in the fitting options "
                                                                 + "(there is an example in the Multivariate Normal Distribution documentation).");
                }

                // Become the newly fitted distribution.
                initialize(means, cov, chol, svd: null);

                return;
            }

            // We have options. In this case, we will either be using the SVD
            // or we can add a regularization constant until the covariance
            // matrix becomes positive semi-definite.

            if (options.Robust)
            {
                svd = new SingularValueDecomposition(cov, true, true, true);

                // No need to apply a regularization constant in this case
                // Become the newly fitted distribution.
                initialize(means, cov, null, svd);

                return;
            }


            chol = new CholeskyDecomposition(cov,
                                             robust: false, lowerTriangular: true);

            // Check if need to add a regularization constant
            double regularization = options.Regularization;

            if (regularization > 0)
            {
                int dimension = observations[0].Length;

                while (!chol.PositiveDefinite)
                {
                    for (int i = 0; i < dimension; i++)
                    {
                        for (int j = 0; j < dimension; j++)
                        {
                            if (Double.IsNaN(cov[i, j]) || Double.IsInfinity(cov[i, j]))
                            {
                                cov[i, j] = 0.0;
                            }
                        }

                        cov[i, i] += regularization;
                    }

                    chol = new CholeskyDecomposition(cov, false, true);
                }
            }

            if (!chol.PositiveDefinite)
            {
                throw new NonPositiveDefiniteMatrixException("Covariance matrix is not positive "
                                                             + "definite. Try specifying a regularization constant in the fitting options "
                                                             + "(there is an example in the Multivariate Normal Distribution documentation).");
            }

            // Become the newly fitted distribution.
            initialize(means, cov, chol, svd: null);
        }
Пример #2
0
        public void AllTests()
        {
            Matrix A, B, C, Z, O, I, R, S, X, SUB, M, T, SQ, DEF, SOL;
            double tmp;

            double[]   columnwise = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 };
            double[]   rowwise = { 1.0, 4.0, 7.0, 10.0, 2.0, 5.0, 8.0, 11.0, 3.0, 6.0, 9.0, 12.0 };
            double[][] avals = { new double[] { 1.0, 4.0, 7.0, 10.0 }, new double[] { 2.0, 5.0, 8.0, 11.0 }, new double[] { 3.0, 6.0, 9.0, 12.0 } };
            double[][] rankdef = avals;
            double[][] tvals = { new double[] { 1.0, 2.0, 3.0 }, new double[] { 4.0, 5.0, 6.0 }, new double[] { 7.0, 8.0, 9.0 }, new double[] { 10.0, 11.0, 12.0 } };
            double[][] subavals = { new double[] { 5.0, 8.0, 11.0 }, new double[] { 6.0, 9.0, 12.0 } };
            double[][] pvals = { new double[] { 25, -5, 10 }, new double[] { -5, 17, 10 }, new double[] { 10, 10, 62 } };
            double[][] ivals = { new double[] { 1.0, 0.0, 0.0, 0.0 }, new double[] { 0.0, 1.0, 0.0, 0.0 }, new double[] { 0.0, 0.0, 1.0, 0.0 } };
            double[][] evals = { new double[] { 0.0, 1.0, 0.0, 0.0 }, new double[] { 1.0, 0.0, 2e-7, 0.0 }, new double[] { 0.0, -2e-7, 0.0, 1.0 }, new double[] { 0.0, 0.0, 1.0, 0.0 } };
            double[][] square = { new double[] { 166.0, 188.0, 210.0 }, new double[] { 188.0, 214.0, 240.0 }, new double[] { 210.0, 240.0, 270.0 } };
            double[][] sqSolution = { new double[] { 13.0 }, new double[] { 15.0 } };
            double[][] condmat = { new double[] { 1.0, 3.0 }, new double[] { 7.0, 9.0 } };
            int        rows = 3, cols = 4;
            int        invalidld = 5;                  /* should trigger bad shape for construction with val */
            int        validld = 3;                    /* leading dimension of intended test Matrices */
            int        nonconformld = 4;               /* leading dimension which is valid, but nonconforming */
            int        ib = 1, ie = 2, jb = 1, je = 3; /* index ranges for sub Matrix */

            int[]  rowindexset       = new int[] { 1, 2 };
            int[]  badrowindexset    = new int[] { 1, 3 };
            int[]  columnindexset    = new int[] { 1, 2, 3 };
            int[]  badcolumnindexset = new int[] { 1, 2, 4 };
            double columnsummax      = 33.0;
            double rowsummax         = 30.0;
            double sumofdiagonals    = 15;
            double sumofsquares      = 650;

            #region Testing constructors and constructor-like methods

            // Constructors and constructor-like methods:
            // double[], int
            // double[,]
            // int, int
            // int, int, double
            // int, int, double[,]
            // Create(double[,])
            // Random(int,int)
            // Identity(int)

            try
            {
                // check that exception is thrown in packed constructor with invalid length
                A = new Matrix(columnwise, invalidld);
                Assert.Fail("Catch invalid length in packed constructor: exception not thrown for invalid input");
            }
            catch (ArgumentException) { }

            A           = new Matrix(columnwise, validld);
            B           = new Matrix(avals);
            tmp         = B[0, 0];
            avals[0][0] = 0.0;
            C           = B - A;
            avals[0][0] = tmp;
            B           = Matrix.Create(avals);
            tmp         = B[0, 0];
            avals[0][0] = 0.0;
            Assert.AreEqual((tmp - B[0, 0]), 0.0, "Create");

            avals[0][0] = columnwise[0];
            I           = new Matrix(ivals);
            NumericAssert.AreAlmostEqual(I, Matrix.Identity(3, 4), "Identity");

            #endregion

            #region Testing access methods

            // Access Methods:
            // getColumnDimension()
            // getRowDimension()
            // getArray()
            // getArrayCopy()
            // getColumnPackedCopy()
            // getRowPackedCopy()
            // get(int,int)
            // GetMatrix(int,int,int,int)
            // GetMatrix(int,int,int[])
            // GetMatrix(int[],int,int)
            // GetMatrix(int[],int[])
            // set(int,int,double)
            // SetMatrix(int,int,int,int,Matrix)
            // SetMatrix(int,int,int[],Matrix)
            // SetMatrix(int[],int,int,Matrix)
            // SetMatrix(int[],int[],Matrix)

            // Various get methods
            B = new Matrix(avals);
            Assert.AreEqual(B.RowCount, rows, "getRowDimension");
            Assert.AreEqual(B.ColumnCount, cols, "getColumnDimension");

            B = new Matrix(avals);
            double[][] barray = (Matrix)B;
            Assert.AreSame(barray, avals, "getArray");

            barray = B.Clone();
            Assert.AreNotSame(barray, avals, "getArrayCopy");
            NumericAssert.AreAlmostEqual(new Matrix(barray), B, "getArrayCopy II");

            //            double[] bpacked = B.ColumnPackedCopy;
            //            try
            //            {
            //                check(bpacked, columnwise);
            //                try_success("getColumnPackedCopy... ", "");
            //            }
            //            catch (System.SystemException e)
            //            {
            //                errorCount = try_failure(errorCount, "getColumnPackedCopy... ", "data not successfully (deep) copied by columns");
            //                System.Console.Out.WriteLine(e.Message);
            //            }
            //            bpacked = B.RowPackedCopy;
            //            try
            //            {
            //                check(bpacked, rowwise);
            //                try_success("getRowPackedCopy... ", "");
            //            }
            //            catch (System.SystemException e)
            //            {
            //                errorCount = try_failure(errorCount, "getRowPackedCopy... ", "data not successfully (deep) copied by rows");
            //                System.Console.Out.WriteLine(e.Message);
            //            }

            try
            {
                tmp = B[B.RowCount, B.ColumnCount - 1];
                Assert.Fail("get(int,int): OutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                tmp = B[B.RowCount - 1, B.ColumnCount];
                Assert.Fail("get(int,int): OutOfBoundsException expected but not thrown II");
            }
            catch (IndexOutOfRangeException) { }
            Assert.AreEqual(B[B.RowCount - 1, B.ColumnCount - 1], avals[B.RowCount - 1][B.ColumnCount - 1], "get(int,int)");

            SUB = new Matrix(subavals);
            try
            {
                M = B.GetMatrix(ib, ie + B.RowCount + 1, jb, je);
                Assert.Fail("GetMatrix(int,int,int,int): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                M = B.GetMatrix(ib, ie, jb, je + B.ColumnCount + 1);
                Assert.Fail("GetMatrix(int,int,int,int): IndexOutOfBoundsException expected but not thrown II");
            }
            catch (IndexOutOfRangeException) { }

            M = B.GetMatrix(ib, ie, jb, je);
            NumericAssert.AreAlmostEqual(SUB, M, "GetMatrix(int,int,int,int)");

            try
            {
                M = B.GetMatrix(ib, ie, badcolumnindexset);
                Assert.Fail("GetMatrix(int,int,int[]): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                M = B.GetMatrix(ib, ie + B.RowCount + 1, columnindexset);
                Assert.Fail("GetMatrix(int,int,int[]): IndexOutOfBoundsException expected but not thrown II");
            }
            catch (IndexOutOfRangeException) { }

            M = B.GetMatrix(ib, ie, columnindexset);
            NumericAssert.AreAlmostEqual(SUB, M, "GetMatrix(int,int,int[])");

            try
            {
                M = B.GetMatrix(badrowindexset, jb, je);
                Assert.Fail("GetMatrix(int[],int,int): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                M = B.GetMatrix(rowindexset, jb, je + B.ColumnCount + 1);
                Assert.Fail("GetMatrix(int[],int,int): IndexOutOfBoundsException expected but not thrown II");
            }
            catch (IndexOutOfRangeException) { }

            M = B.GetMatrix(rowindexset, jb, je);
            NumericAssert.AreAlmostEqual(SUB, M, "GetMatrix(int[],int,int)");

            try
            {
                M = B.GetMatrix(badrowindexset, columnindexset);
                Assert.Fail("GetMatrix(int[],int[]): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                M = B.GetMatrix(rowindexset, badcolumnindexset);
                Assert.Fail("GetMatrix(int[],int[]): IndexOutOfBoundsException expected but not thrown II");
            }
            catch (IndexOutOfRangeException) { }

            M = B.GetMatrix(rowindexset, columnindexset);
            NumericAssert.AreAlmostEqual(SUB, M, "GetMatrix(int[],int[])");

            // Various set methods:
            try
            {
                B[B.RowCount, B.ColumnCount - 1] = 0.0;
                Assert.Fail("set(int,int,double): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                B[B.RowCount - 1, B.ColumnCount] = 0.0;
                Assert.Fail("set(int,int,double): IndexOutOfBoundsException expected but not thrown II");
            }
            catch (IndexOutOfRangeException) { }

            B[ib, jb] = 0.0;
            tmp       = B[ib, jb];
            NumericAssert.AreAlmostEqual(tmp, 0.0, "set(int,int,double)");

            M = new Matrix(2, 3, 0.0);
            try
            {
                B.SetMatrix(ib, ie + B.RowCount + 1, jb, je, M);
                Assert.Fail("SetMatrix(int,int,int,int,Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                B.SetMatrix(ib, ie, jb, je + B.ColumnCount + 1, M);
                Assert.Fail("SetMatrix(int,int,int,int,Matrix): IndexOutOfBoundsException expected but not thrown II");
            }
            catch (IndexOutOfRangeException) { }

            B.SetMatrix(ib, ie, jb, je, M);
            NumericAssert.AreAlmostEqual(M - B.GetMatrix(ib, ie, jb, je), M, "SetMatrix(int,int,int,int,Matrix)");
            B.SetMatrix(ib, ie, jb, je, SUB);
            try
            {
                B.SetMatrix(ib, ie + B.RowCount + 1, columnindexset, M);
                Assert.Fail("SetMatrix(int,int,int[],Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                B.SetMatrix(ib, ie, badcolumnindexset, M);
                Assert.Fail("SetMatrix(int,int,int[],Matrix): IndexOutOfBoundsException expected but not thrown II");
            }
            catch (IndexOutOfRangeException) { }

            B.SetMatrix(ib, ie, columnindexset, M);
            NumericAssert.AreAlmostEqual(M - B.GetMatrix(ib, ie, columnindexset), M, "SetMatrix(int,int,int[],Matrix)");
            B.SetMatrix(ib, ie, jb, je, SUB);
            try
            {
                B.SetMatrix(rowindexset, jb, je + B.ColumnCount + 1, M);
                Assert.Fail("SetMatrix(int[],int,int,Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                B.SetMatrix(badrowindexset, jb, je, M);
                Assert.Fail("SetMatrix(int[],int,int,Matrix): IndexOutOfBoundsException expected but not thrown II");
            }
            catch (IndexOutOfRangeException) { }

            B.SetMatrix(rowindexset, jb, je, M);
            NumericAssert.AreAlmostEqual(M - B.GetMatrix(rowindexset, jb, je), M, "SetMatrix(int[],int,int,Matrix)");

            B.SetMatrix(ib, ie, jb, je, SUB);
            try
            {
                B.SetMatrix(rowindexset, badcolumnindexset, M);
                Assert.Fail("SetMatrix(int[],int[],Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }
            try
            {
                B.SetMatrix(badrowindexset, columnindexset, M);
                Assert.Fail("SetMatrix(int[],int[],Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch (IndexOutOfRangeException) { }

            B.SetMatrix(rowindexset, columnindexset, M);
            NumericAssert.AreAlmostEqual(M - B.GetMatrix(rowindexset, columnindexset), M, "SetMatrix(int[],int[],Matrix)");

            #endregion

            #region Testing array-like methods

            // Array-like methods:
            // Subtract
            // SubtractEquals
            // Add
            // AddEquals
            // ArrayLeftDivide
            // ArrayLeftDivideEquals
            // ArrayRightDivide
            // ArrayRightDivideEquals
            // arrayTimes
            // ArrayMultiplyEquals
            // uminus

            S = new Matrix(columnwise, nonconformld);
            R = Matrix.Random(A.RowCount, A.ColumnCount);
            A = R;
            try
            {
                S = A - S;
                Assert.Fail("Subtract conformance check: nonconformance not raised");
            }
            catch (ArgumentException) { }
            Assert.AreEqual((A - R).Norm1(), 0.0, "Subtract: difference of identical Matrices is nonzero,\nSubsequent use of Subtract should be suspect");

            A = R.Clone();
            A.Subtract(R);
            Z = new Matrix(A.RowCount, A.ColumnCount);
            try
            {
                A.Subtract(S);
                Assert.Fail("SubtractEquals conformance check: nonconformance not raised");
            }
            catch (ArgumentException) { }
            Assert.AreEqual((A - Z).Norm1(), 0.0, "SubtractEquals: difference of identical Matrices is nonzero,\nSubsequent use of Subtract should be suspect");

            A = R.Clone();
            B = Matrix.Random(A.RowCount, A.ColumnCount);
            C = A - B;
            try
            {
                S = A + S;
                Assert.Fail("Add conformance check: nonconformance not raised");
            }
            catch (ArgumentException) { }
            NumericAssert.AreAlmostEqual(C + B, A, "Add");

            C = A - B;
            C.Add(B);
            try
            {
                A.Add(S);
                Assert.Fail("AddEquals conformance check: nonconformance not raised");
            }
            catch (ArgumentException) { }
            NumericAssert.AreAlmostEqual(C, A, "AddEquals");

            A = ((Matrix)R.Clone());
            A.UnaryMinus();
            NumericAssert.AreAlmostEqual(A + R, Z, "UnaryMinus");

            A = (Matrix)R.Clone();
            O = new Matrix(A.RowCount, A.ColumnCount, 1.0);
            try
            {
                Matrix.ArrayDivide(A, S);
                Assert.Fail("ArrayRightDivide conformance check: nonconformance not raised");
            }
            catch (ArgumentException) { }

            C = Matrix.ArrayDivide(A, R);
            NumericAssert.AreAlmostEqual(C, O, "ArrayRightDivide");
            try
            {
                A.ArrayDivide(S);
                Assert.Fail("ArrayRightDivideEquals conformance check: nonconformance not raised");
            }
            catch (ArgumentException) { }

            A.ArrayDivide(R);
            NumericAssert.AreAlmostEqual(A, O, "ArrayRightDivideEquals");

            A = (Matrix)R.Clone();
            B = Matrix.Random(A.RowCount, A.ColumnCount);
            try
            {
                S = Matrix.ArrayMultiply(A, S);
                Assert.Fail("arrayTimes conformance check: nonconformance not raised");
            }
            catch (ArgumentException) { }

            C = Matrix.ArrayMultiply(A, B);
            C.ArrayDivide(B);
            NumericAssert.AreAlmostEqual(C, A, "arrayTimes");
            try
            {
                A.ArrayMultiply(S);
                Assert.Fail("ArrayMultiplyEquals conformance check: nonconformance not raised");
            }
            catch (ArgumentException) { }

            A.ArrayMultiply(B);
            A.ArrayDivide(B);
            NumericAssert.AreAlmostEqual(A, R, "ArrayMultiplyEquals");

            #endregion

            #region Testing linear algebra methods

            // LA methods:
            // Transpose
            // Multiply
            // Condition
            // Rank
            // Determinant
            // trace
            // Norm1
            // norm2
            // normF
            // normInf
            // Solve
            // solveTranspose
            // Inverse
            // chol
            // Eigen
            // lu
            // qr
            // svd

            A = new Matrix(columnwise, 3);
            T = new Matrix(tvals);
            T = Matrix.Transpose(A);
            NumericAssert.AreAlmostEqual(Matrix.Transpose(A), T, "Transpose");
            NumericAssert.AreAlmostEqual(A.Norm1(), columnsummax, "Norm1");
            NumericAssert.AreAlmostEqual(A.NormInf(), rowsummax, "NormInf");
            NumericAssert.AreAlmostEqual(A.NormF(), Math.Sqrt(sumofsquares), "NormF");
            NumericAssert.AreAlmostEqual(A.Trace(), sumofdiagonals, "Trace");
            NumericAssert.AreAlmostEqual(A.GetMatrix(0, A.RowCount - 1, 0, A.RowCount - 1).Determinant(), 0.0, "Determinant");

            SQ = new Matrix(square);
            NumericAssert.AreAlmostEqual(A * Matrix.Transpose(A), SQ, "Multiply(Matrix)");
            NumericAssert.AreAlmostEqual(0.0 * A, Z, "Multiply(double)");

            A = new Matrix(columnwise, 4);
            QRDecomposition QR = A.QRDecomposition;
            R = QR.R;
            NumericAssert.AreAlmostEqual(A, QR.Q * R, "QRDecomposition");

            SingularValueDecomposition SVD = A.SingularValueDecomposition;
            NumericAssert.AreAlmostEqual(A, SVD.LeftSingularVectors * (SVD.S * Matrix.Transpose(SVD.RightSingularVectors)), "SingularValueDecomposition");

            DEF = new Matrix(rankdef);
            NumericAssert.AreAlmostEqual(DEF.Rank(), Math.Min(DEF.RowCount, DEF.ColumnCount) - 1, "Rank");

            B   = new Matrix(condmat);
            SVD = B.SingularValueDecomposition;
            double[] singularvalues = SVD.SingularValues;
            NumericAssert.AreAlmostEqual(B.Condition(), singularvalues[0] / singularvalues[Math.Min(B.RowCount, B.ColumnCount) - 1], "Condition");

            int n = A.ColumnCount;
            A       = A.GetMatrix(0, n - 1, 0, n - 1);
            A[0, 0] = 0.0;
            LUDecomposition LU = A.LUDecomposition;
            NumericAssert.AreAlmostEqual(A.GetMatrix(LU.Pivot, 0, n - 1), LU.L * LU.U, "LUDecomposition");

            X = A.Inverse();
            NumericAssert.AreAlmostEqual(A * X, Matrix.Identity(3, 3), "Inverse");

            O   = new Matrix(SUB.RowCount, 1, 1.0);
            SOL = new Matrix(sqSolution);
            SQ  = SUB.GetMatrix(0, SUB.RowCount - 1, 0, SUB.RowCount - 1);
            NumericAssert.AreAlmostEqual(SQ.Solve(SOL), O, "Solve");

            A = new Matrix(pvals);
            CholeskyDecomposition Chol = A.CholeskyDecomposition;
            Matrix L = Chol.TriangularFactor;
            NumericAssert.AreAlmostEqual(A, L * Matrix.Transpose(L), "CholeskyDecomposition");

            X = Chol.Solve(Matrix.Identity(3, 3));
            NumericAssert.AreAlmostEqual(A * X, Matrix.Identity(3, 3), "CholeskyDecomposition Solve");

            EigenvalueDecomposition Eig = A.EigenvalueDecomposition;
            Matrix D = Eig.BlockDiagonal;
            Matrix V = Eig.EigenVectors;
            NumericAssert.AreAlmostEqual(A * V, V * D, "EigenvalueDecomposition (symmetric)");

            A   = new Matrix(evals);
            Eig = A.EigenvalueDecomposition;
            D   = Eig.BlockDiagonal;
            V   = Eig.EigenVectors;
            NumericAssert.AreAlmostEqual(A * V, V * D, "EigenvalueDecomposition (nonsymmetric)");

            #endregion
        }
Пример #3
0
        /// <summary>
        ///   Fits the underlying distribution to a given set of observations.
        /// </summary>
        ///
        /// <param name="observations">The array of observations to fit the model against. The array
        /// elements can be either of type double (for univariate data) or
        /// type double[] (for multivariate data).</param>
        /// <param name="weights">The weight vector containing the weight for each of the samples.</param>
        /// <param name="options">Optional arguments which may be used during fitting, such
        /// as regularization constants and additional parameters.</param>
        ///
        /// <remarks>
        ///   Although both double[] and double[][] arrays are supported,
        ///   providing a double[] for a multivariate distribution or a
        ///   double[][] for a univariate distribution may have a negative
        ///   impact in performance.
        /// </remarks>
        ///
        public override void Fit(double[][] observations, double[] weights, IFittingOptions options)
        {
            double[] means;
            double[,] cov;

            NormalOptions opt = options as NormalOptions;


            if (weights != null)
            {
#if DEBUG
                double sum = 0;
                for (int i = 0; i < weights.Length; i++)
                {
                    if (Double.IsNaN(weights[i]) || Double.IsInfinity(weights[i]))
                    {
                        throw new Exception("Invalid numbers in the weight vector.");
                    }
                    sum += weights[i];
                }

                if (Math.Abs(sum - 1.0) > 1e-10)
                {
                    throw new Exception("Weights do not sum to one.");
                }
#endif
                // Compute weighted mean vector
                means = Statistics.Tools.Mean(observations, weights);

                // Compute weighted covariance matrix
                if (opt != null && opt.Diagonal)
                {
                    cov = Matrix.Diagonal(Statistics.Tools.WeightedVariance(observations, weights, means));
                }
                else
                {
                    cov = Statistics.Tools.WeightedCovariance(observations, weights, means);
                }
            }
            else
            {
                // Compute mean vector
                means = Statistics.Tools.Mean(observations);

                // Compute covariance matrix
                if (opt != null && opt.Diagonal)
                {
                    cov = Matrix.Diagonal(Statistics.Tools.Variance(observations, means));
                }
                cov = Statistics.Tools.Covariance(observations, means);
            }

            CholeskyDecomposition chol = new CholeskyDecomposition(cov, false, true);

            if (opt != null)
            {
                // Parse optional estimation options
                double regularization = opt.Regularization;

                if (regularization > 0)
                {
                    int dimension = observations[0].Length;

                    while (!chol.PositiveDefinite)
                    {
                        for (int i = 0; i < dimension; i++)
                        {
                            for (int j = 0; j < dimension; j++)
                            {
                                if (Double.IsNaN(cov[i, j]) || Double.IsInfinity(cov[i, j]))
                                {
                                    cov[i, j] = 0.0;
                                }
                            }

                            cov[i, i] += regularization;
                        }

                        chol = new CholeskyDecomposition(cov, false, true);
                    }
                }
            }

            if (!chol.PositiveDefinite)
            {
                throw new NonPositiveDefiniteMatrixException("Covariance matrix is not positive "
                                                             + "definite. Try specifying a regularization constant in the fitting options.");
            }

            // Become the newly fitted distribution.
            initialize(means, cov, chol);
        }
Пример #4
0
        /// <summary>Cholesky decomposition.</summary>
        protected static double[,] chol(double[,] a)
        {
            var chol = new CholeskyDecomposition(a);

            return(chol.LeftTriangularFactor);
        }
Пример #5
0
        public object[,] Compute()
        {
            int[] indices = new int[n];
            for (int i = 0; i < n; ++i)
            {
                indices[i] = i;
            }

            bestScore = double.MinValue;
            int[] bestPermutation = indices;

            pivotIndex = 0;
            swapIndex  = 0;
            iteration  = 0;

            int[] permutation = null;
            while (Permute(bestPermutation, out permutation))
            {
                double[,] permutedData = new double[r, r];

                for (int i = 0; i < n; ++i)
                {
                    for (int j = 0; j <= i; ++j)
                    {
                        permutedData[i, j] = permutedData[j, i] = InputCorrelationConfiguration[permutation[i], permutation[j]];
                    }
                }

                for (int j = 0; j < n; ++j)
                {
                    permutedData[n, j] = permutedData[j, n] = InputCorrelationConfiguration[n, permutation[j]];
                }

                permutedData[n, n] = InputCorrelationConfiguration[n, n];

                double[,] cholesky = new CholeskyDecomposition(permutedData).LeftTriangularFactor;

                double score = Math.Pow(cholesky[r - 1, pivotIndex], 2);
                if (score > bestScore)
                {
                    bestScore       = score;
                    bestPermutation = permutation.ToArray();
                }

                iteration++;
            }

            optimalCorrelationConfiguration = new double[r, r];
            for (int i = 0; i < n; ++i)
            {
                for (int j = 0; j <= i; ++j)
                {
                    optimalCorrelationConfiguration[i, j] = optimalCorrelationConfiguration[j, i] = InputCorrelationConfiguration[bestPermutation[i], bestPermutation[j]];
                }
            }

            for (int j = 0; j < n; ++j)
            {
                optimalCorrelationConfiguration[n, j] = optimalCorrelationConfiguration[j, n] = InputCorrelationConfiguration[n, bestPermutation[j]];
            }

            optimalCorrelationConfiguration[n, n] = InputCorrelationConfiguration[n, n];

            OptimalCholeskyDecomposition = new CholeskyDecomposition(optimalCorrelationConfiguration).LeftTriangularFactor;

            object[,] ret = new object[r + 1, r + 1];
            ret[0, 0]     = "";
            for (int i = 0; i < n; ++i)
            {
                OptimalLabels[i] = InputLabels[bestPermutation[i]];
                ret[0, i + 1]    = ret[i + 1, 0] = OptimalLabels[i];

                for (int j = 0; j < r; ++j)
                {
                    ret[i + 1, j + 1] = OptimalCholeskyDecomposition[i, j];
                }
            }

            OptimalLabels[n] = InputLabels[n];
            ret[0, n + 1]    = ret[n + 1, 0] = OptimalLabels[n];
            for (int j = 0; j < r; ++j)
            {
                ret[n + 1, j + 1] = OptimalCholeskyDecomposition[n, j];
            }

            return(ret);
        }
Пример #6
0
 public CholeskyWrapper(CholeskyDecomposition ch)
 {
     _ch = ch;
 }