/** * <p> * Checks to see if a matrix is orthogonal or isometric. * </p> * * @param Q The matrix being tested. Not modified. * @param tol Tolerance. * @return True if it passes the test. */ public static bool isOrthogonal(DMatrixSparseCSC Q, double tol) { if (Q.numRows < Q.numCols) { throw new ArgumentException("The number of rows must be more than or equal to the number of columns"); } IGrowArray gw = new IGrowArray(); DGrowArray gx = new DGrowArray(); for (int i = 0; i < Q.numRows; i++) { for (int j = i + 1; j < Q.numCols; j++) { double val = CommonOps_DSCC.dotInnerColumns(Q, i, Q, j, gw, gx); if (!(Math.Abs(val) <= tol)) { return(false); } } } return(true); }
private static void fillSequence(IGrowArray perm) { for (int i = 0; i < perm.Length; i++) { perm.data[i] = i; } }
/** * Computes and applies the fill reduction permutation. Either A is returned (unmodified) or the permutated * version of A. * @param A Input matrix. unmodified. * @return A permuted matrix. Might be A or a different matrix. */ public DMatrixSparseCSC apply(DMatrixSparseCSC A) { if (fillReduce == null) { return(A); } fillReduce.process(A); IGrowArray gp = fillReduce.getRow(); if (pinv.Length < gp.Length) { pinv = new int[gp.Length]; } CommonOps_DSCC.permutationInverse(gp.data, pinv, gp.Length); if (symmetric) { CommonOps_DSCC.permuteSymmetric(A, pinv, Aperm, gw); } else { CommonOps_DSCC.permuteRowInv(pinv, A, Aperm); } return(Aperm); }
public static int[] adjust(IGrowArray gwork, int desired, int zeroToM) { int[] w = adjust(gwork, desired); //Arrays.fill(w,0,zeroToM,0); Array.Clear(w, 0, zeroToM); return(w); }
/** * <p>Determines which elements in 'X' will be non-zero when the system below is solved for.</p> * G*X = B * * <p>xi will contain a list of ordered row indexes in B which will be modified starting at xi[top] to xi[n-1]. top * is the value returned by this function.</p> * * <p>See cs_reach in dsparse library to understand the algorithm. This code follow the spirit but not * the details because of differences in the contract.</p> * * @param G (Input) Lower triangular system matrix. Diagonal elements are assumed to be not zero. Not modified. * @param B (Input) Matrix B. Not modified. * @param colB Column in B being solved for * @param pinv (Input, Optional) Column pivots in G. Null if no pivots. * @param xi (Output) List of row indices in B which are non-zero in graph order. Must have length B.numRows * @param gwork workspace array used internally. Can be null. * @return Returns the index of the first element in the xi list. Also known as top. */ public static int searchNzRowsInB(DMatrixSparseCSC G, DMatrixSparseCSC B, int colB, int[] pinv, int[] xi, IGrowArray gwork) { if (xi.Length < B.numRows) { throw new ArgumentException("xi must be at least this long: " + B.numRows); } // this is a change from csparse. CSparse marks an entry by modifying G then reverting it. This can cause // weird unexplained behavior when people start using threads... int[] w = adjust(gwork, B.numRows * 2, B.numRows); // use 'w' as a marker to know which rows in B have been examined. 0 = unexamined and 1 = examined int idx0 = B.col_idx[colB]; int idx1 = B.col_idx[colB + 1]; int top = G.numRows; for (int i = idx0; i < idx1; i++) { int rowB = B.nz_rows[i]; if (w[rowB] == 0) { top = searchNzRowsInB_DFS(rowB, G, top, pinv, xi, w); } } return(top); }
/** * Computes the solution to the triangular system. * * @param G (Input) Lower or upper triangular matrix. diagonal elements must be non-zero. Not modified. * @param lower true for lower triangular and false for upper * @param B (Input) Matrix. Not modified. * @param X (Output) Solution * @param g_x (Optional) Storage for workspace. * @param g_xi (Optional) Storage for workspace. * @param g_w (Optional) Storage for workspace. */ public static void solve(DMatrixSparseCSC G, bool lower, DMatrixSparseCSC B, DMatrixSparseCSC X, DGrowArray g_x, IGrowArray g_xi, IGrowArray g_w) { double[] x = adjust(g_x, G.numRows); if (g_xi == null) { g_xi = new IGrowArray(); } int[] xi = adjust(g_xi, G.numRows); X.nz_length = 0; X.col_idx[0] = 0; X.indicesSorted = false; for (int colB = 0; colB < B.numCols; colB++) { int top = solve(G, lower, B, colB, x, null, g_xi, g_w); int nz_count = X.numRows - top; if (X.nz_values.Length < X.nz_length + nz_count) { X.growMaxLength(X.nz_length * 2 + nz_count, true); } for (int p = top; p < X.numRows; p++, X.nz_length++) { X.nz_rows[X.nz_length] = xi[p]; X.nz_values[X.nz_length] = x[xi[p]]; } X.col_idx[colB + 1] = X.nz_length; } }
/** * Performs matrix addition:<br> * C = αA + βB * * @param alpha scalar value multiplied against A * @param A Matrix * @param beta scalar value multiplied against B * @param B Matrix * @param C Output matrix. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void add(double alpha, DMatrixSparseCSC A, double beta, DMatrixSparseCSC B, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { double[] x = TriangularSolver_DSCC.adjust(gx, A.numRows); int[] w = TriangularSolver_DSCC.adjust(gw, A.numRows, A.numRows); C.indicesSorted = false; C.nz_length = 0; for (int col = 0; col < A.numCols; col++) { C.col_idx[col] = C.nz_length; ImplSparseSparseMult_DSCC.multAddColA(A, col, alpha, C, col + 1, x, w); ImplSparseSparseMult_DSCC.multAddColA(B, col, beta, C, col + 1, x, w); // take the values in the dense vector 'x' and put them into 'C' int idxC0 = C.col_idx[col]; int idxC1 = C.col_idx[col + 1]; for (int i = idxC0; i < idxC1; i++) { C.nz_values[i] = x[C.nz_rows[i]]; } } }
/** * Converts DMatrixSparseTriplet into a DMatrixSparseCSC. Duplicate elements in triplet will result in an * illegal matrix in output having duplicate elements. * * @param src Original matrix which is to be copied. Not modified. * @param dst Destination. Will be a copy. Modified. * @param histStorage Workspace. Can be null. */ public static DMatrixSparseCSC convert(DMatrixSparseTriplet src, DMatrixSparseCSC dst, IGrowArray histStorage) { dst = UtilEjml.reshapeOrDeclare(dst, src.numRows, src.numCols, src.nz_length); int[] hist = UtilEjml.adjustClear(histStorage, src.numCols); // compute the number of elements in each columns for (int i = 0; i < src.nz_length; i++) { hist[src.nz_rowcol.data[i * 2 + 1]]++; } // define col_idx dst.histogramToStructure(hist); System.Array.Copy(dst.col_idx, 0, hist, 0, dst.numCols); // now write the row indexes and the values for (int i = 0; i < src.nz_length; i++) { int row = src.nz_rowcol.data[i * 2]; int col = src.nz_rowcol.data[i * 2 + 1]; double value = src.nz_value.data[i]; int index = hist[col]++; dst.nz_rows[index] = row; dst.nz_values[index] = value; } dst.indicesSorted = false; return(dst); }
/** * Resizes the array to ensure that it is at least of length desired and returns its internal array */ public static int[] adjust(IGrowArray gwork, int desired) { if (gwork == null) { gwork = new IGrowArray(); } gwork.reshape(desired); return(gwork.data); }
public static void multTransA(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { if (A.numCols != C.numRows || B.numCols != C.numCols) { throw new ArgumentException("Inconsistent matrix shapes"); } ImplSparseSparseMult_DSCC.multTransA(A, B, C, gw, gx); }
/** * Performs matrix addition:<br> * C = αA + βB * * @param alpha scalar value multiplied against A * @param A Matrix * @param beta scalar value multiplied against B * @param B Matrix * @param C Output matrix. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void add(double alpha, DMatrixSparseCSC A, double beta, DMatrixSparseCSC B, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { if (A.numRows != B.numRows || A.numCols != B.numCols || A.numRows != C.numRows || A.numCols != C.numCols) { throw new ArgumentException("Inconsistent matrix shapes"); } ImplCommonOps_DSCC.add(alpha, A, beta, B, C, gw, gx); }
/** * Performs an element-wise multiplication.<br> * C[i,j] = A[i,j]*B[i,j]<br> * All matrices must have the same shape. * * @param A (Input) Matrix. * @param B (Input) Matrix * @param C (Ouptut) Matrix. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void elementMult(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { if (A.numCols != B.numCols || A.numRows != B.numRows || A.numCols != C.numCols || A.numRows != C.numRows) { throw new ArgumentException("All inputs must have the same number of rows and columns"); } ImplCommonOps_DSCC.elementMult(A, B, C, gw, gx); }
/** * Performs matrix multiplication. C = A*B<sup>T</sup></sup> * * @param A Matrix * @param B Matrix * @param C Storage for results. Data length is increased if increased if insufficient. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void multTransB(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { if (!B.isIndicesSorted()) { throw new ArgumentException("B must have its indices sorted."); } else if (!CommonOps_DSCC.checkIndicesSorted(B)) { throw new ArgumentException("Crap. Not really sorted"); } double[] x = TriangularSolver_DSCC.adjust(gx, A.numRows); int[] w = TriangularSolver_DSCC.adjust(gw, A.numRows + B.numCols, A.numRows); C.growMaxLength(A.nz_length + B.nz_length, false); C.indicesSorted = false; C.nz_length = 0; C.col_idx[0] = 0; // initialize w is the first index in each column of B int locationB = A.numRows; Array.Copy(B.col_idx, 0, w, locationB, B.numCols); for (int colC = 0; colC < B.numRows; colC++) { C.col_idx[colC + 1] = C.nz_length; // needs a value of B has nothing in the row // find the column in the transposed B int mark = colC + 1; for (int colB = 0; colB < B.numCols; colB++) { int bi = w[locationB + colB]; if (bi < B.col_idx[colB + 1]) { int row = B.nz_rows[bi]; if (row == colC) { multAddColA(A, colB, B.nz_values[bi], C, mark, x, w); w[locationB + colB]++; } } } // take the values in the dense vector 'x' and put them into 'C' int idxC0 = C.col_idx[colC]; int idxC1 = C.col_idx[colC + 1]; for (int i = idxC0; i < idxC1; i++) { C.nz_values[i] = x[C.nz_rows[i]]; } } }
/** * Performs element-wise multiplication:<br> * C_ij = A_ij * B_ij * * @param A (Input) Matrix * @param B (Input) Matrix * @param C (Output) matrix. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void elementMult(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { double[] x = TriangularSolver_DSCC.adjust(gx, A.numRows); int[] w = TriangularSolver_DSCC.adjust(gw, A.numRows); //Arrays.fill(w, 0, A.numRows, -1); // fill with -1. This will be a value less than column for (var i = 0; i < A.numRows; i++) { w[i] = -1; } C.indicesSorted = false; // Hmm I think if B is storted then C will be sorted... C.nz_length = 0; for (int col = 0; col < A.numCols; col++) { int idxA0 = A.col_idx[col]; int idxA1 = A.col_idx[col + 1]; int idxB0 = B.col_idx[col]; int idxB1 = B.col_idx[col + 1]; // compute the maximum number of elements that there can be in this row int maxInRow = Math.Min(idxA1 - idxA0, idxB1 - idxB0); // make sure there are enough non-zero elements in C if (C.nz_length + maxInRow > C.nz_values.Length) { C.growMaxLength(C.nz_values.Length + maxInRow, true); } // update the structure of C C.col_idx[col] = C.nz_length; // mark the rows that appear in A and save their value for (int i = idxA0; i < idxA1; i++) { int row = A.nz_rows[i]; w[row] = col; x[row] = A.nz_values[i]; } // If a row appears in A and B, multiply and set as an element in C for (int i = idxB0; i < idxB1; i++) { int row = B.nz_rows[i]; if (w[row] == col) { C.nz_values[C.nz_length] = x[row] * B.nz_values[i]; C.nz_rows[C.nz_length++] = row; } } } C.col_idx[C.numCols] = C.nz_length; }
public ComputePermutation(bool hasRow, bool hasCol) { if (hasRow) { prow = new IGrowArray(); } if (hasCol) { pcol = new IGrowArray(); } }
/** * Perform matrix transpose * * @param a Input matrix. Not modified * @param a_t Storage for transpose of 'a'. Must be correct shape. data length might be adjusted. * @param gw (Optional) Storage for internal workspace. Can be null. */ public static void transpose(DMatrixSparseCSC a, DMatrixSparseCSC a_t, IGrowArray gw) { if (a_t.numRows != a.numCols || a_t.numCols != a.numRows) { throw new ArgumentException("Unexpected shape for transpose matrix"); } a_t.growMaxLength(a.nz_length, false); a_t.nz_length = a.nz_length; ImplCommonOps_DSCC.transpose(a, a_t, gw); }
/** * <p>Sorts an elimination tree {@link #eliminationTree} into postorder. In a postoredered tree, the d proper * descendants of any node k are numbered k-d through k-1. Non-recursive implementation for better performance.</p> * * <p>post[k] = i means node 'i' of the original tree is node 'k' in the postordered tree.</p> * * <p>See page 44</p> * * @param parent (Input) The elimination tree. * @param N Number of elements in parent * @param post (Output) Postordering permutation. * @param gwork (Optional) Internal workspace. Can be null */ public static void postorder(int[] parent, int N, int[] post, IGrowArray gwork) { if (parent.Length < N) { throw new ArgumentException("parent must be at least of length N"); } if (post.Length < N) { throw new ArgumentException("post must be at least of length N"); } int[] w = adjust(gwork, 3 * N); // w[0] to w[N-1] is initialized to the youngest child of node 'j' // w[N] to w[2N-1] is initialized to the second youngest child of node 'j' // w[2N] to w[3N-1] is the stacked of nodes to be examined in the dfs int next = N; // specify the linked list as being empty initially for (int j = 0; j < N; j++) { w[j] = -1; } // traverse nodes in reverse order for (int j = N - 1; j >= 0; j--) { // skip if j has no parent, i.e. is a root node if (parent[j] == -1) { continue; } // add j to the list of parents w[next + j] = w[parent[j]]; w[parent[j]] = j; } // perform the DFS on each root node int k = 0; for (int j = 0; j < N; j++) { if (parent[j] != -1) { continue; } k = postorder_dfs(j, k, w, post, N); } }
/** * Performs matrix multiplication. C = A*B<sup>T</sup>. B needs to be sorted and will be sorted if it * has not already been sorted. * * @param A (Input) Matrix. Not modified. * @param B (Input) Matrix. Value not modified but indicies will be sorted if not sorted already. * @param C (Output) Storage for results. Data length is increased if increased if insufficient. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void multTransB(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { if (A.numRows != C.numRows || B.numRows != C.numCols) { throw new ArgumentException("Inconsistent matrix shapes"); } if (!B.isIndicesSorted()) { B.sortIndices(null); } ImplSparseSparseMult_DSCC.multTransB(A, B, C, gw, gx); }
/** * Adds the results of adding a column in A and B as a new column in C.<br> * C(:,end+1) = α*A(:,colA) + β*B(:,colB) * * @param alpha scalar * @param A matrix * @param colA column in A * @param beta scalar * @param B matrix * @param colB column in B * @param C Column in C * @param gw workspace */ public static void addColAppend(double alpha, DMatrixSparseCSC A, int colA, double beta, DMatrixSparseCSC B, int colB, DMatrixSparseCSC C, IGrowArray gw) { if (A.numRows != B.numRows || A.numRows != C.numRows) { throw new ArgumentException("Number of rows in A, B, and C do not match"); } int idxA0 = A.col_idx[colA]; int idxA1 = A.col_idx[colA + 1]; int idxB0 = B.col_idx[colB]; int idxB1 = B.col_idx[colB + 1]; C.growMaxColumns(++C.numCols, true); C.growMaxLength(C.nz_length + idxA1 - idxA0 + idxB1 - idxB0, true); int[] w = TriangularSolver_DSCC.adjust(gw, A.numRows); //Arrays.fill(w, 0, A.numRows, -1); for (var i = 0; i < A.numRows; i++) { w[i] = -1; } for (int i = idxA0; i < idxA1; i++) { int row = A.nz_rows[i]; C.nz_rows[C.nz_length] = row; C.nz_values[C.nz_length] = alpha * A.nz_values[i]; w[row] = C.nz_length++; } for (int i = idxB0; i < idxB1; i++) { int row = B.nz_rows[i]; if (w[row] != -1) { C.nz_values[w[row]] += beta * B.nz_values[i]; } else { C.nz_values[C.nz_length] = beta * B.nz_values[i]; C.nz_rows[C.nz_length++] = row; } } C.col_idx[C.numCols] = C.nz_length; }
/** * Performs matrix multiplication. C = A*B * * @param A Matrix * @param B Matrix * @param C Storage for results. Data length is increased if increased if insufficient. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void mult(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { double[] x = TriangularSolver_DSCC.adjust(gx, A.numRows); int[] w = TriangularSolver_DSCC.adjust(gw, A.numRows, A.numRows); C.growMaxLength(A.nz_length + B.nz_length, false); C.indicesSorted = false; C.nz_length = 0; // C(i,j) = sum_k A(i,k) * B(k,j) int idx0 = B.col_idx[0]; for (int bj = 1; bj <= B.numCols; bj++) { int colB = bj - 1; int idx1 = B.col_idx[bj]; C.col_idx[bj] = C.nz_length; if (idx0 == idx1) { continue; } // C(:,j) = sum_k A(:,k)*B(k,j) for (int bi = idx0; bi < idx1; bi++) { int rowB = B.nz_rows[bi]; double valB = B.nz_values[bi]; // B(k,j) k=rowB j=colB multAddColA(A, rowB, valB, C, colB + 1, x, w); } // take the values in the dense vector 'x' and put them into 'C' int idxC0 = C.col_idx[colB]; int idxC1 = C.col_idx[colB + 1]; for (int i = idxC0; i < idxC1; i++) { C.nz_values[i] = x[C.nz_rows[i]]; } idx0 = idx1; } }
/** * <p> * Performs a rank-1 update operation on the submatrix specified by V with the multiply on the right.<br> * <br> * C = (I - γ*v*v<sup>T</sup>)*A<br> * </p> * <p> * The order that matrix multiplies are performed has been carefully selected * to minimize the number of operations. * </p> * * <p> * Before this can become a truly generic operation the submatrix specification needs * to be made more generic. * </p> */ public static void rank1UpdateMultR(DMatrixSparseCSC V, int colV, double gamma, DMatrixSparseCSC A, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { if (V.numRows != A.numRows) { throw new ArgumentException("Number of rows in V and A must match"); } C.nz_length = 0; C.numRows = V.numRows; C.numCols = 0; for (int i = 0; i < A.numCols; i++) { double tau = CommonOps_DSCC.dotInnerColumns(V, colV, A, i, gw, gx); ImplCommonOps_DSCC.addColAppend(1.0, A, i, -gamma * tau, V, colV, C, gw); } }
/** * Computes the inner product of two column vectors taken from the input matrices. * * <p>dot = A(:,colA)'*B(:,colB)</p> * * @param A Matrix * @param colA Column in A * @param B Matrix * @param colB Column in B * @return Dot product */ public static double dotInnerColumns(DMatrixSparseCSC A, int colA, DMatrixSparseCSC B, int colB, IGrowArray gw, DGrowArray gx) { if (A.numRows != B.numRows) { throw new ArgumentException("Number of rows must match."); } int[] w = TriangularSolver_DSCC.adjust(gw, A.numRows); //Arrays.fill(w,0,A.numRows,-1); for (var i = 0; i < A.numRows; i++) { w[i] = -1; } double[] x = TriangularSolver_DSCC.adjust(gx, A.numRows); int length = 0; int idx0 = A.col_idx[colA]; int idx1 = A.col_idx[colA + 1]; for (int i = idx0; i < idx1; i++) { int row = A.nz_rows[i]; x[length] = A.nz_values[i]; w[row] = length++; } double dot = 0; idx0 = B.col_idx[colB]; idx1 = B.col_idx[colB + 1]; for (int i = idx0; i < idx1; i++) { int row = B.nz_rows[i]; if (w[row] != -1) { dot += x[w[row]] * B.nz_values[i]; } } return(dot); }
/** * Performs a matrix transpose. * * @param A Original matrix. Not modified. * @param C Storage for transposed 'a'. Reshaped. * @param gw (Optional) Storage for internal workspace. Can be null. */ public static void transpose(DMatrixSparseCSC A, DMatrixSparseCSC C, IGrowArray gw) { int[] work = TriangularSolver_DSCC.adjust(gw, A.numRows, A.numRows); C.reshape(A.numCols, A.numRows, A.nz_length); // compute the histogram for each row in 'a' int idx0 = A.col_idx[0]; for (int j = 1; j <= A.numCols; j++) { int idx1 = A.col_idx[j]; for (int i = idx0; i < idx1; i++) { if (A.nz_rows.Length <= i) { throw new InvalidOperationException("Egads"); } work[A.nz_rows[i]]++; } idx0 = idx1; } // construct col_idx in the transposed matrix C.colsum(work); // fill in the row indexes idx0 = A.col_idx[0]; for (int j = 1; j <= A.numCols; j++) { int col = j - 1; int idx1 = A.col_idx[j]; for (int i = idx0; i < idx1; i++) { int row = A.nz_rows[i]; int index = work[row]++; C.nz_rows[index] = col; C.nz_values[index] = A.nz_values[i]; } idx0 = idx1; } }
public virtual int[] getRowPivotV(IGrowArray pivot) { return(UtilEjml.pivotVector(this.pivot, LU.numRows, pivot)); }
public void setGwork(IGrowArray gwork) { this.gwork = gwork; }
/** * Computes the inner product of two column vectors taken from the input matrices. * * <p>dot = A(:,colA)'*B(:,colB)</p> * * @param A Matrix * @param colA Column in A * @param B Matrix * @param colB Column in B * @return Dot product */ public static double dotInnerColumns(DMatrixSparseCSC A, int colA, DMatrixSparseCSC B, int colB, IGrowArray gw, DGrowArray gx) { return(ImplSparseSparseMult_DSCC.dotInnerColumns(A, colA, B, colB, gw, gx)); }
/** * Performs matrix multiplication. C = A<sup>T</sup></sup>*B * * @param A Matrix * @param B Matrix * @param C Storage for results. Data length is increased if increased if insufficient. * @param gw (Optional) Storage for internal workspace. Can be null. * @param gx (Optional) Storage for internal workspace. Can be null. */ public static void multTransA(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC C, IGrowArray gw, DGrowArray gx) { double[] x = TriangularSolver_DSCC.adjust(gx, A.numRows); int[] w = TriangularSolver_DSCC.adjust(gw, A.numRows, A.numRows); C.growMaxLength(A.nz_length + B.nz_length, false); C.indicesSorted = true; C.nz_length = 0; C.col_idx[0] = 0; int idxB0 = B.col_idx[0]; for (int bj = 1; bj <= B.numCols; bj++) { int idxB1 = B.col_idx[bj]; C.col_idx[bj] = C.nz_length; if (idxB0 == idxB1) { continue; } // convert the column of B into a dense format and mark which rows are used for (int bi = idxB0; bi < idxB1; bi++) { int rowB = B.nz_rows[bi]; x[rowB] = B.nz_values[bi]; w[rowB] = bj; } // C(colA,colB) = A(:,colA)*B(:,colB) for (int colA = 0; colA < A.numCols; colA++) { int idxA0 = A.col_idx[colA]; int idxA1 = A.col_idx[colA + 1]; double sum = 0; for (int ai = idxA0; ai < idxA1; ai++) { int rowA = A.nz_rows[ai]; if (w[rowA] == bj) { sum += x[rowA] * A.nz_values[ai]; } } if (sum != 0) { if (C.nz_length == C.nz_values.Length) { C.growMaxLength(C.nz_length * 2 + 1, true); } C.nz_values[C.nz_length] = sum; C.nz_rows[C.nz_length++] = colA; } } C.col_idx[bj] = C.nz_length; idxB0 = idxB1; } }
/** * Applies the permutation to upper triangular symmetric matrices. Typically a symmetric matrix only stores the * upper triangular part, so normal permutation will have undesirable results, e.g. the zeros will get mixed * in and will no longer be symmetric. This algorithm will handle the implicit lower triangular and construct * new upper triangular matrix. * * <p>See page cs_symperm() on Page 22 of "Direct Methods for Sparse Linear Systems"</p> * * @param input (Input) Upper triangular symmetric matrix which is to be permuted. * Entries below the diagonal are ignored. * @param permInv (Input) Inverse permutation vector. Specifies new order of the rows and columns. * @param output (Output) Upper triangular symmetric matrix which has the permutation stored in it. Reshaped. * @param gw (Optional) Storage for internal workspace. Can be null. */ public static void permuteSymmetric(DMatrixSparseCSC input, int[] permInv, DMatrixSparseCSC output, IGrowArray gw) { if (input.numRows != input.numCols) { throw new ArgumentException("Input must be a square matrix"); } if (input.numRows != permInv.Length) { throw new ArgumentException("Number of column in input must match length of permInv"); } if (input.numCols != permInv.Length) { throw new ArgumentException("Number of rows in input must match length of permInv"); } int N = input.numCols; int[] w = TriangularSolver_DSCC.adjustClear(gw, N); // histogram with column counts output.reshape(N, N, 0); output.indicesSorted = false; output.col_idx[0] = 0; // determine column counts for output for (int j = 0; j < N; j++) { int j2 = permInv[j]; int idx0 = input.col_idx[j]; int idx1 = input.col_idx[j + 1]; for (int p = idx0; p < idx1; p++) { int i = input.nz_rows[p]; if (i > j) // ignore the lower triangular portion { continue; } int i2 = permInv[i]; w[i2 > j2 ? i2 : j2]++; } } // update structure of output output.colsum(w); for (int j = 0; j < N; j++) { // column j of Input is row j2 of Output int j2 = permInv[j]; int idx0 = input.col_idx[j]; int idx1 = input.col_idx[j + 1]; for (int p = idx0; p < idx1; p++) { int i = input.nz_rows[p]; if (i > j) // ignore the lower triangular portion { continue; } int i2 = permInv[i]; // row i of Input is row i2 of Output int q = w[i2 > j2 ? i2 : j2]++; output.nz_rows[q] = i2 < j2 ? i2 : j2; output.nz_values[q] = input.nz_values[p]; } } }
public void setGw(IGrowArray gw) { this.gw = gw; }
public static void main(String[] args) { IMersenneTwister rand = new MersenneTwisterFast(234); // easy to work with sparse format, but hard to do computations with DMatrixSparseTriplet work = new DMatrixSparseTriplet(5, 4, 5); work.addItem(0, 1, 1.2); work.addItem(3, 0, 3); work.addItem(1, 1, 22.21234); work.addItem(2, 3, 6); // convert into a format that's easier to perform math with DMatrixSparseCSC Z = ConvertDMatrixStruct.convert(work, (DMatrixSparseCSC)null); // print the matrix to standard out in two different formats Z.print(); Console.WriteLine(); Z.printNonZero(); Console.WriteLine(); // Create a large matrix that is 5% filled DMatrixSparseCSC A = RandomMatrices_DSCC.rectangle(ROWS, COLS, (int)(ROWS * COLS * 0.05), rand); // large vector that is 70% filled DMatrixSparseCSC x = RandomMatrices_DSCC.rectangle(COLS, XCOLS, (int)(XCOLS * COLS * 0.7), rand); Console.WriteLine("Done generating random matrices"); // storage for the initial solution DMatrixSparseCSC y = new DMatrixSparseCSC(ROWS, XCOLS, 0); DMatrixSparseCSC z = new DMatrixSparseCSC(ROWS, XCOLS, 0); // To demonstration how to perform sparse math let's multiply: // y=A*x // Optional storage is set to null so that it will declare it internally long before = DateTimeHelper.CurrentTimeMilliseconds; IGrowArray workA = new IGrowArray(A.numRows); DGrowArray workB = new DGrowArray(A.numRows); for (int i = 0; i < 100; i++) { CommonOps_DSCC.mult(A, x, y, workA, workB); CommonOps_DSCC.add(1.5, y, 0.75, y, z, workA, workB); } long after = DateTimeHelper.CurrentTimeMilliseconds; Console.WriteLine("norm = " + NormOps_DSCC.fastNormF(y) + " sparse time = " + (after - before) + " ms"); DMatrixRMaj Ad = ConvertDMatrixStruct.convert(A, (DMatrixRMaj)null); DMatrixRMaj xd = ConvertDMatrixStruct.convert(x, (DMatrixRMaj)null); DMatrixRMaj yd = new DMatrixRMaj(y.numRows, y.numCols); DMatrixRMaj zd = new DMatrixRMaj(y.numRows, y.numCols); before = DateTimeHelper.CurrentTimeMilliseconds; for (int i = 0; i < 100; i++) { CommonOps_DDRM.mult(Ad, xd, yd); CommonOps_DDRM.add(1.5, yd, 0.75, yd, zd); } after = DateTimeHelper.CurrentTimeMilliseconds; Console.WriteLine("norm = " + NormOps_DDRM.fastNormF(yd) + " dense time = " + (after - before) + " ms"); }