1 // This file is part of Eigen, a lightweight C++ template library
4 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #ifndef EIGEN_NO_ASSERTION_CHECKING
11 #define EIGEN_NO_ASSERTION_CHECKING
14 static int nb_temporaries
;
16 #define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { if(size!=0) nb_temporaries++; }
19 #include <Eigen/Cholesky>
22 #define VERIFY_EVALUATION_COUNT(XPR,N) {\
25 if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \
26 VERIFY( (#XPR) && nb_temporaries==N ); \
29 template<typename MatrixType
,template <typename
,int> class CholType
> void test_chol_update(const MatrixType
& symm
)
31 typedef typename
MatrixType::Scalar Scalar
;
32 typedef typename
MatrixType::RealScalar RealScalar
;
33 typedef Matrix
<Scalar
, MatrixType::RowsAtCompileTime
, 1> VectorType
;
35 MatrixType symmLo
= symm
.template triangularView
<Lower
>();
36 MatrixType symmUp
= symm
.template triangularView
<Upper
>();
37 MatrixType symmCpy
= symm
;
39 CholType
<MatrixType
,Lower
> chollo(symmLo
);
40 CholType
<MatrixType
,Upper
> cholup(symmUp
);
42 for (int k
=0; k
<10; ++k
)
44 VectorType vec
= VectorType::Random(symm
.rows());
45 RealScalar sigma
= internal::random
<RealScalar
>();
46 symmCpy
+= sigma
* vec
* vec
.adjoint();
48 // we are doing some downdates, so it might be the case that the matrix is not SPD anymore
49 CholType
<MatrixType
,Lower
> chol(symmCpy
);
50 if(chol
.info()!=Success
)
53 chollo
.rankUpdate(vec
, sigma
);
54 VERIFY_IS_APPROX(symmCpy
, chollo
.reconstructedMatrix());
56 cholup
.rankUpdate(vec
, sigma
);
57 VERIFY_IS_APPROX(symmCpy
, cholup
.reconstructedMatrix());
61 template<typename MatrixType
> void cholesky(const MatrixType
& m
)
63 typedef typename
MatrixType::Index Index
;
64 /* this test covers the following files:
67 Index rows
= m
.rows();
68 Index cols
= m
.cols();
70 typedef typename
MatrixType::Scalar Scalar
;
71 typedef typename NumTraits
<Scalar
>::Real RealScalar
;
72 typedef Matrix
<Scalar
, MatrixType::RowsAtCompileTime
, MatrixType::RowsAtCompileTime
> SquareMatrixType
;
73 typedef Matrix
<Scalar
, MatrixType::RowsAtCompileTime
, 1> VectorType
;
75 MatrixType a0
= MatrixType::Random(rows
,cols
);
76 VectorType vecB
= VectorType::Random(rows
), vecX(rows
);
77 MatrixType matB
= MatrixType::Random(rows
,cols
), matX(rows
,cols
);
78 SquareMatrixType symm
= a0
* a0
.adjoint();
79 // let's make sure the matrix is not singular or near singular
80 for (int k
=0; k
<3; ++k
)
82 MatrixType a1
= MatrixType::Random(rows
,cols
);
83 symm
+= a1
* a1
.adjoint();
86 // to test if really Cholesky only uses the upper triangular part, uncomment the following
87 // FIXME: currently that fails !!
88 //symm.template part<StrictlyLower>().setZero();
91 SquareMatrixType symmUp
= symm
.template triangularView
<Upper
>();
92 SquareMatrixType symmLo
= symm
.template triangularView
<Lower
>();
94 LLT
<SquareMatrixType
,Lower
> chollo(symmLo
);
95 VERIFY_IS_APPROX(symm
, chollo
.reconstructedMatrix());
96 vecX
= chollo
.solve(vecB
);
97 VERIFY_IS_APPROX(symm
* vecX
, vecB
);
98 matX
= chollo
.solve(matB
);
99 VERIFY_IS_APPROX(symm
* matX
, matB
);
101 // test the upper mode
102 LLT
<SquareMatrixType
,Upper
> cholup(symmUp
);
103 VERIFY_IS_APPROX(symm
, cholup
.reconstructedMatrix());
104 vecX
= cholup
.solve(vecB
);
105 VERIFY_IS_APPROX(symm
* vecX
, vecB
);
106 matX
= cholup
.solve(matB
);
107 VERIFY_IS_APPROX(symm
* matX
, matB
);
109 MatrixType neg
= -symmLo
;
111 VERIFY(chollo
.info()==NumericalIssue
);
113 VERIFY_IS_APPROX(MatrixType(chollo
.matrixL().transpose().conjugate()), MatrixType(chollo
.matrixU()));
114 VERIFY_IS_APPROX(MatrixType(chollo
.matrixU().transpose().conjugate()), MatrixType(chollo
.matrixL()));
115 VERIFY_IS_APPROX(MatrixType(cholup
.matrixL().transpose().conjugate()), MatrixType(cholup
.matrixU()));
116 VERIFY_IS_APPROX(MatrixType(cholup
.matrixU().transpose().conjugate()), MatrixType(cholup
.matrixL()));
118 // test some special use cases of SelfCwiseBinaryOp:
119 MatrixType m1
= MatrixType::Random(rows
,cols
), m2(rows
,cols
);
121 m2
+= symmLo
.template selfadjointView
<Lower
>().llt().solve(matB
);
122 VERIFY_IS_APPROX(m2
, m1
+ symmLo
.template selfadjointView
<Lower
>().llt().solve(matB
));
124 m2
-= symmLo
.template selfadjointView
<Lower
>().llt().solve(matB
);
125 VERIFY_IS_APPROX(m2
, m1
- symmLo
.template selfadjointView
<Lower
>().llt().solve(matB
));
127 m2
.noalias() += symmLo
.template selfadjointView
<Lower
>().llt().solve(matB
);
128 VERIFY_IS_APPROX(m2
, m1
+ symmLo
.template selfadjointView
<Lower
>().llt().solve(matB
));
130 m2
.noalias() -= symmLo
.template selfadjointView
<Lower
>().llt().solve(matB
);
131 VERIFY_IS_APPROX(m2
, m1
- symmLo
.template selfadjointView
<Lower
>().llt().solve(matB
));
136 int sign
= internal::random
<int>()%2 ? 1 : -1;
140 symm
= -symm
; // test a negative matrix
143 SquareMatrixType symmUp
= symm
.template triangularView
<Upper
>();
144 SquareMatrixType symmLo
= symm
.template triangularView
<Lower
>();
146 LDLT
<SquareMatrixType
,Lower
> ldltlo(symmLo
);
147 VERIFY_IS_APPROX(symm
, ldltlo
.reconstructedMatrix());
148 vecX
= ldltlo
.solve(vecB
);
149 VERIFY_IS_APPROX(symm
* vecX
, vecB
);
150 matX
= ldltlo
.solve(matB
);
151 VERIFY_IS_APPROX(symm
* matX
, matB
);
153 LDLT
<SquareMatrixType
,Upper
> ldltup(symmUp
);
154 VERIFY_IS_APPROX(symm
, ldltup
.reconstructedMatrix());
155 vecX
= ldltup
.solve(vecB
);
156 VERIFY_IS_APPROX(symm
* vecX
, vecB
);
157 matX
= ldltup
.solve(matB
);
158 VERIFY_IS_APPROX(symm
* matX
, matB
);
160 VERIFY_IS_APPROX(MatrixType(ldltlo
.matrixL().transpose().conjugate()), MatrixType(ldltlo
.matrixU()));
161 VERIFY_IS_APPROX(MatrixType(ldltlo
.matrixU().transpose().conjugate()), MatrixType(ldltlo
.matrixL()));
162 VERIFY_IS_APPROX(MatrixType(ldltup
.matrixL().transpose().conjugate()), MatrixType(ldltup
.matrixU()));
163 VERIFY_IS_APPROX(MatrixType(ldltup
.matrixU().transpose().conjugate()), MatrixType(ldltup
.matrixL()));
165 if(MatrixType::RowsAtCompileTime
==Dynamic
)
167 // note : each inplace permutation requires a small temporary vector (mask)
169 // check inplace solve
171 VERIFY_EVALUATION_COUNT(matX
= ldltlo
.solve(matX
), 0);
172 VERIFY_IS_APPROX(matX
, ldltlo
.solve(matB
).eval());
176 VERIFY_EVALUATION_COUNT(matX
= ldltup
.solve(matX
), 0);
177 VERIFY_IS_APPROX(matX
, ldltup
.solve(matB
).eval());
184 // check matrices coming from linear constraints with Lagrange multipliers
187 SquareMatrixType A
= symm
;
188 int c
= internal::random
<int>(0,rows
-2);
189 A
.bottomRightCorner(c
,c
).setZero();
190 // Make sure a solution exists:
195 VERIFY_IS_APPROX(A
, ldltlo
.reconstructedMatrix());
196 vecX
= ldltlo
.solve(vecB
);
197 VERIFY_IS_APPROX(A
* vecX
, vecB
);
200 // check non-full rank matrices
203 int r
= internal::random
<int>(1,rows
-1);
204 Matrix
<Scalar
,Dynamic
,Dynamic
> a
= Matrix
<Scalar
,Dynamic
,Dynamic
>::Random(rows
,r
);
205 SquareMatrixType A
= a
* a
.adjoint();
206 // Make sure a solution exists:
211 VERIFY_IS_APPROX(A
, ldltlo
.reconstructedMatrix());
212 vecX
= ldltlo
.solve(vecB
);
213 VERIFY_IS_APPROX(A
* vecX
, vecB
);
216 // check matrices with a wide spectrum
219 RealScalar s
= (std::min
)(16,std::numeric_limits
<RealScalar
>::max_exponent10
/8);
220 Matrix
<Scalar
,Dynamic
,Dynamic
> a
= Matrix
<Scalar
,Dynamic
,Dynamic
>::Random(rows
,rows
);
221 Matrix
<RealScalar
,Dynamic
,1> d
= Matrix
<RealScalar
,Dynamic
,1>::Random(rows
);
222 for(int k
=0; k
<rows
; ++k
)
223 d(k
) = d(k
)*std::pow(RealScalar(10),internal::random
<RealScalar
>(-s
,s
));
224 SquareMatrixType A
= a
* d
.asDiagonal() * a
.adjoint();
225 // Make sure a solution exists:
230 VERIFY_IS_APPROX(A
, ldltlo
.reconstructedMatrix());
231 vecX
= ldltlo
.solve(vecB
);
232 VERIFY_IS_APPROX(A
* vecX
, vecB
);
237 CALL_SUBTEST(( test_chol_update
<SquareMatrixType
,LLT
>(symm
) ));
238 CALL_SUBTEST(( test_chol_update
<SquareMatrixType
,LDLT
>(symm
) ));
241 template<typename MatrixType
> void cholesky_cplx(const MatrixType
& m
)
246 // test mixing real/scalar types
248 typedef typename
MatrixType::Index Index
;
250 Index rows
= m
.rows();
251 Index cols
= m
.cols();
253 typedef typename
MatrixType::Scalar Scalar
;
254 typedef typename NumTraits
<Scalar
>::Real RealScalar
;
255 typedef Matrix
<RealScalar
, MatrixType::RowsAtCompileTime
, MatrixType::RowsAtCompileTime
> RealMatrixType
;
256 typedef Matrix
<Scalar
, MatrixType::RowsAtCompileTime
, 1> VectorType
;
258 RealMatrixType a0
= RealMatrixType::Random(rows
,cols
);
259 VectorType vecB
= VectorType::Random(rows
), vecX(rows
);
260 MatrixType matB
= MatrixType::Random(rows
,cols
), matX(rows
,cols
);
261 RealMatrixType symm
= a0
* a0
.adjoint();
262 // let's make sure the matrix is not singular or near singular
263 for (int k
=0; k
<3; ++k
)
265 RealMatrixType a1
= RealMatrixType::Random(rows
,cols
);
266 symm
+= a1
* a1
.adjoint();
270 RealMatrixType symmLo
= symm
.template triangularView
<Lower
>();
272 LLT
<RealMatrixType
,Lower
> chollo(symmLo
);
273 VERIFY_IS_APPROX(symm
, chollo
.reconstructedMatrix());
274 vecX
= chollo
.solve(vecB
);
275 VERIFY_IS_APPROX(symm
* vecX
, vecB
);
276 // matX = chollo.solve(matB);
277 // VERIFY_IS_APPROX(symm * matX, matB);
282 int sign
= internal::random
<int>()%2 ? 1 : -1;
286 symm
= -symm
; // test a negative matrix
289 RealMatrixType symmLo
= symm
.template triangularView
<Lower
>();
291 LDLT
<RealMatrixType
,Lower
> ldltlo(symmLo
);
292 VERIFY_IS_APPROX(symm
, ldltlo
.reconstructedMatrix());
293 vecX
= ldltlo
.solve(vecB
);
294 VERIFY_IS_APPROX(symm
* vecX
, vecB
);
295 // matX = ldltlo.solve(matB);
296 // VERIFY_IS_APPROX(symm * matX, matB);
300 // regression test for bug 241
301 template<typename MatrixType
> void cholesky_bug241(const MatrixType
& m
)
303 eigen_assert(m
.rows() == 2 && m
.cols() == 2);
305 typedef typename
MatrixType::Scalar Scalar
;
306 typedef Matrix
<Scalar
, MatrixType::RowsAtCompileTime
, 1> VectorType
;
312 VectorType vecX
= matA
.ldlt().solve(vecB
);
313 VERIFY_IS_APPROX(matA
* vecX
, vecB
);
316 // LDLT is not guaranteed to work for indefinite matrices, but happens to work fine if matrix is diagonal.
317 // This test checks that LDLT reports correctly that matrix is indefinite.
318 // See http://forum.kde.org/viewtopic.php?f=74&t=106942 and bug 736
319 template<typename MatrixType
> void cholesky_definiteness(const MatrixType
& m
)
321 eigen_assert(m
.rows() == 2 && m
.cols() == 2);
323 LDLT
<MatrixType
> ldlt(2);
328 VERIFY(!ldlt
.isNegative());
329 VERIFY(!ldlt
.isPositive());
334 VERIFY(!ldlt
.isNegative());
335 VERIFY(!ldlt
.isPositive());
340 VERIFY(ldlt
.isNegative());
341 VERIFY(ldlt
.isPositive());
346 VERIFY(!ldlt
.isNegative());
347 VERIFY(ldlt
.isPositive());
352 VERIFY(ldlt
.isNegative());
353 VERIFY(!ldlt
.isPositive());
357 template<typename MatrixType
> void cholesky_verify_assert()
362 VERIFY_RAISES_ASSERT(llt
.matrixL())
363 VERIFY_RAISES_ASSERT(llt
.matrixU())
364 VERIFY_RAISES_ASSERT(llt
.solve(tmp
))
365 VERIFY_RAISES_ASSERT(llt
.solveInPlace(&tmp
))
367 LDLT
<MatrixType
> ldlt
;
368 VERIFY_RAISES_ASSERT(ldlt
.matrixL())
369 VERIFY_RAISES_ASSERT(ldlt
.permutationP())
370 VERIFY_RAISES_ASSERT(ldlt
.vectorD())
371 VERIFY_RAISES_ASSERT(ldlt
.isPositive())
372 VERIFY_RAISES_ASSERT(ldlt
.isNegative())
373 VERIFY_RAISES_ASSERT(ldlt
.solve(tmp
))
374 VERIFY_RAISES_ASSERT(ldlt
.solveInPlace(&tmp
))
380 for(int i
= 0; i
< g_repeat
; i
++) {
381 CALL_SUBTEST_1( cholesky(Matrix
<double,1,1>()) );
382 CALL_SUBTEST_3( cholesky(Matrix2d()) );
383 CALL_SUBTEST_3( cholesky_bug241(Matrix2d()) );
384 CALL_SUBTEST_3( cholesky_definiteness(Matrix2d()) );
385 CALL_SUBTEST_4( cholesky(Matrix3f()) );
386 CALL_SUBTEST_5( cholesky(Matrix4d()) );
387 s
= internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
);
388 CALL_SUBTEST_2( cholesky(MatrixXd(s
,s
)) );
389 s
= internal::random
<int>(1,EIGEN_TEST_MAX_SIZE
/2);
390 CALL_SUBTEST_6( cholesky_cplx(MatrixXcd(s
,s
)) );
393 CALL_SUBTEST_4( cholesky_verify_assert
<Matrix3f
>() );
394 CALL_SUBTEST_7( cholesky_verify_assert
<Matrix3d
>() );
395 CALL_SUBTEST_8( cholesky_verify_assert
<MatrixXf
>() );
396 CALL_SUBTEST_2( cholesky_verify_assert
<MatrixXd
>() );
398 // Test problem size constructors
399 CALL_SUBTEST_9( LLT
<MatrixXf
>(10) );
400 CALL_SUBTEST_9( LDLT
<MatrixXf
>(10) );
402 TEST_SET_BUT_UNUSED_VARIABLE(s
)
403 TEST_SET_BUT_UNUSED_VARIABLE(nb_temporaries
)