virtual public 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) { //X = B.create<DMatrixRBlock>(L.col1, B.numCols); X = new DMatrixRBlock(L.col1, B.numCols); } else { X.reshape(L.col1, B.numCols, blockLength, false); } // 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 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"); } // 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, workspace); // 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); }
/** * 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 decomposeUpper() { 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); //@formatter:off subA.col0 = i; subA.col1 = i + widthA; subA.row0 = subA.col0; subA.row1 = subA.col1; subB.col0 = i + widthA; subB.col1 = T.numCols; subB.row0 = i; subB.row1 = i + widthA; subC.col0 = i + widthA; subC.col1 = T.numCols; subC.row0 = i + widthA; subC.row1 = T.numCols; //@formatter:on // cholesky on inner block A if (!InnerCholesky_DDRB.upper(subA)) { return(false); } // on the last block these operations are not needed. if (widthA == blockLength) { // B = U^-1 B TriangularSolver_DDRB.solveBlock(blockLength, true, subA, subB, true, false); // C = C - B^T * B InnerRankUpdate_DDRB.symmRankNMinus_U(blockLength, subC, subB); } } MatrixOps_DDRB.zeroTriangle(false, T); return(true); }
public static void checkShapeMult(int blockLength, DSubmatrixD1 A, DSubmatrixD1 B, DSubmatrixD1 C) { //@formatter:off int Arow = A.Rows; int Acol = A.Cols; int Brow = B.Rows; int Bcol = B.Cols; int Crow = C.Rows; int Ccol = C.Cols; //@formatter:on if (Arow != Crow) { throw new SystemException("Mismatch A and C rows"); } if (Bcol != Ccol) { throw new SystemException("Mismatch B and C columns"); } if (Acol != Brow) { throw new SystemException("Mismatch A columns and B rows"); } if (!MatrixOps_DDRB.blockAligned(blockLength, A)) { throw new SystemException("Sub-Matrix A is not block aligned"); } if (!MatrixOps_DDRB.blockAligned(blockLength, B)) { throw new SystemException("Sub-Matrix B is not block aligned"); } if (!MatrixOps_DDRB.blockAligned(blockLength, C)) { throw new SystemException("Sub-Matrix C is not block aligned"); } }
/** * <p> * Performs a matrix multiplication on {@link DMatrixRBlock} submatrices.<br> * <br> * c = a * b <br> * <br> * </p> * * <p> * It is assumed that all submatrices start at the beginning of a block and end at the end of a block. * </p> * * @param blockLength Size of the blocks in the submatrix. * @param A A submatrix. Not modified. * @param B A submatrix. Not modified. * @param C Result of the operation. Modified, */ public static void mult(int blockLength, DSubmatrixD1 A, DSubmatrixD1 B, DSubmatrixD1 C) { MatrixOps_DDRB.checkShapeMult(blockLength, A, B, C); //CONCURRENT_BELOW EjmlConcurrency.loopFor(A.row0,A.row1,blockLength,i->{ for (int i = A.row0; i < A.row1; i += blockLength) { int heightA = Math.Min(blockLength, A.row1 - i); for (int j = B.col0; j < B.col1; j += blockLength) { int widthB = Math.Min(blockLength, B.col1 - j); int indexC = (i - A.row0 + C.row0) * C.original.numCols + (j - B.col0 + C.col0) * heightA; for (int k = A.col0; k < A.col1; k += blockLength) { int widthA = Math.Min(blockLength, A.col1 - k); int indexA = i * A.original.numCols + k * heightA; int indexB = (k - A.col0 + B.row0) * B.original.numCols + j * widthA; if (k == A.col0) { InnerMultiplication_DDRB.blockMultSet(A.original.data, B.original.data, C.original.data, indexA, indexB, indexC, heightA, widthA, widthB); } else { InnerMultiplication_DDRB.blockMultPlus(A.original.data, B.original.data, C.original.data, indexA, indexB, indexC, heightA, widthA, widthB); } } } } //CONCURRENT_ABOVE }); }