| // This file is part of Eigen, a lightweight C++ template library | 
 | // for linear algebra. | 
 | // | 
 | // Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr> | 
 | // | 
 | // 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_NO_ASSERTION_CHECKING | 
 | #define EIGEN_NO_ASSERTION_CHECKING | 
 | #endif | 
 |  | 
 | static int nb_temporaries; | 
 |  | 
 | #define EIGEN_DEBUG_MATRIX_CTOR { if(size!=0) nb_temporaries++; } | 
 |  | 
 | #include "main.h" | 
 | #include <Eigen/Cholesky> | 
 | #include <Eigen/QR> | 
 |  | 
 | #define VERIFY_EVALUATION_COUNT(XPR,N) {\ | 
 |     nb_temporaries = 0; \ | 
 |     XPR; \ | 
 |     if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \ | 
 |     VERIFY( (#XPR) && nb_temporaries==N ); \ | 
 |   } | 
 |  | 
 | #ifdef HAS_GSL | 
 | #include "gsl_helper.h" | 
 | #endif | 
 |  | 
 | template<typename MatrixType> void cholesky(const MatrixType& m) | 
 | { | 
 |   typedef typename MatrixType::Index Index; | 
 |   /* this test covers the following files: | 
 |      LLT.h LDLT.h | 
 |   */ | 
 |   Index rows = m.rows(); | 
 |   Index cols = m.cols(); | 
 |  | 
 |   typedef typename MatrixType::Scalar Scalar; | 
 |   typedef typename NumTraits<Scalar>::Real RealScalar; | 
 |   typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType; | 
 |   typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType; | 
 |  | 
 |   MatrixType a0 = MatrixType::Random(rows,cols); | 
 |   VectorType vecB = VectorType::Random(rows), vecX(rows); | 
 |   MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols); | 
 |   SquareMatrixType symm =  a0 * a0.adjoint(); | 
 |   // let's make sure the matrix is not singular or near singular | 
 |   for (int k=0; k<3; ++k) | 
 |   { | 
 |     MatrixType a1 = MatrixType::Random(rows,cols); | 
 |     symm += a1 * a1.adjoint(); | 
 |   } | 
 |  | 
 |   SquareMatrixType symmUp = symm.template triangularView<Upper>(); | 
 |   SquareMatrixType symmLo = symm.template triangularView<Lower>(); | 
 |  | 
 |   // to test if really Cholesky only uses the upper triangular part, uncomment the following | 
 |   // FIXME: currently that fails !! | 
 |   //symm.template part<StrictlyLower>().setZero(); | 
 |  | 
 |   #ifdef HAS_GSL | 
 | //   if (ei_is_same_type<RealScalar,double>::ret) | 
 | //   { | 
 | //     typedef GslTraits<Scalar> Gsl; | 
 | //     typename Gsl::Matrix gMatA=0, gSymm=0; | 
 | //     typename Gsl::Vector gVecB=0, gVecX=0; | 
 | //     convert<MatrixType>(symm, gSymm); | 
 | //     convert<MatrixType>(symm, gMatA); | 
 | //     convert<VectorType>(vecB, gVecB); | 
 | //     convert<VectorType>(vecB, gVecX); | 
 | //     Gsl::cholesky(gMatA); | 
 | //     Gsl::cholesky_solve(gMatA, gVecB, gVecX); | 
 | //     VectorType vecX(rows), _vecX, _vecB; | 
 | //     convert(gVecX, _vecX); | 
 | //     symm.llt().solve(vecB, &vecX); | 
 | //     Gsl::prod(gSymm, gVecX, gVecB); | 
 | //     convert(gVecB, _vecB); | 
 | //     // test gsl itself ! | 
 | //     VERIFY_IS_APPROX(vecB, _vecB); | 
 | //     VERIFY_IS_APPROX(vecX, _vecX); | 
 | // | 
 | //     Gsl::free(gMatA); | 
 | //     Gsl::free(gSymm); | 
 | //     Gsl::free(gVecB); | 
 | //     Gsl::free(gVecX); | 
 | //   } | 
 |   #endif | 
 |  | 
 |   { | 
 |     LLT<SquareMatrixType,Lower> chollo(symmLo); | 
 |     VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix()); | 
 |     vecX = chollo.solve(vecB); | 
 |     VERIFY_IS_APPROX(symm * vecX, vecB); | 
 |     matX = chollo.solve(matB); | 
 |     VERIFY_IS_APPROX(symm * matX, matB); | 
 |  | 
 |     // test the upper mode | 
 |     LLT<SquareMatrixType,Upper> cholup(symmUp); | 
 |     VERIFY_IS_APPROX(symm, cholup.reconstructedMatrix()); | 
 |     vecX = cholup.solve(vecB); | 
 |     VERIFY_IS_APPROX(symm * vecX, vecB); | 
 |     matX = cholup.solve(matB); | 
 |     VERIFY_IS_APPROX(symm * matX, matB); | 
 |  | 
 |     MatrixType neg = -symmLo; | 
 |     chollo.compute(neg); | 
 |     VERIFY(chollo.info()==NumericalIssue); | 
 |   } | 
 |  | 
 |   // LDLT | 
 |   { | 
 |     int sign = ei_random<int>()%2 ? 1 : -1; | 
 |  | 
 |     if(sign == -1) | 
 |     { | 
 |       symm = -symm; // test a negative matrix | 
 |     } | 
 |  | 
 |     SquareMatrixType symmUp = symm.template triangularView<Upper>(); | 
 |     SquareMatrixType symmLo = symm.template triangularView<Lower>(); | 
 |  | 
 |     LDLT<SquareMatrixType,Lower> ldltlo(symmLo); | 
 |     VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix()); | 
 |     vecX = ldltlo.solve(vecB); | 
 |     VERIFY_IS_APPROX(symm * vecX, vecB); | 
 |     matX = ldltlo.solve(matB); | 
 |     VERIFY_IS_APPROX(symm * matX, matB); | 
 |  | 
 |     LDLT<SquareMatrixType,Upper> ldltup(symmUp); | 
 |     VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix()); | 
 |     vecX = ldltup.solve(vecB); | 
 |     VERIFY_IS_APPROX(symm * vecX, vecB); | 
 |     matX = ldltup.solve(matB); | 
 |     VERIFY_IS_APPROX(symm * matX, matB); | 
 |  | 
 |     if(MatrixType::RowsAtCompileTime==Dynamic) | 
 |     { | 
 |       // note : each inplace permutation requires a small temporary vector (mask) | 
 |  | 
 |       // check inplace solve | 
 |       matX = matB; | 
 |       VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0); | 
 |       VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval()); | 
 |  | 
 |  | 
 |       matX = matB; | 
 |       VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0); | 
 |       VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval()); | 
 |     } | 
 |   } | 
 |  | 
 | } | 
 |  | 
 | template<typename MatrixType> void cholesky_verify_assert() | 
 | { | 
 |   MatrixType tmp; | 
 |  | 
 |   LLT<MatrixType> llt; | 
 |   VERIFY_RAISES_ASSERT(llt.matrixL()) | 
 |   VERIFY_RAISES_ASSERT(llt.matrixU()) | 
 |   VERIFY_RAISES_ASSERT(llt.solve(tmp)) | 
 |   VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp)) | 
 |  | 
 |   LDLT<MatrixType> ldlt; | 
 |   VERIFY_RAISES_ASSERT(ldlt.matrixL()) | 
 |   VERIFY_RAISES_ASSERT(ldlt.permutationP()) | 
 |   VERIFY_RAISES_ASSERT(ldlt.vectorD()) | 
 |   VERIFY_RAISES_ASSERT(ldlt.isPositive()) | 
 |   VERIFY_RAISES_ASSERT(ldlt.isNegative()) | 
 |   VERIFY_RAISES_ASSERT(ldlt.solve(tmp)) | 
 |   VERIFY_RAISES_ASSERT(ldlt.solveInPlace(&tmp)) | 
 | } | 
 |  | 
 | void test_cholesky() | 
 | { | 
 |   for(int i = 0; i < g_repeat; i++) { | 
 |     CALL_SUBTEST_1( cholesky(Matrix<double,1,1>()) ); | 
 |     CALL_SUBTEST_2( cholesky(MatrixXd(1,1)) ); | 
 |     CALL_SUBTEST_3( cholesky(Matrix2d()) ); | 
 |     CALL_SUBTEST_4( cholesky(Matrix3f()) ); | 
 |     CALL_SUBTEST_5( cholesky(Matrix4d()) ); | 
 |     CALL_SUBTEST_2( cholesky(MatrixXd(200,200)) ); | 
 |     CALL_SUBTEST_6( cholesky(MatrixXcd(100,100)) ); | 
 |   } | 
 |  | 
 |   CALL_SUBTEST_4( cholesky_verify_assert<Matrix3f>() ); | 
 |   CALL_SUBTEST_7( cholesky_verify_assert<Matrix3d>() ); | 
 |   CALL_SUBTEST_8( cholesky_verify_assert<MatrixXf>() ); | 
 |   CALL_SUBTEST_2( cholesky_verify_assert<MatrixXd>() ); | 
 |  | 
 |   // Test problem size constructors | 
 |   CALL_SUBTEST_9( LLT<MatrixXf>(10) ); | 
 |   CALL_SUBTEST_9( LDLT<MatrixXf>(10) ); | 
 | } |