public virtual void invert(DMatrixRBlock A_inv) { DMatrixRBlock T = decomposer.getT(null); if (A_inv.numRows != T.numRows || A_inv.numCols != T.numCols) { throw new ArgumentException("Unexpected number or rows and/or columns"); } if (temp == null || temp.Length < blockLength * blockLength) { temp = new double[blockLength * blockLength]; } // zero the upper triangular portion of A_inv MatrixOps_DDRB.zeroTriangle(true, A_inv); DSubmatrixD1 L = new DSubmatrixD1(T); DSubmatrixD1 B = new DSubmatrixD1(A_inv); // invert L from cholesky decomposition and write the solution into the lower // triangular portion of A_inv // B = inv(L) TriangularSolver_DDRB.invert(blockLength, false, L, B, temp); // B = L^-T * B // todo could speed up by taking advantage of B being lower triangular // todo take advantage of symmetry TriangularSolver_DDRB.solveL(blockLength, L, B, true); }
public virtual bool decompose(DMatrixRMaj A) { Ablock.numRows = A.numRows; Ablock.numCols = A.numCols; Ablock.blockLength = blockLength; Ablock.data = A.data; int tmpLength = Math.Min(Ablock.blockLength, A.numRows) * A.numCols; if (tmp == null || tmp.Length < tmpLength) { tmp = new double[tmpLength]; } // doing an in-place convert is much more memory efficient at the cost of a little // but of CPU MatrixOps_DDRB.convertRowToBlock(A.numRows, A.numCols, Ablock.blockLength, A.data, tmp); bool ret = alg.decompose(Ablock); // convert it back to the normal format if it wouldn't have been modified if (!alg.inputModified()) { MatrixOps_DDRB.convertBlockToRow(A.numRows, A.numCols, Ablock.blockLength, A.data, tmp); } return(ret); }
public virtual DMatrixRBlock getR(DMatrixRBlock R, bool compact) { int min = Math.Min(dataA.numRows, dataA.numCols); if (R == null) { if (compact) { R = new DMatrixRBlock(min, dataA.numCols, blockLength); } else { R = new DMatrixRBlock(dataA.numRows, dataA.numCols, blockLength); } } else { if (compact) { if (R.numCols != dataA.numCols || R.numRows != min) { throw new ArgumentException("Unexpected dimension."); } } else if (R.numCols != dataA.numCols || R.numRows != dataA.numRows) { throw new ArgumentException("Unexpected dimension."); } } MatrixOps_DDRB.zeroTriangle(false, R); MatrixOps_DDRB.copyTriangle(true, dataA, R); return(R); }
/** * Converts 'A' into a block matrix and call setA() on the block matrix solver. * * @param A The A matrix in the linear equation. Not modified. Reference saved. * @return true if it can solve the system. */ public virtual bool setA(DMatrixRMaj A) { blockA.reshape(A.numRows, A.numCols, false); MatrixOps_DDRB.convert(A, blockA); return(alg.setA(blockA)); }
/** * Creates a block matrix the same size as A_inv, inverts the matrix and copies the results back * onto A_inv. * * @param A_inv Where the inverted matrix saved. Modified. */ public virtual void invert(DMatrixRMaj A_inv) { blockB.reshape(A_inv.numRows, A_inv.numCols, false); alg.invert(blockB); MatrixOps_DDRB.convert(blockB, A_inv); }
/** * Only converts the B matrix and passes that onto solve. Te result is then copied into * the input 'X' matrix. * * @param B A matrix ℜ <sup>m × p</sup>. Not modified. * @param X A matrix ℜ <sup>n × p</sup>, where the solution is written to. Modified. */ public override void solve(DMatrixRMaj B, DMatrixRMaj X) { blockB.reshape(B.numRows, B.numCols, false); MatrixOps_DDRB.convert(B, blockB); // since overwrite B is true X does not need to be passed in alg.solve(blockB, null); MatrixOps_DDRB.convert(blockB, X); }
public virtual /**/ double quality() { return(alg.quality()); } /** * Converts B and X into block matrices and calls the block matrix solve routine. * * @param B A matrix ℜ <sup>m × p</sup>. Not modified. * @param X A matrix ℜ <sup>n × p</sup>, where the solution is written to. Modified. */ public virtual void solve(DMatrixRMaj B, DMatrixRMaj X) { blockB.reshape(B.numRows, B.numCols, false); blockX.reshape(X.numRows, X.numCols, false); MatrixOps_DDRB.convert(B, blockB); alg.solve(blockB, blockX); MatrixOps_DDRB.convert(blockX, X); }
public virtual void convertBlockToRow(int numRows, int numCols, int blockLength, double[] data) { int tmpLength = Math.Min(blockLength, numRows) * numCols; if (tmp == null || tmp.Length < tmpLength) { tmp = new double[tmpLength]; } MatrixOps_DDRB.convertBlockToRow(numRows, numCols, Ablock.blockLength, data, tmp); }
public virtual DMatrixRMaj getT(DMatrixRMaj T) { DMatrixRBlock T_block = ((CholeskyOuterForm_DDRB)alg).getT(null); if (T == null) { T = new DMatrixRMaj(T_block.numRows, T_block.numCols); } MatrixOps_DDRB.convert(T_block, T); // todo set zeros return(T); }
//@Override public DMatrixRMaj getR(DMatrixRMaj R, bool compact) { DMatrixRBlock Rblock; Rblock = ((QRDecompositionHouseholder_DDRB)alg).getR(null, compact); if (R == null) { R = new DMatrixRMaj(Rblock.numRows, Rblock.numCols); } MatrixOps_DDRB.convert(Rblock, R); return(R); }
/** * Sanity checks the input or declares a new matrix. Return matrix is an identity matrix. */ public static DMatrixRBlock initializeQ(DMatrixRBlock Q, int numRows, int numCols, int blockLength, bool compact) { int minLength = Math.Min(numRows, numCols); if (compact) { if (Q == null) { Q = new DMatrixRBlock(numRows, minLength, blockLength); MatrixOps_DDRB.setIdentity(Q); } else { if (Q.numRows != numRows || Q.numCols != minLength) { throw new ArgumentException("Unexpected matrix dimension. Found " + Q.numRows + " " + Q.numCols); } else { MatrixOps_DDRB.setIdentity(Q); } } } else { if (Q == null) { Q = new DMatrixRBlock(numRows, numRows, blockLength); MatrixOps_DDRB.setIdentity(Q); } else { if (Q.numRows != numRows || Q.numCols != numRows) { throw new ArgumentException("Unexpected matrix dimension. Found " + Q.numRows + " " + Q.numCols); } else { MatrixOps_DDRB.setIdentity(Q); } } } return(Q); }
private bool decomposeLower() { int blockLength = T.blockLength; subA.set(T); subB.set(T); subC.set(T); for (int i = 0; i < T.numCols; i += blockLength) { int widthA = Math.Min(blockLength, T.numCols - i); subA.col0 = i; subA.col1 = i + widthA; subA.row0 = subA.col0; subA.row1 = subA.col1; subB.col0 = i; subB.col1 = i + widthA; subB.row0 = i + widthA; subB.row1 = T.numRows; subC.col0 = i + widthA; subC.col1 = T.numRows; subC.row0 = i + widthA; subC.row1 = T.numRows; // cholesky on inner block A if (!InnerCholesky_DDRB.lower(subA)) { return(false); } // on the last block these operations are not needed. if (widthA == blockLength) { // B = L^-1 B TriangularSolver_DDRB.solveBlock(blockLength, false, subA, subB, false, true); // C = C - B * B^T InnerRankUpdate_DDRB.symmRankNMinus_L(blockLength, subC, subB); } } MatrixOps_DDRB.zeroTriangle(true, T); return(true); }
public virtual /**/ double quality() { return(SpecializedOps_DDRM.qualityTriangular(decomposer.getT(null))); } /** * If X == null then the solution is written into B. Otherwise the solution is copied * from B into X. */ public virtual void solve(DMatrixRBlock B, DMatrixRBlock X) { if (B.blockLength != blockLength) { throw new ArgumentException("Unexpected blocklength in B."); } DSubmatrixD1 L = new DSubmatrixD1(decomposer.getT(null)); if (X != null) { if (X.blockLength != blockLength) { throw new ArgumentException("Unexpected blocklength in X."); } if (X.numRows != L.col1) { throw new ArgumentException("Not enough rows in X"); } } if (B.numRows != L.col1) { throw new ArgumentException("Not enough rows in B"); } // L * L^T*X = B // Solve for Y: L*Y = B TriangularSolver_DDRB.solve(blockLength, false, L, new DSubmatrixD1(B), false); // L^T * X = Y TriangularSolver_DDRB.solve(blockLength, false, L, new DSubmatrixD1(B), true); if (X != null) { // copy the solution from B into X MatrixOps_DDRB.extractAligned(B, X); } }
public virtual /**/ double quality() { return(SpecializedOps_DDRM.qualityTriangular(decomposer.getQR())); } public virtual void solve(DMatrixRBlock B, DMatrixRBlock X) { if (B.numCols != X.numCols) { throw new ArgumentException("Columns of B and X do not match"); } if (QR.numCols != X.numRows) { throw new ArgumentException("Rows in X do not match the columns in A"); } if (QR.numRows != B.numRows) { throw new ArgumentException("Rows in B do not match the rows in A."); } if (B.blockLength != QR.blockLength || X.blockLength != QR.blockLength) { throw new ArgumentException("All matrices must have the same block length."); } // The system being solved for can be described as: // Q*R*X = B // First apply householder reflectors to B // Y = Q^T*B decomposer.applyQTran(B); // Second solve for Y using the upper triangle matrix R and the just computed Y // X = R^-1 * Y MatrixOps_DDRB.extractAligned(B, X); // extract a block aligned matrix int M = Math.Min(QR.numRows, QR.numCols); TriangularSolver_DDRB.solve(QR.blockLength, true, new DSubmatrixD1(QR, 0, M, 0, M), new DSubmatrixD1(X), false); } /** * Invert by solving for against an identity matrix. * * @param A_inv Where the inverted matrix saved. Modified. */ public virtual void invert(DMatrixRBlock A_inv) { int M = Math.Min(QR.numRows, QR.numCols); if (A_inv.numRows != M || A_inv.numCols != M) { throw new ArgumentException("A_inv must be square an have dimension " + M); } // Solve for A^-1 // Q*R*A^-1 = I // Apply householder reflectors to the identity matrix // y = Q^T*I = Q^T MatrixOps_DDRB.setIdentity(A_inv); decomposer.applyQTran(A_inv); // Solve using upper triangular R matrix // R*A^-1 = y // A^-1 = R^-1*y TriangularSolver_DDRB.solve(QR.blockLength, true, new DSubmatrixD1(QR, 0, M, 0, M), new DSubmatrixD1(A_inv), false); }