public DoubleMatrix2D LowerTriangular(DoubleMatrix2D A) { int rows = A.Rows; int columns = A.Columns; int min = System.Math.Min(rows, columns); for (int r = min; --r >= 0;) { for (int c = min; --c >= 0;) { if (r < c) { A[r, c] = 0; } else if (r == c) { A[r, c] = 1; } } } if (columns > rows) { A.ViewPart(0, min, rows, columns - min).Assign(0); } return(A); }
public void TestUpdating() { // first row var m = DoubleFactory2D.Dense.Make(_a.ViewColumn(0).ToArray(), _a.Rows); var initialSVD = new SingularValueDecomposition(m); var u = initialSVD.U; var s = initialSVD.S; var v = initialSVD.V; // second row var d = DoubleFactory2D.Dense.Make(_a.ViewColumn(1).ToArray(), _a.Rows); var l = u.ViewDice().ZMult(d, null); var uu = u.ZMult(u.ViewDice(), null); var ul = uu.ZMult(d, null); var h = d.Copy().Assign(uu.ZMult(d, null), BinaryFunctions.Minus); var k = Math.Sqrt(d.Aggregate(BinaryFunctions.Plus, a => a * a) - (2 * l.Aggregate(BinaryFunctions.Plus, a => a * a)) + ul.Aggregate(BinaryFunctions.Plus, a => a * a)); var j1 = h.Assign(UnaryFunctions.Div(k)); Assert.AreEqual(j1.Assign(UnaryFunctions.Mult(k)), h); var q = DoubleFactory2D.Dense.Compose( new[] { new[] { s, l }, new[] { null, DoubleFactory2D.Dense.Make(1, 1, k) } }); var svdq = new SingularValueDecomposition(q); var u2 = DoubleFactory2D.Dense.AppendColumns(u, j1).ZMult(svdq.U, null); var s2 = svdq.S; var v2 = DoubleFactory2D.Dense.ComposeDiagonal(v, DoubleFactory2D.Dense.Identity(1)).ZMult( svdq.V, null); var svd = new SingularValueDecomposition(_a.ViewPart(0, 0, _a.Rows, 2)); Assert.AreEqual(svd.S, s2); }
/// <summary> /// Least squares solution of <i>A*X = B</i>; <i>returns X</i>. /// </summary> /// <param name="B">A matrix with as many rows as <i>A</i> and any number of columns.</param> /// <returns><i>X</i> that minimizes the two norm of <i>Q*R*X - B</i>.</returns> /// <exception cref="ArgumentException">if <i>B.Rows != A.Rows</i>.</exception> /// <exception cref="ArgumentException">if <i>!this.hasFullRank()</i> (<i>A</i> is rank deficient).</exception> public DoubleMatrix2D Solve(DoubleMatrix2D B) { Functions F = Functions.functions; if (B.Rows != m) { throw new ArgumentException(Cern.LocalizedResources.Instance().Exception_MatrixRowDimensionsMustAgree); } if (!this.HasFullRank) { throw new ArgumentException(Cern.LocalizedResources.Instance().Exception_MatrixIsRankDeficient); } // Copy right hand side int nx = B.Columns; DoubleMatrix2D X = B.Copy(); // Compute Y = transpose(Q)*B for (int k = 0; k < n; k++) { for (int j = 0; j < nx; j++) { double s = 0.0; for (int i = k; i < m; i++) { s += QR[i, k] * X[i, j]; } s = -s / QR[k, k]; for (int i = k; i < m; i++) { X[i, j] = X[i, j] + s * QR[i, k]; } } } // Solve R*X = Y; for (int k = n - 1; k >= 0; k--) { for (int j = 0; j < nx; j++) { X[k, j] = X[k, j] / Rdiag[k]; } for (int i = 0; i < k; i++) { for (int j = 0; j < nx; j++) { X[i, j] = X[i, j] - X[k, j] * QR[i, k]; } } } return(X.ViewPart(0, 0, n, nx)); }
/// <summary> /// Reduced rank-<code>k</code> decomposition. /// Assume that the singular values are ordered. /// Discard the lowest singular values and the corresponding columns of U and V. /// </summary> /// <param name="r">The reduced rank.</param> public void Reduce(int r) { if (r < _n) { _u = _u.ViewPart(0, 0, _u.Rows, r); if (_v != null) { _v = _v.ViewPart(0, 0, _v.Rows, r); } var s = new double[r]; Array.Copy(_s, s, r); _s = s; _n = r; } }
/// <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); }
public DoubleMatrix2D UpperTriangular(DoubleMatrix2D A) { int rows = A.Rows; int columns = A.Columns; int min = System.Math.Min(rows, columns); for (int r = min; --r >= 0;) { for (int c = min; --c >= 0;) { if (r > c) { A[r, c] = 0; } } } if (columns < rows) { A.ViewPart(min, 0, rows - min, columns).Assign(0); } return(A); }
public DoubleMatrix2D[] SplitStridedNN(DoubleMatrix2D A, int threshold, long flops) { /* * determine how to split and parallelize best into blocks * if more B.Columns than tasks --> split B.Columns, as follows: * * xx|xx|xxx B * xx|xx|xxx * xx|xx|xxx * A * xxx xx|xx|xxx C * xxx xx|xx|xxx * xxx xx|xx|xxx * xxx xx|xx|xxx * xxx xx|xx|xxx * * if less B.Columns than tasks --> split A.rows, as follows: * * xxxxxxx B * xxxxxxx * xxxxxxx * A * xxx xxxxxxx C * xxx xxxxxxx * --- ------- * xxx xxxxxxx * xxx xxxxxxx * --- ------- * xxx xxxxxxx * */ //long flops = 2L*A.Rows*A.Columns*A.Columns; int noOfTasks = (int)System.Math.Min(flops / threshold, this.maxThreads); // each thread should process at least 30000 flops Boolean splitHoriz = (A.Columns < noOfTasks); //Boolean splitHoriz = (A.Columns >= noOfTasks); int p = splitHoriz ? A.Rows : A.Columns; noOfTasks = System.Math.Min(p, noOfTasks); if (noOfTasks < 2) { // parallelization doesn't pay off (too much start up overhead) return(null); } // set up concurrent tasks int span = p / noOfTasks; DoubleMatrix2D[] blocks = new DoubleMatrix2D[noOfTasks]; for (int i = 0; i < noOfTasks; i++) { int offset = i * span; if (i == noOfTasks - 1) { span = p - span * i; // last span may be a bit larger } DoubleMatrix2D AA, BB, CC; if (!splitHoriz) { // split B along columns into blocks blocks[i] = A.ViewPart(0, i, A.Rows, A.Columns - i).ViewStrides(1, noOfTasks); } else { // split A along rows into blocks blocks[i] = A.ViewPart(i, 0, A.Rows - i, A.Columns).ViewStrides(noOfTasks, 1); } } return(blocks); }
public void Dgemv(bool transposeA, double alpha, DoubleMatrix2D A, DoubleMatrix1D x, double beta, DoubleMatrix1D y) { /* * split A, as follows: * * x x * x * x * A * xxx x y * xxx x * --- - * xxx x * xxx x * --- - * xxx x * */ if (transposeA) { Dgemv(false, alpha, A.ViewDice(), x, beta, y); return; } int m = A.Rows; int n = A.Columns; long flops = 2L * m * n; int noOfTasks = (int)System.Math.Min(flops / 30000, this.maxThreads); // each thread should process at least 30000 flops int width = A.Rows; noOfTasks = System.Math.Min(width, noOfTasks); if (noOfTasks < 2) { // parallelization doesn't pay off (too much start up overhead) seqBlas.Dgemv(transposeA, alpha, A, x, beta, y); return; } // set up concurrent tasks int span = width / noOfTasks; //FJTask[] subTasks = new FJTask[noOfTasks]; for (int i = 0; i < noOfTasks; i++) { int offset = i * span; if (i == noOfTasks - 1) { span = width - span * i; // last span may be a bit larger } // split A along rows into blocks DoubleMatrix2D AA = A.ViewPart(offset, 0, span, n); DoubleMatrix1D yy = y.ViewPart(offset, span); // subTasks[i] = new FJTask() // { // public void run() // { // seqBlas.Dgemv(transposeA, alpha, AA, x, beta, yy); // //Console.WriteLine("Hello "+offset); // } //}; Action task = (() => { seqBlas.Dgemv(transposeA, alpha, AA, x, beta, yy); }); // run tasks and wait for completion try { this.smp.TaskGroup.QueueTask(() => task()); } catch (TaskCanceledException exc) { } } }
public void Dgemm(bool transposeA, bool transposeB, double alpha, DoubleMatrix2D A, DoubleMatrix2D B, double beta, DoubleMatrix2D C) { /* * determine how to split and parallelize best into blocks * if more B.columns than tasks --> split B.columns, as follows: * * xx|xx|xxx B * xx|xx|xxx * xx|xx|xxx * A * xxx xx|xx|xxx C * xxx xx|xx|xxx * xxx xx|xx|xxx * xxx xx|xx|xxx * xxx xx|xx|xxx * * if less B.columns than tasks --> split A.rows, as follows: * * xxxxxxx B * xxxxxxx * xxxxxxx * A * xxx xxxxxxx C * xxx xxxxxxx * --- ------- * xxx xxxxxxx * xxx xxxxxxx * --- ------- * xxx xxxxxxx * */ if (transposeA) { Dgemm(false, transposeB, alpha, A.ViewDice(), B, beta, C); return; } if (transposeB) { Dgemm(transposeA, false, alpha, A, B.ViewDice(), beta, C); return; } int m = A.Rows; int n = A.Columns; int p = B.Columns; if (B.Rows != n) { throw new ArgumentException("Matrix2D inner dimensions must agree:" + A.ToStringShort() + ", " + B.ToStringShort()); } if (C.Rows != m || C.Columns != p) { throw new ArgumentException("Incompatibel result matrix: " + A.ToStringShort() + ", " + B.ToStringShort() + ", " + C.ToStringShort()); } if (A == C || B == C) { throw new ArgumentException("Matrices must not be identical"); } long flops = 2L * m * n * p; int noOfTasks = (int)System.Math.Min(flops / 30000, this.maxThreads); // each thread should process at least 30000 flops Boolean splitB = (p >= noOfTasks); int width = splitB ? p : m; noOfTasks = System.Math.Min(width, noOfTasks); if (noOfTasks < 2) { // parallelization doesn't pay off (too much start up overhead) seqBlas.Dgemm(transposeA, transposeB, alpha, A, B, beta, C); return; } // set up concurrent tasks int span = width / noOfTasks; //FJTask[] subTasks = new FJTask[noOfTasks]; for (int i = 0; i < noOfTasks; i++) { int offset = i * span; if (i == noOfTasks - 1) { span = width - span * i; // last span may be a bit larger } DoubleMatrix2D AA, BB, CC; if (splitB) { // split B along columns into blocks AA = A; BB = B.ViewPart(0, offset, n, span); CC = C.ViewPart(0, offset, m, span); } else { // split A along rows into blocks AA = A.ViewPart(offset, 0, span, n); BB = B; CC = C.ViewPart(offset, 0, span, p); } Action task = (() => { seqBlas.Dgemm(transposeA, transposeB, alpha, AA, BB, beta, CC); }); // run tasks and wait for completion try { this.smp.TaskGroup.QueueTask(() => task()); } catch (TaskCanceledException exc) { } } }
///// <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> /// Constructs and returns a new <i>sub-range view</i> which is the sub matrix <i>A[fromRow..toRow,fromColumn..toColumn]</i>. /// The returned matrix is backed by this matrix, so changes in the returned matrix are reflected in this matrix, and vice-versa. /// Use idioms like <i>result = subMatrix(..D).Copy()</i> to generate an independent sub matrix. /// </summary> /// <param name="A">the source matrix.</param> /// <param name="fromRow">The index of the first row (inclusive).</param> /// <param name="toRow">The index of the last row (inclusive).</param> /// <param name="fromColumn">The index of the first column (inclusive).</param> /// <param name="toColumn">The index of the last column (inclusive).</param> /// <returns>a new sub-range view.</returns> /// <exception cref="IndexOutOfRangeException">if <i>fromColumn < 0 || toColumn - fromColumn + 1 < 0 || toColumn >= A.Columns || fromRow < 0 || toRow - fromRow + 1 < 0 || toRow >= A.Rows</i></exception> public static DoubleMatrix2D SubMatrix(DoubleMatrix2D A, int fromRow, int toRow, int fromColumn, int toColumn) { return(A.ViewPart(fromRow, fromColumn, toRow - fromRow + 1, toColumn - fromColumn + 1)); }