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> /// Outer product of two vectors; Sets <i>A[i,j] = x[i] * y[j]</i>. /// </summary> /// <param name="x">the first source vector.</param> /// <param name="y">the second source vector.</param> /// <param name="A">the matrix to hold the resultsd Set this parameter to <i>null</i> to indicate that a new result matrix shall be constructed.</param> /// <returns>A (for convenience only).</returns> public static DoubleMatrix2D MultOuter(DoubleMatrix1D x, DoubleMatrix1D y, DoubleMatrix2D A) { int rows = x.Size; int columns = y.Size; if (A == null) { A = x.Like2D(rows, columns); } if (A.Rows != rows || A.Columns != columns) { throw new ArgumentException(); } for (int row = rows; --row >= 0;) { A.ViewRow(row).Assign(y); } for (int column = columns; --column >= 0;) { A.ViewColumn(column).Assign(x, BinaryFunctions.Mult); } return(A); }
/// <summary> /// Constructs and returns the covariance matrix of the given matrix. /// The covariance matrix is a square, symmetric matrix consisting of nothing but covariance coefficientsd /// The rows and the columns represent the variables, the cells represent covariance coefficientsd /// The diagonal cells (i.ed the covariance between a variable and itself) will equal the variances. /// The covariance of two column vectors x and y is given by <i>cov(x,y) = (1/n) * Sum((x[i]-mean(x)) * (y[i]-mean(y)))</i>. /// See the <A HREF="http://www.cquest.utoronto.ca/geog/ggr270y/notes/not05efg.html"> math definition</A>. /// Compares two column vectors at a timed Use dice views to compare two row vectors at a time. /// </summary> /// <param name="matrix">any matrix; a column holds the values of a given variable.</param> /// <returns>the covariance matrix (<i>n x n, n=matrix.Columns</i>).</returns> public static DoubleMatrix2D Covariance(DoubleMatrix2D matrix) { int rows = matrix.Rows; int columns = matrix.Columns; DoubleMatrix2D covariance = new DenseDoubleMatrix2D(columns, columns); double[] sums = new double[columns]; DoubleMatrix1D[] cols = new DoubleMatrix1D[columns]; for (int i = columns; --i >= 0;) { cols[i] = matrix.ViewColumn(i); sums[i] = cols[i].ZSum(); } for (int i = columns; --i >= 0;) { for (int j = i + 1; --j >= 0;) { double sumOfProducts = cols[i].ZDotProduct(cols[j]); double cov = (sumOfProducts - sums[i] * sums[j] / rows) / rows; covariance[i, j] = cov; covariance[j, i] = cov; // symmetric } } return(covariance); }
/// <summary> /// Sorts the matrix rows into ascending order, according to the <i>natural ordering</i> of the matrix values in the given column. /// </summary> /// <param name="matrix"> /// The matrix to be sorted. /// </param> /// <param name="column"> /// The index of the column inducing the order. /// </param> /// <returns> /// A new matrix view having rows sorted by the given column. /// </returns> /// <exception cref="IndexOutOfRangeException"> /// If <i>column < 0 || column >= matrix.columns()</i>. /// </exception> public DoubleMatrix2D Sort(DoubleMatrix2D matrix, int column) { if (column < 0 || column >= matrix.Columns) { throw new IndexOutOfRangeException("column=" + column + ", matrix=" + AbstractFormatter.Shape(matrix)); } var rowIndexes = new int[matrix.Rows]; // row indexes to reorder instead of matrix itself for (int i = rowIndexes.Length; --i >= 0;) { rowIndexes[i] = i; } DoubleMatrix1D col = matrix.ViewColumn(column); RunSort( rowIndexes, 0, rowIndexes.Length, (a, b) => { double av = col[a]; double bv = col[b]; if (Double.IsNaN(av) || Double.IsNaN(bv)) { return(CompareNaN(av, bv)); // swap NaNs to the end } return(av < bv ? -1 : (av == bv ? 0 : 1)); }); // view the matrix according to the reordered row indexes // take all columns in the original order return(matrix.ViewSelection(rowIndexes, null)); }
/// <summary> /// Returns the one-norm of matrix <i>A</i>, which is the maximum absolute column sum. /// </summary> /// <param name="A">The matrix A</param> /// <returns>The one-norm of A.</returns> public static double Norm1(DoubleMatrix2D A) { double max = 0; for (int column = A.Columns; --column >= 0;) { max = System.Math.Max(max, Norm1(A.ViewColumn(column))); } return(max); }
/// <summary> /// Same as <see cref="Cern.Colt.Partitioning.Partition(int[], int, int, int[], int, int, int[])"/> /// except that it <i>synchronously</i> partitions the rows of the given matrix by the values of the given matrix column; /// This is essentially the same as partitioning a list of composite objects by some instance variable; /// In other words, two entire rows of the matrix are swapped, whenever two column values indicate so. /// <p> /// Let's say, a "row" is an "object" (tuple, d-dimensional point). /// A "column" is the list of "object" values of a given variable (field, dimension). /// A "matrix" is a list of "objects" (tuples, points). /// <p> /// Now, rows (objects, tuples) are partially sorted according to their values in one given variable (dimension). /// Two entire rows of the matrix are swapped, whenever two column values indicate so. /// <p> /// Note that arguments are not checked for validity. /// /// </summary> /// <param name="matrix"> /// the matrix to be partitioned. /// </param> /// <param name="rowIndexes"> /// the index of the i-th row; is modified by this method to reflect partitioned indexes. /// </param> /// <param name="rowFrom"> /// the index of the first row (inclusive). /// </param> /// <param name="rowTo"> /// the index of the last row (inclusive). /// </param> /// <param name="column"> /// the index of the column to partition on. /// </param> /// <param name="splitters"> /// the values at which the rows shall be split into intervals. /// Must be sorted ascending and must not contain multiple identical values. /// These preconditions are not checked; be sure that they are met. /// </param> /// <param name="splitFrom"> /// the index of the first splitter element to be considered. /// </param> /// <param name="splitTo"> /// the index of the last splitter element to be considered. /// The method considers the splitter elements<i>splitters[splitFrom] .d splitters[splitTo]</i>. /// </param> /// <param name="splitIndexes"> /// a list into which this method fills the indexes of rows delimiting intervals. /// Upon return <i>splitIndexes[splitFrom..splitTo]</i> will be set accordingly. /// Therefore, must satisfy <i>splitIndexes.Length >= splitters.Length</i>. /// </param> /// <example> /// <table border="1" cellspacing="0"> /// <tr nowrap> /// <td valign="top"><i>8 x 3 matrix:<br> /// 23, 22, 21<br> /// 20, 19, 18<br> /// 17, 16, 15<br> /// 14, 13, 12<br> /// 11, 10, 9<br> /// 8, 7, 6<br> /// 5, 4, 3<br> /// 2, 1, 0 </i></td> /// <td align="left" valign="top"> /// <p><i>column = 0;<br> /// rowIndexes = {0,1,2,.d,matrix.Rows-1}; /// rowFrom = 0;<br> /// rowTo = matrix.Rows-1;<br> /// splitters = {5,10,12}<br> /// c = 0; <br> /// d = splitters.Length-1;<br> /// partition(matrix,rowIndexes,rowFrom,rowTo,column,splitters,c,d,splitIndexes);<br> /// ==><br> /// splitIndexes == {0, 2, 3}<br> /// rowIndexes == {7, 6, 5, 4, 0, 1, 2, 3}</i></p> /// </td> /// <td valign="top"> /// The matrix IS NOT REORDERED.<br> /// Here is how it would look<br> /// like, if it would be reordered<br> /// accoring to <i>rowIndexes</i>.<br> /// <i>8 x 3 matrix:<br> /// 2, 1, 0<br> /// 5, 4, 3<br> /// 8, 7, 6<br> /// 11, 10, 9<br> /// 23, 22, 21<br> /// 20, 19, 18<br> /// 17, 16, 15<br> /// 14, 13, 12 </i></td> /// </tr> /// </table> /// </example> public static void Partition(DoubleMatrix2D matrix, int[] rowIndexes, int rowFrom, int rowTo, int column, double[] splitters, int splitFrom, int splitTo, int[] splitIndexes) { if (rowFrom < 0 || rowTo >= matrix.Rows || rowTo >= rowIndexes.Length) { throw new ArgumentException(); } if (column < 0 || column >= matrix.Columns) { throw new ArgumentException(); } if (splitFrom < 0 || splitTo >= splitters.Length) { throw new ArgumentException(); } if (splitIndexes.Length < splitters.Length) { throw new ArgumentException(); } // this one knows how to swap two row indexes (a,b) int[] g = rowIndexes; Swapper swapper = new Swapper((b, c) => { int tmp = g[b]; g[b] = g[c]; g[c] = tmp; }); // compare splitter[a] with columnView[rowIndexes[b]] DoubleMatrix1D columnView = matrix.ViewColumn(column); IntComparator comp = new IntComparator((a, b) => { double av = splitters[a]; double bv = columnView[g[b]]; return(av < bv ? -1 : (av == bv ? 0 : 1)); }); // compare columnView[rowIndexes[a]] with columnView[rowIndexes[b]] IntComparator comp2 = new IntComparator((a, b) => { double av = columnView[g[a]]; double bv = columnView[g[b]]; return(av < bv ? -1 : (av == bv ? 0 : 1)); }); // compare splitter[a] with splitter[b] IntComparator comp3 = new IntComparator((a, b) => { double av = splitters[a]; double bv = splitters[b]; return(av < bv ? -1 : (av == bv ? 0 : 1)); }); // generic partitioning does the main work of reordering row indexes Cern.Colt.Partitioning.GenericPartition(rowFrom, rowTo, splitFrom, splitTo, splitIndexes, comp, comp2, comp3, swapper); }
/// <summary> /// A matrix <i>A</i> is <i>diagonally dominant by column</i> if the absolute value of each diagonal element is larger than the sum of the absolute values of theoff-diagonal elements in the corresponding column. /// <i>returns true if for all i: abs(A[i,i]) > Sum(abs(A[j,i])); j != i.</i> /// Matrix may but need not be square. /// <p> /// Note: Ignores tolerance. /// <summary> public Boolean IsDiagonallyDominantByColumn(DoubleMatrix2D A) { Cern.Jet.Math.Functions F = Cern.Jet.Math.Functions.functions; double epsilon = Tolerance; int min = System.Math.Min(A.Rows, A.Columns); for (int i = min; --i >= 0;) { double diag = System.Math.Abs(A[i, i]); diag += diag; if (diag <= A.ViewColumn(i).Aggregate(F2.Plus, F1.Abs)) { return(false); } } return(true); }
/// <summary> /// Modifies the given matrix square matrix<i>A</i> such that it is diagonally dominant by row and column, hence non-singular, hence invertible. /// For testing purposes only. /// <summary> ///<param name = "A" > the square matrix to modify.</param> ///<exception cref = "ArgumentException" >if <i>!isSquare(A)</i>. </exception> public void GenerateNonSingular(DoubleMatrix2D A) { CheckSquare(A); var F = Cern.Jet.Math.Functions.functions; int min = System.Math.Min(A.Rows, A.Columns); for (int i = min; --i >= 0;) { A[i, i] = 0; } for (int i = min; --i >= 0;) { double rowSum = A.ViewRow(i).Aggregate(F2.Plus, F1.Abs); double colSum = A.ViewColumn(i).Aggregate(F2.Plus, F1.Abs); A[i, i] = System.Math.Max(rowSum, colSum) + i + 1; } }
/// <summary> /// Applies the given aggregation functions to each column and stores the results in a the result matrix. /// If matrix has shape <i>m x n</i>, then result must have shape <i>aggr.Length x n</i>. /// Tip: To do aggregations on rows use dice views (transpositions), as in <i>aggregate(matrix.viewDice(),aggr,result.viewDice())</i>. /// </summary> /// <param name="matrix">any matrix; a column holds the values of a given variable.</param> /// <param name="aggr">the aggregation functions to be applied to each column.</param> /// <param name="result">the matrix to hold the aggregation results.</param> /// <returns><i>result</i> (for convenience only).</returns> /// <see cref="Formatter"/> /// <see cref="Hep.Aida.Bin.BinFunction1D"/> /// <see cref="Hep.Aida.Bin.BinFunctions1D"/> public static DoubleMatrix2D Aggregate(DoubleMatrix2D matrix, Hep.Aida.Bin.BinFunction1D[] aggr, DoubleMatrix2D result) { var bin = new DynamicBin1D(); var elements = new double[matrix.Rows]; var values = elements; for (int column = matrix.Columns; --column >= 0;) { matrix.ViewColumn(column).ToArray(ref elements); // copy column into values bin.Clear(); bin.AddAllOf(new DoubleArrayList(values)); for (int i = aggr.Length; --i >= 0;) { result[i, column] = aggr[i](bin); } } return(result); }
public static DoubleMatrix2D PermuteRows(DoubleMatrix2D A, int[] indexes, int[] work) { // check validity int size = A.Rows; if (indexes.Length != size) { throw new IndexOutOfRangeException("invalid permutation"); } /* * int i=size; * int a; * while (--i >= 0 && (a=indexes[i])==i) if (a < 0 || a >= size) throw new IndexOutOfRangeException("invalid permutation"); * if (i<0) return; // nothing to permute */ int columns = A.Columns; if (columns < size / 10) { // quicker double[] doubleWork = new double[size]; for (int j = A.Columns; --j >= 0;) { Permute(A.ViewColumn(j), indexes, doubleWork); } return(A); } var swapper = new Cern.Colt.Swapper((a, b) => { A.ViewRow(a).Swap(A.ViewRow(b)); } ); Cern.Colt.GenericPermuting.permute(indexes, swapper, work, null); return(A); }
/// <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> /// Constructs and returns the distance matrix of the given matrix. /// The distance matrix is a square, symmetric matrix consisting of nothing but distance coefficientsd /// The rows and the columns represent the variables, the cells represent distance coefficientsd /// The diagonal cells (i.ed the distance between a variable and itself) will be zero. /// Compares two column vectors at a timed Use dice views to compare two row vectors at a time. /// </summary> /// <param name="matrix">any matrix; a column holds the values of a given variable (vector).</param> /// <param name="distanceFunction">(EUCLID, CANBERRA, ..d, or any user defined distance function operating on two vectors).</param> /// <returns>the distance matrix (<i>n x n, n=matrix.Columns</i>).</returns> public static DoubleMatrix2D Distance(DoubleMatrix2D matrix, VectorVectorFunction distanceFunction) { int columns = matrix.Columns; DoubleMatrix2D distance = new DenseDoubleMatrix2D(columns, columns); // cache views DoubleMatrix1D[] cols = new DoubleMatrix1D[columns]; for (int i = columns; --i >= 0;) { cols[i] = matrix.ViewColumn(i); } // work out all permutations for (int i = columns; --i >= 0;) { for (int j = i; --j >= 0;) { double d = distanceFunction(cols[i], cols[j]); distance[i, j] = d; distance[j, i] = d; // symmetric } } return(distance); }
/// <summary> /// Constructs and returns a new QR decomposition object; computed by Householder reflections; /// The decomposed matrices can be retrieved via instance methods of the returned decomposition object. /// Return a decomposition object to access <i>R</i> and the Householder vectors <i>H</i>, and to compute <i>Q</i>. /// </summary> /// <param name="A">A rectangular matrix.</param> /// <exception cref="ArgumentException">if <i>A.Rows < A.Columns</i>.</exception> public QRDecomposition(DoubleMatrix2D A) { Property.DEFAULT.CheckRectangular(A); Functions F = Functions.functions; // Initialize. QR = A.Copy(); m = A.Rows; n = A.Columns; Rdiag = A.Like1D(n); //Rdiag = new double[n]; DoubleDoubleFunction hypot = Algebra.HypotFunction(); // precompute and cache some views to avoid regenerating them time and again DoubleMatrix1D[] QRcolumns = new DoubleMatrix1D[n]; DoubleMatrix1D[] QRcolumnsPart = new DoubleMatrix1D[n]; for (int k = 0; k < n; k++) { QRcolumns[k] = QR.ViewColumn(k); QRcolumnsPart[k] = QR.ViewColumn(k).ViewPart(k, m - k); } // Main loop. for (int k = 0; k < n; k++) { //DoubleMatrix1D QRcolk = QR.ViewColumn(k).ViewPart(k,m-k); // Compute 2-norm of k-th column without under/overflow. double nrm = 0; //if (k<m) nrm = QRcolumnsPart[k].aggregate(hypot,F.identity); for (int i = k; i < m; i++) { // fixes bug reported by [email protected] nrm = Algebra.Hypot(nrm, QR[i, k]); } if (nrm != 0.0) { // Form k-th Householder vector. if (QR[k, k] < 0) { nrm = -nrm; } QRcolumnsPart[k].Assign(F2.Div(nrm)); /* * for (int i = k; i < m; i++) { * QR[i][k] /= nrm; * } */ QR[k, k] = QR[k, k] + 1; // Apply transformation to remaining columns. for (int j = k + 1; j < n; j++) { DoubleMatrix1D QRcolj = QR.ViewColumn(j).ViewPart(k, m - k); double s = QRcolumnsPart[k].ZDotProduct(QRcolj); /* * // fixes bug reported by John Chambers * DoubleMatrix1D QRcolj = QR.ViewColumn(j).ViewPart(k,m-k); * double s = QRcolumnsPart[k].ZDotProduct(QRcolumns[j]); * double s = 0.0; * for (int i = k; i < m; i++) { * s += QR[i][k]*QR[i][j]; * } */ s = -s / QR[k, k]; //QRcolumnsPart[j].Assign(QRcolumns[k], F.PlusMult(s)); for (int i = k; i < m; i++) { QR[i, j] = QR[i, j] + s * QR[i, k]; } } } Rdiag[k] = -nrm; } }
public void Decompose(DoubleMatrix2D A) { int CUT_OFF = 10; // setup LU = A; int m = A.Rows; int n = A.Columns; // setup pivot vector if (this.piv == null || this.piv.Length != m) { this.piv = new int[m]; } for (int i = m; --i >= 0;) { piv[i] = i; } pivsign = 1; if (m * n == 0) { LU = LU; return; // nothing to do } //precompute and cache some views to avoid regenerating them time and again DoubleMatrix1D[] LUrows = new DoubleMatrix1D[m]; for (int i = 0; i < m; i++) { LUrows[i] = LU.ViewRow(i); } IntArrayList nonZeroIndexes = new IntArrayList(); // sparsity DoubleMatrix1D LUcolj = LU.ViewColumn(0).Like(); // blocked column j Cern.Jet.Math.Mult multFunction = Cern.Jet.Math.Mult.CreateInstance(0); // Outer loop. for (int j = 0; j < n; j++) { // blocking (make copy of j-th column to localize references) LUcolj.Assign(LU.ViewColumn(j)); // sparsity detection int maxCardinality = m / CUT_OFF; // == heuristic depending on speedup LUcolj.GetNonZeros(nonZeroIndexes, null, maxCardinality); int cardinality = nonZeroIndexes.Count; Boolean sparse = (cardinality < maxCardinality); // Apply previous transformations. for (int i = 0; i < m; i++) { int kmax = System.Math.Min(i, j); double s; if (sparse) { s = LUrows[i].ZDotProduct(LUcolj, 0, kmax, nonZeroIndexes); } else { s = LUrows[i].ZDotProduct(LUcolj, 0, kmax); } double before = LUcolj[i]; double after = before - s; LUcolj[i] = after; // LUcolj is a copy LU[i, j] = after; // this is the original if (sparse) { if (before == 0 && after != 0) { // nasty bug fixed! int pos = nonZeroIndexes.BinarySearch(i); pos = -pos - 1; nonZeroIndexes.Insert(pos, i); } if (before != 0 && after == 0) { nonZeroIndexes.Remove(nonZeroIndexes.BinarySearch(i)); } } } // Find pivot and exchange if necessary. int p = j; if (p < m) { double max = System.Math.Abs(LUcolj[p]); for (int i = j + 1; i < m; i++) { double v = System.Math.Abs(LUcolj[i]); if (v > max) { p = i; max = v; } } } if (p != j) { LUrows[p].Swap(LUrows[j]); int k = piv[p]; piv[p] = piv[j]; piv[j] = k; pivsign = -pivsign; } // Compute multipliers. double jj; if (j < m && (jj = LU[j, j]) != 0.0) { multFunction.Multiplicator = 1 / jj; LU.ViewColumn(j).ViewPart(j + 1, m - (j + 1)).Assign(multFunction); } } LU = LU; }