// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #include #include #include #include #include #include #ifndef EIGEN_TEST_FUNC #error EIGEN_TEST_FUNC must be defined #endif #define DEFAULT_REPEAT 10 namespace Eigen { static std::vector g_test_stack; static int g_repeat; } #define EI_PP_MAKE_STRING2(S) #S #define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S) #define EIGEN_DEFAULT_IO_FORMAT IOFormat(4, 0, " ", "\n", "", "", "", "") #ifndef EIGEN_NO_ASSERTION_CHECKING namespace Eigen { static const bool should_raise_an_assert = false; // Used to avoid to raise two exceptions at a time in which // case the exception is not properly caught. // This may happen when a second exceptions is raise in a destructor. static bool no_more_assert = false; struct ei_assert_exception { ei_assert_exception(void) {} ~ei_assert_exception() { Eigen::no_more_assert = false; } }; } // If EIGEN_DEBUG_ASSERTS is defined and if no assertion is raised while // one should have been, then the list of excecuted assertions is printed out. // // EIGEN_DEBUG_ASSERTS is not enabled by default as it // significantly increases the compilation time // and might even introduce side effects that would hide // some memory errors. #ifdef EIGEN_DEBUG_ASSERTS namespace Eigen { static bool ei_push_assert = false; static std::vector ei_assert_list; } #define ei_assert(a) \ if( (!(a)) && (!no_more_assert) ) \ { \ Eigen::no_more_assert = true; \ throw Eigen::ei_assert_exception(); \ } \ else if (Eigen::ei_push_assert) \ { \ ei_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__)" ("EI_PP_MAKE_STRING(__LINE__)") : "#a) ); \ } #define VERIFY_RAISES_ASSERT(a) \ { \ Eigen::no_more_assert = false; \ try { \ Eigen::ei_assert_list.clear(); \ Eigen::ei_push_assert = true; \ a; \ Eigen::ei_push_assert = false; \ std::cerr << "One of the following asserts should have been raised:\n"; \ for (uint ai=0 ; ai #include // required for createRandomMatrixOfRank #define VERIFY(a) do { if (!(a)) { \ std::cerr << "Test " << g_test_stack.back() << " failed in "EI_PP_MAKE_STRING(__FILE__) << " (" << EI_PP_MAKE_STRING(__LINE__) << ")" \ << std::endl << " " << EI_PP_MAKE_STRING(a) << std::endl << std::endl; \ exit(2); \ } } while (0) #define VERIFY_IS_APPROX(a, b) VERIFY(test_ei_isApprox(a, b)) #define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_ei_isApprox(a, b)) #define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_ei_isMuchSmallerThan(a, b)) #define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_ei_isMuchSmallerThan(a, b)) #define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_ei_isApproxOrLessThan(a, b)) #define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_ei_isApproxOrLessThan(a, b)) #define VERIFY_IS_UNITARY(a) VERIFY(test_isUnitary(a)) #define CALL_SUBTEST(FUNC) do { \ g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \ FUNC; \ g_test_stack.pop_back(); \ } while (0) namespace Eigen { template inline typename NumTraits::Real test_precision(); template<> inline int test_precision() { return 0; } template<> inline float test_precision() { return 1e-3f; } template<> inline double test_precision() { return 1e-6; } template<> inline float test_precision >() { return test_precision(); } template<> inline double test_precision >() { return test_precision(); } template<> inline long double test_precision() { return 1e-6; } inline bool test_ei_isApprox(const int& a, const int& b) { return ei_isApprox(a, b, test_precision()); } inline bool test_ei_isMuchSmallerThan(const int& a, const int& b) { return ei_isMuchSmallerThan(a, b, test_precision()); } inline bool test_ei_isApproxOrLessThan(const int& a, const int& b) { return ei_isApproxOrLessThan(a, b, test_precision()); } inline bool test_ei_isApprox(const float& a, const float& b) { return ei_isApprox(a, b, test_precision()); } inline bool test_ei_isMuchSmallerThan(const float& a, const float& b) { return ei_isMuchSmallerThan(a, b, test_precision()); } inline bool test_ei_isApproxOrLessThan(const float& a, const float& b) { return ei_isApproxOrLessThan(a, b, test_precision()); } inline bool test_ei_isApprox(const double& a, const double& b) { return ei_isApprox(a, b, test_precision()); } inline bool test_ei_isMuchSmallerThan(const double& a, const double& b) { return ei_isMuchSmallerThan(a, b, test_precision()); } inline bool test_ei_isApproxOrLessThan(const double& a, const double& b) { return ei_isApproxOrLessThan(a, b, test_precision()); } inline bool test_ei_isApprox(const std::complex& a, const std::complex& b) { return ei_isApprox(a, b, test_precision >()); } inline bool test_ei_isMuchSmallerThan(const std::complex& a, const std::complex& b) { return ei_isMuchSmallerThan(a, b, test_precision >()); } inline bool test_ei_isApprox(const std::complex& a, const std::complex& b) { return ei_isApprox(a, b, test_precision >()); } inline bool test_ei_isMuchSmallerThan(const std::complex& a, const std::complex& b) { return ei_isMuchSmallerThan(a, b, test_precision >()); } inline bool test_ei_isApprox(const long double& a, const long double& b) { return ei_isApprox(a, b, test_precision()); } inline bool test_ei_isMuchSmallerThan(const long double& a, const long double& b) { return ei_isMuchSmallerThan(a, b, test_precision()); } inline bool test_ei_isApproxOrLessThan(const long double& a, const long double& b) { return ei_isApproxOrLessThan(a, b, test_precision()); } template inline bool test_ei_isApprox(const Type1& a, const Type2& b) { return a.isApprox(b, test_precision()); } template inline bool test_ei_isMuchSmallerThan(const MatrixBase& m1, const MatrixBase& m2) { return m1.isMuchSmallerThan(m2, test_precision::Scalar>()); } template inline bool test_ei_isMuchSmallerThan(const MatrixBase& m, const typename NumTraits::Scalar>::Real& s) { return m.isMuchSmallerThan(s, test_precision::Scalar>()); } template inline bool test_isUnitary(const MatrixBase& m) { return m.isUnitary(test_precision::Scalar>()); } template void createRandomMatrixOfRank(int desired_rank, int rows, int cols, MatrixType& m) { typedef typename ei_traits::Scalar Scalar; typedef Matrix VectorType; MatrixType a = MatrixType::Random(rows,rows); MatrixType d = MatrixType::Identity(rows,cols); MatrixType b = MatrixType::Random(cols,cols); // set the diagonal such that only desired_rank non-zero entries reamain const int diag_size = std::min(d.rows(),d.cols()); d.diagonal().segment(desired_rank, diag_size-desired_rank) = VectorType::Zero(diag_size-desired_rank); HouseholderQR qra(a); HouseholderQR qrb(b); m = qra.matrixQ() * d * qrb.matrixQ(); } } // end namespace Eigen template struct GetDifferentType; template<> struct GetDifferentType { typedef double type; }; template<> struct GetDifferentType { typedef float type; }; template struct GetDifferentType > { typedef std::complex::type> type; }; // forward declaration of the main test function void EIGEN_CAT(test_,EIGEN_TEST_FUNC)(); using namespace Eigen; int main(int argc, char *argv[]) { bool has_set_repeat = false; bool has_set_seed = false; bool need_help = false; unsigned int seed = 0; int repeat = DEFAULT_REPEAT; for(int i = 1; i < argc; i++) { if(argv[i][0] == 'r') { if(has_set_repeat) { std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl; return 1; } repeat = atoi(argv[i]+1); has_set_repeat = true; if(repeat <= 0) { std::cout << "Invalid \'repeat\' value " << argv[i]+1 << std::endl; return 1; } } else if(argv[i][0] == 's') { if(has_set_seed) { std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl; return 1; } seed = int(strtoul(argv[i]+1, 0, 10)); has_set_seed = true; bool ok = seed!=0; if(!ok) { std::cout << "Invalid \'seed\' value " << argv[i]+1 << std::endl; return 1; } } else { need_help = true; } } if(need_help) { std::cout << "This test application takes the following optional arguments:" << std::endl; std::cout << " rN Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl; std::cout << " sN Use N as seed for random numbers (default: based on current time)" << std::endl; return 1; } if(!has_set_seed) seed = (unsigned int) time(NULL); if(!has_set_repeat) repeat = DEFAULT_REPEAT; std::cout << "Initializing random number generator with seed " << seed << std::endl; srand(seed); std::cout << "Repeating each test " << repeat << " times" << std::endl; Eigen::g_repeat = repeat; Eigen::g_test_stack.push_back(EI_PP_MAKE_STRING(EIGEN_TEST_FUNC)); EIGEN_CAT(test_,EIGEN_TEST_FUNC)(); return 0; }