Home | History | Annotate | Download | only in eigen2
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra. Eigen itself is part of the KDE project.
      3 //
      4 // Copyright (C) 2008 Benoit Jacob <jacob.benoit.1 (at) 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 
     10 #include "main.h"
     11 #include <Eigen/LU>
     12 
     13 template<typename Derived>
     14 void doSomeRankPreservingOperations(Eigen::MatrixBase<Derived>& m)
     15 {
     16   typedef typename Derived::RealScalar RealScalar;
     17   for(int a = 0; a < 3*(m.rows()+m.cols()); a++)
     18   {
     19     RealScalar d = Eigen::ei_random<RealScalar>(-1,1);
     20     int i = Eigen::ei_random<int>(0,m.rows()-1); // i is a random row number
     21     int j;
     22     do {
     23       j = Eigen::ei_random<int>(0,m.rows()-1);
     24     } while (i==j); // j is another one (must be different)
     25     m.row(i) += d * m.row(j);
     26 
     27     i = Eigen::ei_random<int>(0,m.cols()-1); // i is a random column number
     28     do {
     29       j = Eigen::ei_random<int>(0,m.cols()-1);
     30     } while (i==j); // j is another one (must be different)
     31     m.col(i) += d * m.col(j);
     32   }
     33 }
     34 
     35 template<typename MatrixType> void lu_non_invertible()
     36 {
     37   /* this test covers the following files:
     38      LU.h
     39   */
     40   // NOTE there seems to be a problem with too small sizes -- could easily lie in the doSomeRankPreservingOperations function
     41   int rows = ei_random<int>(20,200), cols = ei_random<int>(20,200), cols2 = ei_random<int>(20,200);
     42   int rank = ei_random<int>(1, std::min(rows, cols)-1);
     43 
     44   MatrixType m1(rows, cols), m2(cols, cols2), m3(rows, cols2), k(1,1);
     45   m1 = MatrixType::Random(rows,cols);
     46   if(rows <= cols)
     47     for(int i = rank; i < rows; i++) m1.row(i).setZero();
     48   else
     49     for(int i = rank; i < cols; i++) m1.col(i).setZero();
     50   doSomeRankPreservingOperations(m1);
     51 
     52   LU<MatrixType> lu(m1);
     53   typename LU<MatrixType>::KernelResultType m1kernel = lu.kernel();
     54   typename LU<MatrixType>::ImageResultType m1image = lu.image();
     55 
     56   VERIFY(rank == lu.rank());
     57   VERIFY(cols - lu.rank() == lu.dimensionOfKernel());
     58   VERIFY(!lu.isInjective());
     59   VERIFY(!lu.isInvertible());
     60   VERIFY(lu.isSurjective() == (lu.rank() == rows));
     61   VERIFY((m1 * m1kernel).isMuchSmallerThan(m1));
     62   VERIFY(m1image.lu().rank() == rank);
     63   MatrixType sidebyside(m1.rows(), m1.cols() + m1image.cols());
     64   sidebyside << m1, m1image;
     65   VERIFY(sidebyside.lu().rank() == rank);
     66   m2 = MatrixType::Random(cols,cols2);
     67   m3 = m1*m2;
     68   m2 = MatrixType::Random(cols,cols2);
     69   lu.solve(m3, &m2);
     70   VERIFY_IS_APPROX(m3, m1*m2);
     71   /* solve now always returns true
     72   m3 = MatrixType::Random(rows,cols2);
     73   VERIFY(!lu.solve(m3, &m2));
     74   */
     75 }
     76 
     77 template<typename MatrixType> void lu_invertible()
     78 {
     79   /* this test covers the following files:
     80      LU.h
     81   */
     82   typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
     83   int size = ei_random<int>(10,200);
     84 
     85   MatrixType m1(size, size), m2(size, size), m3(size, size);
     86   m1 = MatrixType::Random(size,size);
     87 
     88   if (ei_is_same_type<RealScalar,float>::ret)
     89   {
     90     // let's build a matrix more stable to inverse
     91     MatrixType a = MatrixType::Random(size,size*2);
     92     m1 += a * a.adjoint();
     93   }
     94 
     95   LU<MatrixType> lu(m1);
     96   VERIFY(0 == lu.dimensionOfKernel());
     97   VERIFY(size == lu.rank());
     98   VERIFY(lu.isInjective());
     99   VERIFY(lu.isSurjective());
    100   VERIFY(lu.isInvertible());
    101   VERIFY(lu.image().lu().isInvertible());
    102   m3 = MatrixType::Random(size,size);
    103   lu.solve(m3, &m2);
    104   VERIFY_IS_APPROX(m3, m1*m2);
    105   VERIFY_IS_APPROX(m2, lu.inverse()*m3);
    106   m3 = MatrixType::Random(size,size);
    107   VERIFY(lu.solve(m3, &m2));
    108 }
    109 
    110 void test_eigen2_lu()
    111 {
    112   for(int i = 0; i < g_repeat; i++) {
    113     CALL_SUBTEST_1( lu_non_invertible<MatrixXf>() );
    114     CALL_SUBTEST_2( lu_non_invertible<MatrixXd>() );
    115     CALL_SUBTEST_3( lu_non_invertible<MatrixXcf>() );
    116     CALL_SUBTEST_4( lu_non_invertible<MatrixXcd>() );
    117     CALL_SUBTEST_1( lu_invertible<MatrixXf>() );
    118     CALL_SUBTEST_2( lu_invertible<MatrixXd>() );
    119     CALL_SUBTEST_3( lu_invertible<MatrixXcf>() );
    120     CALL_SUBTEST_4( lu_invertible<MatrixXcd>() );
    121   }
    122 }
    123