package util.linalg;
/**
* A tridiagonal decomposition that decomposes
* a symmetric matrix A into U*T*Ut where T
* is tridiagonal and U is a orthonormal matrix.
* @author Andrew Guillory gtg008g@mail.gatech.edu
* @version 1.0
*/
public class TridiagonalDecomposition {
/**
* The tridiagonal matrix t
*/
private RectangularMatrix t;
/**
* The orthonormal matrix
*/
private RectangularMatrix u;
/**
* Create a new tridiagonal decomposition
* @param a the matrix to decompose
*/
public TridiagonalDecomposition(Matrix a) {
t = new RectangularMatrix((Matrix) a.copy());
u = RectangularMatrix.eye(a.n());
decompose();
}
/**
* Decomposes the matrix through a series of
* householder reflections from the left and right.
* This is exactly the same as the hessenber decomposition
* except that symmetry is exploited to save a few
* flops.
*/
private void decompose() {
// the first n - 2 columns
for (int i = 0; i < t.n() - 2; i++) {
// extract the column
Vector c = t.getColumn(i);
// the vector we want to reflect
// the k+1:n elements of the column
// into (r, 0, 0, ...) for some r
Vector x = c.get(i+1, c.size());
// create the householder reflection, beta and v
HouseholderReflection hr = new HouseholderReflection(x);
Vector v = hr.getV();
double beta = hr.getBeta();
// apply to the t matrix from the left and from the right
// applying from the left to A(i+1:n,i)
// from the right to A(i,i+1:n)
// and from both sides at the same time to A(i+1:n,i+1:n)
// create w = beta*A(i,i+1:n)*v for the one sided updates
Vector w = new DenseVector(v.size() + 1);
for (int row = i; row < t.n(); row++) {
for (int column = i+1; column < t.n(); column++) {
w.set(row-i, w.get(row-i) +
t.get(row, column) * v.get(column-(i+1)));
}
w.set(row-i, w.get(row-i) * beta);
}
// z vector for the simulatenous updates
// equal to p-(beta*pt*v/2)*v
// where p = beta*A(i+1:n,i+1:n)*v
Vector z = w.get(1, w.size());
z = z.minus(v.times(beta*z.dotProduct(v)/2));
// apply the outer product update to the matrix
// set
// A(i+1:n,i+1:n) = A(i+1:n,i+1:n) - v*zt - z*vt
// A(i+1:n,i) = A(i+1,n) - v*wt
// A(i,i+1:n) = A(i,i+1:n) - w*vt
for (int row = i; row < t.n(); row++) {
for (int column = i; column < t.n(); column++) {
if (row > i && column > i) {
t.set(row,column, t.get(row,column)
- v.get(row-(i+1)) * z.get(column-(i+1))
- v.get(column-(i+1)) * z.get(row-(i+1)));
} else if (row > i) {
t.set(row, column, t.get(row,column)
- v.get(row-(i+1)) * w.get(column-i));
} else if (column > i) {
t.set(row, column, t.get(row,column)
- v.get(column-(i+1)) * w.get(row-i));
}
}
}
// accumulate the u from the right
hr.applyRight(u, 0, u.m(), i+1, u.n());
}
}
/**
* Get the tridiagonal matrix t
* @return the tridiagonal matrix
*/
public RectangularMatrix getT() {
return t;
}
/**
* Get the orthonormal matrix u
* @return the orthonormal matrix
*/
public RectangularMatrix getU() {
return u;
}
}