/// <summary> /// Constructs and returns a new Cholesky decomposition object for a symmetric and positive definite matrix; /// The decomposed matrices can be retrieved via instance methods of the returned decomposition object. /// /// Return a structure to access <i>L</i> and <i>isSymmetricPositiveDefinite</i> flag. /// </summary> /// <param name="A">Square, symmetric matrix.</param> /// <exception cref="ArgumentException">if <i>A</i> is not square.</exception> public CholeskyDecomposition(DoubleMatrix2D A) { Property.DEFAULT.CheckSquare(A); // Initialize. //double[][] A = Arg.getArray(); n = A.Rows; //L = new double[n][n]; mL = A.Like(n, n); isSymmetricPositiveDefinite = (A.Columns == n); //precompute and cache some views to avoid regenerating them time and again DoubleMatrix1D[] Lrows = new DoubleMatrix1D[n]; for (int j = 0; j < n; j++) { Lrows[j] = mL.ViewRow(j); } // Main loop. for (int j = 0; j < n; j++) { //double[] Lrowj = L[j]; //DoubleMatrix1D Lrowj = L.ViewRow(j); double d = 0.0; for (int k = 0; k < j; k++) { //double[] Lrowk = L[k]; double s = Lrows[k].ZDotProduct(Lrows[j], 0, k); /* * DoubleMatrix1D Lrowk = L.ViewRow(k); * double s = 0.0; * for (int i = 0; i < k; i++) { * s += Lrowk.getQuick(i)*Lrowj.getQuick(i); * } */ s = (A[j, k] - s) / mL[k, k]; Lrows[j][k] = s; d = d + s * s; isSymmetricPositiveDefinite = isSymmetricPositiveDefinite && (A[k, j] == A[j, k]); } d = A[j, j] - d; isSymmetricPositiveDefinite = isSymmetricPositiveDefinite && (d > 0.0); mL[j, j] = System.Math.Sqrt(System.Math.Max(d, 0.0)); for (int k = j + 1; k < n; k++) { mL[j, k] = 0.0; } } }
/// <summary> /// Copies the columns of the indicated rows into a new sub matrix. /// <i>sub[0..rowIndexes.Length-1,0..columnTo-columnFrom] = A[rowIndexes(:),columnFrom..columnTo]</i>; /// The returned matrix is <i>not backed</i> by this matrix, so changes in the returned matrix are <i>not reflected</i> in this matrix, and vice-versa. /// </summary> /// <param name="A">the source matrix to copy from.</param> /// <param name="rowIndexes">the indexes of the rows to copyd May be unsorted.</param> /// <param name="columnFrom">the index of the first column to copy (inclusive).</param> /// <param name="columnTo">the index of the last column to copy (inclusive).</param> /// <returns>a new sub matrix; with <i>sub.Rows==rowIndexes.Length; sub.Columns==columnTo-columnFrom+1</i>.</returns> /// <exception cref="IndexOutOfRangeException">if <i>columnFrom < 0 || columnTo-columnFrom+1 < 0 || columnTo+1>matrix.Columns || for any row=rowIndexes[i]: row < 0 || row >= matrix.Rows</i>.</exception> private static DoubleMatrix2D SubMatrix(DoubleMatrix2D A, int[] rowIndexes, int columnFrom, int columnTo) { int width = columnTo - columnFrom + 1; int rows = A.Rows; A = A.ViewPart(0, columnFrom, rows, width); DoubleMatrix2D sub = A.Like(rowIndexes.Length, width); for (int r = rowIndexes.Length; --r >= 0;) { int row = rowIndexes[r]; if (row < 0 || row >= rows) { throw new IndexOutOfRangeException("Illegal Index"); } sub.ViewRow(r).Assign(A.ViewRow(row)); } return(sub); }
/// <summary> /// Copies the rows of the indicated columns into a new sub matrix. /// <i>sub[0..rowTo-rowFrom,0..columnIndexes.Length-1] = A[rowFrom..rowTo,columnIndexes(:)]</i>; /// The returned matrix is <i>not backed</i> by this matrix, so changes in the returned matrix are <i>not reflected</i> in this matrix, and vice-versa. /// </summary> /// <param name="A">the source matrix to copy from.</param> /// <param name="rowFrom">the index of the first row to copy (inclusive).</param> /// <param name="rowTo">the index of the last row to copy (inclusive).</param> /// <param name="columnIndexes">the indexes of the columns to copyd May be unsorted.</param> /// <returns>a new sub matrix; with <i>sub.Rows==rowTo-rowFrom+1; sub.Columns==columnIndexes.Length</i>.</returns> /// <exception cref="IndexOutOfRangeException">if <i>rowFrom < 0 || rowTo-rowFrom + 1 < 0 || rowTo + 1 > matrix.Rows || for any col = columnIndexes[i]: col < 0 || col >= matrix.Columns</i>.</exception> private static DoubleMatrix2D SubMatrix(DoubleMatrix2D A, int rowFrom, int rowTo, int[] columnIndexes) { if (rowTo - rowFrom >= A.Rows) { throw new IndexOutOfRangeException("Too many rows"); } int height = rowTo - rowFrom + 1; int columns = A.Columns; A = A.ViewPart(rowFrom, 0, height, columns); DoubleMatrix2D sub = A.Like(height, columnIndexes.Length); for (int c = columnIndexes.Length; --c >= 0;) { int column = columnIndexes[c]; if (column < 0 || column >= columns) { throw new IndexOutOfRangeException("Illegal Index"); } sub.ViewColumn(c).Assign(A.ViewColumn(column)); } return(sub); }
///// <summary> ///// ///// </summary> ///// <param name="matrix"></param> ///// <param name="rowNames"></param> ///// <param name="columnNames"></param> ///// <param name="rowAxisName"></param> ///// <param name="columnAxisName"></param> ///// <param name="title"></param> ///// <returns></returns> //public String ToTitleString(ObjectMatrix2D matrix, String[] rowNames, String[] columnNames, String rowAxisName, String columnAxisName, String title) //{ // if (matrix.Size == 0) return "Empty matrix"; // String oldFormat = this.formatString; // this.formatString = LEFT; // int rows = matrix.Rows; // int columns = matrix.Columns; // // determine how many rows and columns are needed // int r = 0; // int c = 0; // r += (columnNames == null ? 0 : 1); // c += (rowNames == null ? 0 : 1); // c += (rowAxisName == null ? 0 : 1); // c += (rowNames != null || rowAxisName != null ? 1 : 0); // int height = r + System.Math.Max(rows, rowAxisName == null ? 0 : rowAxisName.Length); // int width = c + columns; // // make larger matrix holding original matrix and naming strings // Cern.Colt.Matrix.ObjectMatrix2D titleMatrix = matrix.Like(height, width); // // insert original matrix into larger matrix // titleMatrix.ViewPart(r, c, rows, columns).Assign(matrix); // // insert column axis name in leading row // if (r > 0) titleMatrix.ViewRow(0).ViewPart(c, columns).Assign(columnNames); // // insert row axis name in leading column // if (rowAxisName != null) // { // String[] rowAxisStrings = new String[rowAxisName.Length]; // for (int i = rowAxisName.Length; --i >= 0;) rowAxisStrings[i] = rowAxisName.Substring(i, i + 1); // titleMatrix.ViewColumn(0).ViewPart(r, rowAxisName.Length).Assign(rowAxisStrings); // } // // insert row names in next leading columns // if (rowNames != null) titleMatrix.ViewColumn(c - 2).ViewPart(r, rows).Assign(rowNames); // // insert vertical "---------" separator line in next leading column // if (c > 0) titleMatrix.ViewColumn(c - 2 + 1).ViewPart(0, rows + r).Assign("|"); // // convert the large matrix to a string // Boolean oldPrintShape = this.printShape; // this.printShape = false; // String str = ToString(titleMatrix); // this.printShape = oldPrintShape; // // insert horizontal "--------------" separator line // var total = new StringBuilder(str); // if (columnNames != null) // { // int i = str.IndexOf(rowSeparator); // total.Insert(i + 1, Repeat('-', i) + rowSeparator); // } // else if (columnAxisName != null) // { // int i = str.IndexOf(rowSeparator); // total.Insert(0, Repeat('-', i) + rowSeparator); // } // // insert line for column axis name // if (columnAxisName != null) // { // int j = 0; // if (c > 0) j = str.IndexOf('|'); // String s = Blanks(j); // if (c > 0) s = s + "| "; // s = s + columnAxisName + "\n"; // total.Insert(0, s); // } // // insert title // if (title != null) total.Insert(0, title + "\n"); // this.formatString = oldFormat; // return total.ToString(); //} /// <summary> /// Same as <i>toTitleString</i> except that additionally statistical aggregates (mean, median, sum, etcd) of rows and columns are printed. /// Pass <i>null</i> to one or more parameters to indicate that the corresponding decoration element shall not appear in the string converted matrix. /// </summary> /// <param name="matrix">The matrix to format.</param> /// <param name="rowNames">The headers of all rows (to be put to the left of the matrix).</param> /// <param name="columnNames">The headers of all columns (to be put to above the matrix).</param> /// <param name="rowAxisName">The label of the y-axis.</param> /// <param name="columnAxisName">The label of the x-axis.</param> /// <param name="title">The overall title of the matrix to be formatted.</param> /// <param name="aggr">the aggregation functions to be applied to columns and rows.</param> /// <returns>the matrix converted to a string.</returns> /// <see cref="Hep.Aida.Bin.BinFunction1D"/> /// <see cref="Hep.Aida.Bin.BinFunctions1D"/> public String ToTitleString(DoubleMatrix2D matrix, String[] rowNames, String[] columnNames, String rowAxisName, String columnAxisName, String title, Hep.Aida.Bin.BinFunction1D[] aggr) { if (matrix.Size == 0) { return("Empty matrix"); } if (aggr == null || aggr.Length == 0) { return(ToTitleString(matrix, rowNames, columnNames, rowAxisName, columnAxisName, title)); } DoubleMatrix2D rowStats = matrix.Like(matrix.Rows, aggr.Length); // hold row aggregations DoubleMatrix2D colStats = matrix.Like(aggr.Length, matrix.Columns); // hold column aggregations Cern.Colt.Matrix.DoubleAlgorithms.Statistics.Aggregate(matrix, aggr, colStats); // aggregate an entire column at a time Cern.Colt.Matrix.DoubleAlgorithms.Statistics.Aggregate(matrix.ViewDice(), aggr, rowStats.ViewDice()); // aggregate an entire row at a time // turn into strings // tmp holds "matrix" plus "colStats" below (needed so that numbers in a columns can be decimal point aligned) DoubleMatrix2D tmp = matrix.Like(matrix.Rows + aggr.Length, matrix.Columns); tmp.ViewPart(0, 0, matrix.Rows, matrix.Columns).Assign(matrix); tmp.ViewPart(matrix.Rows, 0, aggr.Length, matrix.Columns).Assign(colStats); String[][] s1 = Format(tmp); Align(s1); String[][] s2 = Format(rowStats); Align(s2); // copy strings into a large matrix holding the source matrix and all aggregations Cern.Colt.Matrix.ObjectMatrix2D allStats = Cern.Colt.Matrix.ObjectFactory2D.Dense.Make(matrix.Rows + aggr.Length, matrix.Columns + aggr.Length + 1); allStats.ViewPart(0, 0, matrix.Rows + aggr.Length, matrix.Columns).Assign(s1); allStats.ViewColumn(matrix.Columns).Assign("|"); allStats.ViewPart(0, matrix.Columns + 1, matrix.Rows, aggr.Length).Assign(s2); // append a vertical "|" separator plus names of aggregation functions to line holding columnNames if (columnNames != null) { var list = new List <Object>(columnNames); list.Add("|"); list.AddRange(aggr.Select(x => x.Method.Name).ToList()); columnNames = list.ToStringArray(); } // append names of aggregation functions to line holding rowNames if (rowNames != null) { var list = new List <Object>(rowNames); list.AddRange(aggr.Select(x => x.Method.Name).ToList()); rowNames = list.ToStringArray(); } // turn large matrix into string String s = new Cern.Colt.Matrix.ObjectAlgorithms.Formatter().ToTitleString(allStats, rowNames, columnNames, rowAxisName, columnAxisName, title); // insert a horizontal "----------------------" separation line above the column stats // determine insertion position and line width int last = s.Length + 1; int secondLast = last; int v = System.Math.Max(0, rowAxisName == null ? 0 : rowAxisName.Length - matrix.Rows - aggr.Length); for (int k = 0; k < aggr.Length + 1 + v; k++) { // scan "aggr.Length+1+v" lines backwards secondLast = last; last = s.LastIndexOf(rowSeparator, last - 1); } StringBuilder buf = new StringBuilder(s); buf.Insert(secondLast, rowSeparator + Repeat('-', secondLast - last - 1)); return(buf.ToString()); }
/// <summary> /// Construct and returns a new 2-d matrix <i>of the corresponding dynamic type</i>, entirelly independent of the receiver. /// For example, if the receiver is an instance of type <see cref="DenseDoubleMatrix1D"/> the new matrix must also be of type <see cref="DenseDoubleMatrix2D"/>, /// if the receiver is an instance of type <see cref="SparseDoubleMatrix1D"/> the new matrix must also be of type <see cref="SparseDoubleMatrix2D"/>, etc. /// /// /// </summary> /// <param name="rows">the number of rows the matrix shall have.</param> /// <param name="columns">the number of columns the matrix shall have.</param> /// <returns>a new matrix of the corresponding dynamic type.</returns> public override DoubleMatrix2D Like2D(int rows, int columns) { return(content2D.Like(rows, columns)); }
/// <summary> /// Linear algebraic matrix power; <i>B = A<sup>k</sup> <==> B = A*A*...*A</i>. /// <ul> /// <li><i>p >= 1: B = A*A*...*A</i>.</li> /// <li><i>p == 0: B = identity matrix</i>.</li> /// <li><i>p < 0: B = pow(inverse(A),-p)</i>.</li> /// </ul> /// Implementation: Based on logarithms of 2, memory usage minimized. /// </summary> /// <param name="A">the source matrix; must be square; stays unaffected by this operation.</param> /// <param name="p">the exponent, can be any number.</param> /// <returns><i>B</i>, a newly constructed result matrix; storage-independent of <i>A</i>.</returns> ///<exception cref="ArgumentException">if <i>!property().isSquare(A)</i>.</exception> public static DoubleMatrix2D Pow(DoubleMatrix2D A, int p) { // matrix multiplication based on log2 method: A*A*....*A is slow, ((A * A)^2)^2 * ..D is faster // allocates two auxiliary matrices as work space IBlas blas = SmpBlas.smpBlas; // for parallel matrix mult; if not initialized defaults to sequential blas Property.DEFAULT.CheckSquare(A); if (p < 0) { A = Inverse(A); p = -p; } if (p == 0) { return(DoubleFactory2D.Dense.Identity(A.Rows)); } DoubleMatrix2D T = A.Like(); // temporary if (p == 1) { return(T.Assign(A)); // safes one auxiliary matrix allocation } if (p == 2) { blas.Dgemm(false, false, 1, A, A, 0, T); // mult(A,A); // safes one auxiliary matrix allocation return(T); } int k = Cern.Colt.Bitvector.QuickBitVector.MostSignificantBit(p); // index of highest bit in state "true" /* * this is the naive version: * DoubleMatrix2D B = A.Copy(); * for (int i=0; i<p-1; i++) { * B = mult(B,A); * } * return B; */ // here comes the optimized version: //cern.colt.Timer timer = new cern.colt.Timer().start(); int i = 0; while (i <= k && (p & (1 << i)) == 0) { // while (bit i of p == false) // A = mult(A,A); would allocate a lot of temporary memory blas.Dgemm(false, false, 1, A, A, 0, T); // A.zMult(A,T); DoubleMatrix2D swap = A; A = T; T = swap; // swap A with T i++; } DoubleMatrix2D B = A.Copy(); i++; for (; i <= k; i++) { // A = mult(A,A); would allocate a lot of temporary memory blas.Dgemm(false, false, 1, A, A, 0, T); // A.zMult(A,T); DoubleMatrix2D swap = A; A = T; T = swap; // swap A with T if ((p & (1 << i)) != 0) { // if (bit i of p == true) // B = mult(B,A); would allocate a lot of temporary memory blas.Dgemm(false, false, 1, B, A, 0, T); // B.zMult(A,T); swap = B; B = T; T = swap; // swap B with T } } //timer.stop().Display(); return(B); }