Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // This file is part of Eigen, a lightweight C++ template library
0002 // for linear algebra.
0003 //
0004 // Copyright (C) 2009 Claire Maurice
0005 // Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
0006 // Copyright (C) 2010,2012 Jitse Niesen <jitse@maths.leeds.ac.uk>
0007 //
0008 // This Source Code Form is subject to the terms of the Mozilla
0009 // Public License v. 2.0. If a copy of the MPL was not distributed
0010 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
0011 
0012 #ifndef EIGEN_COMPLEX_EIGEN_SOLVER_H
0013 #define EIGEN_COMPLEX_EIGEN_SOLVER_H
0014 
0015 #include "./ComplexSchur.h"
0016 
0017 namespace Eigen { 
0018 
0019 /** \eigenvalues_module \ingroup Eigenvalues_Module
0020   *
0021   *
0022   * \class ComplexEigenSolver
0023   *
0024   * \brief Computes eigenvalues and eigenvectors of general complex matrices
0025   *
0026   * \tparam _MatrixType the type of the matrix of which we are
0027   * computing the eigendecomposition; this is expected to be an
0028   * instantiation of the Matrix class template.
0029   *
0030   * The eigenvalues and eigenvectors of a matrix \f$ A \f$ are scalars
0031   * \f$ \lambda \f$ and vectors \f$ v \f$ such that \f$ Av = \lambda v
0032   * \f$.  If \f$ D \f$ is a diagonal matrix with the eigenvalues on
0033   * the diagonal, and \f$ V \f$ is a matrix with the eigenvectors as
0034   * its columns, then \f$ A V = V D \f$. The matrix \f$ V \f$ is
0035   * almost always invertible, in which case we have \f$ A = V D V^{-1}
0036   * \f$. This is called the eigendecomposition.
0037   *
0038   * The main function in this class is compute(), which computes the
0039   * eigenvalues and eigenvectors of a given function. The
0040   * documentation for that function contains an example showing the
0041   * main features of the class.
0042   *
0043   * \sa class EigenSolver, class SelfAdjointEigenSolver
0044   */
0045 template<typename _MatrixType> class ComplexEigenSolver
0046 {
0047   public:
0048 
0049     /** \brief Synonym for the template parameter \p _MatrixType. */
0050     typedef _MatrixType MatrixType;
0051 
0052     enum {
0053       RowsAtCompileTime = MatrixType::RowsAtCompileTime,
0054       ColsAtCompileTime = MatrixType::ColsAtCompileTime,
0055       Options = MatrixType::Options,
0056       MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
0057       MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
0058     };
0059 
0060     /** \brief Scalar type for matrices of type #MatrixType. */
0061     typedef typename MatrixType::Scalar Scalar;
0062     typedef typename NumTraits<Scalar>::Real RealScalar;
0063     typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3
0064 
0065     /** \brief Complex scalar type for #MatrixType.
0066       *
0067       * This is \c std::complex<Scalar> if #Scalar is real (e.g.,
0068       * \c float or \c double) and just \c Scalar if #Scalar is
0069       * complex.
0070       */
0071     typedef std::complex<RealScalar> ComplexScalar;
0072 
0073     /** \brief Type for vector of eigenvalues as returned by eigenvalues().
0074       *
0075       * This is a column vector with entries of type #ComplexScalar.
0076       * The length of the vector is the size of #MatrixType.
0077       */
0078     typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options&(~RowMajor), MaxColsAtCompileTime, 1> EigenvalueType;
0079 
0080     /** \brief Type for matrix of eigenvectors as returned by eigenvectors().
0081       *
0082       * This is a square matrix with entries of type #ComplexScalar.
0083       * The size is the same as the size of #MatrixType.
0084       */
0085     typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime> EigenvectorType;
0086 
0087     /** \brief Default constructor.
0088       *
0089       * The default constructor is useful in cases in which the user intends to
0090       * perform decompositions via compute().
0091       */
0092     ComplexEigenSolver()
0093             : m_eivec(),
0094               m_eivalues(),
0095               m_schur(),
0096               m_isInitialized(false),
0097               m_eigenvectorsOk(false),
0098               m_matX()
0099     {}
0100 
0101     /** \brief Default Constructor with memory preallocation
0102       *
0103       * Like the default constructor but with preallocation of the internal data
0104       * according to the specified problem \a size.
0105       * \sa ComplexEigenSolver()
0106       */
0107     explicit ComplexEigenSolver(Index size)
0108             : m_eivec(size, size),
0109               m_eivalues(size),
0110               m_schur(size),
0111               m_isInitialized(false),
0112               m_eigenvectorsOk(false),
0113               m_matX(size, size)
0114     {}
0115 
0116     /** \brief Constructor; computes eigendecomposition of given matrix.
0117       *
0118       * \param[in]  matrix  Square matrix whose eigendecomposition is to be computed.
0119       * \param[in]  computeEigenvectors  If true, both the eigenvectors and the
0120       *    eigenvalues are computed; if false, only the eigenvalues are
0121       *    computed.
0122       *
0123       * This constructor calls compute() to compute the eigendecomposition.
0124       */
0125     template<typename InputType>
0126     explicit ComplexEigenSolver(const EigenBase<InputType>& matrix, bool computeEigenvectors = true)
0127             : m_eivec(matrix.rows(),matrix.cols()),
0128               m_eivalues(matrix.cols()),
0129               m_schur(matrix.rows()),
0130               m_isInitialized(false),
0131               m_eigenvectorsOk(false),
0132               m_matX(matrix.rows(),matrix.cols())
0133     {
0134       compute(matrix.derived(), computeEigenvectors);
0135     }
0136 
0137     /** \brief Returns the eigenvectors of given matrix.
0138       *
0139       * \returns  A const reference to the matrix whose columns are the eigenvectors.
0140       *
0141       * \pre Either the constructor
0142       * ComplexEigenSolver(const MatrixType& matrix, bool) or the member
0143       * function compute(const MatrixType& matrix, bool) has been called before
0144       * to compute the eigendecomposition of a matrix, and
0145       * \p computeEigenvectors was set to true (the default).
0146       *
0147       * This function returns a matrix whose columns are the eigenvectors. Column
0148       * \f$ k \f$ is an eigenvector corresponding to eigenvalue number \f$ k
0149       * \f$ as returned by eigenvalues().  The eigenvectors are normalized to
0150       * have (Euclidean) norm equal to one. The matrix returned by this
0151       * function is the matrix \f$ V \f$ in the eigendecomposition \f$ A = V D
0152       * V^{-1} \f$, if it exists.
0153       *
0154       * Example: \include ComplexEigenSolver_eigenvectors.cpp
0155       * Output: \verbinclude ComplexEigenSolver_eigenvectors.out
0156       */
0157     const EigenvectorType& eigenvectors() const
0158     {
0159       eigen_assert(m_isInitialized && "ComplexEigenSolver is not initialized.");
0160       eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
0161       return m_eivec;
0162     }
0163 
0164     /** \brief Returns the eigenvalues of given matrix.
0165       *
0166       * \returns A const reference to the column vector containing the eigenvalues.
0167       *
0168       * \pre Either the constructor
0169       * ComplexEigenSolver(const MatrixType& matrix, bool) or the member
0170       * function compute(const MatrixType& matrix, bool) has been called before
0171       * to compute the eigendecomposition of a matrix.
0172       *
0173       * This function returns a column vector containing the
0174       * eigenvalues. Eigenvalues are repeated according to their
0175       * algebraic multiplicity, so there are as many eigenvalues as
0176       * rows in the matrix. The eigenvalues are not sorted in any particular
0177       * order.
0178       *
0179       * Example: \include ComplexEigenSolver_eigenvalues.cpp
0180       * Output: \verbinclude ComplexEigenSolver_eigenvalues.out
0181       */
0182     const EigenvalueType& eigenvalues() const
0183     {
0184       eigen_assert(m_isInitialized && "ComplexEigenSolver is not initialized.");
0185       return m_eivalues;
0186     }
0187 
0188     /** \brief Computes eigendecomposition of given matrix.
0189       *
0190       * \param[in]  matrix  Square matrix whose eigendecomposition is to be computed.
0191       * \param[in]  computeEigenvectors  If true, both the eigenvectors and the
0192       *    eigenvalues are computed; if false, only the eigenvalues are
0193       *    computed.
0194       * \returns    Reference to \c *this
0195       *
0196       * This function computes the eigenvalues of the complex matrix \p matrix.
0197       * The eigenvalues() function can be used to retrieve them.  If
0198       * \p computeEigenvectors is true, then the eigenvectors are also computed
0199       * and can be retrieved by calling eigenvectors().
0200       *
0201       * The matrix is first reduced to Schur form using the
0202       * ComplexSchur class. The Schur decomposition is then used to
0203       * compute the eigenvalues and eigenvectors.
0204       *
0205       * The cost of the computation is dominated by the cost of the
0206       * Schur decomposition, which is \f$ O(n^3) \f$ where \f$ n \f$
0207       * is the size of the matrix.
0208       *
0209       * Example: \include ComplexEigenSolver_compute.cpp
0210       * Output: \verbinclude ComplexEigenSolver_compute.out
0211       */
0212     template<typename InputType>
0213     ComplexEigenSolver& compute(const EigenBase<InputType>& matrix, bool computeEigenvectors = true);
0214 
0215     /** \brief Reports whether previous computation was successful.
0216       *
0217       * \returns \c Success if computation was successful, \c NoConvergence otherwise.
0218       */
0219     ComputationInfo info() const
0220     {
0221       eigen_assert(m_isInitialized && "ComplexEigenSolver is not initialized.");
0222       return m_schur.info();
0223     }
0224 
0225     /** \brief Sets the maximum number of iterations allowed. */
0226     ComplexEigenSolver& setMaxIterations(Index maxIters)
0227     {
0228       m_schur.setMaxIterations(maxIters);
0229       return *this;
0230     }
0231 
0232     /** \brief Returns the maximum number of iterations. */
0233     Index getMaxIterations()
0234     {
0235       return m_schur.getMaxIterations();
0236     }
0237 
0238   protected:
0239     
0240     static void check_template_parameters()
0241     {
0242       EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
0243     }
0244     
0245     EigenvectorType m_eivec;
0246     EigenvalueType m_eivalues;
0247     ComplexSchur<MatrixType> m_schur;
0248     bool m_isInitialized;
0249     bool m_eigenvectorsOk;
0250     EigenvectorType m_matX;
0251 
0252   private:
0253     void doComputeEigenvectors(RealScalar matrixnorm);
0254     void sortEigenvalues(bool computeEigenvectors);
0255 };
0256 
0257 
0258 template<typename MatrixType>
0259 template<typename InputType>
0260 ComplexEigenSolver<MatrixType>& 
0261 ComplexEigenSolver<MatrixType>::compute(const EigenBase<InputType>& matrix, bool computeEigenvectors)
0262 {
0263   check_template_parameters();
0264   
0265   // this code is inspired from Jampack
0266   eigen_assert(matrix.cols() == matrix.rows());
0267 
0268   // Do a complex Schur decomposition, A = U T U^*
0269   // The eigenvalues are on the diagonal of T.
0270   m_schur.compute(matrix.derived(), computeEigenvectors);
0271 
0272   if(m_schur.info() == Success)
0273   {
0274     m_eivalues = m_schur.matrixT().diagonal();
0275     if(computeEigenvectors)
0276       doComputeEigenvectors(m_schur.matrixT().norm());
0277     sortEigenvalues(computeEigenvectors);
0278   }
0279 
0280   m_isInitialized = true;
0281   m_eigenvectorsOk = computeEigenvectors;
0282   return *this;
0283 }
0284 
0285 
0286 template<typename MatrixType>
0287 void ComplexEigenSolver<MatrixType>::doComputeEigenvectors(RealScalar matrixnorm)
0288 {
0289   const Index n = m_eivalues.size();
0290 
0291   matrixnorm = numext::maxi(matrixnorm,(std::numeric_limits<RealScalar>::min)());
0292 
0293   // Compute X such that T = X D X^(-1), where D is the diagonal of T.
0294   // The matrix X is unit triangular.
0295   m_matX = EigenvectorType::Zero(n, n);
0296   for(Index k=n-1 ; k>=0 ; k--)
0297   {
0298     m_matX.coeffRef(k,k) = ComplexScalar(1.0,0.0);
0299     // Compute X(i,k) using the (i,k) entry of the equation X T = D X
0300     for(Index i=k-1 ; i>=0 ; i--)
0301     {
0302       m_matX.coeffRef(i,k) = -m_schur.matrixT().coeff(i,k);
0303       if(k-i-1>0)
0304         m_matX.coeffRef(i,k) -= (m_schur.matrixT().row(i).segment(i+1,k-i-1) * m_matX.col(k).segment(i+1,k-i-1)).value();
0305       ComplexScalar z = m_schur.matrixT().coeff(i,i) - m_schur.matrixT().coeff(k,k);
0306       if(z==ComplexScalar(0))
0307       {
0308         // If the i-th and k-th eigenvalue are equal, then z equals 0.
0309         // Use a small value instead, to prevent division by zero.
0310         numext::real_ref(z) = NumTraits<RealScalar>::epsilon() * matrixnorm;
0311       }
0312       m_matX.coeffRef(i,k) = m_matX.coeff(i,k) / z;
0313     }
0314   }
0315 
0316   // Compute V as V = U X; now A = U T U^* = U X D X^(-1) U^* = V D V^(-1)
0317   m_eivec.noalias() = m_schur.matrixU() * m_matX;
0318   // .. and normalize the eigenvectors
0319   for(Index k=0 ; k<n ; k++)
0320   {
0321     m_eivec.col(k).normalize();
0322   }
0323 }
0324 
0325 
0326 template<typename MatrixType>
0327 void ComplexEigenSolver<MatrixType>::sortEigenvalues(bool computeEigenvectors)
0328 {
0329   const Index n =  m_eivalues.size();
0330   for (Index i=0; i<n; i++)
0331   {
0332     Index k;
0333     m_eivalues.cwiseAbs().tail(n-i).minCoeff(&k);
0334     if (k != 0)
0335     {
0336       k += i;
0337       std::swap(m_eivalues[k],m_eivalues[i]);
0338       if(computeEigenvectors)
0339     m_eivec.col(i).swap(m_eivec.col(k));
0340     }
0341   }
0342 }
0343 
0344 } // end namespace Eigen
0345 
0346 #endif // EIGEN_COMPLEX_EIGEN_SOLVER_H