Home | History | Annotate | Download | only in test
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1 (at) gmail.com>
      5 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud (at) inria.fr>
      6 //
      7 // This Source Code Form is subject to the terms of the Mozilla
      8 // Public License v. 2.0. If a copy of the MPL was not distributed
      9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
     10 
     11 #include <cstdlib>
     12 #include <cerrno>
     13 #include <ctime>
     14 #include <iostream>
     15 #include <fstream>
     16 #include <string>
     17 #include <vector>
     18 #include <typeinfo>
     19 #include <limits>
     20 #include <algorithm>
     21 #include <sstream>
     22 #include <complex>
     23 #include <deque>
     24 #include <queue>
     25 
     26 #define min(A,B) please_protect_your_min_with_parentheses
     27 #define max(A,B) please_protect_your_max_with_parentheses
     28 
     29 #define FORBIDDEN_IDENTIFIER (this_identifier_is_forbidden_to_avoid_clashes) this_identifier_is_forbidden_to_avoid_clashes
     30 // B0 is defined in POSIX header termios.h
     31 #define B0 FORBIDDEN_IDENTIFIER
     32 
     33 // the following file is automatically generated by cmake
     34 #include "split_test_helper.h"
     35 
     36 #ifdef NDEBUG
     37 #undef NDEBUG
     38 #endif
     39 
     40 // bounds integer values for AltiVec
     41 #ifdef __ALTIVEC__
     42 #define EIGEN_MAKING_DOCS
     43 #endif
     44 
     45 #ifndef EIGEN_TEST_FUNC
     46 #error EIGEN_TEST_FUNC must be defined
     47 #endif
     48 
     49 #define DEFAULT_REPEAT 10
     50 
     51 #ifdef __ICC
     52 // disable warning #279: controlling expression is constant
     53 #pragma warning disable 279
     54 #endif
     55 
     56 namespace Eigen
     57 {
     58   static std::vector<std::string> g_test_stack;
     59   static int g_repeat;
     60   static unsigned int g_seed;
     61   static bool g_has_set_repeat, g_has_set_seed;
     62 }
     63 
     64 #define EI_PP_MAKE_STRING2(S) #S
     65 #define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S)
     66 
     67 #define EIGEN_DEFAULT_IO_FORMAT IOFormat(4, 0, "  ", "\n", "", "", "", "")
     68 
     69 #ifndef EIGEN_NO_ASSERTION_CHECKING
     70 
     71   namespace Eigen
     72   {
     73     static const bool should_raise_an_assert = false;
     74 
     75     // Used to avoid to raise two exceptions at a time in which
     76     // case the exception is not properly caught.
     77     // This may happen when a second exceptions is triggered in a destructor.
     78     static bool no_more_assert = false;
     79     static bool report_on_cerr_on_assert_failure = true;
     80 
     81     struct eigen_assert_exception
     82     {
     83       eigen_assert_exception(void) {}
     84       ~eigen_assert_exception() { Eigen::no_more_assert = false; }
     85     };
     86   }
     87   // If EIGEN_DEBUG_ASSERTS is defined and if no assertion is triggered while
     88   // one should have been, then the list of excecuted assertions is printed out.
     89   //
     90   // EIGEN_DEBUG_ASSERTS is not enabled by default as it
     91   // significantly increases the compilation time
     92   // and might even introduce side effects that would hide
     93   // some memory errors.
     94   #ifdef EIGEN_DEBUG_ASSERTS
     95 
     96     namespace Eigen
     97     {
     98       namespace internal
     99       {
    100         static bool push_assert = false;
    101       }
    102       static std::vector<std::string> eigen_assert_list;
    103     }
    104     #define eigen_assert(a)                       \
    105       if( (!(a)) && (!no_more_assert) )     \
    106       { \
    107         if(report_on_cerr_on_assert_failure) \
    108           std::cerr <<  #a << " " __FILE__ << "(" << __LINE__ << ")\n"; \
    109         Eigen::no_more_assert = true;       \
    110         throw Eigen::eigen_assert_exception(); \
    111       }                                     \
    112       else if (Eigen::internal::push_assert)       \
    113       {                                     \
    114         eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__) " (" EI_PP_MAKE_STRING(__LINE__) ") : " #a) ); \
    115       }
    116 
    117     #define VERIFY_RAISES_ASSERT(a)                                                   \
    118       {                                                                               \
    119         Eigen::no_more_assert = false;                                                \
    120         Eigen::eigen_assert_list.clear();                                                \
    121         Eigen::internal::push_assert = true;                                                 \
    122         Eigen::report_on_cerr_on_assert_failure = false;                              \
    123         try {                                                                         \
    124           a;                                                                          \
    125           std::cerr << "One of the following asserts should have been triggered:\n";  \
    126           for (uint ai=0 ; ai<eigen_assert_list.size() ; ++ai)                           \
    127             std::cerr << "  " << eigen_assert_list[ai] << "\n";                          \
    128           VERIFY(Eigen::should_raise_an_assert && # a);                               \
    129         } catch (Eigen::eigen_assert_exception) {                                        \
    130           Eigen::internal::push_assert = false; VERIFY(true);                                \
    131         }                                                                             \
    132         Eigen::report_on_cerr_on_assert_failure = true;                               \
    133         Eigen::internal::push_assert = false;                                                \
    134       }
    135 
    136   #else // EIGEN_DEBUG_ASSERTS
    137     // see bug 89. The copy_bool here is working around a bug in gcc <= 4.3
    138     #define eigen_assert(a) \
    139       if( (!Eigen::internal::copy_bool(a)) && (!no_more_assert) )\
    140       {                                       \
    141         Eigen::no_more_assert = true;         \
    142         if(report_on_cerr_on_assert_failure)  \
    143           eigen_plain_assert(a);              \
    144         else                                  \
    145           throw Eigen::eigen_assert_exception(); \
    146       }
    147     #define VERIFY_RAISES_ASSERT(a) {                             \
    148         Eigen::no_more_assert = false;                            \
    149         Eigen::report_on_cerr_on_assert_failure = false;          \
    150         try {                                                     \
    151           a;                                                      \
    152           VERIFY(Eigen::should_raise_an_assert && # a);           \
    153         }                                                         \
    154         catch (Eigen::eigen_assert_exception&) { VERIFY(true); }     \
    155         Eigen::report_on_cerr_on_assert_failure = true;           \
    156       }
    157 
    158   #endif // EIGEN_DEBUG_ASSERTS
    159 
    160   #define EIGEN_USE_CUSTOM_ASSERT
    161 
    162 #else // EIGEN_NO_ASSERTION_CHECKING
    163 
    164   #define VERIFY_RAISES_ASSERT(a) {}
    165 
    166 #endif // EIGEN_NO_ASSERTION_CHECKING
    167 
    168 
    169 #define EIGEN_INTERNAL_DEBUGGING
    170 #include <Eigen/QR> // required for createRandomPIMatrixOfRank
    171 
    172 static void verify_impl(bool condition, const char *testname, const char *file, int line, const char *condition_as_string)
    173 {
    174   if (!condition)
    175   {
    176     std::cerr << "Test " << testname << " failed in " << file << " (" << line << ")" \
    177       << std::endl << "    " << condition_as_string << std::endl << std::endl; \
    178     abort();
    179   }
    180 }
    181 
    182 #define VERIFY(a) ::verify_impl(a, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a))
    183 
    184 #define VERIFY_IS_EQUAL(a, b) VERIFY(test_is_equal(a, b))
    185 #define VERIFY_IS_APPROX(a, b) VERIFY(test_isApprox(a, b))
    186 #define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_isApprox(a, b))
    187 #define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_isMuchSmallerThan(a, b))
    188 #define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_isMuchSmallerThan(a, b))
    189 #define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_isApproxOrLessThan(a, b))
    190 #define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_isApproxOrLessThan(a, b))
    191 
    192 #define VERIFY_IS_UNITARY(a) VERIFY(test_isUnitary(a))
    193 
    194 #define CALL_SUBTEST(FUNC) do { \
    195     g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \
    196     FUNC; \
    197     g_test_stack.pop_back(); \
    198   } while (0)
    199 
    200 
    201 namespace Eigen {
    202 
    203 template<typename T> inline typename NumTraits<T>::Real test_precision() { return NumTraits<T>::dummy_precision(); }
    204 template<> inline float test_precision<float>() { return 1e-3f; }
    205 template<> inline double test_precision<double>() { return 1e-6; }
    206 template<> inline float test_precision<std::complex<float> >() { return test_precision<float>(); }
    207 template<> inline double test_precision<std::complex<double> >() { return test_precision<double>(); }
    208 template<> inline long double test_precision<long double>() { return 1e-6; }
    209 
    210 inline bool test_isApprox(const int& a, const int& b)
    211 { return internal::isApprox(a, b, test_precision<int>()); }
    212 inline bool test_isMuchSmallerThan(const int& a, const int& b)
    213 { return internal::isMuchSmallerThan(a, b, test_precision<int>()); }
    214 inline bool test_isApproxOrLessThan(const int& a, const int& b)
    215 { return internal::isApproxOrLessThan(a, b, test_precision<int>()); }
    216 
    217 inline bool test_isApprox(const float& a, const float& b)
    218 { return internal::isApprox(a, b, test_precision<float>()); }
    219 inline bool test_isMuchSmallerThan(const float& a, const float& b)
    220 { return internal::isMuchSmallerThan(a, b, test_precision<float>()); }
    221 inline bool test_isApproxOrLessThan(const float& a, const float& b)
    222 { return internal::isApproxOrLessThan(a, b, test_precision<float>()); }
    223 inline bool test_isApprox(const double& a, const double& b)
    224 { return internal::isApprox(a, b, test_precision<double>()); }
    225 
    226 inline bool test_isMuchSmallerThan(const double& a, const double& b)
    227 { return internal::isMuchSmallerThan(a, b, test_precision<double>()); }
    228 inline bool test_isApproxOrLessThan(const double& a, const double& b)
    229 { return internal::isApproxOrLessThan(a, b, test_precision<double>()); }
    230 
    231 inline bool test_isApprox(const std::complex<float>& a, const std::complex<float>& b)
    232 { return internal::isApprox(a, b, test_precision<std::complex<float> >()); }
    233 inline bool test_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b)
    234 { return internal::isMuchSmallerThan(a, b, test_precision<std::complex<float> >()); }
    235 
    236 inline bool test_isApprox(const std::complex<double>& a, const std::complex<double>& b)
    237 { return internal::isApprox(a, b, test_precision<std::complex<double> >()); }
    238 inline bool test_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b)
    239 { return internal::isMuchSmallerThan(a, b, test_precision<std::complex<double> >()); }
    240 
    241 inline bool test_isApprox(const long double& a, const long double& b)
    242 {
    243     bool ret = internal::isApprox(a, b, test_precision<long double>());
    244     if (!ret) std::cerr
    245         << std::endl << "    actual   = " << a
    246         << std::endl << "    expected = " << b << std::endl << std::endl;
    247     return ret;
    248 }
    249 
    250 inline bool test_isMuchSmallerThan(const long double& a, const long double& b)
    251 { return internal::isMuchSmallerThan(a, b, test_precision<long double>()); }
    252 inline bool test_isApproxOrLessThan(const long double& a, const long double& b)
    253 { return internal::isApproxOrLessThan(a, b, test_precision<long double>()); }
    254 
    255 template<typename Type1, typename Type2>
    256 inline bool test_isApprox(const Type1& a, const Type2& b)
    257 {
    258   return a.isApprox(b, test_precision<typename Type1::Scalar>());
    259 }
    260 
    261 // The idea behind this function is to compare the two scalars a and b where
    262 // the scalar ref is a hint about the expected order of magnitude of a and b.
    263 // Therefore, if for some reason a and b are very small compared to ref,
    264 // we won't issue a false negative.
    265 // This test could be: abs(a-b) <= eps * ref
    266 // However, it seems that simply comparing a+ref and b+ref is more sensitive to true error.
    267 template<typename Scalar,typename ScalarRef>
    268 inline bool test_isApproxWithRef(const Scalar& a, const Scalar& b, const ScalarRef& ref)
    269 {
    270   return test_isApprox(a+ref, b+ref);
    271 }
    272 
    273 template<typename Derived1, typename Derived2>
    274 inline bool test_isMuchSmallerThan(const MatrixBase<Derived1>& m1,
    275                                    const MatrixBase<Derived2>& m2)
    276 {
    277   return m1.isMuchSmallerThan(m2, test_precision<typename internal::traits<Derived1>::Scalar>());
    278 }
    279 
    280 template<typename Derived>
    281 inline bool test_isMuchSmallerThan(const MatrixBase<Derived>& m,
    282                                    const typename NumTraits<typename internal::traits<Derived>::Scalar>::Real& s)
    283 {
    284   return m.isMuchSmallerThan(s, test_precision<typename internal::traits<Derived>::Scalar>());
    285 }
    286 
    287 template<typename Derived>
    288 inline bool test_isUnitary(const MatrixBase<Derived>& m)
    289 {
    290   return m.isUnitary(test_precision<typename internal::traits<Derived>::Scalar>());
    291 }
    292 
    293 template<typename T, typename U>
    294 bool test_is_equal(const T& actual, const U& expected)
    295 {
    296     if (actual==expected)
    297         return true;
    298     // false:
    299     std::cerr
    300         << std::endl << "    actual   = " << actual
    301         << std::endl << "    expected = " << expected << std::endl << std::endl;
    302     return false;
    303 }
    304 
    305 /** Creates a random Partial Isometry matrix of given rank.
    306   *
    307   * A partial isometry is a matrix all of whose singular values are either 0 or 1.
    308   * This is very useful to test rank-revealing algorithms.
    309   */
    310 template<typename MatrixType>
    311 void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typename MatrixType::Index rows, typename MatrixType::Index cols, MatrixType& m)
    312 {
    313   typedef typename internal::traits<MatrixType>::Index Index;
    314   typedef typename internal::traits<MatrixType>::Scalar Scalar;
    315   enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
    316 
    317   typedef Matrix<Scalar, Dynamic, 1> VectorType;
    318   typedef Matrix<Scalar, Rows, Rows> MatrixAType;
    319   typedef Matrix<Scalar, Cols, Cols> MatrixBType;
    320 
    321   if(desired_rank == 0)
    322   {
    323     m.setZero(rows,cols);
    324     return;
    325   }
    326 
    327   if(desired_rank == 1)
    328   {
    329     // here we normalize the vectors to get a partial isometry
    330     m = VectorType::Random(rows).normalized() * VectorType::Random(cols).normalized().transpose();
    331     return;
    332   }
    333 
    334   MatrixAType a = MatrixAType::Random(rows,rows);
    335   MatrixType d = MatrixType::Identity(rows,cols);
    336   MatrixBType  b = MatrixBType::Random(cols,cols);
    337 
    338   // set the diagonal such that only desired_rank non-zero entries reamain
    339   const Index diag_size = (std::min)(d.rows(),d.cols());
    340   if(diag_size != desired_rank)
    341     d.diagonal().segment(desired_rank, diag_size-desired_rank) = VectorType::Zero(diag_size-desired_rank);
    342 
    343   HouseholderQR<MatrixAType> qra(a);
    344   HouseholderQR<MatrixBType> qrb(b);
    345   m = qra.householderQ() * d * qrb.householderQ();
    346 }
    347 
    348 template<typename PermutationVectorType>
    349 void randomPermutationVector(PermutationVectorType& v, typename PermutationVectorType::Index size)
    350 {
    351   typedef typename PermutationVectorType::Index Index;
    352   typedef typename PermutationVectorType::Scalar Scalar;
    353   v.resize(size);
    354   for(Index i = 0; i < size; ++i) v(i) = Scalar(i);
    355   if(size == 1) return;
    356   for(Index n = 0; n < 3 * size; ++n)
    357   {
    358     Index i = internal::random<Index>(0, size-1);
    359     Index j;
    360     do j = internal::random<Index>(0, size-1); while(j==i);
    361     std::swap(v(i), v(j));
    362   }
    363 }
    364 
    365 } // end namespace Eigen
    366 
    367 template<typename T> struct GetDifferentType;
    368 
    369 template<> struct GetDifferentType<float> { typedef double type; };
    370 template<> struct GetDifferentType<double> { typedef float type; };
    371 template<typename T> struct GetDifferentType<std::complex<T> >
    372 { typedef std::complex<typename GetDifferentType<T>::type> type; };
    373 
    374 template<typename T> std::string type_name() { return "other"; }
    375 template<> std::string type_name<float>() { return "float"; }
    376 template<> std::string type_name<double>() { return "double"; }
    377 template<> std::string type_name<int>() { return "int"; }
    378 template<> std::string type_name<std::complex<float> >() { return "complex<float>"; }
    379 template<> std::string type_name<std::complex<double> >() { return "complex<double>"; }
    380 template<> std::string type_name<std::complex<int> >() { return "complex<int>"; }
    381 
    382 // forward declaration of the main test function
    383 void EIGEN_CAT(test_,EIGEN_TEST_FUNC)();
    384 
    385 using namespace Eigen;
    386 
    387 void set_repeat_from_string(const char *str)
    388 {
    389   errno = 0;
    390   g_repeat = int(strtoul(str, 0, 10));
    391   if(errno || g_repeat <= 0)
    392   {
    393     std::cout << "Invalid repeat value " << str << std::endl;
    394     exit(EXIT_FAILURE);
    395   }
    396   g_has_set_repeat = true;
    397 }
    398 
    399 void set_seed_from_string(const char *str)
    400 {
    401   errno = 0;
    402   g_seed = strtoul(str, 0, 10);
    403   if(errno || g_seed == 0)
    404   {
    405     std::cout << "Invalid seed value " << str << std::endl;
    406     exit(EXIT_FAILURE);
    407   }
    408   g_has_set_seed = true;
    409 }
    410 
    411 int main(int argc, char *argv[])
    412 {
    413     g_has_set_repeat = false;
    414     g_has_set_seed = false;
    415     bool need_help = false;
    416 
    417     for(int i = 1; i < argc; i++)
    418     {
    419       if(argv[i][0] == 'r')
    420       {
    421         if(g_has_set_repeat)
    422         {
    423           std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
    424           return 1;
    425         }
    426         set_repeat_from_string(argv[i]+1);
    427       }
    428       else if(argv[i][0] == 's')
    429       {
    430         if(g_has_set_seed)
    431         {
    432           std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
    433           return 1;
    434         }
    435          set_seed_from_string(argv[i]+1);
    436       }
    437       else
    438       {
    439         need_help = true;
    440       }
    441     }
    442 
    443     if(need_help)
    444     {
    445       std::cout << "This test application takes the following optional arguments:" << std::endl;
    446       std::cout << "  rN     Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl;
    447       std::cout << "  sN     Use N as seed for random numbers (default: based on current time)" << std::endl;
    448       std::cout << std::endl;
    449       std::cout << "If defined, the environment variables EIGEN_REPEAT and EIGEN_SEED" << std::endl;
    450       std::cout << "will be used as default values for these parameters." << std::endl;
    451       return 1;
    452     }
    453 
    454     char *env_EIGEN_REPEAT = getenv("EIGEN_REPEAT");
    455     if(!g_has_set_repeat && env_EIGEN_REPEAT)
    456       set_repeat_from_string(env_EIGEN_REPEAT);
    457     char *env_EIGEN_SEED = getenv("EIGEN_SEED");
    458     if(!g_has_set_seed && env_EIGEN_SEED)
    459       set_seed_from_string(env_EIGEN_SEED);
    460 
    461     if(!g_has_set_seed) g_seed = (unsigned int) time(NULL);
    462     if(!g_has_set_repeat) g_repeat = DEFAULT_REPEAT;
    463 
    464     std::cout << "Initializing random number generator with seed " << g_seed << std::endl;
    465     srand(g_seed);
    466     std::cout << "Repeating each test " << g_repeat << " times" << std::endl;
    467 
    468     Eigen::g_test_stack.push_back(EI_PP_MAKE_STRING(EIGEN_TEST_FUNC));
    469 
    470     EIGEN_CAT(test_,EIGEN_TEST_FUNC)();
    471     return 0;
    472 }
    473