/** * <p> * Performs a matrix multiplication with a transpose on {@link DMatrixRBlock} submatrices.<br> * <br> * c = a * b <sup>T</sup> <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 Length 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 multTransB(int blockLength, DSubmatrixD1 A, DSubmatrixD1 B, DSubmatrixD1 C) { for (int i = A.row0; i < A.row1; i += blockLength) { int heightA = Math.Min(blockLength, A.row1 - i); for (int j = B.row0; j < B.row1; j += blockLength) { int widthC = Math.Min(blockLength, B.row1 - j); int indexC = (i - A.row0 + C.row0) * C.original.numCols + (j - B.row0 + 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 = j * B.original.numCols + (k - A.col0 + B.col0) * widthC; if (k == A.col0) { InnerMultiplication_DDRB.blockMultSetTransB(A.original.data, B.original.data, C.original.data, indexA, indexB, indexC, heightA, widthA, widthC); } else { InnerMultiplication_DDRB.blockMultPlusTransB(A.original.data, B.original.data, C.original.data, indexA, indexB, indexC, heightA, widthA, widthC); } } } } }
public static void multTransB(DMatrixRBlock A, DMatrixRBlock B, DMatrixRBlock C) { if (A.numCols != B.numCols) { throw new ArgumentException("Columns in A are incompatible with columns in B"); } if (A.numRows != C.numRows) { throw new ArgumentException("Rows in A are incompatible with rows in C"); } if (B.numRows != C.numCols) { throw new ArgumentException("Rows in B are incompatible with columns in C"); } if (A.blockLength != B.blockLength || A.blockLength != C.blockLength) { throw new ArgumentException("Block lengths are not all the same."); } int blockLength = A.blockLength; DSubmatrixD1 Asub = new DSubmatrixD1(A, 0, A.numRows, 0, A.numCols); DSubmatrixD1 Bsub = new DSubmatrixD1(B, 0, B.numRows, 0, B.numCols); DSubmatrixD1 Csub = new DSubmatrixD1(C, 0, C.numRows, 0, C.numCols); MatrixMult_DDRB.multTransB(blockLength, Asub, Bsub, Csub); }
/** * <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) { // checkInput( blockLength,A,B,C); 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); } } } }
/** * <p> * Row vector scale:<br> * scale: b<sub>i</sub> = α*a<sub>i</sub><br> * where 'a' and 'b' are row vectors within the row block vector A and B. * </p> * * @param A submatrix. Not modified. * @param rowA which row in A the vector is contained in. * @param alpha scale factor. * @param B submatrix that the results are written to. Modified. * @param offset Index at which the vectors start at. * @param end Index at which the vectors end at. */ public static void scale_row(int blockLength, DSubmatrixD1 A, int rowA, double alpha, DSubmatrixD1 B, int rowB, int offset, int end) { double[] dataA = A.original.data; double[] dataB = B.original.data; // handle the case where offset is more than a block int startI = offset - offset % blockLength; offset = offset % blockLength; // handle rows in any block int rowBlockA = A.row0 + rowA - rowA % blockLength; rowA = rowA % blockLength; int rowBlockB = B.row0 + rowB - rowB % blockLength; rowB = rowB % blockLength; int heightA = Math.Min(blockLength, A.row1 - rowBlockA); int heightB = Math.Min(blockLength, B.row1 - rowBlockB); for (int i = startI; i < end; i += blockLength) { int segment = Math.Min(blockLength, end - i); int widthA = Math.Min(blockLength, A.col1 - A.col0 - i); int widthB = Math.Min(blockLength, B.col1 - B.col0 - i); int indexA = rowBlockA * A.original.numCols + (A.col0 + i) * heightA + rowA * widthA; int indexB = rowBlockB * B.original.numCols + (B.col0 + i) * heightB + rowB * widthB; if (i == startI) { indexA += offset; indexB += offset; for (int j = offset; j < segment; j++) { dataB[indexB++] = alpha * dataA[indexA++]; } } else { for (int j = 0; j < segment; j++) { dataB[indexB++] = alpha * dataA[indexA++]; } } } }
/** * Inverts an upper or lower triangular block submatrix. * * @param blockLength * @param upper Is it upper or lower triangular. * @param T Triangular matrix that is to be inverted. Overwritten with solution. Modified. * @param temp Work space variable that is size blockLength*blockLength. */ public static void invert(int blockLength, bool upper, DSubmatrixD1 T, double[] temp) { if (upper) { throw new ArgumentException("Upper triangular matrices not supported yet"); } if (temp.Length < blockLength * blockLength) { throw new ArgumentException("Temp must be at least blockLength*blockLength long."); } 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); for (int w = 0; w < temp.Length; w++) { temp[w] = 0; } for (int k = j; k < i; k += blockLength) { int widthT = Math.Min(T.col1 - (k + T.col0), blockLength); int indL = offsetT + T.original.numCols * (i + T.row0) + heightT * (k + T.col0); int indX = offsetT + T.original.numCols * (k + T.row0) + widthT * (j + T.col0); InnerMultiplication_DDRB.blockMultMinus(dataT, dataT, temp, indL, indX, 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); Array.Copy(temp, 0, dataT, indexX, widthX * heightT); } InnerTriangularSolver_DDRB.invertLower(dataT, heightT, indexII); } }
/** * <p> * Row vector add:<br> * add: c<sub>i</sub> = α*a<sub>i</sub> + βB<sub>i</sub><br> * where 'a', 'b', and 'c' are row vectors within the row block vectors of A, B, and C respectively. * </p> * * @param blockLength Length of each inner matrix block. * @param A submatrix. Not modified. * @param rowA which row in A the vector is contained in. * @param alpha scale factor of A * @param B submatrix. Not modified. * @param rowB which row in B the vector is contained in. * @param beta scale factor of B * @param C submatrix where the results are written to. Modified. * @param rowC which row in C is the vector contained. * @param offset Index at which the vectors start at. * @param end Index at which the vectors end at. */ public static void add_row(int blockLength, DSubmatrixD1 A, int rowA, double alpha, DSubmatrixD1 B, int rowB, double beta, DSubmatrixD1 C, int rowC, int offset, int end) { int heightA = Math.Min(blockLength, A.row1 - A.row0); int heightB = Math.Min(blockLength, B.row1 - B.row0); int heightC = Math.Min(blockLength, C.row1 - C.row0); // handle the case where offset is more than a block int startI = offset - offset % blockLength; offset = offset % blockLength; double[] dataA = A.original.data; double[] dataB = B.original.data; double[] dataC = C.original.data; for (int i = startI; i < end; i += blockLength) { int segment = Math.Min(blockLength, end - i); int widthA = Math.Min(blockLength, A.col1 - A.col0 - i); int widthB = Math.Min(blockLength, B.col1 - B.col0 - i); int widthC = Math.Min(blockLength, C.col1 - C.col0 - i); int indexA = A.row0 * A.original.numCols + (A.col0 + i) * heightA + rowA * widthA; int indexB = B.row0 * B.original.numCols + (B.col0 + i) * heightB + rowB * widthB; int indexC = C.row0 * C.original.numCols + (C.col0 + i) * heightC + rowC * widthC; if (i == startI) { indexA += offset; indexB += offset; indexC += offset; for (int j = offset; j < segment; j++) { dataC[indexC++] = alpha * dataA[indexA++] + beta * dataB[indexB++]; } } else { for (int j = 0; j < segment; j++) { dataC[indexC++] = alpha * dataA[indexA++] + beta * dataB[indexB++]; } } } }
/** * <p> * Rank N update function for a symmetric inner submatrix and only operates on the upper * triangular portion of the submatrix.<br> * <br> * A = A - B <sup>T</sup>B * </p> */ public static void symmRankNMinus_U(int blockLength, 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"); } 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 = i; 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; if (i == j) { // only the upper portion of this block needs to be modified since it is along a diagonal multTransABlockMinus_U(B.original.data, A.original.data, indexB_i, indexB_j, indexA, heightB, widthB_i, widthB_j); } else { multTransABlockMinus(B.original.data, A.original.data, indexB_i, indexB_j, indexA, heightB, widthB_i, widthB_j); } } } }
/** * <p> * Performs an in-place solve operation on the provided block aligned sub-matrices.<br> * <br> * B = T<sup>-1</sup> B<br> * <br> * where T is a triangular matrix. T or B can be transposed. T is a square matrix of arbitrary * size and B has the same number of rows as T and an arbitrary number of columns. * </p> * * @param blockLength Size of the inner blocks. * @param upper If T is upper or lower triangular. * @param T An upper or lower triangular matrix. Not modified. * @param B A matrix whose height is the same as T's width. Solution is written here. Modified. */ public static void solve(int blockLength, bool upper, DSubmatrixD1 T, DSubmatrixD1 B, bool transT) { if (upper) { solveR(blockLength, T, B, transT); } else { solveL(blockLength, T, B, transT); } }
/** * <p> * Rank N update function for a symmetric inner submatrix and only operates on the lower * triangular portion of the submatrix.<br> * <br> * A = A - B*B<sup>T</sup><br> * </p> */ public static void symmRankNMinus_L(int blockLength, DSubmatrixD1 A, DSubmatrixD1 B) { int widthB = B.col1 - B.col0; if (widthB > blockLength) { throw new ArgumentException("Width of B cannot be greater than the block length"); } int N = B.row1 - B.row0; if (A.col1 - A.col0 != N) { throw new ArgumentException("A does not have the expected number of columns based on B's height"); } if (A.row1 - A.row0 != N) { throw new ArgumentException("A does not have the expected number of rows based on B's height"); } for (int i = B.row0; i < B.row1; i += blockLength) { int heightB_i = Math.Min(blockLength, B.row1 - i); int indexB_i = i * B.original.numCols + heightB_i * B.col0; int rowA = i - B.row0 + A.row0; int heightA = Math.Min(blockLength, A.row1 - rowA); for (int j = B.row0; j <= i; j += blockLength) { int widthB_j = Math.Min(blockLength, B.row1 - j); int indexA = rowA * A.original.numCols + (j - B.row0 + A.col0) * heightA; int indexB_j = j * B.original.numCols + widthB_j * B.col0; if (i == j) { multTransBBlockMinus_L(B.original.data, A.original.data, indexB_i, indexB_j, indexA, widthB, heightB_i, widthB_j); } else { multTransBBlockMinus(B.original.data, A.original.data, indexB_i, indexB_j, indexA, widthB, heightB_i, widthB_j); } } } }
/** * <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"); } 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); } } }
/** * Checks to see if the submatrix has its boundaries along inner blocks. * * @param blockLength Size of an inner block. * @param A Submatrix. * @return If it is block aligned or not. */ public static bool blockAligned(int blockLength, DSubmatrixD1 A) { if (A.col0 % blockLength != 0) { return(false); } if (A.row0 % blockLength != 0) { return(false); } if (A.col1 % blockLength != 0 && A.col1 != A.original.numCols) { return(false); } if (A.row1 % blockLength != 0 && A.row1 != A.original.numRows) { return(false); } return(true); }
private static void checkInput(int blockLength, DSubmatrixD1 A, DSubmatrixD1 B, DSubmatrixD1 C) { int Arow = A.getRows(); int Acol = A.getCols(); int Brow = B.getRows(); int Bcol = B.getCols(); int Crow = C.getRows(); int Ccol = C.getCols(); if (Arow != Crow) { throw new InvalidOperationException("Mismatch A and C rows"); } if (Bcol != Ccol) { throw new InvalidOperationException("Mismatch B and C columns"); } if (Acol != Brow) { throw new InvalidOperationException("Mismatch A columns and B rows"); } if (!MatrixOps_DDRB.blockAligned(blockLength, A)) { throw new InvalidOperationException("Sub-Matrix A is not block aligned"); } if (!MatrixOps_DDRB.blockAligned(blockLength, B)) { throw new InvalidOperationException("Sub-Matrix B is not block aligned"); } if (!MatrixOps_DDRB.blockAligned(blockLength, C)) { throw new InvalidOperationException("Sub-Matrix C is not block aligned"); } }
/** * <p> * vector dot/inner product from one row vector and one column vector:<br> * dot: c = sum a<sub>i</sub>*b<sub>i</sub><br> * where 'a' is a row vector 'b' is a column vectors within the row block vector A and B, and 'c' is a scalar. * </p> * * @param A block row vector. Not modified. * @param rowA which row in A the vector is contained in. * @param B block column vector. Not modified. * @param colB which column in B is the vector contained in. * @param offset Index at which the vectors start at. * @param end Index at which the vectors end at. * @return Results of the dot product. */ public static double dot_row_col(int blockLength, DSubmatrixD1 A, int rowA, DSubmatrixD1 B, int colB, int offset, int end) { // handle the case where offset is more than a block int startI = offset - offset % blockLength; offset = offset % blockLength; double[] dataA = A.original.data; double[] dataB = B.original.data; double total = 0; // handle rows in any block int rowBlockA = A.row0 + rowA - rowA % blockLength; rowA = rowA % blockLength; int colBlockB = B.col0 + colB - colB % blockLength; colB = colB % blockLength; int heightA = Math.Min(blockLength, A.row1 - rowBlockA); int widthB = Math.Min(blockLength, B.col1 - colBlockB); if (A.col1 - A.col0 != B.col1 - B.col0) { throw new InvalidOperationException(); } for (int i = startI; i < end; i += blockLength) { int segment = Math.Min(blockLength, end - i); int widthA = Math.Min(blockLength, A.col1 - A.col0 - i); int heightB = Math.Min(blockLength, B.row1 - B.row0 - i); int indexA = rowBlockA * A.original.numCols + (A.col0 + i) * heightA + rowA * widthA; int indexB = (B.row0 + i) * B.original.numCols + colBlockB * heightB + colB; if (i == startI) { indexA += offset; indexB += offset * widthB; for (int j = offset; j < segment; j++, indexB += widthB) { total += dataB[indexB] * dataA[indexA++]; } } else { for (int j = 0; j < segment; j++, indexB += widthB) { total += dataB[indexB] * dataA[indexA++]; } } } return(total); }
/** * <p> * Solves upper triangular systems:<br> * <br> * B = R<sup>-1</sup> B<br> * <br> * </p> * * <p>Only the first B.numRows rows in R will be processed. Lower triangular elements are ignored.<p> * * <p> Reverse or forward substitution is used depending upon L being transposed or not. </p> * * @param blockLength * @param R Upper triangular with dimensions m by m. Not modified. * @param B A matrix with dimensions m by n. Solution is written into here. Modified. * @param transR Is the triangular matrix transposed? */ public static void solveR(int blockLength, DSubmatrixD1 R, DSubmatrixD1 B, bool transR) { int lengthR = B.row1 - B.row0; if (R.getCols() != lengthR) { throw new ArgumentException("Number of columns in R must be equal to the number of rows in B"); } else if (R.getRows() != lengthR) { throw new ArgumentException("Number of rows in R must be equal to the number of rows in B"); } DSubmatrixD1 Y = new DSubmatrixD1(B.original); DSubmatrixD1 Rinner = new DSubmatrixD1(R.original); DSubmatrixD1 Binner = new DSubmatrixD1(B.original); int startI, stepI; if (transR) { startI = 0; stepI = blockLength; } else { startI = lengthR - lengthR % blockLength; if (startI == lengthR && lengthR >= blockLength) { startI -= blockLength; } stepI = -blockLength; } for (int i = startI;; i += stepI) { if (transR) { if (i >= lengthR) { break; } } else { if (i < 0) { break; } } // width and height of the inner T(i,i) block int widthT = Math.Min(blockLength, lengthR - i); Rinner.col0 = R.col0 + i; Rinner.col1 = Rinner.col0 + widthT; Rinner.row0 = R.row0 + i; Rinner.row1 = Rinner.row0 + widthT; Binner.col0 = B.col0; Binner.col1 = B.col1; Binner.row0 = B.row0 + i; Binner.row1 = Binner.row0 + widthT; // solve the top row block // B(i,:) = T(i,i)^-1 Y(i,:) solveBlock(blockLength, true, Rinner, Binner, transR, false); bool updateY; if (transR) { updateY = Rinner.row1 < R.row1; } else { updateY = Rinner.row0 > 0; } if (updateY) { // Y[i,:] = Y[i,:] - sum j=1:i-1 { T[i,j] B[j,i] } // where i is the next block down // The summation is a block inner product if (transR) { Rinner.col0 = Rinner.col1; Rinner.col1 = Math.Min(Rinner.col0 + blockLength, R.col1); Rinner.row0 = R.row0; //Rinner.row1 = Rinner.row1; Binner.row0 = B.row0; //Binner.row1 = Binner.row1; Y.row0 = Binner.row1; Y.row1 = Math.Min(Y.row0 + blockLength, B.row1); } else { Rinner.row1 = Rinner.row0; Rinner.row0 = Rinner.row1 - blockLength; Rinner.col1 = R.col1; // Binner.row0 = Binner.row0; Binner.row1 = B.row1; Y.row0 = Binner.row0 - blockLength; Y.row1 = Binner.row0; } // step through each block column for (int k = B.col0; k < B.col1; k += blockLength) { Binner.col0 = k; Binner.col1 = Math.Min(k + blockLength, B.col1); Y.col0 = Binner.col0; Y.col1 = Binner.col1; if (transR) { // Y = Y - T^T * B MatrixMult_DDRB.multMinusTransA(blockLength, Rinner, Binner, Y); } else { // Y = Y - T * B MatrixMult_DDRB.multMinus(blockLength, Rinner, Binner, Y); } } } } }
/** * <p> * Solves lower triangular systems:<br> * <br> * B = L<sup>-1</sup> B<br> * <br> * </p> * * <p> Reverse or forward substitution is used depending upon L being transposed or not. </p> * * @param blockLength * @param L Lower triangular with dimensions m by m. Not modified. * @param B A matrix with dimensions m by n. Solution is written into here. Modified. * @param transL Is the triangular matrix transposed? */ public static void solveL(int blockLength, DSubmatrixD1 L, DSubmatrixD1 B, bool transL) { DSubmatrixD1 Y = new DSubmatrixD1(B.original); DSubmatrixD1 Linner = new DSubmatrixD1(L.original); DSubmatrixD1 Binner = new DSubmatrixD1(B.original); int lengthL = B.row1 - B.row0; int startI, stepI; if (transL) { startI = lengthL - lengthL % blockLength; if (startI == lengthL && lengthL >= blockLength) { startI -= blockLength; } stepI = -blockLength; } else { startI = 0; stepI = blockLength; } for (int i = startI;; i += stepI) { if (transL) { if (i < 0) { break; } } else { if (i >= lengthL) { break; } } // width and height of the inner T(i,i) block int widthT = Math.Min(blockLength, lengthL - i); Linner.col0 = L.col0 + i; Linner.col1 = Linner.col0 + widthT; Linner.row0 = L.row0 + i; Linner.row1 = Linner.row0 + widthT; Binner.col0 = B.col0; Binner.col1 = B.col1; Binner.row0 = B.row0 + i; Binner.row1 = Binner.row0 + widthT; // solve the top row block // B(i,:) = T(i,i)^-1 Y(i,:) solveBlock(blockLength, false, Linner, Binner, transL, false); bool updateY; if (transL) { updateY = Linner.row0 > 0; } else { updateY = Linner.row1 < L.row1; } if (updateY) { // Y[i,:] = Y[i,:] - sum j=1:i-1 { T[i,j] B[j,i] } // where i is the next block down // The summation is a block inner product if (transL) { Linner.col1 = Linner.col0; Linner.col0 = Linner.col1 - blockLength; Linner.row1 = L.row1; //Tinner.col1 = Tinner.col1; // Binner.row0 = Binner.row0; Binner.row1 = B.row1; Y.row0 = Binner.row0 - blockLength; Y.row1 = Binner.row0; } else { Linner.row0 = Linner.row1; Linner.row1 = Math.Min(Linner.row0 + blockLength, L.row1); Linner.col0 = L.col0; //Tinner.col1 = Tinner.col1; Binner.row0 = B.row0; //Binner.row1 = Binner.row1; Y.row0 = Binner.row1; Y.row1 = Math.Min(Y.row0 + blockLength, B.row1); } // step through each block column for (int k = B.col0; k < B.col1; k += blockLength) { Binner.col0 = k; Binner.col1 = Math.Min(k + blockLength, B.col1); Y.col0 = Binner.col0; Y.col1 = Binner.col1; if (transL) { // Y = Y - T^T * B MatrixMult_DDRB.multMinusTransA(blockLength, Linner, Binner, Y); } else { // Y = Y - T * B MatrixMult_DDRB.multMinus(blockLength, Linner, Binner, Y); } } } } }
/** * <p> * Performs an in-place solve operation where T is contained in a single block.<br> * <br> * B = T<sup>-1</sup> B<br> * <br> * where T is a triangular matrix contained in an inner block. T or B can be transposed. T must be a single complete inner block * and B is either a column block vector or row block vector. * </p> * * @param blockLength Size of the inner blocks in the block matrix. * @param upper If T is upper or lower triangular. * @param T An upper or lower triangular matrix that is contained in an inner block. Not modified. * @param B A block aligned row or column submatrix. Modified. * @param transT If T is transposed or not. * @param transB If B is transposed or not. */ public static void solveBlock(int blockLength, bool upper, DSubmatrixD1 T, DSubmatrixD1 B, bool transT, bool transB) { int Trows = T.row1 - T.row0; if (Trows > blockLength) { throw new ArgumentException("T can be at most the size of a block"); } // number of rows in a block. The submatrix can be smaller than a block int blockT_rows = Math.Min(blockLength, T.original.numRows - T.row0); int blockT_cols = Math.Min(blockLength, T.original.numCols - T.col0); int offsetT = T.row0 * T.original.numCols + blockT_rows * T.col0; double[] dataT = T.original.data; double[] dataB = B.original.data; if (transB) { if (upper) { if (transT) { throw new ArgumentException("Operation not yet supported"); } else { throw new ArgumentException("Operation not yet supported"); } } else { if (transT) { throw new ArgumentException("Operation not yet supported"); } else { for (int i = B.row0; i < B.row1; i += blockLength) { int N = Math.Min(B.row1, i + blockLength) - i; int offsetB = i * B.original.numCols + N * B.col0; InnerTriangularSolver_DDRB.solveLTransB(dataT, dataB, blockT_rows, N, blockT_rows, offsetT, offsetB); } } } } else { if (Trows != B.row1 - B.row0) { throw new ArgumentException("T and B must have the same number of rows."); } if (upper) { if (transT) { for (int i = B.col0; i < B.col1; i += blockLength) { int offsetB = B.row0 * B.original.numCols + Trows * i; int N = Math.Min(B.col1, i + blockLength) - i; InnerTriangularSolver_DDRB.solveTransU(dataT, dataB, Trows, N, Trows, offsetT, offsetB); } } else { for (int i = B.col0; i < B.col1; i += blockLength) { int offsetB = B.row0 * B.original.numCols + Trows * i; int N = Math.Min(B.col1, i + blockLength) - i; InnerTriangularSolver_DDRB.solveU(dataT, dataB, Trows, N, Trows, offsetT, offsetB); } } } else { if (transT) { for (int i = B.col0; i < B.col1; i += blockLength) { int offsetB = B.row0 * B.original.numCols + Trows * i; int N = Math.Min(B.col1, i + blockLength) - i; InnerTriangularSolver_DDRB.solveTransL(dataT, dataB, Trows, N, blockT_cols, offsetT, offsetB); } } else { for (int i = B.col0; i < B.col1; i += blockLength) { int offsetB = B.row0 * B.original.numCols + Trows * i; int N = Math.Min(B.col1, i + blockLength) - i; InnerTriangularSolver_DDRB.solveL(dataT, dataB, Trows, N, blockT_cols, offsetT, offsetB); } } } } }