/** * <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, DSubmatrixD1 Y, double[] gamma, int i) { double max = BlockHouseHolder_DDRB.findMaxRow(blockLength, Y, i, i + 1); if (max == 0.0) { return(false); } else { // computes tau and normalizes u by max double tau = computeTauAndDivideRow(blockLength, Y, i, i + 1, max); // divide u by u_0 double u_0 = Y.get(i, i + 1) + tau; VectorOps_DDRB.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); }
/** * <p> * Computes W from the householder reflectors stored in the columns of the row block * submatrix Y. * </p> * * <p> * Y = v<sup>(1)</sup><br> * W = -β<sub>1</sub>v<sup>(1)</sup><br> * for j=2:r<br> * z = -β(I +WY<sup>T</sup>)v<sup>(j)</sup> <br> * W = [W z]<br> * Y = [Y v<sup>(j)</sup>]<br> * end<br> * <br> * where v<sup>(.)</sup> are the house holder vectors, and r is the block length. Note that * Y already contains the householder vectors so it does not need to be modified. * </p> * * <p> * Y and W are assumed to have the same number of rows and columns. * </p> */ public static void computeW_row(int blockLength, DSubmatrixD1 Y, DSubmatrixD1 W, double[] beta, int betaIndex) { int heightY = Y.row1 - Y.row0; CommonOps_DDRM.fill(W.original, 0); // W = -beta*v(1) BlockHouseHolder_DDRB.scale_row(blockLength, Y, W, 0, 1, -beta[betaIndex++]); int min = Math.Min(heightY, W.col1 - W.col0); // set up rest of the rows for (int i = 1; i < min; i++) { // w=-beta*(I + W*Y^T)*u double b = -beta[betaIndex++]; // w = w -beta*W*(Y^T*u) for (int j = 0; j < i; j++) { double yv = BlockHouseHolder_DDRB.innerProdRow(blockLength, Y, i, Y, j, 1); VectorOps_DDRB.add_row(blockLength, W, i, 1, W, j, b * yv, W, i, 1, Y.col1 - Y.col0); } //w=w -beta*u + stuff above BlockHouseHolder_DDRB.add_row(blockLength, Y, i, b, W, i, 1, W, i, 1, Y.col1 - Y.col0); } }
public static double innerProdRowSymm(int blockLength, DSubmatrixD1 A, int rowA, DSubmatrixD1 B, int rowB, int zeroOffset) { int offset = rowA + zeroOffset; if (offset + B.col0 >= B.col1) { return(0); } if (offset < rowB) { // take in account the one in 'A' double total = B.get(offset, rowB); total += VectorOps_DDRB.dot_row_col(blockLength, A, rowA, B, rowB, offset + 1, rowB); total += VectorOps_DDRB.dot_row(blockLength, A, rowA, B, rowB, rowB, A.col1 - A.col0); return(total); } else { // take in account the one in 'A' double total = B.get(rowB, offset); total += VectorOps_DDRB.dot_row(blockLength, A, rowA, B, rowB, offset + 1, A.col1 - A.col0); return(total); } }
/** * <p> * Computes the 'y' vector and stores the result in 'v'<br> * <br> * y = -γ(A + U*V^T + V*U^T)u * </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 computeY(int blockLength, DSubmatrixD1 A, DSubmatrixD1 V, int row, double gamma) { // Elements in 'y' before 'row' are known to be zero and the element at 'row' // is not used. Thus only elements after row and after are computed. // y = A*u multA_u(blockLength, A, V, row); for (int i = 0; i < row; i++) { // y = y + u_i*v_i^t*u + v_i*u_i^t*u // v_i^t*u double dot_v_u = BlockHouseHolder_DDRB.innerProdRow(blockLength, A, row, V, i, 1); // u_i^t*u double dot_u_u = BlockHouseHolder_DDRB.innerProdRow(blockLength, A, row, A, i, 1); // y = y + u_i*(v_i^t*u) // the ones in these 'u' are skipped over since the next submatrix of A // is only updated VectorOps_DDRB.add_row(blockLength, V, row, 1, A, i, dot_v_u, V, row, row + 1, A.col1 - A.col0); // y = y + v_i*(u_i^t*u) // the 1 in U is taken account above VectorOps_DDRB.add_row(blockLength, V, row, 1, V, i, dot_u_u, V, row, row + 1, A.col1 - A.col0); } // y = -gamma*y VectorOps_DDRB.scale_row(blockLength, V, row, -gamma, V, row, row + 1, V.col1 - V.col0); }
/** * <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, DSubmatrixD1 A, DSubmatrixD1 V, int row) { int height = Math.Min(blockLength, A.row1 - A.row0); double[] dataA = A.original.data; double[] 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; double u_row = (i + 1 == row) ? 1.0 : dataA[indexU]; double v_row = dataV[indexV]; // take in account the leading one double 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_DDRB.add_row(blockLength, A, row, 1, V, i, u_row, A, row, row, A.col1 - A.col0); VectorOps_DDRB.add_row(blockLength, A, row, 1, A, i, v_row, A, row, row, A.col1 - A.col0); A.set(i, i + 1, before); } }
public static void add_row(int blockLength, DSubmatrixD1 A, int rowA, double alpha, DSubmatrixD1 B, int rowB, double beta, DSubmatrixD1 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_DDRB.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, DSubmatrixD1 Y, DSubmatrixD1 W, int row, int zeroOffset, double 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_DDRB.scale_row(blockLength, Y, row, val, W, row, offset + 1, Y.col1 - Y.col0); }
/** * <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, DSubmatrixD1 A, DSubmatrixD1 V, int row, double gamma) { // val=(y^T*u) double val = BlockHouseHolder_DDRB.innerProdRow(blockLength, A, row, V, row, 1); // take in account the one double before = A.get(row, row + 1); A.set(row, row + 1, 1); // v = y - (1/2)gamma*val * u VectorOps_DDRB.add_row(blockLength, V, row, 1, A, row, -0.5 * gamma * val, V, row, row + 1, A.col1 - A.col0); A.set(row, row + 1, before); }