/** * Initializes class data structures and parameters */ void initialize(DMatrixSparseCSC A) { m = A.numRows; n = A.numCols; int s = 4 * n + (ata ? (n + m + 1) : 0); gw.reshape(s); w = gw.data; // compute the transpose of A At.reshape(A.numCols, A.numRows, A.nz_length); CommonOps_DSCC.transpose(A, At, gw); // initialize w //Arrays.fill(w, 0, s, -1); // assign all values in workspace to -1 for (var i = 0; i < s; i++) { w[i] = -1; } ancestor = 0; maxfirst = n; prevleaf = 2 * n; first = 3 * n; }
/** * 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); }
//@Override public DMatrixSparseCSC getRowPivot(DMatrixSparseCSC pivot) { if (pivot == null) { pivot = new DMatrixSparseCSC(L.numRows, L.numRows, 0); } pivot.reshape(L.numRows, L.numRows, L.numRows); CommonOps_DSCC.permutationMatrix(pinv, true, L.numRows, pivot); return(pivot); }
/** * 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]]; } } }
//@Override public void solve(DMatrixRMaj B, DMatrixRMaj X) { double[] b = TriangularSolver_DSCC.adjust(gb, B.numRows); double[] bp = TriangularSolver_DSCC.adjust(gbp, B.numRows); double[] x = TriangularSolver_DSCC.adjust(gx, X.numRows); int[] pinv = qr.getStructure().getPinv(); // process each column in X and B individually for (int colX = 0; colX < X.numCols; colX++) { int index = colX; for (int i = 0; i < B.numRows; i++, index += X.numCols) { b[i] = B.data[index]; } // apply row pivots CommonOps_DSCC.permuteInv(pinv, b, bp, m); // apply Householder reflectors for (int j = 0; j < n; j++) { QrHelperFunctions_DSCC.applyHouseholder(qr.getV(), j, qr.getBeta(j), bp); } // Solve for R*x = b TriangularSolver_DSCC.solveU(qr.getR(), bp); // undo the permutation double[] output; if (qr.isFillPermutated()) { CommonOps_DSCC.permute(qr.getFillPermutation(), bp, x, X.numRows); output = x; } else { output = bp; } index = colX; for (int i = 0; i < X.numRows; i++, index += X.numCols) { X.data[index] = output[i]; } } }
//@Override public void solve(DMatrixRMaj B, DMatrixRMaj X) { // if( B.numCols != X.numCols || B.numRows != numRows || X.numRows != numCols) { // throw new ArgumentException("Unexpected matrix size"); // } int[] pinv = decomposition.getPinv(); int[] q = decomposition.getReducePermutation(); double[] x = TriangularSolver_DSCC.adjust(gx, X.numRows); double[] b = TriangularSolver_DSCC.adjust(gb, B.numRows); DMatrixSparseCSC L = decomposition.getL(); DMatrixSparseCSC U = decomposition.getU(); bool reduceFill = decomposition.getReduceFill() != null; // process each column in X and B individually for (int colX = 0; colX < X.numCols; colX++) { int index = colX; for (int i = 0; i < B.numRows; i++, index += X.numCols) { b[i] = B.data[index]; } CommonOps_DSCC.permuteInv(pinv, b, x, X.numRows); TriangularSolver_DSCC.solveL(L, x); TriangularSolver_DSCC.solveU(U, x); double[] d; if (reduceFill) { CommonOps_DSCC.permute(q, x, b, X.numRows); d = b; } else { d = x; } index = colX; for (int i = 0; i < X.numRows; i++, index += X.numCols) { X.data[index] = d[i]; } } }
/** * <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); } }
public static void main(string[] args) { // create a random matrix that can be solved int N = 5; IMersenneTwister rand = new MersenneTwisterFast(234); DMatrixSparseCSC A = RandomMatrices_DSCC.rectangle(N, N, N * N / 4, rand); RandomMatrices_DSCC.ensureNotSingular(A, rand); // Create the LU decomposition LUSparseDecomposition_F64 <DMatrixSparseCSC> decompose = DecompositionFactory_DSCC.lu(FillReducing.NONE); // Decompose the matrix. // If you care about the A matrix being modified call decompose.inputModified() if (!decompose.decompose(A)) { throw new InvalidOperationException("The matrix is singular"); } // Extract new copies of the L and U matrices DMatrixSparseCSC L = decompose.getLower(null); DMatrixSparseCSC U = decompose.getUpper(null); DMatrixSparseCSC P = decompose.getRowPivot(null); // Storage for an intermediate step DMatrixSparseCSC tmp = (DMatrixSparseCSC)A.createLike(); // Storage for the inverse matrix DMatrixSparseCSC Ainv = (DMatrixSparseCSC)A.createLike(); // Solve for the inverse: P*I = L*U*inv(A) TriangularSolver_DSCC.solve(L, true, P, tmp, null, null, null); TriangularSolver_DSCC.solve(U, false, tmp, Ainv, null, null, null); // Make sure the inverse has been found. A*inv(A) = identity should be an identity matrix DMatrixSparseCSC found = (DMatrixSparseCSC)A.createLike(); CommonOps_DSCC.mult(A, Ainv, found); found.print(); }
//@Override public DMatrixSparseCSC getR(DMatrixSparseCSC R, bool compact) { if (R == null) { R = new DMatrixSparseCSC(0, 0, 0); } R.set(this.R); if (m > n) { // there should only be only zeros past row n R.numRows = compact ? n : m; } else if (n > m && V.numRows != m) { DMatrixSparseCSC tmp = new DMatrixSparseCSC(m, n, 0); CommonOps_DSCC.extractRows(R, 0, m, tmp); R.set(tmp); } return(R); }
//@Override public DMatrixSparseCSC getQ(DMatrixSparseCSC Q, bool compact) { if (Q == null) { Q = new DMatrixSparseCSC(1, 1, 0); } if (compact) { Q.reshape(V.numRows, n, 0); } else { Q.reshape(V.numRows, m, 0); } DMatrixSparseCSC I = CommonOps_DSCC.identity(V.numRows, Q.numCols); for (int i = V.numCols - 1; i >= 0; i--) { QrHelperFunctions_DSCC.rank1UpdateMultR(V, i, beta[i], I, Q, gwork, gx); I.set(Q); } // Apply P transpose to Q CommonOps_DSCC.permutationInverse(structure.pinv, structureP, V.numRows); CommonOps_DSCC.permuteRowInv(structureP, Q, I); // Remove fictitious rows if (V.numRows > m) { CommonOps_DSCC.extractRows(I, 0, m, Q); } else { Q.set(I); } return(Q); }
//@Override public void solve(DMatrixRMaj B, DMatrixRMaj X) { DMatrixSparseCSC L = cholesky.getL(); int N = L.numRows; double[] b = TriangularSolver_DSCC.adjust(gb, N); double[] x = TriangularSolver_DSCC.adjust(gx, N); int[] Pinv = reduce.getArrayPinv(); for (int col = 0; col < B.numCols; col++) { int index = col; for (int i = 0; i < N; i++, index += B.numCols) { b[i] = B.data[index]; } if (Pinv != null) { CommonOps_DSCC.permuteInv(Pinv, b, x, N); TriangularSolver_DSCC.solveL(L, x); TriangularSolver_DSCC.solveTranL(L, x); CommonOps_DSCC.permute(Pinv, x, b, N); } else { TriangularSolver_DSCC.solveL(L, b); TriangularSolver_DSCC.solveTranL(L, b); } index = col; for (int i = 0; i < N; i++, index += X.numCols) { X.data[index] = b[i]; } } }
//@Override public void minus(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC output) { CommonOps_DSCC.add(1, A, -1, B, output, null, null); }
//@Override public void mult(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC output) { CommonOps_DSCC.mult(A, B, output); }
//@Override public void transpose(DMatrixSparseCSC input, DMatrixSparseCSC output) { CommonOps_DSCC.transpose(input, output, null); }
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"); }