/** * 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]]; } } }
/** * 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; }
/** * 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; } }
/** * 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; } }
/** * 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; } }