1 // This file is part of Eigen, a lightweight C++ template library
4 // Copyright (C) 2008-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
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/.
14 template<typename MatrixType
>
15 typename
MatrixType::RealScalar
matrix_l1_norm(const MatrixType
& m
) {
16 return m
.cwiseAbs().colwise().sum().maxCoeff();
19 template<typename MatrixType
> void lu_non_invertible()
21 typedef typename
MatrixType::Index Index
;
22 typedef typename
MatrixType::RealScalar RealScalar
;
23 /* this test covers the following files:
26 Index rows
, cols
, cols2
;
27 if(MatrixType::RowsAtCompileTime
==Dynamic
)
29 rows
= internal::random
<Index
>(2,EIGEN_TEST_MAX_SIZE
);
33 rows
= MatrixType::RowsAtCompileTime
;
35 if(MatrixType::ColsAtCompileTime
==Dynamic
)
37 cols
= internal::random
<Index
>(2,EIGEN_TEST_MAX_SIZE
);
38 cols2
= internal::random
<int>(2,EIGEN_TEST_MAX_SIZE
);
42 cols2
= cols
= MatrixType::ColsAtCompileTime
;
46 RowsAtCompileTime
= MatrixType::RowsAtCompileTime
,
47 ColsAtCompileTime
= MatrixType::ColsAtCompileTime
49 typedef typename
internal::kernel_retval_base
<FullPivLU
<MatrixType
> >::ReturnType KernelMatrixType
;
50 typedef typename
internal::image_retval_base
<FullPivLU
<MatrixType
> >::ReturnType ImageMatrixType
;
51 typedef Matrix
<typename
MatrixType::Scalar
, ColsAtCompileTime
, ColsAtCompileTime
>
53 typedef Matrix
<typename
MatrixType::Scalar
, RowsAtCompileTime
, RowsAtCompileTime
>
56 Index rank
= internal::random
<Index
>(1, (std::min
)(rows
, cols
)-1);
58 // The image of the zero matrix should consist of a single (zero) column vector
59 VERIFY((MatrixType::Zero(rows
,cols
).fullPivLu().image(MatrixType::Zero(rows
,cols
)).cols() == 1));
61 MatrixType
m1(rows
, cols
), m3(rows
, cols2
);
62 CMatrixType
m2(cols
, cols2
);
63 createRandomPIMatrixOfRank(rank
, rows
, cols
, m1
);
65 FullPivLU
<MatrixType
> lu
;
67 // The special value 0.01 below works well in tests. Keep in mind that we're only computing the rank
68 // of singular values are either 0 or 1.
69 // So it's not clear at all that the epsilon should play any role there.
70 lu
.setThreshold(RealScalar(0.01));
73 MatrixType
u(rows
,cols
);
74 u
= lu
.matrixLU().template triangularView
<Upper
>();
75 RMatrixType l
= RMatrixType::Identity(rows
,rows
);
76 l
.block(0,0,rows
,(std::min
)(rows
,cols
)).template triangularView
<StrictlyLower
>()
77 = lu
.matrixLU().block(0,0,rows
,(std::min
)(rows
,cols
));
79 VERIFY_IS_APPROX(lu
.permutationP() * m1
* lu
.permutationQ(), l
*u
);
81 KernelMatrixType m1kernel
= lu
.kernel();
82 ImageMatrixType m1image
= lu
.image(m1
);
84 VERIFY_IS_APPROX(m1
, lu
.reconstructedMatrix());
85 VERIFY(rank
== lu
.rank());
86 VERIFY(cols
- lu
.rank() == lu
.dimensionOfKernel());
87 VERIFY(!lu
.isInjective());
88 VERIFY(!lu
.isInvertible());
89 VERIFY(!lu
.isSurjective());
90 VERIFY((m1
* m1kernel
).isMuchSmallerThan(m1
));
91 VERIFY(m1image
.fullPivLu().rank() == rank
);
92 VERIFY_IS_APPROX(m1
* m1
.adjoint() * m1image
, m1image
);
94 m2
= CMatrixType::Random(cols
,cols2
);
96 m2
= CMatrixType::Random(cols
,cols2
);
97 // test that the code, which does resize(), may be applied to an xpr
98 m2
.block(0,0,m2
.rows(),m2
.cols()) = lu
.solve(m3
);
99 VERIFY_IS_APPROX(m3
, m1
*m2
);
101 // test solve with transposed
102 m3
= MatrixType::Random(rows
,cols2
);
103 m2
= m1
.transpose()*m3
;
104 m3
= MatrixType::Random(rows
,cols2
);
105 lu
.template _solve_impl_transposed
<false>(m2
, m3
);
106 VERIFY_IS_APPROX(m2
, m1
.transpose()*m3
);
107 m3
= MatrixType::Random(rows
,cols2
);
108 m3
= lu
.transpose().solve(m2
);
109 VERIFY_IS_APPROX(m2
, m1
.transpose()*m3
);
111 // test solve with conjugate transposed
112 m3
= MatrixType::Random(rows
,cols2
);
113 m2
= m1
.adjoint()*m3
;
114 m3
= MatrixType::Random(rows
,cols2
);
115 lu
.template _solve_impl_transposed
<true>(m2
, m3
);
116 VERIFY_IS_APPROX(m2
, m1
.adjoint()*m3
);
117 m3
= MatrixType::Random(rows
,cols2
);
118 m3
= lu
.adjoint().solve(m2
);
119 VERIFY_IS_APPROX(m2
, m1
.adjoint()*m3
);
122 template<typename MatrixType
> void lu_invertible()
124 /* this test covers the following files:
127 typedef typename NumTraits
<typename
MatrixType::Scalar
>::Real RealScalar
;
128 Index size
= MatrixType::RowsAtCompileTime
;
130 size
= internal::random
<Index
>(1,EIGEN_TEST_MAX_SIZE
);
132 MatrixType
m1(size
, size
), m2(size
, size
), m3(size
, size
);
133 FullPivLU
<MatrixType
> lu
;
134 lu
.setThreshold(RealScalar(0.01));
136 m1
= MatrixType::Random(size
,size
);
138 } while(!lu
.isInvertible());
140 VERIFY_IS_APPROX(m1
, lu
.reconstructedMatrix());
141 VERIFY(0 == lu
.dimensionOfKernel());
142 VERIFY(lu
.kernel().cols() == 1); // the kernel() should consist of a single (zero) column vector
143 VERIFY(size
== lu
.rank());
144 VERIFY(lu
.isInjective());
145 VERIFY(lu
.isSurjective());
146 VERIFY(lu
.isInvertible());
147 VERIFY(lu
.image(m1
).fullPivLu().isInvertible());
148 m3
= MatrixType::Random(size
,size
);
150 VERIFY_IS_APPROX(m3
, m1
*m2
);
151 MatrixType m1_inverse
= lu
.inverse();
152 VERIFY_IS_APPROX(m2
, m1_inverse
*m3
);
154 RealScalar rcond
= (RealScalar(1) / matrix_l1_norm(m1
)) / matrix_l1_norm(m1_inverse
);
155 const RealScalar rcond_est
= lu
.rcond();
156 // Verify that the estimated condition number is within a factor of 10 of the
158 VERIFY(rcond_est
> rcond
/ 10 && rcond_est
< rcond
* 10);
160 // test solve with transposed
161 lu
.template _solve_impl_transposed
<false>(m3
, m2
);
162 VERIFY_IS_APPROX(m3
, m1
.transpose()*m2
);
163 m3
= MatrixType::Random(size
,size
);
164 m3
= lu
.transpose().solve(m2
);
165 VERIFY_IS_APPROX(m2
, m1
.transpose()*m3
);
167 // test solve with conjugate transposed
168 lu
.template _solve_impl_transposed
<true>(m3
, m2
);
169 VERIFY_IS_APPROX(m3
, m1
.adjoint()*m2
);
170 m3
= MatrixType::Random(size
,size
);
171 m3
= lu
.adjoint().solve(m2
);
172 VERIFY_IS_APPROX(m2
, m1
.adjoint()*m3
);
174 // Regression test for Bug 302
175 MatrixType m4
= MatrixType::Random(size
,size
);
176 VERIFY_IS_APPROX(lu
.solve(m3
*m4
), lu
.solve(m3
)*m4
);
179 template<typename MatrixType
> void lu_partial_piv()
181 /* this test covers the following files:
184 typedef typename
MatrixType::Index Index
;
185 typedef typename NumTraits
<typename
MatrixType::Scalar
>::Real RealScalar
;
186 Index size
= internal::random
<Index
>(1,4);
188 MatrixType
m1(size
, size
), m2(size
, size
), m3(size
, size
);
190 PartialPivLU
<MatrixType
> plu(m1
);
192 VERIFY_IS_APPROX(m1
, plu
.reconstructedMatrix());
194 m3
= MatrixType::Random(size
,size
);
196 VERIFY_IS_APPROX(m3
, m1
*m2
);
197 MatrixType m1_inverse
= plu
.inverse();
198 VERIFY_IS_APPROX(m2
, m1_inverse
*m3
);
200 RealScalar rcond
= (RealScalar(1) / matrix_l1_norm(m1
)) / matrix_l1_norm(m1_inverse
);
201 const RealScalar rcond_est
= plu
.rcond();
202 // Verify that the estimate is within a factor of 10 of the truth.
203 VERIFY(rcond_est
> rcond
/ 10 && rcond_est
< rcond
* 10);
205 // test solve with transposed
206 plu
.template _solve_impl_transposed
<false>(m3
, m2
);
207 VERIFY_IS_APPROX(m3
, m1
.transpose()*m2
);
208 m3
= MatrixType::Random(size
,size
);
209 m3
= plu
.transpose().solve(m2
);
210 VERIFY_IS_APPROX(m2
, m1
.transpose()*m3
);
212 // test solve with conjugate transposed
213 plu
.template _solve_impl_transposed
<true>(m3
, m2
);
214 VERIFY_IS_APPROX(m3
, m1
.adjoint()*m2
);
215 m3
= MatrixType::Random(size
,size
);
216 m3
= plu
.adjoint().solve(m2
);
217 VERIFY_IS_APPROX(m2
, m1
.adjoint()*m3
);
220 template<typename MatrixType
> void lu_verify_assert()
224 FullPivLU
<MatrixType
> lu
;
225 VERIFY_RAISES_ASSERT(lu
.matrixLU())
226 VERIFY_RAISES_ASSERT(lu
.permutationP())
227 VERIFY_RAISES_ASSERT(lu
.permutationQ())
228 VERIFY_RAISES_ASSERT(lu
.kernel())
229 VERIFY_RAISES_ASSERT(lu
.image(tmp
))
230 VERIFY_RAISES_ASSERT(lu
.solve(tmp
))
231 VERIFY_RAISES_ASSERT(lu
.determinant())
232 VERIFY_RAISES_ASSERT(lu
.rank())
233 VERIFY_RAISES_ASSERT(lu
.dimensionOfKernel())
234 VERIFY_RAISES_ASSERT(lu
.isInjective())
235 VERIFY_RAISES_ASSERT(lu
.isSurjective())
236 VERIFY_RAISES_ASSERT(lu
.isInvertible())
237 VERIFY_RAISES_ASSERT(lu
.inverse())
239 PartialPivLU
<MatrixType
> plu
;
240 VERIFY_RAISES_ASSERT(plu
.matrixLU())
241 VERIFY_RAISES_ASSERT(plu
.permutationP())
242 VERIFY_RAISES_ASSERT(plu
.solve(tmp
))
243 VERIFY_RAISES_ASSERT(plu
.determinant())
244 VERIFY_RAISES_ASSERT(plu
.inverse())
249 for(int i
= 0; i
< g_repeat
; i
++) {
250 CALL_SUBTEST_1( lu_non_invertible
<Matrix3f
>() );
251 CALL_SUBTEST_1( lu_invertible
<Matrix3f
>() );
252 CALL_SUBTEST_1( lu_verify_assert
<Matrix3f
>() );
254 CALL_SUBTEST_2( (lu_non_invertible
<Matrix
<double, 4, 6> >()) );
255 CALL_SUBTEST_2( (lu_verify_assert
<Matrix
<double, 4, 6> >()) );
257 CALL_SUBTEST_3( lu_non_invertible
<MatrixXf
>() );
258 CALL_SUBTEST_3( lu_invertible
<MatrixXf
>() );
259 CALL_SUBTEST_3( lu_verify_assert
<MatrixXf
>() );
261 CALL_SUBTEST_4( lu_non_invertible
<MatrixXd
>() );
262 CALL_SUBTEST_4( lu_invertible
<MatrixXd
>() );
263 CALL_SUBTEST_4( lu_partial_piv
<MatrixXd
>() );
264 CALL_SUBTEST_4( lu_verify_assert
<MatrixXd
>() );
266 CALL_SUBTEST_5( lu_non_invertible
<MatrixXcf
>() );
267 CALL_SUBTEST_5( lu_invertible
<MatrixXcf
>() );
268 CALL_SUBTEST_5( lu_verify_assert
<MatrixXcf
>() );
270 CALL_SUBTEST_6( lu_non_invertible
<MatrixXcd
>() );
271 CALL_SUBTEST_6( lu_invertible
<MatrixXcd
>() );
272 CALL_SUBTEST_6( lu_partial_piv
<MatrixXcd
>() );
273 CALL_SUBTEST_6( lu_verify_assert
<MatrixXcd
>() );
275 CALL_SUBTEST_7(( lu_non_invertible
<Matrix
<float,Dynamic
,16> >() ));
277 // Test problem size constructors
278 CALL_SUBTEST_9( PartialPivLU
<MatrixXf
>(10) );
279 CALL_SUBTEST_9( FullPivLU
<MatrixXf
>(10, 20); );