/** * <p> * Performs a matrix multiplication on {@link DMatrixRBlock} submatrices.<br> * <br> * c = 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 multPlus(int blockLength, DSubmatrixD1 A, DSubmatrixD1 B, DSubmatrixD1 C) { // 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; InnerMultiplication_DDRB.blockMultPlus(A.original.data, B.original.data, C.original.data, indexA, indexB, indexC, heightA, widthA, widthB); } } } //CONCURRENT_ABOVE }); }
/** * <p> * Performs:<br> * <br> * A = A + α B <sup>T</sup>B * </p> * * @param blockLength Size of the block in the block matrix. * @param alpha scaling factor for right hand side. * @param A Block aligned submatrix. * @param B Block aligned submatrix. */ public static void rankNUpdate(int blockLength, double alpha, DSubmatrixD1 A, DSubmatrixD1 B) { int heightB = B.row1 - B.row0; if (heightB > blockLength) { throw new ArgumentException("Height of B cannot be greater than the block length"); } int N = B.col1 - B.col0; if (A.col1 - A.col0 != N) { throw new ArgumentException("A does not have the expected number of columns based on B's width"); } if (A.row1 - A.row0 != N) { throw new ArgumentException("A does not have the expected number of rows based on B's width"); } //CONCURRENT_BELOW EjmlConcurrency.loopFor(B.col0,B.col1,blockLength,i->{ for (int i = B.col0; i < B.col1; i += blockLength) { int indexB_i = B.row0 * B.original.numCols + i * heightB; int widthB_i = Math.Min(blockLength, B.col1 - i); int rowA = i - B.col0 + A.row0; int heightA = Math.Min(blockLength, A.row1 - rowA); for (int j = B.col0; j < B.col1; j += blockLength) { int widthB_j = Math.Min(blockLength, B.col1 - j); int indexA = rowA * A.original.numCols + (j - B.col0 + A.col0) * heightA; int indexB_j = B.row0 * B.original.numCols + j * heightB; InnerMultiplication_DDRB.blockMultPlusTransA(alpha, B.original.data, B.original.data, A.original.data, indexB_i, indexB_j, indexA, heightB, widthB_i, widthB_j); } } //CONCURRENT_ABOVE }); }
/** * <p> * Performs a matrix multiplication on the block aligned submatrices. A is * assumed to be block column vector that is lower triangular with diagonal elements set to 1.<br> * <br> * C = A^T * B * </p> */ public static void multTransA_vecCol(int blockLength, DSubmatrixD1 A, DSubmatrixD1 B, DSubmatrixD1 C) { int widthA = A.col1 - A.col0; if (widthA > blockLength) { throw new ArgumentException("A is expected to be at most one block wide."); } //CONCURRENT_BELOW EjmlConcurrency.loopFor(B.col0, B.col1, blockLength, j -> { for (int j = B.col0; j < B.col1; j += blockLength) { int widthB = Math.Min(blockLength, B.col1 - j); int indexC = C.row0 * C.original.numCols + (j - B.col0 + C.col0) * widthA; for (int k = A.row0; k < A.row1; k += blockLength) { int heightA = Math.Min(blockLength, A.row1 - k); int indexA = k * A.original.numCols + A.col0 * heightA; int indexB = (k - A.row0 + B.row0) * B.original.numCols + j * heightA; if (k == A.row0) { multTransABlockSet_lowerTriag(A.original.data, B.original.data, C.original.data, indexA, indexB, indexC, heightA, widthA, widthB); } else { InnerMultiplication_DDRB.blockMultPlusTransA(A.original.data, B.original.data, C.original.data, indexA, indexB, indexC, heightA, widthA, widthB); } } } //CONCURRENT_ABOVE }); }
/** * Special multiplication that takes in account the zeros and one in Y, which * is the matrix that stores the householder vectors. */ public static void multAdd_zeros(int blockLength, DSubmatrixD1 Y, DSubmatrixD1 B, DSubmatrixD1 C) { int widthY = Y.col1 - Y.col0; //CONCURRENT_BELOW EjmlConcurrency.loopFor(Y.row0, Y.row1, blockLength, i -> { for (int i = Y.row0; i < Y.row1; i += blockLength) { int heightY = Math.Min(blockLength, Y.row1 - i); for (int j = B.col0; j < B.col1; j += blockLength) { int widthB = Math.Min(blockLength, B.col1 - j); int indexC = (i - Y.row0 + C.row0) * C.original.numCols + (j - B.col0 + C.col0) * heightY; for (int k = Y.col0; k < Y.col1; k += blockLength) { int indexY = i * Y.original.numCols + k * heightY; int indexB = (k - Y.col0 + B.row0) * B.original.numCols + j * widthY; if (i == Y.row0) { multBlockAdd_zerosone(Y.original.data, B.original.data, C.original.data, indexY, indexB, indexC, heightY, widthY, widthB); } else { InnerMultiplication_DDRB.blockMultPlus(Y.original.data, B.original.data, C.original.data, indexY, indexB, indexC, heightY, widthY, widthB); } } } } //CONCURRENT_ABOVE }); }
/** * Inverts an upper or lower triangular block submatrix. Uses a row-oriented approach. * * @param upper Is it upper or lower triangular. * @param T Triangular matrix that is to be inverted. Must be block aligned. Not Modified. * @param T_inv Where the inverse is stored. This can be the same as T. Modified. * @param workspace Work space variable that is size blockLength*blockLength. */ public static void invert(int blockLength, bool upper, DSubmatrixD1 T, DSubmatrixD1 T_inv, GrowArray <DGrowArray> workspace) { if (upper) { throw new ArgumentException("Upper triangular matrices not supported yet"); } //CONCURRENT_INLINE if (T.original == T_inv.original) //CONCURRENT_INLINE throw new ArgumentException("Same instance not allowed for concurrent"); //if (workspace == null) // workspace = new GrowArray<DGrowArray>(new DGrowArray()); //else // workspace.reset(); if (T.row0 != T_inv.row0 || T.row1 != T_inv.row1 || T.col0 != T_inv.col0 || T.col1 != T_inv.col1) { throw new ArgumentException("T and T_inv must be at the same elements in the matrix"); } int blockSize = blockLength * blockLength; //CONCURRENT_REMOVE_BELOW double[] temp = workspace.grow().reshape(blockSize).data; int M = T.row1 - T.row0; double[] dataT = T.original.data; double[] dataX = T_inv.original.data; int offsetT = T.row0 * T.original.numCols + M * T.col0; for (int rowT = 0; rowT < M; rowT += blockLength) { int _rowT = rowT; // Needed for concurrent lambdas int heightT = Math.Min(T.row1 - (rowT + T.row0), blockLength); int indexII = offsetT + T.original.numCols * (rowT + T.row0) + heightT * (rowT + T.col0); //CONCURRENT_BELOW EjmlConcurrency.loopFor(0, rowT, blockLength, workspace, ( work, colT ) -> { for (int colT = 0; colT < rowT; colT += blockLength) { //CONCURRENT_INLINE double[] temp = work.reshape(blockSize).data; int widthX = Math.Min(T.col1 - (colT + T.col0), blockLength); Array.Fill(temp, 0); for (int k = colT; k < _rowT; k += blockLength) { int widthT = Math.Min(T.col1 - (k + T.col0), blockLength); int indexL2 = offsetT + T.original.numCols * (_rowT + T.row0) + heightT * (k + T.col0); int indexX2 = offsetT + T.original.numCols * (k + T.row0) + widthT * (colT + T.col0); InnerMultiplication_DDRB.blockMultMinus(dataT, dataX, temp, indexL2, indexX2, 0, heightT, widthT, widthX); } int indexX = offsetT + T.original.numCols * (_rowT + T.row0) + heightT * (colT + T.col0); InnerTriangularSolver_DDRB.solveL(dataT, temp, heightT, widthX, heightT, indexII, 0); System.Array.Copy(temp, 0, dataX, indexX, widthX * heightT); } //CONCURRENT_ABOVE }); InnerTriangularSolver_DDRB.invertLower(dataT, dataX, heightT, indexII, indexII); } }
//CONCURRENT_OMIT_BEGIN /** * Inverts an upper or lower triangular block submatrix. Uses a row oriented approach. * * @param upper Is it upper or lower triangular. * @param T Triangular matrix that is to be inverted. Overwritten with solution. Modified. * @param workspace Work space variable that is size blockLength*blockLength. */ public static void invert(int blockLength, bool upper, DSubmatrixD1 T, GrowArray <DGrowArray> workspace) { if (upper) { throw new ArgumentException("Upper triangular matrices not supported yet"); } // FORCE to disable workspace = null; if (workspace == null) { //workspace = new GrowArray<>(DGrowArray::new); } else { workspace.reset(); } int blockSize = blockLength * blockLength; double[] temp = workspace.grow().reshape(blockSize).data; int M = T.row1 - T.row0; double[] dataT = T.original.data; int offsetT = T.row0 * T.original.numCols + M * T.col0; for (int i = 0; i < M; i += blockLength) { int heightT = Math.Min(T.row1 - (i + T.row0), blockLength); int indexII = offsetT + T.original.numCols * (i + T.row0) + heightT * (i + T.col0); for (int j = 0; j < i; j += blockLength) { int widthX = Math.Min(T.col1 - (j + T.col0), blockLength); Array.Fill(temp, 0); for (int k = j; k < i; k += blockLength) { int widthT = Math.Min(T.col1 - (k + T.col0), blockLength); int indexL2 = offsetT + T.original.numCols * (i + T.row0) + heightT * (k + T.col0); int indexX2 = offsetT + T.original.numCols * (k + T.row0) + widthT * (j + T.col0); InnerMultiplication_DDRB.blockMultMinus(dataT, dataT, temp, indexL2, indexX2, 0, heightT, widthT, widthX); } int indexX = offsetT + T.original.numCols * (i + T.row0) + heightT * (j + T.col0); InnerTriangularSolver_DDRB.solveL(dataT, temp, heightT, widthX, heightT, indexII, 0); System.Array.Copy(temp, 0, dataT, indexX, widthX * heightT); } InnerTriangularSolver_DDRB.invertLower(dataT, heightT, indexII); } }