2008-06-08 15:03:23 +00:00
|
|
|
// This file is part of Eigen, a lightweight C++ template library
|
2009-05-22 20:25:33 +02:00
|
|
|
// for linear algebra.
|
2008-06-08 15:03:23 +00:00
|
|
|
//
|
2009-12-23 12:30:05 +01:00
|
|
|
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
|
2008-06-08 15:03:23 +00:00
|
|
|
//
|
|
|
|
|
// Eigen 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.
|
|
|
|
|
//
|
|
|
|
|
// Alternatively, you can redistribute it and/or
|
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
|
// published by the Free Software Foundation; either version 2 of
|
|
|
|
|
// the License, or (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// Eigen 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 or the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
// License and a copy of the GNU General Public License along with
|
|
|
|
|
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
#ifndef EIGEN_HESSENBERGDECOMPOSITION_H
|
|
|
|
|
#define EIGEN_HESSENBERGDECOMPOSITION_H
|
|
|
|
|
|
2009-09-04 09:23:38 +02:00
|
|
|
/** \eigenvalues_module \ingroup Eigenvalues_Module
|
2008-11-22 19:51:05 +00:00
|
|
|
* \nonstableyet
|
2008-07-22 10:54:42 +00:00
|
|
|
*
|
|
|
|
|
* \class HessenbergDecomposition
|
2008-06-08 15:03:23 +00:00
|
|
|
*
|
2010-03-28 17:33:56 +01:00
|
|
|
* \brief Reduces a square matrix to Hessenberg form by an orthogonal similarity transformation
|
2008-06-08 15:03:23 +00:00
|
|
|
*
|
2010-03-28 17:33:56 +01:00
|
|
|
* \tparam _MatrixType the type of the matrix of which we are computing the Hessenberg decomposition
|
2008-06-08 15:03:23 +00:00
|
|
|
*
|
2010-03-28 17:33:56 +01:00
|
|
|
* This class performs an Hessenberg decomposition of a matrix \f$ A \f$. In
|
|
|
|
|
* the real case, the Hessenberg decomposition consists of an orthogonal
|
|
|
|
|
* matrix \f$ Q \f$ and a Hessenberg matrix \f$ H \f$ such that \f$ A = Q H
|
|
|
|
|
* Q^T \f$. An orthogonal matrix is a matrix whose inverse equals its
|
|
|
|
|
* transpose (\f$ Q^{-1} = Q^T \f$). A Hessenberg matrix has zeros below the
|
|
|
|
|
* subdiagonal, so it is almost upper triangular. The Hessenberg decomposition
|
|
|
|
|
* of a complex matrix is \f$ A = Q H Q^* \f$ with \f$ Q \f$ unitary (that is,
|
|
|
|
|
* \f$ Q^{-1} = Q^* \f$).
|
2008-06-08 15:03:23 +00:00
|
|
|
*
|
2010-03-28 17:33:56 +01:00
|
|
|
* Call the function compute() to compute the Hessenberg decomposition of a
|
|
|
|
|
* given matrix. Alternatively, you can use the
|
|
|
|
|
* HessenbergDecomposition(const MatrixType&) constructor which computes the
|
|
|
|
|
* Hessenberg decomposition at construction time. Once the decomposition is
|
|
|
|
|
* computed, you can use the matrixH() and matrixQ() functions to construct
|
|
|
|
|
* the matrices H and Q in the decomposition.
|
|
|
|
|
*
|
|
|
|
|
* The documentation for matrixH() contains an example of the typical use of
|
|
|
|
|
* this class.
|
|
|
|
|
*
|
|
|
|
|
* \sa class ComplexSchur, class Tridiagonalization, \ref QR_Module "QR Module"
|
2008-06-08 15:03:23 +00:00
|
|
|
*/
|
|
|
|
|
template<typename _MatrixType> class HessenbergDecomposition
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
typedef _MatrixType MatrixType;
|
|
|
|
|
enum {
|
|
|
|
|
Size = MatrixType::RowsAtCompileTime,
|
2010-03-08 19:31:27 +01:00
|
|
|
SizeMinusOne = Size == Dynamic ? Dynamic : Size - 1,
|
|
|
|
|
Options = MatrixType::Options,
|
|
|
|
|
MaxSize = MatrixType::MaxRowsAtCompileTime,
|
|
|
|
|
MaxSizeMinusOne = MaxSize == Dynamic ? Dynamic : MaxSize - 1
|
2008-08-03 20:23:06 +00:00
|
|
|
};
|
2010-03-28 17:33:56 +01:00
|
|
|
|
|
|
|
|
/** \brief Scalar type for matrices of type \p _MatrixType. */
|
2010-03-08 19:31:27 +01:00
|
|
|
typedef typename MatrixType::Scalar Scalar;
|
2010-03-28 17:33:56 +01:00
|
|
|
|
|
|
|
|
/** \brief Type for vector of Householder coefficients.
|
|
|
|
|
*
|
|
|
|
|
* This is column vector with entries of type #Scalar. The length of the
|
|
|
|
|
* vector is one less than the size of \p _MatrixType, if it is a
|
|
|
|
|
* fixed-side type.
|
|
|
|
|
*/
|
2010-03-19 02:12:23 -04:00
|
|
|
typedef Matrix<Scalar, SizeMinusOne, 1, Options & ~RowMajor, MaxSizeMinusOne, 1> CoeffVectorType;
|
2008-06-08 15:03:23 +00:00
|
|
|
|
2010-03-28 17:33:56 +01:00
|
|
|
/** \brief Default constructor; the decomposition will be computed later.
|
|
|
|
|
*
|
|
|
|
|
* \param [in] size The size of the matrix whose Hessenberg decomposition will be computed.
|
|
|
|
|
*
|
|
|
|
|
* The default constructor is useful in cases in which the user intends to
|
|
|
|
|
* perform decompositions via compute(). The \p size parameter is only
|
|
|
|
|
* used as a hint. It is not an error to give a wrong \p size, but it may
|
|
|
|
|
* impair performance.
|
|
|
|
|
*
|
|
|
|
|
* \sa compute() for an example.
|
2008-06-14 13:02:41 +00:00
|
|
|
*/
|
|
|
|
|
HessenbergDecomposition(int size = Size==Dynamic ? 2 : Size)
|
2010-04-21 17:15:57 +02:00
|
|
|
: m_matrix(size,size),
|
|
|
|
|
m_temp(size)
|
2009-12-23 12:30:05 +01:00
|
|
|
{
|
|
|
|
|
if(size>1)
|
|
|
|
|
m_hCoeffs.resize(size-1);
|
|
|
|
|
}
|
2008-06-08 15:03:23 +00:00
|
|
|
|
2010-03-28 17:33:56 +01:00
|
|
|
/** \brief Constructor; computes Hessenberg decomposition of given matrix.
|
|
|
|
|
*
|
|
|
|
|
* \param[in] matrix Square matrix whose Hessenberg decomposition is to be computed.
|
|
|
|
|
*
|
|
|
|
|
* This constructor calls compute() to compute the Hessenberg
|
|
|
|
|
* decomposition.
|
|
|
|
|
*
|
|
|
|
|
* \sa matrixH() for an example.
|
|
|
|
|
*/
|
2008-06-08 15:03:23 +00:00
|
|
|
HessenbergDecomposition(const MatrixType& matrix)
|
2010-04-21 17:15:57 +02:00
|
|
|
: m_matrix(matrix),
|
|
|
|
|
m_temp(matrix.rows())
|
2008-06-08 15:03:23 +00:00
|
|
|
{
|
2009-12-23 12:30:05 +01:00
|
|
|
if(matrix.rows()<2)
|
2009-12-23 12:18:54 +01:00
|
|
|
return;
|
|
|
|
|
m_hCoeffs.resize(matrix.rows()-1,1);
|
2010-04-21 17:15:57 +02:00
|
|
|
_compute(m_matrix, m_hCoeffs, m_temp);
|
2008-06-08 15:03:23 +00:00
|
|
|
}
|
|
|
|
|
|
2010-03-28 17:33:56 +01:00
|
|
|
/** \brief Computes Hessenberg decomposition of given matrix.
|
|
|
|
|
*
|
|
|
|
|
* \param[in] matrix Square matrix whose Hessenberg decomposition is to be computed.
|
|
|
|
|
*
|
|
|
|
|
* The Hessenberg decomposition is computed by bringing the columns of the
|
|
|
|
|
* matrix successively in the required form using Householder reflections
|
|
|
|
|
* (see, e.g., Algorithm 7.4.2 in Golub \& Van Loan, <i>%Matrix
|
|
|
|
|
* Computations</i>). The cost is \f$ 10n^3/3 \f$ flops, where \f$ n \f$
|
|
|
|
|
* denotes the size of the given matrix.
|
2008-06-08 15:03:23 +00:00
|
|
|
*
|
2010-03-28 17:33:56 +01:00
|
|
|
* This method reuses of the allocated data in the HessenbergDecomposition
|
|
|
|
|
* object.
|
|
|
|
|
*
|
|
|
|
|
* Example: \include HessenbergDecomposition_compute.cpp
|
|
|
|
|
* Output: \verbinclude HessenbergDecomposition_compute.out
|
2008-06-08 15:03:23 +00:00
|
|
|
*/
|
|
|
|
|
void compute(const MatrixType& matrix)
|
|
|
|
|
{
|
|
|
|
|
m_matrix = matrix;
|
2009-12-23 12:30:05 +01:00
|
|
|
if(matrix.rows()<2)
|
2009-12-23 12:18:54 +01:00
|
|
|
return;
|
2008-06-08 15:03:23 +00:00
|
|
|
m_hCoeffs.resize(matrix.rows()-1,1);
|
2010-04-21 17:15:57 +02:00
|
|
|
_compute(m_matrix, m_hCoeffs, m_temp);
|
2008-06-08 15:03:23 +00:00
|
|
|
}
|
|
|
|
|
|
2010-03-28 17:33:56 +01:00
|
|
|
/** \brief Returns the Householder coefficients.
|
|
|
|
|
*
|
|
|
|
|
* \returns a const reference to the vector of Householder coefficients
|
|
|
|
|
*
|
|
|
|
|
* \pre Either the constructor HessenbergDecomposition(const MatrixType&)
|
|
|
|
|
* or the member function compute(const MatrixType&) has been called
|
|
|
|
|
* before to compute the Hessenberg decomposition of a matrix.
|
|
|
|
|
*
|
|
|
|
|
* The Householder coefficients allow the reconstruction of the matrix
|
|
|
|
|
* \f$ Q \f$ in the Hessenberg decomposition from the packed data.
|
2008-06-08 15:03:23 +00:00
|
|
|
*
|
2010-03-28 17:33:56 +01:00
|
|
|
* \sa packedMatrix(), \ref Householder_Module "Householder module"
|
2008-06-08 15:03:23 +00:00
|
|
|
*/
|
2009-09-16 14:34:08 +02:00
|
|
|
const CoeffVectorType& householderCoefficients() const { return m_hCoeffs; }
|
2008-06-08 15:03:23 +00:00
|
|
|
|
2010-03-28 17:33:56 +01:00
|
|
|
/** \brief Returns the internal representation of the decomposition
|
|
|
|
|
*
|
|
|
|
|
* \returns a const reference to a matrix with the internal representation
|
|
|
|
|
* of the decomposition.
|
|
|
|
|
*
|
|
|
|
|
* \pre Either the constructor HessenbergDecomposition(const MatrixType&)
|
|
|
|
|
* or the member function compute(const MatrixType&) has been called
|
|
|
|
|
* before to compute the Hessenberg decomposition of a matrix.
|
2008-06-08 15:03:23 +00:00
|
|
|
*
|
|
|
|
|
* The returned matrix contains the following information:
|
|
|
|
|
* - the upper part and lower sub-diagonal represent the Hessenberg matrix H
|
|
|
|
|
* - the rest of the lower part contains the Householder vectors that, combined with
|
|
|
|
|
* Householder coefficients returned by householderCoefficients(),
|
2010-03-28 17:33:56 +01:00
|
|
|
* allows to reconstruct the matrix Q as
|
|
|
|
|
* \f$ Q = H_{N-1} \ldots H_1 H_0 \f$.
|
|
|
|
|
* Here, the matrices \f$ H_i \f$ are the Householder transformations
|
|
|
|
|
* \f$ H_i = (I - h_i v_i v_i^T) \f$
|
|
|
|
|
* where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and
|
|
|
|
|
* \f$ v_i \f$ is the Householder vector defined by
|
|
|
|
|
* \f$ v_i = [ 0, \ldots, 0, 1, M(i+2,i), \ldots, M(N-1,i) ]^T \f$
|
|
|
|
|
* with M the matrix returned by this function.
|
2008-06-08 15:03:23 +00:00
|
|
|
*
|
|
|
|
|
* See LAPACK for further details on this packed storage.
|
2010-03-28 17:33:56 +01:00
|
|
|
*
|
|
|
|
|
* Example: \include HessenbergDecomposition_packedMatrix.cpp
|
|
|
|
|
* Output: \verbinclude HessenbergDecomposition_packedMatrix.out
|
|
|
|
|
*
|
|
|
|
|
* \sa householderCoefficients()
|
2008-06-08 15:03:23 +00:00
|
|
|
*/
|
|
|
|
|
const MatrixType& packedMatrix(void) const { return m_matrix; }
|
|
|
|
|
|
2010-03-28 17:33:56 +01:00
|
|
|
/** \brief Reconstructs the orthogonal matrix Q in the decomposition
|
|
|
|
|
*
|
|
|
|
|
* \returns the matrix Q
|
|
|
|
|
*
|
|
|
|
|
* \pre Either the constructor HessenbergDecomposition(const MatrixType&)
|
|
|
|
|
* or the member function compute(const MatrixType&) has been called
|
|
|
|
|
* before to compute the Hessenberg decomposition of a matrix.
|
|
|
|
|
*
|
|
|
|
|
* This function reconstructs the matrix Q from the Householder
|
|
|
|
|
* coefficients and the packed matrix stored internally. This
|
|
|
|
|
* reconstruction requires \f$ 4n^3 / 3 \f$ flops.
|
|
|
|
|
*
|
|
|
|
|
* \sa matrixH() for an example
|
|
|
|
|
*/
|
2009-08-17 17:41:01 +02:00
|
|
|
MatrixType matrixQ() const;
|
2010-03-28 17:33:56 +01:00
|
|
|
|
|
|
|
|
/** \brief Constructs the Hessenberg matrix H in the decomposition
|
|
|
|
|
*
|
|
|
|
|
* \returns the matrix H
|
|
|
|
|
*
|
|
|
|
|
* \pre Either the constructor HessenbergDecomposition(const MatrixType&)
|
|
|
|
|
* or the member function compute(const MatrixType&) has been called
|
|
|
|
|
* before to compute the Hessenberg decomposition of a matrix.
|
|
|
|
|
*
|
|
|
|
|
* This function copies the matrix H from internal data. The upper part
|
|
|
|
|
* (including the subdiagonal) of the packed matrix as returned by
|
|
|
|
|
* packedMatrix() contains the matrix H. This function copies those
|
|
|
|
|
* entries in a newly created matrix and sets the remaining entries to
|
|
|
|
|
* zero. It may sometimes be sufficient to directly use the packed matrix
|
|
|
|
|
* instead of creating a new one.
|
|
|
|
|
*
|
|
|
|
|
* Example: \include HessenbergDecomposition_matrixH.cpp
|
|
|
|
|
* Output: \verbinclude HessenbergDecomposition_matrixH.out
|
|
|
|
|
*
|
|
|
|
|
* \sa matrixQ(), packedMatrix()
|
|
|
|
|
*/
|
2009-08-17 17:41:01 +02:00
|
|
|
MatrixType matrixH() const;
|
2008-06-08 15:03:23 +00:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
2010-04-16 11:25:50 -04:00
|
|
|
typedef Matrix<Scalar, 1, Size, Options | RowMajor, 1, MaxSize> VectorType;
|
2010-03-28 17:33:56 +01:00
|
|
|
typedef typename NumTraits<Scalar>::Real RealScalar;
|
2010-04-21 17:15:57 +02:00
|
|
|
static void _compute(MatrixType& matA, CoeffVectorType& hCoeffs, VectorType& temp);
|
|
|
|
|
|
2008-06-08 15:03:23 +00:00
|
|
|
protected:
|
|
|
|
|
MatrixType m_matrix;
|
|
|
|
|
CoeffVectorType m_hCoeffs;
|
2010-04-21 17:15:57 +02:00
|
|
|
VectorType m_temp;
|
2008-06-08 15:03:23 +00:00
|
|
|
};
|
|
|
|
|
|
2008-06-14 13:02:41 +00:00
|
|
|
#ifndef EIGEN_HIDE_HEAVY_CODE
|
2008-06-08 15:03:23 +00:00
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* Performs a tridiagonal decomposition of \a matA in place.
|
|
|
|
|
*
|
|
|
|
|
* \param matA the input selfadjoint matrix
|
|
|
|
|
* \param hCoeffs returned Householder coefficients
|
|
|
|
|
*
|
|
|
|
|
* The result is written in the lower triangular part of \a matA.
|
|
|
|
|
*
|
2010-03-28 17:33:56 +01:00
|
|
|
* Implemented from Golub's "%Matrix Computations", algorithm 8.3.1.
|
2008-06-08 15:03:23 +00:00
|
|
|
*
|
|
|
|
|
* \sa packedMatrix()
|
|
|
|
|
*/
|
|
|
|
|
template<typename MatrixType>
|
2010-04-21 17:15:57 +02:00
|
|
|
void HessenbergDecomposition<MatrixType>::_compute(MatrixType& matA, CoeffVectorType& hCoeffs, VectorType& temp)
|
2008-06-08 15:03:23 +00:00
|
|
|
{
|
|
|
|
|
assert(matA.rows()==matA.cols());
|
|
|
|
|
int n = matA.rows();
|
2010-04-21 17:15:57 +02:00
|
|
|
temp.resize(n);
|
2009-08-17 17:41:01 +02:00
|
|
|
for (int i = 0; i<n-1; ++i)
|
2008-06-08 15:03:23 +00:00
|
|
|
{
|
|
|
|
|
// let's consider the vector v = i-th column starting at position i+1
|
2009-08-17 17:41:01 +02:00
|
|
|
int remainingSize = n-i-1;
|
|
|
|
|
RealScalar beta;
|
|
|
|
|
Scalar h;
|
2010-01-04 21:24:43 -05:00
|
|
|
matA.col(i).tail(remainingSize).makeHouseholderInPlace(h, beta);
|
2009-08-17 17:41:01 +02:00
|
|
|
matA.col(i).coeffRef(i+1) = beta;
|
2008-06-08 15:03:23 +00:00
|
|
|
hCoeffs.coeffRef(i) = h;
|
|
|
|
|
|
2009-08-17 17:41:01 +02:00
|
|
|
// Apply similarity transformation to remaining columns,
|
|
|
|
|
// i.e., compute A = H A H'
|
2009-09-03 11:39:44 +02:00
|
|
|
|
2009-08-17 17:41:01 +02:00
|
|
|
// A = H A
|
|
|
|
|
matA.corner(BottomRight, remainingSize, remainingSize)
|
2010-01-04 21:24:43 -05:00
|
|
|
.applyHouseholderOnTheLeft(matA.col(i).tail(remainingSize-1), h, &temp.coeffRef(0));
|
2008-06-08 15:03:23 +00:00
|
|
|
|
2009-08-17 17:41:01 +02:00
|
|
|
// A = A H'
|
|
|
|
|
matA.corner(BottomRight, n, remainingSize)
|
2010-01-04 21:24:43 -05:00
|
|
|
.applyHouseholderOnTheRight(matA.col(i).tail(remainingSize-1).conjugate(), ei_conj(h), &temp.coeffRef(0));
|
2008-06-08 15:03:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename MatrixType>
|
|
|
|
|
typename HessenbergDecomposition<MatrixType>::MatrixType
|
2009-08-17 17:41:01 +02:00
|
|
|
HessenbergDecomposition<MatrixType>::matrixQ() const
|
2008-06-08 15:03:23 +00:00
|
|
|
{
|
|
|
|
|
int n = m_matrix.rows();
|
2008-07-21 00:34:46 +00:00
|
|
|
MatrixType matQ = MatrixType::Identity(n,n);
|
2010-03-08 19:31:27 +01:00
|
|
|
VectorType temp(n);
|
2008-06-08 15:03:23 +00:00
|
|
|
for (int i = n-2; i>=0; i--)
|
|
|
|
|
{
|
2009-08-17 17:41:01 +02:00
|
|
|
matQ.corner(BottomRight,n-i-1,n-i-1)
|
2010-01-04 21:24:43 -05:00
|
|
|
.applyHouseholderOnTheLeft(m_matrix.col(i).tail(n-i-2), ei_conj(m_hCoeffs.coeff(i)), &temp.coeffRef(0,0));
|
2008-06-08 15:03:23 +00:00
|
|
|
}
|
|
|
|
|
return matQ;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-14 13:02:41 +00:00
|
|
|
#endif // EIGEN_HIDE_HEAVY_CODE
|
|
|
|
|
|
2008-06-08 15:03:23 +00:00
|
|
|
template<typename MatrixType>
|
|
|
|
|
typename HessenbergDecomposition<MatrixType>::MatrixType
|
2009-08-17 17:41:01 +02:00
|
|
|
HessenbergDecomposition<MatrixType>::matrixH() const
|
2008-06-08 15:03:23 +00:00
|
|
|
{
|
|
|
|
|
// FIXME should this function (and other similar) rather take a matrix as argument
|
2008-06-14 13:02:41 +00:00
|
|
|
// and fill it (to avoid temporaries)
|
2008-06-08 15:03:23 +00:00
|
|
|
int n = m_matrix.rows();
|
|
|
|
|
MatrixType matH = m_matrix;
|
2008-06-15 11:54:18 +00:00
|
|
|
if (n>2)
|
2010-01-07 21:15:32 +01:00
|
|
|
matH.corner(BottomLeft,n-2, n-2).template triangularView<Lower>().setZero();
|
2008-06-08 15:03:23 +00:00
|
|
|
return matH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // EIGEN_HESSENBERGDECOMPOSITION_H
|