/** * <p> * A = (I + W Y<sup>T</sup>)<sup>T</sup>A<BR> * A = A + Y (W<sup>T</sup>A)<BR> * <br> * where A is a submatrix of the input matrix. * </p> */ protected void updateA(FSubmatrixD1 A) { setW(); A.row0 = Y.row0; A.row1 = Y.row1; A.col0 = Y.col1; A.col1 = Y.original.numCols; WTA.row0 = 0; WTA.col0 = 0; WTA.row1 = W.col1 - W.col0; WTA.col1 = A.col1 - A.col0; WTA.original.reshape(WTA.row1, WTA.col1, false); if (A.col1 > A.col0) { BlockHouseHolder_FDRB.computeW_Column(blockLength, Y, W, temp, gammas, Y.col0); MatrixMult_FDRB.multTransA(blockLength, W, A, WTA); BlockHouseHolder_FDRB.multAdd_zeros(blockLength, Y, WTA, A); } else if (saveW) { BlockHouseHolder_FDRB.computeW_Column(blockLength, Y, W, temp, gammas, Y.col0); } }
/** * Specialized version of applyQ() that allows the zeros in an identity matrix * to be taken advantage of depending on if isIdentity is true or not. * * @param B * @param isIdentity If B is an identity matrix. */ public void applyQ(FMatrixRBlock B, bool isIdentity) { int minDimen = Math.Min(dataA.numCols, dataA.numRows); FSubmatrixD1 subB = new FSubmatrixD1(B); W.col0 = W.row0 = 0; Y.row1 = W.row1 = dataA.numRows; WTA.row0 = WTA.col0 = 0; int start = minDimen - minDimen % blockLength; if (start == minDimen) { start -= blockLength; } if (start < 0) { start = 0; } // (Q1^T * (Q2^T * (Q3^t * A))) for (int i = start; i >= 0; i -= blockLength) { Y.col0 = i; Y.col1 = Math.Min(Y.col0 + blockLength, dataA.numCols); Y.row0 = i; if (isIdentity) { subB.col0 = i; } subB.row0 = i; setW(); WTA.row1 = Y.col1 - Y.col0; WTA.col1 = subB.col1 - subB.col0; WTA.original.reshape(WTA.row1, WTA.col1, false); // Compute W matrix from reflectors stored in Y if (!saveW) { BlockHouseHolder_FDRB.computeW_Column(blockLength, Y, W, temp, gammas, Y.col0); } // Apply the Qi to Q BlockHouseHolder_FDRB.multTransA_vecCol(blockLength, Y, subB, WTA); MatrixMult_FDRB.multPlus(blockLength, W, WTA, subB); } }
/** * <p> * Multiplies the provided matrix by Q<sup>T</sup> using householder reflectors. This is more * efficient that computing Q then applying it to the matrix. * </p> * * <p> * Q = Q*(I - γ W*Y^T)<br> * QR = A ≥ R = Q^T*A = (Q3^T * (Q2^T * (Q1^t * A))) * </p> * * @param B Matrix which Q is applied to. Modified. */ public void applyQTran(FMatrixRBlock B) { int minDimen = Math.Min(dataA.numCols, dataA.numRows); FSubmatrixD1 subB = new FSubmatrixD1(B); W.col0 = W.row0 = 0; Y.row1 = W.row1 = dataA.numRows; WTA.row0 = WTA.col0 = 0; // (Q3^T * (Q2^T * (Q1^t * A))) for (int i = 0; i < minDimen; i += blockLength) { Y.col0 = i; Y.col1 = Math.Min(Y.col0 + blockLength, dataA.numCols); Y.row0 = i; subB.row0 = i; // subB.row1 = B.numRows; // subB.col0 = 0; // subB.col1 = B.numCols; setW(); // W.original.reshape(W.row1,W.col1,false); WTA.row0 = 0; WTA.col0 = 0; WTA.row1 = W.col1 - W.col0; WTA.col1 = subB.col1 - subB.col0; WTA.original.reshape(WTA.row1, WTA.col1, false); // Compute W matrix from reflectors stored in Y if (!saveW) { BlockHouseHolder_FDRB.computeW_Column(blockLength, Y, W, temp, gammas, Y.col0); } // Apply the Qi to Q MatrixMult_FDRB.multTransA(blockLength, W, subB, WTA); BlockHouseHolder_FDRB.multAdd_zeros(blockLength, Y, WTA, subB); } }
public virtual FMatrixRBlock getQ(FMatrixRBlock Q, bool transposed) { Q = QRDecompositionHouseholder_FDRB.initializeQ(Q, A.numRows, A.numCols, A.blockLength, false); int height = Math.Min(A.blockLength, A.numRows); V.reshape(height, A.numCols, false); this.tmp.reshape(height, A.numCols, false); FSubmatrixD1 subQ = new FSubmatrixD1(Q); FSubmatrixD1 subU = new FSubmatrixD1(A); FSubmatrixD1 subW = new FSubmatrixD1(V); FSubmatrixD1 tmp = new FSubmatrixD1(this.tmp); int N = A.numRows; int start = N - N % A.blockLength; if (start == N) { start -= A.blockLength; } if (start < 0) { start = 0; } // (Q1^T * (Q2^T * (Q3^t * A))) for (int i = start; i >= 0; i -= A.blockLength) { int blockSize = Math.Min(A.blockLength, N - i); subW.col0 = i; subW.row1 = blockSize; subW.original.reshape(subW.row1, subW.col1, false); if (transposed) { tmp.row0 = i; tmp.row1 = A.numCols; tmp.col0 = 0; tmp.col1 = blockSize; } else { tmp.col0 = i; tmp.row1 = blockSize; } tmp.original.reshape(tmp.row1, tmp.col1, false); subU.col0 = i; subU.row0 = i; subU.row1 = subU.row0 + blockSize; // zeros and ones are saved and overwritten in U so that standard matrix multiplication can be used copyZeros(subU); // compute W for Q(i) = ( I + W*Y^T) TridiagonalHelper_FDRB.computeW_row(A.blockLength, subU, subW, gammas, i); subQ.col0 = i; subQ.row0 = i; // Apply the Qi to Q // Qi = I + W*U^T // Note that U and V are really row vectors. but standard notation assumed they are column vectors. // which is why the functions called don't match the math above // (I + W*U^T)*Q // F=U^T*Q(i) if (transposed) { MatrixMult_FDRB.multTransB(A.blockLength, subQ, subU, tmp); } else { MatrixMult_FDRB.mult(A.blockLength, subU, subQ, tmp); } // Q(i+1) = Q(i) + W*F if (transposed) { MatrixMult_FDRB.multPlus(A.blockLength, tmp, subW, subQ); } else { MatrixMult_FDRB.multPlusTransA(A.blockLength, subW, tmp, subQ); } replaceZeros(subU); } return(Q); }