/// <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); }
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 }
/// <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); }
/// <summary>Cholesky decomposition.</summary> protected static double[,] chol(double[,] a) { var chol = new CholeskyDecomposition(a); return(chol.LeftTriangularFactor); }
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); }
public CholeskyWrapper(CholeskyDecomposition ch) { _ch = ch; }