/** * <p> * Applies the reflectors that have been computed previously to the specified row. * <br> * A = A + u*v^T + v*u^T only along the specified row in A. * </p> * * @param blockLength * @param A Contains the reflectors and the row being updated. * @param V Contains previously computed 'v' vectors. * @param row The row of 'A' that is to be updated. */ public static void applyReflectorsToRow(int blockLength, FSubmatrixD1 A, FSubmatrixD1 V, int row) { int height = Math.Min(blockLength, A.row1 - A.row0); float[] dataA = A.original.data; float[] dataV = V.original.data; int indexU, indexV; // for each previously computed reflector for (int i = 0; i < row; i++) { int width = Math.Min(blockLength, A.col1 - A.col0); indexU = A.original.numCols * A.row0 + height * A.col0 + i * width + row; indexV = V.original.numCols * V.row0 + height * V.col0 + i * width + row; float u_row = (i + 1 == row) ? 1.0f : dataA[indexU]; float v_row = dataV[indexV]; // take in account the leading one float before = A.get(i, i + 1); A.set(i, i + 1, 1); // grab only the relevant row from A = A + u*v^T + v*u^T VectorOps_FDRB.add_row(blockLength, A, row, 1, V, i, u_row, A, row, row, A.col1 - A.col0); VectorOps_FDRB.add_row(blockLength, A, row, 1, A, i, v_row, A, row, row, A.col1 - A.col0); A.set(i, i + 1, before); } }
public virtual bool decompose(FMatrixRBlock orig) { if (orig.numCols != orig.numRows) { throw new ArgumentException("Input matrix must be square."); } init(orig); FSubmatrixD1 subA = new FSubmatrixD1(A); FSubmatrixD1 subV = new FSubmatrixD1(V); FSubmatrixD1 subU = new FSubmatrixD1(A); int N = orig.numCols; for (int i = 0; i < N; i += A.blockLength) { // Console.WriteLine("-------- triag i "+i); int height = Math.Min(A.blockLength, A.numRows - i); subA.col0 = subU.col0 = i; subA.row0 = subU.row0 = i; subU.row1 = subU.row0 + height; subV.col0 = i; subV.row1 = height; subV.original.reshape(subV.row1, subV.col1, false); // bidiagonalize the top row TridiagonalHelper_FDRB.tridiagUpperRow(A.blockLength, subA, gammas, subV); // apply Householder reflectors to the lower portion using block multiplication if (subU.row1 < orig.numCols) { // take in account the 1 in the last row. The others are skipped over. float before = subU.get(A.blockLength - 1, A.blockLength); subU.set(A.blockLength - 1, A.blockLength, 1); // A = A + U*V^T + V*U^T multPlusTransA(A.blockLength, subU, subV, subA); multPlusTransA(A.blockLength, subV, subU, subA); subU.set(A.blockLength - 1, A.blockLength, before); } } return(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); }
/** * <p> * Computes the householder vector that is used to create reflector for the column. * The results are stored in the original matrix. * </p> * * <p> * The householder vector 'u' is computed as follows:<br> * <br> * u(1) = 1 <br> * u(i) = x(i)/(τ + x(1))<br> * </p> * * The first element is implicitly assumed to be one and not written. * * @return If there was any problems or not. true = no problem. */ public static bool computeHouseHolderCol(int blockLength, FSubmatrixD1 Y, float[] gamma, int i) { float max = BlockHouseHolder_FDRB.findMaxCol(blockLength, Y, i); if (max == 0.0f) { return(false); } else { // computes tau and normalizes u by max float tau = computeTauAndDivideCol(blockLength, Y, i, max); // divide u by u_0 float u_0 = Y.get(i, i) + tau; divideElementsCol(blockLength, Y, i, u_0); gamma[Y.col0 + i] = u_0 / tau; tau *= max; // after the reflector is applied the column would be all zeros but be -tau in the first element Y.set(i, i, -tau); } return(true); }
/** * <p> * Computes the householder vector from the specified row * </p> * * <p> * The householder vector 'u' is computed as follows:<br> * <br> * u(1) = 1 <br> * u(i) = x(i)/(τ + x(1))<br> * </p> * * The first element is implicitly assumed to be one and not written. * * @return If there was any problems or not. true = no problem. */ public static bool computeHouseHolderRow(int blockLength, FSubmatrixD1 Y, float[] gamma, int i) { float max = BlockHouseHolder_FDRB.findMaxRow(blockLength, Y, i, i + 1); if (max == 0.0f) { return(false); } else { // computes tau and normalizes u by max float tau = computeTauAndDivideRow(blockLength, Y, i, i + 1, max); // divide u by u_0 float u_0 = Y.get(i, i + 1) + tau; VectorOps_FDRB.div_row(blockLength, Y, i, u_0, Y, i, i + 1, Y.col1 - Y.col0); gamma[Y.row0 + i] = u_0 / tau; // after the reflector is applied the column would be all zeros but be -tau in the first element Y.set(i, i + 1, -tau * max); } return(true); }
private void replaceZeros(FSubmatrixD1 subU) { int N = Math.Min(A.blockLength, subU.col1 - subU.col0); for (int i = 0; i < N; i++) { // save the zeros for (int j = 0; j <= i; j++) { subU.set(i, j, zerosM.get(i, j)); } // save the one if (subU.col0 + i + 1 < subU.original.numCols) { subU.set(i, i + 1, zerosM.get(i, i + 1)); } } }
/** * <p> * Final computation for a single row of 'v':<br> * <br> * v = y -(1/2)γ(y^T*u)*u * </p> * * @param blockLength * @param A * @param V * @param row * @param gamma */ public static void computeRowOfV(int blockLength, FSubmatrixD1 A, FSubmatrixD1 V, int row, float gamma) { // val=(y^T*u) float val = BlockHouseHolder_FDRB.innerProdRow(blockLength, A, row, V, row, 1); // take in account the one float before = A.get(row, row + 1); A.set(row, row + 1, 1); // v = y - (1/2)gamma*val * u VectorOps_FDRB.add_row(blockLength, V, row, 1, A, row, -0.5f * gamma * val, V, row, row + 1, A.col1 - A.col0); A.set(row, row + 1, before); }
/** * <p> * Multiples the appropriate submatrix of A by the specified reflector and stores * the result ('y') in V.<br> * <br> * y = A*u<br> * </p> * * @param blockLength * @param A Contains the 'A' matrix and 'u' vector. * @param V Where resulting 'y' row vectors are stored. * @param row row in matrix 'A' that 'u' vector and the row in 'V' that 'y' is stored in. */ public static void multA_u(int blockLength, FSubmatrixD1 A, FSubmatrixD1 V, int row) { int heightMatA = A.row1 - A.row0; for (int i = row + 1; i < heightMatA; i++) { float val = innerProdRowSymm(blockLength, A, row, A, i, 1); V.set(row, i, val); } }
public static void add_row(int blockLength, FSubmatrixD1 A, int rowA, float alpha, FSubmatrixD1 B, int rowB, float beta, FSubmatrixD1 C, int rowC, int zeroOffset, int end) { int offset = rowA + zeroOffset; if (C.col0 + offset >= C.col1) { return; } // handle leading one C.set(rowC, offset, alpha + B.get(rowB, offset) * beta); VectorOps_FDRB.add_row(blockLength, A, rowA, alpha, B, rowB, beta, C, rowC, offset + 1, end); }
/** * Scales the elements in the specified row starting at element colStart by 'val'.<br> * W = val*Y * * Takes in account zeros and leading one automatically. * * @param zeroOffset How far off the diagonal is the first element in the vector. */ public static void scale_row(int blockLength, FSubmatrixD1 Y, FSubmatrixD1 W, int row, int zeroOffset, float val) { int offset = row + zeroOffset; if (offset >= W.col1 - W.col0) { return; } // handle the one W.set(row, offset, val); // scale rest of the vector VectorOps_FDRB.scale_row(blockLength, Y, row, val, W, row, offset + 1, Y.col1 - Y.col0); }