1c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// This file is part of Eigen, a lightweight C++ template library
2c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// for linear algebra.
3c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath//
4c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
6c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath//
7c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// This Source Code Form is subject to the terms of the Mozilla
8c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Public License v. 2.0. If a copy of the MPL was not distributed
9c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
11c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "main.h"
12c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <limits>
13c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <Eigen/Eigenvalues>
14c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
15c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
16c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
17c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  typedef typename MatrixType::Index Index;
18c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  /* this test covers the following files:
19c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath     EigenSolver.h, SelfAdjointEigenSolver.h (and indirectly: Tridiagonalization.h)
20c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  */
21c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index rows = m.rows();
22c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index cols = m.cols();
23c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
24c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  typedef typename MatrixType::Scalar Scalar;
25c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  typedef typename NumTraits<Scalar>::Real RealScalar;
26c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
27c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  RealScalar largerEps = 10*test_precision<RealScalar>();
28c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
29c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  MatrixType a = MatrixType::Random(rows,cols);
30c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  MatrixType a1 = MatrixType::Random(rows,cols);
31c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  MatrixType symmA =  a.adjoint() * a + a1.adjoint() * a1;
32615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  MatrixType symmC = symmA;
33615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray
34615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  // randomly nullify some rows/columns
35615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  {
36615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray    Index count = 1;//internal::random<Index>(-cols,cols);
37615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray    for(Index k=0; k<count; ++k)
38615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray    {
39615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray      Index i = internal::random<Index>(0,cols-1);
40615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray      symmA.row(i).setZero();
41615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray      symmA.col(i).setZero();
42615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray    }
43615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  }
44615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray
45c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  symmA.template triangularView<StrictlyUpper>().setZero();
46615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  symmC.template triangularView<StrictlyUpper>().setZero();
47c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
48c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  MatrixType b = MatrixType::Random(rows,cols);
49c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  MatrixType b1 = MatrixType::Random(rows,cols);
50c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1;
51c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  symmB.template triangularView<StrictlyUpper>().setZero();
52c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
53c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  SelfAdjointEigenSolver<MatrixType> eiSymm(symmA);
54c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  SelfAdjointEigenSolver<MatrixType> eiDirect;
55c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  eiDirect.computeDirect(symmA);
56c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // generalized eigen pb
57615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  GeneralizedSelfAdjointEigenSolver<MatrixType> eiSymmGen(symmC, symmB);
58c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
59c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_EQUAL(eiSymm.info(), Success);
60c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY((symmA.template selfadjointView<Lower>() * eiSymm.eigenvectors()).isApprox(
61c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps));
62c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_APPROX(symmA.template selfadjointView<Lower>().eigenvalues(), eiSymm.eigenvalues());
63c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
64c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_EQUAL(eiDirect.info(), Success);
65c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY((symmA.template selfadjointView<Lower>() * eiDirect.eigenvectors()).isApprox(
66c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          eiDirect.eigenvectors() * eiDirect.eigenvalues().asDiagonal(), largerEps));
67c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_APPROX(symmA.template selfadjointView<Lower>().eigenvalues(), eiDirect.eigenvalues());
68c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
69c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  SelfAdjointEigenSolver<MatrixType> eiSymmNoEivecs(symmA, false);
70c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_EQUAL(eiSymmNoEivecs.info(), Success);
71c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmNoEivecs.eigenvalues());
72c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
73c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // generalized eigen problem Ax = lBx
74615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  eiSymmGen.compute(symmC, symmB,Ax_lBx);
75c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
76615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  VERIFY((symmC.template selfadjointView<Lower>() * eiSymmGen.eigenvectors()).isApprox(
77c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          symmB.template selfadjointView<Lower>() * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
78c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
79c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // generalized eigen problem BAx = lx
80615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  eiSymmGen.compute(symmC, symmB,BAx_lx);
81c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
82615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  VERIFY((symmB.template selfadjointView<Lower>() * (symmC.template selfadjointView<Lower>() * eiSymmGen.eigenvectors())).isApprox(
83c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath         (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
84c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
85c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // generalized eigen problem ABx = lx
86615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  eiSymmGen.compute(symmC, symmB,ABx_lx);
87c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
88615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  VERIFY((symmC.template selfadjointView<Lower>() * (symmB.template selfadjointView<Lower>() * eiSymmGen.eigenvectors())).isApprox(
89c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath         (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
90c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
91c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
92615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  eiSymm.compute(symmC);
93c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  MatrixType sqrtSymmA = eiSymm.operatorSqrt();
94615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView<Lower>()), sqrtSymmA*sqrtSymmA);
95615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  VERIFY_IS_APPROX(sqrtSymmA, symmC.template selfadjointView<Lower>()*eiSymm.operatorInverseSqrt());
96c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
97c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  MatrixType id = MatrixType::Identity(rows, cols);
98c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_IS_APPROX(id.template selfadjointView<Lower>().operatorNorm(), RealScalar(1));
99c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
100c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  SelfAdjointEigenSolver<MatrixType> eiSymmUninitialized;
101c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_RAISES_ASSERT(eiSymmUninitialized.info());
102c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvalues());
103c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors());
104c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt());
105c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt());
106c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
107c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  eiSymmUninitialized.compute(symmA, false);
108c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors());
109c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt());
110c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt());
111c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
112c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // test Tridiagonalization's methods
113615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  Tridiagonalization<MatrixType> tridiag(symmC);
114c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // FIXME tridiag.matrixQ().adjoint() does not work
115615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray  VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView<Lower>()), tridiag.matrixQ() * tridiag.matrixT().eval() * MatrixType(tridiag.matrixQ()).adjoint());
116c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
117c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  if (rows > 1)
118c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
119c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // Test matrix with NaN
120615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray    symmC(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
121615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray    SelfAdjointEigenSolver<MatrixType> eiSymmNaN(symmC);
122c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    VERIFY_IS_EQUAL(eiSymmNaN.info(), NoConvergence);
123c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
124c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
125c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
126c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid test_eigensolver_selfadjoint()
127c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
1287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  int s = 0;
129c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  for(int i = 0; i < g_repeat; i++) {
130c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // very important to test 3x3 and 2x2 matrices since we provide special paths for them
131615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray    CALL_SUBTEST_1( selfadjointeigensolver(Matrix2f()) );
132c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_1( selfadjointeigensolver(Matrix2d()) );
133c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) );
134615d816d068b4d0f5e8df601930b5f160bf7eda1Tim Murray    CALL_SUBTEST_1( selfadjointeigensolver(Matrix3d()) );
135c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) );
136c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
137c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(s,s)) );
138c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
139c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(s,s)) );
140c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
141c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_5( selfadjointeigensolver(MatrixXcd(s,s)) );
142c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
143c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
144c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_9( selfadjointeigensolver(Matrix<std::complex<double>,Dynamic,Dynamic,RowMajor>(s,s)) );
145c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
146c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // some trivial but implementation-wise tricky cases
147c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(1,1)) );
148c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(2,2)) );
149c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_6( selfadjointeigensolver(Matrix<double,1,1>()) );
150c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    CALL_SUBTEST_7( selfadjointeigensolver(Matrix<double,2,2>()) );
151c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
152c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
153c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // Test problem size constructors
154c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
1557faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  CALL_SUBTEST_8(SelfAdjointEigenSolver<MatrixXf> tmp1(s));
1567faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  CALL_SUBTEST_8(Tridiagonalization<MatrixXf> tmp2(s));
157c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
1587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  TEST_SET_BUT_UNUSED_VARIABLE(s)
159c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
160c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
161