private bool performDecomposition(DMatrixSparseCSC A) { int[] c = TriangularSolver_DSCC.adjust(gw, N); int[] s = TriangularSolver_DSCC.adjust(gs, N); double[] x = TriangularSolver_DSCC.adjust(gx, N); Array.Copy(L.col_idx, 0, c, 0, N); for (int k = 0; k < N; k++) { //---- Nonzero pattern of L(k,:) int top = TriangularSolver_DSCC.searchNzRowsElim(A, k, parent, s, c); // x(0:k) is now zero x[k] = 0; int idx0 = A.col_idx[k]; int idx1 = A.col_idx[k + 1]; // x = full(triu(C(:,k))) for (int q = idx0; q < idx1; q++) { if (A.nz_rows[q] <= k) { x[A.nz_rows[q]] = A.nz_values[q]; } } double d = x[k]; // d = C(k,k) x[k] = 0; // clear x for k+1 iteration //---- Triangular Solve for (; top < N; top++) { int i = s[top]; double lki = x[i] / L.nz_values[L.col_idx[i]]; // L(k,i) = x(i) / L(i,i) x[i] = 0; for (int r = L.col_idx[i] + 1; r < c[i]; r++) { x[L.nz_rows[r]] -= L.nz_values[r] * lki; } d -= lki * lki; // d = d - L(k,i)**L(k,i) int t = c[i]++; L.nz_rows[t] = k; // store L(k,i) in column i L.nz_values[t] = lki; } //----- Compute L(k,k) if (d <= 0) { // it's not positive definite return(false); } int p = c[k]++; L.nz_rows[p] = k; L.nz_values[p] = Math.Sqrt(d); } return(true); }
public void performSymbolic(DMatrixSparseCSC A) { init(A.numCols); TriangularSolver_DSCC.eliminationTree(A, false, parent, gw); TriangularSolver_DSCC.postorder(parent, N, post, gw); columnCounter.process(A, parent, post, counts); L.reshape(A.numRows, A.numCols, 0); L.colsum(counts); }
/** * Count the number of non-zero elements in R */ void countNonZeroInR(int[] parent) { TriangularSolver_DSCC.postorder(parent, n, post, gwork); columnCounts.process(A, parent, post, countsR); nz_in_R = 0; for (int k = 0; k < n; k++) { nz_in_R += countsR[k]; } if (nz_in_R < 0) { throw new InvalidOperationException("Too many elements. Numerical overflow in R counts"); } }
//@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]; } } }
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 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]; } } }
/** * Examins the structure of A for QR decomposition * @param A matrix which is to be decomposed * @return true if the solution is valid or false if the decomposition can't be performed (i.e. requires column pivots) */ public bool process(DMatrixSparseCSC A) { init(A); TriangularSolver_DSCC.eliminationTree(A, true, parent, gwork); countNonZeroInR(parent); countNonZeroInV(parent); // if more columns than rows it's possible that Q*R != A. That's because a householder // would need to be created that's outside the m by m Q matrix. In reality it has // a partial solution. Column pivot are needed. if (m < n) { for (int row = 0; row < m; row++) { if (gwork.data[head + row] < 0) { return(false); } } } return(true); }
//@Override public /**/ double quality() { return(TriangularSolver_DSCC.qualityTriangular(qr.getR())); }
/** * 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]; } } }
private bool performLU(DMatrixSparseCSC A) { int m = A.numRows; int n = A.numCols; int[] q = applyReduce.getArrayP(); // main loop for computing L and U for (int k = 0; k < n; k++) { //--------- Triangular Solve L.col_idx[k] = L.nz_length; // start of column k U.col_idx[k] = U.nz_length; // grow storage in L and U if needed if (L.nz_length + n > L.nz_values.Length) { L.growMaxLength(2 * L.nz_values.Length + n, true); } if (U.nz_length + n > U.nz_values.Length) { U.growMaxLength(2 * U.nz_values.Length + n, true); } int col = q != null ? q[k] : k; int top = TriangularSolver_DSCC.solve(L, true, A, col, x, pinv, gxi, gw); int[] xi = gxi.data; //--------- Find the Next Pivot. That will be the row with the largest value // int ipiv = -1; double a = -double.MaxValue; for (int p = top; p < n; p++) { int i = xi[p]; // x(i) is nonzero if (pinv[i] < 0) { double t; if ((t = Math.Abs(x[i])) > a) { a = t; ipiv = i; } } else { U.nz_rows[U.nz_length] = pinv[i]; U.nz_values[U.nz_length++] = x[i]; } } if (ipiv == -1 || a <= 0) { singular = true; return(false); } // NOTE: The line is commented out below. It can cause a poor pivot to be selected. Instead of the largest // row it will pick whatever is in this column. it does try to make sure it's not zero, but I'm not // sure what it's purpose is. // if( pinv[col] < 0 && Math.Abs(x[col]) >= a*tol ) { // ipiv = col; // } //---------- Divide by the pivot double pivot = x[ipiv]; U.nz_rows[U.nz_length] = k; U.nz_values[U.nz_length++] = pivot; // last entry in U(:k) us U(k,k) pinv[ipiv] = k; L.nz_rows[L.nz_length] = ipiv; // First entry L(:,k) is L(k,k) = 1 L.nz_values[L.nz_length++] = 1; for (int p = top; p < n; p++) { int i = xi[p]; if (pinv[i] < 0) { // x(i) is entry in L(:,k) L.nz_rows[L.nz_length] = i; L.nz_values[L.nz_length++] = x[i] / pivot; } x[i] = 0; } } //----------- Finalize L and U L.col_idx[n] = L.nz_length; U.col_idx[n] = U.nz_length; for (int p = 0; p < L.nz_length; p++) { L.nz_rows[p] = pinv[L.nz_rows[p]]; } // Console.WriteLine(" reduce "+(reduceFill!=null)); // System.out.print(" pinv[ "); // for (int i = 0; i < A.numCols; i++) { // System.out.printf("%2d ",pinv[i]); // } // Console.WriteLine(" ]"); return(true); }
//@Override public double quality() { return(TriangularSolver_DSCC.qualityTriangular(decomposition.getU())); }
//@Override public double quality() { return(TriangularSolver_DSCC.qualityTriangular(cholesky.getL())); }