aboutsummaryrefslogtreecommitdiff
path: root/test/eigensolver_selfadjoint.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/eigensolver_selfadjoint.cpp')
-rw-r--r--test/eigensolver_selfadjoint.cpp180
1 files changed, 147 insertions, 33 deletions
diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp
index 38689cfbf..39ad4130e 100644
--- a/test/eigensolver_selfadjoint.cpp
+++ b/test/eigensolver_selfadjoint.cpp
@@ -9,8 +9,62 @@
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
+#include "svd_fill.h"
#include <limits>
#include <Eigen/Eigenvalues>
+#include <Eigen/SparseCore>
+
+
+template<typename MatrixType> void selfadjointeigensolver_essential_check(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ RealScalar eival_eps = numext::mini<RealScalar>(test_precision<RealScalar>(), NumTraits<Scalar>::dummy_precision()*20000);
+
+ SelfAdjointEigenSolver<MatrixType> eiSymm(m);
+ VERIFY_IS_EQUAL(eiSymm.info(), Success);
+
+ RealScalar scaling = m.cwiseAbs().maxCoeff();
+
+ if(scaling<(std::numeric_limits<RealScalar>::min)())
+ {
+ VERIFY(eiSymm.eigenvalues().cwiseAbs().maxCoeff() <= (std::numeric_limits<RealScalar>::min)());
+ }
+ else
+ {
+ VERIFY_IS_APPROX((m.template selfadjointView<Lower>() * eiSymm.eigenvectors())/scaling,
+ (eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal())/scaling);
+ }
+ VERIFY_IS_APPROX(m.template selfadjointView<Lower>().eigenvalues(), eiSymm.eigenvalues());
+ VERIFY_IS_UNITARY(eiSymm.eigenvectors());
+
+ if(m.cols()<=4)
+ {
+ SelfAdjointEigenSolver<MatrixType> eiDirect;
+ eiDirect.computeDirect(m);
+ VERIFY_IS_EQUAL(eiDirect.info(), Success);
+ if(! eiSymm.eigenvalues().isApprox(eiDirect.eigenvalues(), eival_eps) )
+ {
+ std::cerr << "reference eigenvalues: " << eiSymm.eigenvalues().transpose() << "\n"
+ << "obtained eigenvalues: " << eiDirect.eigenvalues().transpose() << "\n"
+ << "diff: " << (eiSymm.eigenvalues()-eiDirect.eigenvalues()).transpose() << "\n"
+ << "error (eps): " << (eiSymm.eigenvalues()-eiDirect.eigenvalues()).norm() / eiSymm.eigenvalues().norm() << " (" << eival_eps << ")\n";
+ }
+ if(scaling<(std::numeric_limits<RealScalar>::min)())
+ {
+ VERIFY(eiDirect.eigenvalues().cwiseAbs().maxCoeff() <= (std::numeric_limits<RealScalar>::min)());
+ }
+ else
+ {
+ VERIFY_IS_APPROX(eiSymm.eigenvalues()/scaling, eiDirect.eigenvalues()/scaling);
+ VERIFY_IS_APPROX((m.template selfadjointView<Lower>() * eiDirect.eigenvectors())/scaling,
+ (eiDirect.eigenvectors() * eiDirect.eigenvalues().asDiagonal())/scaling);
+ VERIFY_IS_APPROX(m.template selfadjointView<Lower>().eigenvalues()/scaling, eiDirect.eigenvalues()/scaling);
+ }
+
+ VERIFY_IS_UNITARY(eiDirect.eigenvectors());
+ }
+}
template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
{
@@ -31,17 +85,8 @@ template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
MatrixType symmC = symmA;
- // randomly nullify some rows/columns
- {
- Index count = 1;//internal::random<Index>(-cols,cols);
- for(Index k=0; k<count; ++k)
- {
- Index i = internal::random<Index>(0,cols-1);
- symmA.row(i).setZero();
- symmA.col(i).setZero();
- }
- }
-
+ svd_fill_random(symmA,Symmetric);
+
symmA.template triangularView<StrictlyUpper>().setZero();
symmC.template triangularView<StrictlyUpper>().setZero();
@@ -49,23 +94,13 @@ template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
MatrixType b1 = MatrixType::Random(rows,cols);
MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1;
symmB.template triangularView<StrictlyUpper>().setZero();
+
+ CALL_SUBTEST( selfadjointeigensolver_essential_check(symmA) );
SelfAdjointEigenSolver<MatrixType> eiSymm(symmA);
- SelfAdjointEigenSolver<MatrixType> eiDirect;
- eiDirect.computeDirect(symmA);
// generalized eigen pb
GeneralizedSelfAdjointEigenSolver<MatrixType> eiSymmGen(symmC, symmB);
- VERIFY_IS_EQUAL(eiSymm.info(), Success);
- VERIFY((symmA.template selfadjointView<Lower>() * eiSymm.eigenvectors()).isApprox(
- eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps));
- VERIFY_IS_APPROX(symmA.template selfadjointView<Lower>().eigenvalues(), eiSymm.eigenvalues());
-
- VERIFY_IS_EQUAL(eiDirect.info(), Success);
- VERIFY((symmA.template selfadjointView<Lower>() * eiDirect.eigenvectors()).isApprox(
- eiDirect.eigenvectors() * eiDirect.eigenvalues().asDiagonal(), largerEps));
- VERIFY_IS_APPROX(symmA.template selfadjointView<Lower>().eigenvalues(), eiDirect.eigenvalues());
-
SelfAdjointEigenSolver<MatrixType> eiSymmNoEivecs(symmA, false);
VERIFY_IS_EQUAL(eiSymmNoEivecs.info(), Success);
VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmNoEivecs.eigenvalues());
@@ -111,37 +146,111 @@ template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
// test Tridiagonalization's methods
Tridiagonalization<MatrixType> tridiag(symmC);
- // FIXME tridiag.matrixQ().adjoint() does not work
+ VERIFY_IS_APPROX(tridiag.diagonal(), tridiag.matrixT().diagonal());
+ VERIFY_IS_APPROX(tridiag.subDiagonal(), tridiag.matrixT().template diagonal<-1>());
+ Matrix<RealScalar,Dynamic,Dynamic> T = tridiag.matrixT();
+ if(rows>1 && cols>1) {
+ // FIXME check that upper and lower part are 0:
+ //VERIFY(T.topRightCorner(rows-2, cols-2).template triangularView<Upper>().isZero());
+ }
+ VERIFY_IS_APPROX(tridiag.diagonal(), T.diagonal());
+ VERIFY_IS_APPROX(tridiag.subDiagonal(), T.template diagonal<1>());
VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView<Lower>()), tridiag.matrixQ() * tridiag.matrixT().eval() * MatrixType(tridiag.matrixQ()).adjoint());
+ VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView<Lower>()), tridiag.matrixQ() * tridiag.matrixT() * tridiag.matrixQ().adjoint());
- if (rows > 1)
+ // Test computation of eigenvalues from tridiagonal matrix
+ if(rows > 1)
+ {
+ SelfAdjointEigenSolver<MatrixType> eiSymmTridiag;
+ eiSymmTridiag.computeFromTridiagonal(tridiag.matrixT().diagonal(), tridiag.matrixT().diagonal(-1), ComputeEigenvectors);
+ VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmTridiag.eigenvalues());
+ VERIFY_IS_APPROX(tridiag.matrixT(), eiSymmTridiag.eigenvectors().real() * eiSymmTridiag.eigenvalues().asDiagonal() * eiSymmTridiag.eigenvectors().real().transpose());
+ }
+
+ if (rows > 1 && rows < 20)
{
// Test matrix with NaN
symmC(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
SelfAdjointEigenSolver<MatrixType> eiSymmNaN(symmC);
VERIFY_IS_EQUAL(eiSymmNaN.info(), NoConvergence);
}
+
+ // regression test for bug 1098
+ {
+ SelfAdjointEigenSolver<MatrixType> eig(a.adjoint() * a);
+ eig.compute(a.adjoint() * a);
+ }
+
+ // regression test for bug 478
+ {
+ a.setZero();
+ SelfAdjointEigenSolver<MatrixType> ei3(a);
+ VERIFY_IS_EQUAL(ei3.info(), Success);
+ VERIFY_IS_MUCH_SMALLER_THAN(ei3.eigenvalues().norm(),RealScalar(1));
+ VERIFY((ei3.eigenvectors().transpose()*ei3.eigenvectors().transpose()).eval().isIdentity());
+ }
+}
+
+template<int>
+void bug_854()
+{
+ Matrix3d m;
+ m << 850.961, 51.966, 0,
+ 51.966, 254.841, 0,
+ 0, 0, 0;
+ selfadjointeigensolver_essential_check(m);
+}
+
+template<int>
+void bug_1014()
+{
+ Matrix3d m;
+ m << 0.11111111111111114658, 0, 0,
+ 0, 0.11111111111111109107, 0,
+ 0, 0, 0.11111111111111107719;
+ selfadjointeigensolver_essential_check(m);
+}
+
+template<int>
+void bug_1225()
+{
+ Matrix3d m1, m2;
+ m1.setRandom();
+ m1 = m1*m1.transpose();
+ m2 = m1.triangularView<Upper>();
+ SelfAdjointEigenSolver<Matrix3d> eig1(m1);
+ SelfAdjointEigenSolver<Matrix3d> eig2(m2.selfadjointView<Upper>());
+ VERIFY_IS_APPROX(eig1.eigenvalues(), eig2.eigenvalues());
+}
+
+template<int>
+void bug_1204()
+{
+ SparseMatrix<double> A(2,2);
+ A.setIdentity();
+ SelfAdjointEigenSolver<Eigen::SparseMatrix<double> > eig(A);
}
void test_eigensolver_selfadjoint()
{
int s = 0;
for(int i = 0; i < g_repeat; i++) {
+ // trivial test for 1x1 matrices:
+ CALL_SUBTEST_1( selfadjointeigensolver(Matrix<float, 1, 1>()));
+ CALL_SUBTEST_1( selfadjointeigensolver(Matrix<double, 1, 1>()));
// very important to test 3x3 and 2x2 matrices since we provide special paths for them
- CALL_SUBTEST_1( selfadjointeigensolver(Matrix2f()) );
- CALL_SUBTEST_1( selfadjointeigensolver(Matrix2d()) );
- CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) );
- CALL_SUBTEST_1( selfadjointeigensolver(Matrix3d()) );
+ CALL_SUBTEST_12( selfadjointeigensolver(Matrix2f()) );
+ CALL_SUBTEST_12( selfadjointeigensolver(Matrix2d()) );
+ CALL_SUBTEST_13( selfadjointeigensolver(Matrix3f()) );
+ CALL_SUBTEST_13( selfadjointeigensolver(Matrix3d()) );
CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) );
+
s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(s,s)) );
- s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(s,s)) );
- s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
CALL_SUBTEST_5( selfadjointeigensolver(MatrixXcd(s,s)) );
-
- s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
CALL_SUBTEST_9( selfadjointeigensolver(Matrix<std::complex<double>,Dynamic,Dynamic,RowMajor>(s,s)) );
+ TEST_SET_BUT_UNUSED_VARIABLE(s)
// some trivial but implementation-wise tricky cases
CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(1,1)) );
@@ -149,6 +258,11 @@ void test_eigensolver_selfadjoint()
CALL_SUBTEST_6( selfadjointeigensolver(Matrix<double,1,1>()) );
CALL_SUBTEST_7( selfadjointeigensolver(Matrix<double,2,2>()) );
}
+
+ CALL_SUBTEST_13( bug_854<0>() );
+ CALL_SUBTEST_13( bug_1014<0>() );
+ CALL_SUBTEST_13( bug_1204<0>() );
+ CALL_SUBTEST_13( bug_1225<0>() );
// Test problem size constructors
s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);