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) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com> 5// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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 <ctime> 13#include <iostream> 14#include <string> 15#include <vector> 16 17#ifndef EIGEN_TEST_FUNC 18#error EIGEN_TEST_FUNC must be defined 19#endif 20 21#define DEFAULT_REPEAT 10 22 23namespace Eigen 24{ 25 static std::vector<std::string> g_test_stack; 26 static int g_repeat; 27} 28 29#define EI_PP_MAKE_STRING2(S) #S 30#define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S) 31 32#define EI_PP_CAT2(a,b) a ## b 33#define EI_PP_CAT(a,b) EI_PP_CAT2(a,b) 34 35#ifndef EIGEN_NO_ASSERTION_CHECKING 36 37 namespace Eigen 38 { 39 static const bool should_raise_an_assert = false; 40 41 // Used to avoid to raise two exceptions at a time in which 42 // case the exception is not properly caught. 43 // This may happen when a second exceptions is raise in a destructor. 44 static bool no_more_assert = false; 45 46 struct eigen_assert_exception 47 { 48 eigen_assert_exception(void) {} 49 ~eigen_assert_exception() { Eigen::no_more_assert = false; } 50 }; 51 } 52 53 // If EIGEN_DEBUG_ASSERTS is defined and if no assertion is raised while 54 // one should have been, then the list of excecuted assertions is printed out. 55 // 56 // EIGEN_DEBUG_ASSERTS is not enabled by default as it 57 // significantly increases the compilation time 58 // and might even introduce side effects that would hide 59 // some memory errors. 60 #ifdef EIGEN_DEBUG_ASSERTS 61 62 namespace Eigen 63 { 64 static bool ei_push_assert = false; 65 static std::vector<std::string> eigen_assert_list; 66 } 67 68 #define eigen_assert(a) \ 69 if( (!(a)) && (!no_more_assert) ) \ 70 { \ 71 Eigen::no_more_assert = true; \ 72 throw Eigen::eigen_assert_exception(); \ 73 } \ 74 else if (Eigen::ei_push_assert) \ 75 { \ 76 eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__)" ("EI_PP_MAKE_STRING(__LINE__)") : "#a) ); \ 77 } 78 79 #define VERIFY_RAISES_ASSERT(a) \ 80 { \ 81 Eigen::no_more_assert = false; \ 82 try { \ 83 Eigen::eigen_assert_list.clear(); \ 84 Eigen::ei_push_assert = true; \ 85 a; \ 86 Eigen::ei_push_assert = false; \ 87 std::cerr << "One of the following asserts should have been raised:\n"; \ 88 for (uint ai=0 ; ai<eigen_assert_list.size() ; ++ai) \ 89 std::cerr << " " << eigen_assert_list[ai] << "\n"; \ 90 VERIFY(Eigen::should_raise_an_assert && # a); \ 91 } catch (Eigen::eigen_assert_exception e) { \ 92 Eigen::ei_push_assert = false; VERIFY(true); \ 93 } \ 94 } 95 96 #else // EIGEN_DEBUG_ASSERTS 97 98 #undef eigen_assert 99 100 // see bug 89. The copy_bool here is working around a bug in gcc <= 4.3 101 #define eigen_assert(a) \ 102 if( (!Eigen::internal::copy_bool(a)) && (!no_more_assert) ) \ 103 { \ 104 Eigen::no_more_assert = true; \ 105 throw Eigen::eigen_assert_exception(); \ 106 } 107 108 #define VERIFY_RAISES_ASSERT(a) { \ 109 Eigen::no_more_assert = false; \ 110 try { a; VERIFY(Eigen::should_raise_an_assert && # a); } \ 111 catch (Eigen::eigen_assert_exception e) { VERIFY(true); } \ 112 } 113 114 #endif // EIGEN_DEBUG_ASSERTS 115 116 #define EIGEN_USE_CUSTOM_ASSERT 117 118#else // EIGEN_NO_ASSERTION_CHECKING 119 120 #define VERIFY_RAISES_ASSERT(a) {} 121 122#endif // EIGEN_NO_ASSERTION_CHECKING 123 124 125#define EIGEN_INTERNAL_DEBUGGING 126#define EIGEN_NICE_RANDOM 127#include <Eigen/Array> 128 129 130#define VERIFY(a) do { if (!(a)) { \ 131 std::cerr << "Test " << g_test_stack.back() << " failed in "EI_PP_MAKE_STRING(__FILE__) << " (" << EI_PP_MAKE_STRING(__LINE__) << ")" \ 132 << std::endl << " " << EI_PP_MAKE_STRING(a) << std::endl << std::endl; \ 133 abort(); \ 134 } } while (0) 135 136#define VERIFY_IS_APPROX(a, b) VERIFY(test_ei_isApprox(a, b)) 137#define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_ei_isApprox(a, b)) 138#define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_ei_isMuchSmallerThan(a, b)) 139#define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_ei_isMuchSmallerThan(a, b)) 140#define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_ei_isApproxOrLessThan(a, b)) 141#define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_ei_isApproxOrLessThan(a, b)) 142 143#define CALL_SUBTEST(FUNC) do { \ 144 g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \ 145 FUNC; \ 146 g_test_stack.pop_back(); \ 147 } while (0) 148 149namespace Eigen { 150 151template<typename T> inline typename NumTraits<T>::Real test_precision(); 152template<> inline int test_precision<int>() { return 0; } 153template<> inline float test_precision<float>() { return 1e-3f; } 154template<> inline double test_precision<double>() { return 1e-6; } 155template<> inline float test_precision<std::complex<float> >() { return test_precision<float>(); } 156template<> inline double test_precision<std::complex<double> >() { return test_precision<double>(); } 157template<> inline long double test_precision<long double>() { return 1e-6; } 158 159inline bool test_ei_isApprox(const int& a, const int& b) 160{ return ei_isApprox(a, b, test_precision<int>()); } 161inline bool test_ei_isMuchSmallerThan(const int& a, const int& b) 162{ return ei_isMuchSmallerThan(a, b, test_precision<int>()); } 163inline bool test_ei_isApproxOrLessThan(const int& a, const int& b) 164{ return ei_isApproxOrLessThan(a, b, test_precision<int>()); } 165 166inline bool test_ei_isApprox(const float& a, const float& b) 167{ return ei_isApprox(a, b, test_precision<float>()); } 168inline bool test_ei_isMuchSmallerThan(const float& a, const float& b) 169{ return ei_isMuchSmallerThan(a, b, test_precision<float>()); } 170inline bool test_ei_isApproxOrLessThan(const float& a, const float& b) 171{ return ei_isApproxOrLessThan(a, b, test_precision<float>()); } 172 173inline bool test_ei_isApprox(const double& a, const double& b) 174{ return ei_isApprox(a, b, test_precision<double>()); } 175inline bool test_ei_isMuchSmallerThan(const double& a, const double& b) 176{ return ei_isMuchSmallerThan(a, b, test_precision<double>()); } 177inline bool test_ei_isApproxOrLessThan(const double& a, const double& b) 178{ return ei_isApproxOrLessThan(a, b, test_precision<double>()); } 179 180inline bool test_ei_isApprox(const std::complex<float>& a, const std::complex<float>& b) 181{ return ei_isApprox(a, b, test_precision<std::complex<float> >()); } 182inline bool test_ei_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b) 183{ return ei_isMuchSmallerThan(a, b, test_precision<std::complex<float> >()); } 184 185inline bool test_ei_isApprox(const std::complex<double>& a, const std::complex<double>& b) 186{ return ei_isApprox(a, b, test_precision<std::complex<double> >()); } 187inline bool test_ei_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b) 188{ return ei_isMuchSmallerThan(a, b, test_precision<std::complex<double> >()); } 189 190inline bool test_ei_isApprox(const long double& a, const long double& b) 191{ return ei_isApprox(a, b, test_precision<long double>()); } 192inline bool test_ei_isMuchSmallerThan(const long double& a, const long double& b) 193{ return ei_isMuchSmallerThan(a, b, test_precision<long double>()); } 194inline bool test_ei_isApproxOrLessThan(const long double& a, const long double& b) 195{ return ei_isApproxOrLessThan(a, b, test_precision<long double>()); } 196 197template<typename Type1, typename Type2> 198inline bool test_ei_isApprox(const Type1& a, const Type2& b) 199{ 200 return a.isApprox(b, test_precision<typename Type1::Scalar>()); 201} 202 203template<typename Derived1, typename Derived2> 204inline bool test_ei_isMuchSmallerThan(const MatrixBase<Derived1>& m1, 205 const MatrixBase<Derived2>& m2) 206{ 207 return m1.isMuchSmallerThan(m2, test_precision<typename ei_traits<Derived1>::Scalar>()); 208} 209 210template<typename Derived> 211inline bool test_ei_isMuchSmallerThan(const MatrixBase<Derived>& m, 212 const typename NumTraits<typename ei_traits<Derived>::Scalar>::Real& s) 213{ 214 return m.isMuchSmallerThan(s, test_precision<typename ei_traits<Derived>::Scalar>()); 215} 216 217} // end namespace Eigen 218 219template<typename T> struct GetDifferentType; 220 221template<> struct GetDifferentType<float> { typedef double type; }; 222template<> struct GetDifferentType<double> { typedef float type; }; 223template<typename T> struct GetDifferentType<std::complex<T> > 224{ typedef std::complex<typename GetDifferentType<T>::type> type; }; 225 226// forward declaration of the main test function 227void EI_PP_CAT(test_,EIGEN_TEST_FUNC)(); 228 229using namespace Eigen; 230 231#ifdef EIGEN_TEST_PART_1 232#define CALL_SUBTEST_1(FUNC) CALL_SUBTEST(FUNC) 233#else 234#define CALL_SUBTEST_1(FUNC) 235#endif 236 237#ifdef EIGEN_TEST_PART_2 238#define CALL_SUBTEST_2(FUNC) CALL_SUBTEST(FUNC) 239#else 240#define CALL_SUBTEST_2(FUNC) 241#endif 242 243#ifdef EIGEN_TEST_PART_3 244#define CALL_SUBTEST_3(FUNC) CALL_SUBTEST(FUNC) 245#else 246#define CALL_SUBTEST_3(FUNC) 247#endif 248 249#ifdef EIGEN_TEST_PART_4 250#define CALL_SUBTEST_4(FUNC) CALL_SUBTEST(FUNC) 251#else 252#define CALL_SUBTEST_4(FUNC) 253#endif 254 255#ifdef EIGEN_TEST_PART_5 256#define CALL_SUBTEST_5(FUNC) CALL_SUBTEST(FUNC) 257#else 258#define CALL_SUBTEST_5(FUNC) 259#endif 260 261#ifdef EIGEN_TEST_PART_6 262#define CALL_SUBTEST_6(FUNC) CALL_SUBTEST(FUNC) 263#else 264#define CALL_SUBTEST_6(FUNC) 265#endif 266 267#ifdef EIGEN_TEST_PART_7 268#define CALL_SUBTEST_7(FUNC) CALL_SUBTEST(FUNC) 269#else 270#define CALL_SUBTEST_7(FUNC) 271#endif 272 273#ifdef EIGEN_TEST_PART_8 274#define CALL_SUBTEST_8(FUNC) CALL_SUBTEST(FUNC) 275#else 276#define CALL_SUBTEST_8(FUNC) 277#endif 278 279#ifdef EIGEN_TEST_PART_9 280#define CALL_SUBTEST_9(FUNC) CALL_SUBTEST(FUNC) 281#else 282#define CALL_SUBTEST_9(FUNC) 283#endif 284 285#ifdef EIGEN_TEST_PART_10 286#define CALL_SUBTEST_10(FUNC) CALL_SUBTEST(FUNC) 287#else 288#define CALL_SUBTEST_10(FUNC) 289#endif 290 291#ifdef EIGEN_TEST_PART_11 292#define CALL_SUBTEST_11(FUNC) CALL_SUBTEST(FUNC) 293#else 294#define CALL_SUBTEST_11(FUNC) 295#endif 296 297#ifdef EIGEN_TEST_PART_12 298#define CALL_SUBTEST_12(FUNC) CALL_SUBTEST(FUNC) 299#else 300#define CALL_SUBTEST_12(FUNC) 301#endif 302 303#ifdef EIGEN_TEST_PART_13 304#define CALL_SUBTEST_13(FUNC) CALL_SUBTEST(FUNC) 305#else 306#define CALL_SUBTEST_13(FUNC) 307#endif 308 309#ifdef EIGEN_TEST_PART_14 310#define CALL_SUBTEST_14(FUNC) CALL_SUBTEST(FUNC) 311#else 312#define CALL_SUBTEST_14(FUNC) 313#endif 314 315#ifdef EIGEN_TEST_PART_15 316#define CALL_SUBTEST_15(FUNC) CALL_SUBTEST(FUNC) 317#else 318#define CALL_SUBTEST_15(FUNC) 319#endif 320 321#ifdef EIGEN_TEST_PART_16 322#define CALL_SUBTEST_16(FUNC) CALL_SUBTEST(FUNC) 323#else 324#define CALL_SUBTEST_16(FUNC) 325#endif 326 327 328 329int main(int argc, char *argv[]) 330{ 331 bool has_set_repeat = false; 332 bool has_set_seed = false; 333 bool need_help = false; 334 unsigned int seed = 0; 335 int repeat = DEFAULT_REPEAT; 336 337 for(int i = 1; i < argc; i++) 338 { 339 if(argv[i][0] == 'r') 340 { 341 if(has_set_repeat) 342 { 343 std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl; 344 return 1; 345 } 346 repeat = std::atoi(argv[i]+1); 347 has_set_repeat = true; 348 if(repeat <= 0) 349 { 350 std::cout << "Invalid \'repeat\' value " << argv[i]+1 << std::endl; 351 return 1; 352 } 353 } 354 else if(argv[i][0] == 's') 355 { 356 if(has_set_seed) 357 { 358 std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl; 359 return 1; 360 } 361 seed = int(std::strtoul(argv[i]+1, 0, 10)); 362 has_set_seed = true; 363 bool ok = seed!=0; 364 if(!ok) 365 { 366 std::cout << "Invalid \'seed\' value " << argv[i]+1 << std::endl; 367 return 1; 368 } 369 } 370 else 371 { 372 need_help = true; 373 } 374 } 375 376 if(need_help) 377 { 378 std::cout << "This test application takes the following optional arguments:" << std::endl; 379 std::cout << " rN Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl; 380 std::cout << " sN Use N as seed for random numbers (default: based on current time)" << std::endl; 381 return 1; 382 } 383 384 if(!has_set_seed) seed = (unsigned int) std::time(NULL); 385 if(!has_set_repeat) repeat = DEFAULT_REPEAT; 386 387 std::cout << "Initializing random number generator with seed " << seed << std::endl; 388 std::srand(seed); 389 std::cout << "Repeating each test " << repeat << " times" << std::endl; 390 391 Eigen::g_repeat = repeat; 392 Eigen::g_test_stack.push_back(EI_PP_MAKE_STRING(EIGEN_TEST_FUNC)); 393 394 EI_PP_CAT(test_,EIGEN_TEST_FUNC)(); 395 return 0; 396} 397 398 399 400