package util.linalg; /** * A class implementing a bidiagonal decomposition. * Decomposes a general matrix A into U*B*Vt * where B is bidiagonal and U and Vt are * orthonormal. * @author Andrew Guillory gtg008g@mail.gatech.edu * @version 1.0 */ public class BidiagonalDecomposition { /** * The resulting u matrix */ private RectangularMatrix u; /** * The resulting v matrix */ private RectangularMatrix v; /** * The resulting bidiagonal matrix b's diagonal */ private RectangularMatrix b; /** * Create a bidiagonal decomposition of the given matrix * @param matrix the matrix to decompose */ public BidiagonalDecomposition(Matrix matrix) { b = new RectangularMatrix(matrix); u = RectangularMatrix.eye(b.m()); v = RectangularMatrix.eye(b.n()); decompose(); } /** * Perform the decomposition. * Uses householder reflections to zero out all of * subdiagonal and entries and entries to the right * of the superdiagonal */ private void decompose() { int mnmin = Math.min(b.n(), b.m()); // loop through columns of b for (int i = 0; i < mnmin; i++) { if (i < b.m() - 1) { // extract the column Vector column = b.getColumn(i); // extract out the porition we want to reflect // into e1 Vector x = column.get(i, column.size()); // calculate the householder reflection for // this vector HouseholderReflection h = new HouseholderReflection(x); // update the b from the left h.applyLeft(b, i, b.m(), i, b.n()); // and u from the right h.applyRight(u, 0, u.m(), i, u.n()); } // zero out the row if (i < b.n() - 2) { // extract out the row we want to reflect Vector row = b.getRow(i); // extract out the porition we are going to be reflecting Vector x = row.get(i+1, row.size()); // construct the householder reflection HouseholderReflection h = new HouseholderReflection(x); // update the b from the right h.applyRight(b, i, b.m(), i+1, b.n()); // and v from the right h.applyRight(v, 0, v.m(), i+1, v.n()); } } // chase the extra value up the matrix (for n > m) if (b.n() > b.m()) { // for each row for (int i = b.m()-1; i >= 0; i--) { // the values we want to cancel out double x = b.get(i,i); double y = b.get(i,b.m()); // construct the givens rotation // and cancel out from the right GivensRotation g = new GivensRotation(x, y); // affects only columns i and m g.applyRight(b, i, b.m()); g.applyRight(v, i, b.m()); } } } /** * Get the bidiagonal matrix b * @return the bidiagonal */ public RectangularMatrix getB() { return b; } /** * Get the orthonormal matrix u * @return the orthornomal */ public RectangularMatrix getU() { return u; } /** * Get the orthonormal matrix v * @return the orthonormal */ public RectangularMatrix getV() { return v; } }