All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ejml.alg.dense.decomposition.hessenberg.HessenbergSimilarDecomposition Maven / Gradle / Ivy

Go to download

A fast and easy to use dense matrix linear algebra library written in Java.

There is a newer version: 0.25
Show newest version
/*
 * Copyright (c) 2009-2012, Peter Abeles. All Rights Reserved.
 *
 * This file is part of Efficient Java Matrix Library (EJML).
 *
 * EJML is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * EJML is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EJML.  If not, see .
 */

package org.ejml.alg.dense.decomposition.hessenberg;

import org.ejml.alg.dense.decomposition.qr.QrHelperFunctions;
import org.ejml.data.DenseMatrix64F;
import org.ejml.factory.DecompositionInterface;
import org.ejml.ops.CommonOps;

/**
 * 

* Finds the decomposition of a matrix in the form of:
*
* A = OHOT
*
* where A is an m by m matrix, O is an orthogonal matrix, and H is an upper Hessenberg matrix. *

* *

* A matrix is upper Hessenberg if aij = 0 for all i > j+1. For example, the following matrix * is upper Hessenberg.
*
* WRITE IT OUT USING A TABLE *

* *

* This decomposition is primarily used as a step for computing the eigenvalue decomposition of a matrix. * The basic algorithm comes from David S. Watkins, "Fundamentals of MatrixComputations" Second Edition. *

*/ // TODO create a column based one similar to what was done for QR decomposition? public class HessenbergSimilarDecomposition implements DecompositionInterface { // A combined matrix that stores te upper Hessenberg matrix and the orthogonal matrix. private DenseMatrix64F QH; // number of rows and columns of the matrix being decompose private int N; // the first element in the orthogonal vectors private double gammas[]; // temporary storage private double b[]; private double u[]; /** * Creates a decomposition that won't need to allocate new memory if it is passed matrices up to * the specified size. * * @param initialSize Expected size of the matrices it will decompose. */ public HessenbergSimilarDecomposition( int initialSize ) { gammas = new double[ initialSize ]; b = new double[ initialSize ]; u = new double[ initialSize ]; } public HessenbergSimilarDecomposition() { this(5); } /** * Computes the decomposition of the provided matrix. If no errors are detected then true is returned, * false otherwise. * @param A The matrix that is being decomposed. Not modified. * @return If it detects any errors or not. */ @Override public boolean decompose( DenseMatrix64F A ) { if( A.numRows != A.numCols ) throw new IllegalArgumentException("A must be square."); QH = A; N = A.numCols; if( b.length < N ) { b = new double[ N ]; gammas = new double[ N ]; u = new double[ N ]; } return _decompose(); } @Override public boolean inputModified() { return true; } /** * The raw QH matrix that is stored internally. * * @return QH matrix. */ public DenseMatrix64F getQH() { return QH; } /** * An upper Hessenberg matrix from the decompostion. * * @param H If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted H matrix. */ public DenseMatrix64F getH( DenseMatrix64F H ) { if( H == null ) { H = new DenseMatrix64F(N,N); } else if( N != H.numRows || N != H.numCols ) throw new IllegalArgumentException("The provided H must have the same dimensions as the decomposed matrix."); else H.zero(); // copy the first row System.arraycopy(QH.data, 0, H.data, 0, N); for( int i = 1; i < N; i++ ) { for( int j = i-1; j < N; j++ ) { H.set(i,j, QH.get(i,j)); } } return H; } /** * An orthogonal matrix that has the following property: H = QTAQ * * @param Q If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public DenseMatrix64F getQ( DenseMatrix64F Q ) { if( Q == null ) { Q = new DenseMatrix64F(N,N); for( int i = 0; i < N; i++ ) { Q.data[i*N+i] = 1; } } else if( N != Q.numRows || N != Q.numCols ) throw new IllegalArgumentException("The provided H must have the same dimensions as the decomposed matrix."); else CommonOps.setIdentity(Q); for( int j = N-2; j >= 0; j-- ) { u[j+1] = 1; for( int i = j+2; i < N; i++ ) { u[i] = QH.get(i,j); } QrHelperFunctions.rank1UpdateMultR(Q,u,gammas[j],j+1,j+1,N,b); } return Q; } /** * Internal function for computing the decomposition. */ private boolean _decompose() { double h[] = QH.data; for( int k = 0; k < N-2; k++ ) { // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow double max = 0; for( int i = k+1; i < N; i++ ) { // copy the householder vector to vector outside of the matrix to reduce caching issues // big improvement on larger matrices and a relatively small performance hit on small matrices. double val = u[i] = h[i*N+k]; val = Math.abs(val); if( val > max ) max = val; } if( max > 0 ) { // -------- set up the reflector Q_k double tau = 0; // normalize to reduce overflow/underflow // and compute tau for the reflector for( int i = k+1; i < N; i++ ) { double val = u[i] /= max; tau += val*val; } tau = Math.sqrt(tau); if( u[k+1] < 0 ) tau = -tau; // write the reflector into the lower left column of the matrix double nu = u[k+1] + tau; u[k+1] = 1.0; for( int i = k+2; i < N; i++ ) { h[i*N+k] = u[i] /= nu; } double gamma = nu/tau; gammas[k] = gamma; // ---------- multiply on the left by Q_k QrHelperFunctions.rank1UpdateMultR(QH,u,gamma,k+1,k+1,N,b); // ---------- multiply on the right by Q_k QrHelperFunctions.rank1UpdateMultL(QH,u,gamma,0,k+1,N); // since the first element in the householder vector is known to be 1 // store the full upper hessenberg h[(k+1)*N+k] = -tau*max; } else { gammas[k] = 0; } } return true; } public double[] getGammas() { return gammas; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy