public virtual void invert(FMatrixRBlock A_inv) { FMatrixRBlock 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 float[blockLength * blockLength]; } // zero the upper triangular portion of A_inv MatrixOps_FDRB.zeroTriangle(true, A_inv); FSubmatrixD1 L = new FSubmatrixD1(T); FSubmatrixD1 B = new FSubmatrixD1(A_inv); // invert L from cholesky decomposition and write the solution into the lower // triangular portion of A_inv // B = inv(L) TriangularSolver_FDRB.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_FDRB.solveL(blockLength, L, B, true); }
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_FDRB.lower(subA)) { return(false); } // on the last block these operations are not needed. if (widthA == blockLength) { // B = L^-1 B TriangularSolver_FDRB.solveBlock(blockLength, false, subA, subB, false, true); // C = C - B * B^T InnerRankUpdate_FDRB.symmRankNMinus_L(blockLength, subC, subB); } } MatrixOps_FDRB.zeroTriangle(true, T); return(true); }
public virtual /**/ double quality() { return(SpecializedOps_FDRM.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(FMatrixRBlock B, FMatrixRBlock X) { if (B.blockLength != blockLength) { throw new ArgumentException("Unexpected blocklength in B."); } FSubmatrixD1 L = new FSubmatrixD1(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_FDRB.solve(blockLength, false, L, new FSubmatrixD1(B), false); // L^T * X = Y TriangularSolver_FDRB.solve(blockLength, false, L, new FSubmatrixD1(B), true); if (X != null) { // copy the solution from B into X MatrixOps_FDRB.extractAligned(B, X); } }
public virtual /**/ double quality() { return(SpecializedOps_FDRM.qualityTriangular(decomposer.getQR())); } public virtual void solve(FMatrixRBlock B, FMatrixRBlock 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_FDRB.extractAligned(B, X); // extract a block aligned matrix int M = Math.Min(QR.numRows, QR.numCols); TriangularSolver_FDRB.solve(QR.blockLength, true, new FSubmatrixD1(QR, 0, M, 0, M), new FSubmatrixD1(X), false); } /** * Invert by solving for against an identity matrix. * * @param A_inv Where the inverted matrix saved. Modified. */ public virtual void invert(FMatrixRBlock 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_FDRB.setIdentity(A_inv); decomposer.applyQTran(A_inv); // Solve using upper triangular R matrix // R*A^-1 = y // A^-1 = R^-1*y TriangularSolver_FDRB.solve(QR.blockLength, true, new FSubmatrixD1(QR, 0, M, 0, M), new FSubmatrixD1(A_inv), false); }