You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
8.7 KiB

  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2008-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
  5. //
  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/.
  9. #include "main.h"
  10. #include <Eigen/LU>
  11. using namespace std;
  12. template<typename MatrixType> void lu_non_invertible()
  13. {
  14. typedef typename MatrixType::Index Index;
  15. typedef typename MatrixType::RealScalar RealScalar;
  16. /* this test covers the following files:
  17. LU.h
  18. */
  19. Index rows, cols, cols2;
  20. if(MatrixType::RowsAtCompileTime==Dynamic)
  21. {
  22. rows = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE);
  23. }
  24. else
  25. {
  26. rows = MatrixType::RowsAtCompileTime;
  27. }
  28. if(MatrixType::ColsAtCompileTime==Dynamic)
  29. {
  30. cols = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE);
  31. cols2 = internal::random<int>(2,EIGEN_TEST_MAX_SIZE);
  32. }
  33. else
  34. {
  35. cols2 = cols = MatrixType::ColsAtCompileTime;
  36. }
  37. enum {
  38. RowsAtCompileTime = MatrixType::RowsAtCompileTime,
  39. ColsAtCompileTime = MatrixType::ColsAtCompileTime
  40. };
  41. typedef typename internal::kernel_retval_base<FullPivLU<MatrixType> >::ReturnType KernelMatrixType;
  42. typedef typename internal::image_retval_base<FullPivLU<MatrixType> >::ReturnType ImageMatrixType;
  43. typedef Matrix<typename MatrixType::Scalar, ColsAtCompileTime, ColsAtCompileTime>
  44. CMatrixType;
  45. typedef Matrix<typename MatrixType::Scalar, RowsAtCompileTime, RowsAtCompileTime>
  46. RMatrixType;
  47. Index rank = internal::random<Index>(1, (std::min)(rows, cols)-1);
  48. // The image of the zero matrix should consist of a single (zero) column vector
  49. VERIFY((MatrixType::Zero(rows,cols).fullPivLu().image(MatrixType::Zero(rows,cols)).cols() == 1));
  50. MatrixType m1(rows, cols), m3(rows, cols2);
  51. CMatrixType m2(cols, cols2);
  52. createRandomPIMatrixOfRank(rank, rows, cols, m1);
  53. FullPivLU<MatrixType> lu;
  54. // The special value 0.01 below works well in tests. Keep in mind that we're only computing the rank
  55. // of singular values are either 0 or 1.
  56. // So it's not clear at all that the epsilon should play any role there.
  57. lu.setThreshold(RealScalar(0.01));
  58. lu.compute(m1);
  59. MatrixType u(rows,cols);
  60. u = lu.matrixLU().template triangularView<Upper>();
  61. RMatrixType l = RMatrixType::Identity(rows,rows);
  62. l.block(0,0,rows,(std::min)(rows,cols)).template triangularView<StrictlyLower>()
  63. = lu.matrixLU().block(0,0,rows,(std::min)(rows,cols));
  64. VERIFY_IS_APPROX(lu.permutationP() * m1 * lu.permutationQ(), l*u);
  65. KernelMatrixType m1kernel = lu.kernel();
  66. ImageMatrixType m1image = lu.image(m1);
  67. VERIFY_IS_APPROX(m1, lu.reconstructedMatrix());
  68. VERIFY(rank == lu.rank());
  69. VERIFY(cols - lu.rank() == lu.dimensionOfKernel());
  70. VERIFY(!lu.isInjective());
  71. VERIFY(!lu.isInvertible());
  72. VERIFY(!lu.isSurjective());
  73. VERIFY((m1 * m1kernel).isMuchSmallerThan(m1));
  74. VERIFY(m1image.fullPivLu().rank() == rank);
  75. VERIFY_IS_APPROX(m1 * m1.adjoint() * m1image, m1image);
  76. m2 = CMatrixType::Random(cols,cols2);
  77. m3 = m1*m2;
  78. m2 = CMatrixType::Random(cols,cols2);
  79. // test that the code, which does resize(), may be applied to an xpr
  80. m2.block(0,0,m2.rows(),m2.cols()) = lu.solve(m3);
  81. VERIFY_IS_APPROX(m3, m1*m2);
  82. // test solve with transposed
  83. m3 = MatrixType::Random(rows,cols2);
  84. m2 = m1.transpose()*m3;
  85. m3 = MatrixType::Random(rows,cols2);
  86. lu.template _solve_impl_transposed<false>(m2, m3);
  87. VERIFY_IS_APPROX(m2, m1.transpose()*m3);
  88. m3 = MatrixType::Random(rows,cols2);
  89. m3 = lu.transpose().solve(m2);
  90. VERIFY_IS_APPROX(m2, m1.transpose()*m3);
  91. // test solve with conjugate transposed
  92. m3 = MatrixType::Random(rows,cols2);
  93. m2 = m1.adjoint()*m3;
  94. m3 = MatrixType::Random(rows,cols2);
  95. lu.template _solve_impl_transposed<true>(m2, m3);
  96. VERIFY_IS_APPROX(m2, m1.adjoint()*m3);
  97. m3 = MatrixType::Random(rows,cols2);
  98. m3 = lu.adjoint().solve(m2);
  99. VERIFY_IS_APPROX(m2, m1.adjoint()*m3);
  100. }
  101. template<typename MatrixType> void lu_invertible()
  102. {
  103. /* this test covers the following files:
  104. LU.h
  105. */
  106. typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
  107. Index size = MatrixType::RowsAtCompileTime;
  108. if( size==Dynamic)
  109. size = internal::random<Index>(1,EIGEN_TEST_MAX_SIZE);
  110. MatrixType m1(size, size), m2(size, size), m3(size, size);
  111. FullPivLU<MatrixType> lu;
  112. lu.setThreshold(RealScalar(0.01));
  113. do {
  114. m1 = MatrixType::Random(size,size);
  115. lu.compute(m1);
  116. } while(!lu.isInvertible());
  117. VERIFY_IS_APPROX(m1, lu.reconstructedMatrix());
  118. VERIFY(0 == lu.dimensionOfKernel());
  119. VERIFY(lu.kernel().cols() == 1); // the kernel() should consist of a single (zero) column vector
  120. VERIFY(size == lu.rank());
  121. VERIFY(lu.isInjective());
  122. VERIFY(lu.isSurjective());
  123. VERIFY(lu.isInvertible());
  124. VERIFY(lu.image(m1).fullPivLu().isInvertible());
  125. m3 = MatrixType::Random(size,size);
  126. m2 = lu.solve(m3);
  127. VERIFY_IS_APPROX(m3, m1*m2);
  128. VERIFY_IS_APPROX(m2, lu.inverse()*m3);
  129. // test solve with transposed
  130. lu.template _solve_impl_transposed<false>(m3, m2);
  131. VERIFY_IS_APPROX(m3, m1.transpose()*m2);
  132. m3 = MatrixType::Random(size,size);
  133. m3 = lu.transpose().solve(m2);
  134. VERIFY_IS_APPROX(m2, m1.transpose()*m3);
  135. // test solve with conjugate transposed
  136. lu.template _solve_impl_transposed<true>(m3, m2);
  137. VERIFY_IS_APPROX(m3, m1.adjoint()*m2);
  138. m3 = MatrixType::Random(size,size);
  139. m3 = lu.adjoint().solve(m2);
  140. VERIFY_IS_APPROX(m2, m1.adjoint()*m3);
  141. // Regression test for Bug 302
  142. MatrixType m4 = MatrixType::Random(size,size);
  143. VERIFY_IS_APPROX(lu.solve(m3*m4), lu.solve(m3)*m4);
  144. }
  145. template<typename MatrixType> void lu_partial_piv()
  146. {
  147. /* this test covers the following files:
  148. PartialPivLU.h
  149. */
  150. typedef typename MatrixType::Index Index;
  151. Index size = internal::random<Index>(1,4);
  152. MatrixType m1(size, size), m2(size, size), m3(size, size);
  153. m1.setRandom();
  154. PartialPivLU<MatrixType> plu(m1);
  155. VERIFY_IS_APPROX(m1, plu.reconstructedMatrix());
  156. m3 = MatrixType::Random(size,size);
  157. m2 = plu.solve(m3);
  158. VERIFY_IS_APPROX(m3, m1*m2);
  159. VERIFY_IS_APPROX(m2, plu.inverse()*m3);
  160. // test solve with transposed
  161. plu.template _solve_impl_transposed<false>(m3, m2);
  162. VERIFY_IS_APPROX(m3, m1.transpose()*m2);
  163. m3 = MatrixType::Random(size,size);
  164. m3 = plu.transpose().solve(m2);
  165. VERIFY_IS_APPROX(m2, m1.transpose()*m3);
  166. // test solve with conjugate transposed
  167. plu.template _solve_impl_transposed<true>(m3, m2);
  168. VERIFY_IS_APPROX(m3, m1.adjoint()*m2);
  169. m3 = MatrixType::Random(size,size);
  170. m3 = plu.adjoint().solve(m2);
  171. VERIFY_IS_APPROX(m2, m1.adjoint()*m3);
  172. }
  173. template<typename MatrixType> void lu_verify_assert()
  174. {
  175. MatrixType tmp;
  176. FullPivLU<MatrixType> lu;
  177. VERIFY_RAISES_ASSERT(lu.matrixLU())
  178. VERIFY_RAISES_ASSERT(lu.permutationP())
  179. VERIFY_RAISES_ASSERT(lu.permutationQ())
  180. VERIFY_RAISES_ASSERT(lu.kernel())
  181. VERIFY_RAISES_ASSERT(lu.image(tmp))
  182. VERIFY_RAISES_ASSERT(lu.solve(tmp))
  183. VERIFY_RAISES_ASSERT(lu.determinant())
  184. VERIFY_RAISES_ASSERT(lu.rank())
  185. VERIFY_RAISES_ASSERT(lu.dimensionOfKernel())
  186. VERIFY_RAISES_ASSERT(lu.isInjective())
  187. VERIFY_RAISES_ASSERT(lu.isSurjective())
  188. VERIFY_RAISES_ASSERT(lu.isInvertible())
  189. VERIFY_RAISES_ASSERT(lu.inverse())
  190. PartialPivLU<MatrixType> plu;
  191. VERIFY_RAISES_ASSERT(plu.matrixLU())
  192. VERIFY_RAISES_ASSERT(plu.permutationP())
  193. VERIFY_RAISES_ASSERT(plu.solve(tmp))
  194. VERIFY_RAISES_ASSERT(plu.determinant())
  195. VERIFY_RAISES_ASSERT(plu.inverse())
  196. }
  197. void test_lu()
  198. {
  199. for(int i = 0; i < g_repeat; i++) {
  200. CALL_SUBTEST_1( lu_non_invertible<Matrix3f>() );
  201. CALL_SUBTEST_1( lu_invertible<Matrix3f>() );
  202. CALL_SUBTEST_1( lu_verify_assert<Matrix3f>() );
  203. CALL_SUBTEST_2( (lu_non_invertible<Matrix<double, 4, 6> >()) );
  204. CALL_SUBTEST_2( (lu_verify_assert<Matrix<double, 4, 6> >()) );
  205. CALL_SUBTEST_3( lu_non_invertible<MatrixXf>() );
  206. CALL_SUBTEST_3( lu_invertible<MatrixXf>() );
  207. CALL_SUBTEST_3( lu_verify_assert<MatrixXf>() );
  208. CALL_SUBTEST_4( lu_non_invertible<MatrixXd>() );
  209. CALL_SUBTEST_4( lu_invertible<MatrixXd>() );
  210. CALL_SUBTEST_4( lu_partial_piv<MatrixXd>() );
  211. CALL_SUBTEST_4( lu_verify_assert<MatrixXd>() );
  212. CALL_SUBTEST_5( lu_non_invertible<MatrixXcf>() );
  213. CALL_SUBTEST_5( lu_invertible<MatrixXcf>() );
  214. CALL_SUBTEST_5( lu_verify_assert<MatrixXcf>() );
  215. CALL_SUBTEST_6( lu_non_invertible<MatrixXcd>() );
  216. CALL_SUBTEST_6( lu_invertible<MatrixXcd>() );
  217. CALL_SUBTEST_6( lu_partial_piv<MatrixXcd>() );
  218. CALL_SUBTEST_6( lu_verify_assert<MatrixXcd>() );
  219. CALL_SUBTEST_7(( lu_non_invertible<Matrix<float,Dynamic,16> >() ));
  220. // Test problem size constructors
  221. CALL_SUBTEST_9( PartialPivLU<MatrixXf>(10) );
  222. CALL_SUBTEST_9( FullPivLU<MatrixXf>(10, 20); );
  223. }
  224. }