diff --git a/Eigen/src/QR/EigenSolver.h b/Eigen/src/QR/EigenSolver.h index 44917d139..1b392cbb9 100644 --- a/Eigen/src/QR/EigenSolver.h +++ b/Eigen/src/QR/EigenSolver.h @@ -58,9 +58,50 @@ template class EigenSolver compute(matrix); } - MatrixType eigenvectors(void) const { return m_eivec; } + // TODO compute the complex eigen vectors + // MatrixType eigenvectors(void) const { return m_eivec; } - EigenvalueType eigenvalues(void) const { return m_eivalues; } + /** \returns a real matrix V of pseudo eigenvectors. + * + * Let D be the block diagonal matrix with the real eigenvalues in 1x1 blocks, + * and any complex values u+iv in 2x2 blocks [u v ; -v u]. Then, the matrices D + * and V satisfy A*V = V*D. + * + * More precisely, if the diagonal matrix of the eigen values is:\n + * \f$ + * \left[ \begin{array}{cccccc} + * u+iv & & & & & \\ + * & u-iv & & & & \\ + * & & a+ib & & & \\ + * & & & a-ib & & \\ + * & & & & x & \\ + * & & & & & y \\ + * \end{array} \right] + * \f$ \n + * then, we have:\n + * \f$ + * D =\left[ \begin{array}{cccccc} + * u & v & & & & \\ + * -v & u & & & & \\ + * & & a & b & & \\ + * & & -b & a & & \\ + * & & & & x & \\ + * & & & & & y \\ + * \end{array} \right] + * \f$ + * + * \sa pseudoEigenvalueMatrix() + */ + const MatrixType& pseudoEigenvectors() const { return m_eivec; } + + /** \returns the real block diagonal matrix D of the eigenvalues. + * + * See pseudoEigenvectors() for the details. + */ + MatrixType pseudoEigenvalueMatrix() const; + + /** \returns the eigenvalues as a column vector */ + EigenvalueType eigenvalues() const { return m_eivalues; } void compute(const MatrixType& matrix); @@ -74,6 +115,25 @@ template class EigenSolver EigenvalueType m_eivalues; }; +template +MatrixType EigenSolver::pseudoEigenvalueMatrix() const +{ + int n = m_eivec.cols(); + MatrixType matD = MatrixType::Zero(n,n); + for (int i=0; i(i,i) << ei_real(m_eivalues.coeff(i)), ei_imag(m_eivalues.coeff(i)), + -ei_imag(m_eivalues.coeff(i)), ei_real(m_eivalues.coeff(i)); + i++; + } + } + return matD; +} + template void EigenSolver::compute(const MatrixType& matrix) { diff --git a/test/eigensolver.cpp b/test/eigensolver.cpp index beccdc321..9ede071f0 100644 --- a/test/eigensolver.cpp +++ b/test/eigensolver.cpp @@ -29,7 +29,7 @@ #include "gsl_helper.h" #endif -template void eigensolver(const MatrixType& m) +template void selfadjointeigensolver(const MatrixType& m) { /* this test covers the following files: EigenSolver.h, SelfAdjointEigenSolver.h (and indirectly: Tridiagonalization.h) @@ -69,11 +69,11 @@ template void eigensolver(const MatrixType& m) convert(symmB, gSymmB); convert(symmA, gEvec); gEval = GslTraits::createVector(rows); - + Gsl::eigen_symm(gSymmA, gEval, gEvec); convert(gEval, _eval); convert(gEvec, _evec); - + // test gsl itself ! VERIFY((symmA * _evec).isApprox(_evec * _eval.asDiagonal().eval(), largerEps)); @@ -108,13 +108,40 @@ template void eigensolver(const MatrixType& m) VERIFY((symmA * eiSymmGen.eigenvectors()).isApprox( symmB * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal().eval()), largerEps)); -// EigenSolver eiNotSymmButSymm(covMat); -// VERIFY_IS_APPROX((covMat.template cast()) * (eiNotSymmButSymm.eigenvectors().template cast()), -// (eiNotSymmButSymm.eigenvectors().template cast()) * (eiNotSymmButSymm.eigenvalues().asDiagonal())); +} -// EigenSolver eiNotSymm(a); -// VERIFY_IS_APPROX(a.template cast() * eiNotSymm.eigenvectors().template cast(), -// eiNotSymm.eigenvectors().template cast() * eiNotSymm.eigenvalues().asDiagonal()); +template void eigensolver(const MatrixType& m) +{ + /* this test covers the following files: + EigenSolver.h + */ + int rows = m.rows(); + int cols = m.cols(); + + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef Matrix VectorType; + typedef Matrix RealVectorType; + typedef typename std::complex::Real> Complex; + + RealScalar largerEps = 10*test_precision(); + + MatrixType a = MatrixType::Random(rows,cols); + MatrixType a1 = MatrixType::Random(rows,cols); + MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1; + +// MatrixType b = MatrixType::Random(rows,cols); +// MatrixType b1 = MatrixType::Random(rows,cols); +// MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1; + + EigenSolver ei0(symmA); + VERIFY_IS_APPROX((symmA.template cast()) * (ei0.pseudoEigenvectors().template cast()), + (ei0.pseudoEigenvectors().template cast()) * (ei0.eigenvalues().asDiagonal())); + + a = a + symmA; + EigenSolver ei1(a); + + VERIFY_IS_APPROX(a * ei1.pseudoEigenvectors(), ei1.pseudoEigenvectors() * ei1.pseudoEigenvalueMatrix()); } @@ -122,10 +149,12 @@ void test_eigensolver() { for(int i = 0; i < g_repeat; i++) { // very important to test a 3x3 matrix since we provide a special path for it - CALL_SUBTEST( eigensolver(Matrix3f()) ); + CALL_SUBTEST( selfadjointeigensolver(Matrix3f()) ); + CALL_SUBTEST( selfadjointeigensolver(Matrix4d()) ); + CALL_SUBTEST( selfadjointeigensolver(MatrixXf(7,7)) ); + CALL_SUBTEST( selfadjointeigensolver(MatrixXcd(5,5)) ); + CALL_SUBTEST( selfadjointeigensolver(MatrixXd(19,19)) ); + CALL_SUBTEST( eigensolver(Matrix4d()) ); - CALL_SUBTEST( eigensolver(MatrixXf(7,7)) ); - CALL_SUBTEST( eigensolver(MatrixXcd(5,5)) ); - CALL_SUBTEST( eigensolver(MatrixXd(19,19)) ); } }