diff options
Diffstat (limited to 'eigen/test/main.h')
-rw-r--r-- | eigen/test/main.h | 284 |
1 files changed, 239 insertions, 45 deletions
diff --git a/eigen/test/main.h b/eigen/test/main.h index 6642048..25d2dcf 100644 --- a/eigen/test/main.h +++ b/eigen/test/main.h @@ -41,7 +41,14 @@ #include <complex> #include <deque> #include <queue> +#include <cassert> #include <list> +#if __cplusplus >= 201103L +#include <random> +#ifdef EIGEN_USE_THREADS +#include <future> +#endif +#endif // To test that all calls from Eigen code to std::min() and std::max() are // protected by parenthesis against macro expansion, the min()/max() macros @@ -49,14 +56,48 @@ // compiler error. #define min(A,B) please_protect_your_min_with_parentheses #define max(A,B) please_protect_your_max_with_parentheses +#define isnan(X) please_protect_your_isnan_with_parentheses +#define isinf(X) please_protect_your_isinf_with_parentheses +#define isfinite(X) please_protect_your_isfinite_with_parentheses +#ifdef M_PI +#undef M_PI +#endif +#define M_PI please_use_EIGEN_PI_instead_of_M_PI #define FORBIDDEN_IDENTIFIER (this_identifier_is_forbidden_to_avoid_clashes) this_identifier_is_forbidden_to_avoid_clashes // B0 is defined in POSIX header termios.h #define B0 FORBIDDEN_IDENTIFIER +// Unit tests calling Eigen's blas library must preserve the default blocking size +// to avoid troubles. +#ifndef EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS +#define EIGEN_DEBUG_SMALL_PRODUCT_BLOCKS +#endif // shuts down ICC's remark #593: variable "XXX" was set but never used -#define TEST_SET_BUT_UNUSED_VARIABLE(X) X = X + 0; +#define TEST_SET_BUT_UNUSED_VARIABLE(X) EIGEN_UNUSED_VARIABLE(X) + +#ifdef TEST_ENABLE_TEMPORARY_TRACKING + +static long int nb_temporaries; +static long int nb_temporaries_on_assert = -1; + +inline void on_temporary_creation(long int size) { + // here's a great place to set a breakpoint when debugging failures in this test! + if(size!=0) nb_temporaries++; + if(nb_temporaries_on_assert>0) assert(nb_temporaries<nb_temporaries_on_assert); +} + +#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { on_temporary_creation(size); } + +#define VERIFY_EVALUATION_COUNT(XPR,N) {\ + nb_temporaries = 0; \ + XPR; \ + if(nb_temporaries!=N) { std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; }\ + VERIFY( (#XPR) && nb_temporaries==N ); \ + } + +#endif // the following file is automatically generated by cmake #include "split_test_helper.h" @@ -71,7 +112,7 @@ #endif // bounds integer values for AltiVec -#ifdef __ALTIVEC__ +#if defined(__ALTIVEC__) || defined(__VSX__) #define EIGEN_MAKING_DOCS #endif @@ -84,16 +125,26 @@ namespace Eigen { static std::vector<std::string> g_test_stack; + // level == 0 <=> abort if test fail + // level >= 1 <=> warning message to std::cerr if test fail + static int g_test_level = 0; static int g_repeat; static unsigned int g_seed; static bool g_has_set_repeat, g_has_set_seed; } +#define TRACK std::cerr << __FILE__ << " " << __LINE__ << std::endl +// #define TRACK while() + #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", "", "", "", "") +#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(__CUDA_ARCH__) + #define EIGEN_EXCEPTIONS +#endif + #ifndef EIGEN_NO_ASSERTION_CHECKING namespace Eigen @@ -135,33 +186,35 @@ namespace Eigen if(report_on_cerr_on_assert_failure) \ std::cerr << #a << " " __FILE__ << "(" << __LINE__ << ")\n"; \ Eigen::no_more_assert = true; \ - throw Eigen::eigen_assert_exception(); \ + EIGEN_THROW_X(Eigen::eigen_assert_exception()); \ } \ else if (Eigen::internal::push_assert) \ { \ eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__) " (" EI_PP_MAKE_STRING(__LINE__) ") : " #a) ); \ } + #ifdef EIGEN_EXCEPTIONS #define VERIFY_RAISES_ASSERT(a) \ { \ Eigen::no_more_assert = false; \ - Eigen::eigen_assert_list.clear(); \ - Eigen::internal::push_assert = true; \ + Eigen::eigen_assert_list.clear(); \ + Eigen::internal::push_assert = true; \ Eigen::report_on_cerr_on_assert_failure = false; \ try { \ a; \ std::cerr << "One of the following asserts should have been triggered:\n"; \ - for (uint ai=0 ; ai<eigen_assert_list.size() ; ++ai) \ - std::cerr << " " << eigen_assert_list[ai] << "\n"; \ + for (uint ai=0 ; ai<eigen_assert_list.size() ; ++ai) \ + std::cerr << " " << eigen_assert_list[ai] << "\n"; \ VERIFY(Eigen::should_raise_an_assert && # a); \ - } catch (Eigen::eigen_assert_exception) { \ - Eigen::internal::push_assert = false; VERIFY(true); \ + } catch (Eigen::eigen_assert_exception) { \ + Eigen::internal::push_assert = false; VERIFY(true); \ } \ Eigen::report_on_cerr_on_assert_failure = true; \ - Eigen::internal::push_assert = false; \ + Eigen::internal::push_assert = false; \ } + #endif //EIGEN_EXCEPTIONS - #else // EIGEN_DEBUG_ASSERTS + #elif !defined(__CUDACC__) // EIGEN_DEBUG_ASSERTS // see bug 89. The copy_bool here is working around a bug in gcc <= 4.3 #define eigen_assert(a) \ if( (!Eigen::internal::copy_bool(a)) && (!no_more_assert) )\ @@ -170,22 +223,30 @@ namespace Eigen if(report_on_cerr_on_assert_failure) \ eigen_plain_assert(a); \ else \ - throw Eigen::eigen_assert_exception(); \ + EIGEN_THROW_X(Eigen::eigen_assert_exception()); \ } - #define VERIFY_RAISES_ASSERT(a) { \ + #ifdef EIGEN_EXCEPTIONS + #define VERIFY_RAISES_ASSERT(a) { \ Eigen::no_more_assert = false; \ Eigen::report_on_cerr_on_assert_failure = false; \ try { \ a; \ VERIFY(Eigen::should_raise_an_assert && # a); \ } \ - catch (Eigen::eigen_assert_exception&) { VERIFY(true); } \ + catch (Eigen::eigen_assert_exception&) { VERIFY(true); } \ Eigen::report_on_cerr_on_assert_failure = true; \ } - + #endif //EIGEN_EXCEPTIONS #endif // EIGEN_DEBUG_ASSERTS +#ifndef VERIFY_RAISES_ASSERT + #define VERIFY_RAISES_ASSERT(a) \ + std::cout << "Can't VERIFY_RAISES_ASSERT( " #a " ) with exceptions disabled\n"; +#endif + + #if !defined(__CUDACC__) #define EIGEN_USE_CUSTOM_ASSERT + #endif #else // EIGEN_NO_ASSERTION_CHECKING @@ -201,6 +262,8 @@ inline void verify_impl(bool condition, const char *testname, const char *file, { if (!condition) { + if(Eigen::g_test_level>0) + std::cerr << "WARNING: "; std::cerr << "Test " << testname << " failed in " << file << " (" << line << ")" << std::endl << " " << condition_as_string << std::endl; std::cerr << "Stack:\n"; @@ -208,14 +271,20 @@ inline void verify_impl(bool condition, const char *testname, const char *file, for(int i=test_stack_size-1; i>=0; --i) std::cerr << " - " << Eigen::g_test_stack[i] << "\n"; std::cerr << "\n"; - abort(); + if(Eigen::g_test_level==0) + abort(); } } #define VERIFY(a) ::verify_impl(a, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a)) -#define VERIFY_IS_EQUAL(a, b) VERIFY(test_is_equal(a, b)) -#define VERIFY_IS_APPROX(a, b) VERIFY(test_isApprox(a, b)) +#define VERIFY_GE(a, b) ::verify_impl(a >= b, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a >= b)) +#define VERIFY_LE(a, b) ::verify_impl(a <= b, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a <= b)) + + +#define VERIFY_IS_EQUAL(a, b) VERIFY(test_is_equal(a, b, true)) +#define VERIFY_IS_NOT_EQUAL(a, b) VERIFY(test_is_equal(a, b, false)) +#define VERIFY_IS_APPROX(a, b) VERIFY(verifyIsApprox(a, b)) #define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_isApprox(a, b)) #define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_isMuchSmallerThan(a, b)) #define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_isMuchSmallerThan(a, b)) @@ -236,9 +305,10 @@ namespace Eigen { template<typename T> inline typename NumTraits<T>::Real test_precision() { return NumTraits<T>::dummy_precision(); } template<> inline float test_precision<float>() { return 1e-3f; } template<> inline double test_precision<double>() { return 1e-6; } +template<> inline long double test_precision<long double>() { return 1e-6l; } template<> inline float test_precision<std::complex<float> >() { return test_precision<float>(); } template<> inline double test_precision<std::complex<double> >() { return test_precision<double>(); } -template<> inline long double test_precision<long double>() { return 1e-6; } +template<> inline long double test_precision<std::complex<long double> >() { return test_precision<long double>(); } inline bool test_isApprox(const int& a, const int& b) { return internal::isApprox(a, b, test_precision<int>()); } @@ -253,14 +323,15 @@ inline bool test_isMuchSmallerThan(const float& a, const float& b) { return internal::isMuchSmallerThan(a, b, test_precision<float>()); } inline bool test_isApproxOrLessThan(const float& a, const float& b) { return internal::isApproxOrLessThan(a, b, test_precision<float>()); } + inline bool test_isApprox(const double& a, const double& b) { return internal::isApprox(a, b, test_precision<double>()); } - inline bool test_isMuchSmallerThan(const double& a, const double& b) { return internal::isMuchSmallerThan(a, b, test_precision<double>()); } inline bool test_isApproxOrLessThan(const double& a, const double& b) { return internal::isApproxOrLessThan(a, b, test_precision<double>()); } +#ifndef EIGEN_TEST_NO_COMPLEX inline bool test_isApprox(const std::complex<float>& a, const std::complex<float>& b) { return internal::isApprox(a, b, test_precision<std::complex<float> >()); } inline bool test_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b) @@ -271,6 +342,15 @@ inline bool test_isApprox(const std::complex<double>& a, const std::complex<doub inline bool test_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b) { return internal::isMuchSmallerThan(a, b, test_precision<std::complex<double> >()); } +#ifndef EIGEN_TEST_NO_LONGDOUBLE +inline bool test_isApprox(const std::complex<long double>& a, const std::complex<long double>& b) +{ return internal::isApprox(a, b, test_precision<std::complex<long double> >()); } +inline bool test_isMuchSmallerThan(const std::complex<long double>& a, const std::complex<long double>& b) +{ return internal::isMuchSmallerThan(a, b, test_precision<std::complex<long double> >()); } +#endif +#endif + +#ifndef EIGEN_TEST_NO_LONGDOUBLE inline bool test_isApprox(const long double& a, const long double& b) { bool ret = internal::isApprox(a, b, test_precision<long double>()); @@ -284,13 +364,127 @@ inline bool test_isMuchSmallerThan(const long double& a, const long double& b) { return internal::isMuchSmallerThan(a, b, test_precision<long double>()); } inline bool test_isApproxOrLessThan(const long double& a, const long double& b) { return internal::isApproxOrLessThan(a, b, test_precision<long double>()); } +#endif // EIGEN_TEST_NO_LONGDOUBLE + +inline bool test_isApprox(const half& a, const half& b) +{ return internal::isApprox(a, b, test_precision<half>()); } +inline bool test_isMuchSmallerThan(const half& a, const half& b) +{ return internal::isMuchSmallerThan(a, b, test_precision<half>()); } +inline bool test_isApproxOrLessThan(const half& a, const half& b) +{ return internal::isApproxOrLessThan(a, b, test_precision<half>()); } + +// test_relative_error returns the relative difference between a and b as a real scalar as used in isApprox. +template<typename T1,typename T2> +typename NumTraits<typename T1::RealScalar>::NonInteger test_relative_error(const EigenBase<T1> &a, const EigenBase<T2> &b) +{ + using std::sqrt; + typedef typename NumTraits<typename T1::RealScalar>::NonInteger RealScalar; + typename internal::nested_eval<T1,2>::type ea(a.derived()); + typename internal::nested_eval<T2,2>::type eb(b.derived()); + return sqrt(RealScalar((ea-eb).cwiseAbs2().sum()) / RealScalar((std::min)(eb.cwiseAbs2().sum(),ea.cwiseAbs2().sum()))); +} + +template<typename T1,typename T2> +typename T1::RealScalar test_relative_error(const T1 &a, const T2 &b, const typename T1::Coefficients* = 0) +{ + return test_relative_error(a.coeffs(), b.coeffs()); +} + +template<typename T1,typename T2> +typename T1::Scalar test_relative_error(const T1 &a, const T2 &b, const typename T1::MatrixType* = 0) +{ + return test_relative_error(a.matrix(), b.matrix()); +} + +template<typename S, int D> +S test_relative_error(const Translation<S,D> &a, const Translation<S,D> &b) +{ + return test_relative_error(a.vector(), b.vector()); +} + +template <typename S, int D, int O> +S test_relative_error(const ParametrizedLine<S,D,O> &a, const ParametrizedLine<S,D,O> &b) +{ + return (std::max)(test_relative_error(a.origin(), b.origin()), test_relative_error(a.origin(), b.origin())); +} + +template <typename S, int D> +S test_relative_error(const AlignedBox<S,D> &a, const AlignedBox<S,D> &b) +{ + return (std::max)(test_relative_error((a.min)(), (b.min)()), test_relative_error((a.max)(), (b.max)())); +} + +template<typename Derived> class SparseMatrixBase; +template<typename T1,typename T2> +typename T1::RealScalar test_relative_error(const MatrixBase<T1> &a, const SparseMatrixBase<T2> &b) +{ + return test_relative_error(a,b.toDense()); +} + +template<typename Derived> class SparseMatrixBase; +template<typename T1,typename T2> +typename T1::RealScalar test_relative_error(const SparseMatrixBase<T1> &a, const MatrixBase<T2> &b) +{ + return test_relative_error(a.toDense(),b); +} + +template<typename Derived> class SparseMatrixBase; +template<typename T1,typename T2> +typename T1::RealScalar test_relative_error(const SparseMatrixBase<T1> &a, const SparseMatrixBase<T2> &b) +{ + return test_relative_error(a.toDense(),b.toDense()); +} + +template<typename T1,typename T2> +typename NumTraits<typename NumTraits<T1>::Real>::NonInteger test_relative_error(const T1 &a, const T2 &b, typename internal::enable_if<internal::is_arithmetic<typename NumTraits<T1>::Real>::value, T1>::type* = 0) +{ + typedef typename NumTraits<typename NumTraits<T1>::Real>::NonInteger RealScalar; + return numext::sqrt(RealScalar(numext::abs2(a-b))/RealScalar((numext::mini)(numext::abs2(a),numext::abs2(b)))); +} + +template<typename T> +T test_relative_error(const Rotation2D<T> &a, const Rotation2D<T> &b) +{ + return test_relative_error(a.angle(), b.angle()); +} + +template<typename T> +T test_relative_error(const AngleAxis<T> &a, const AngleAxis<T> &b) +{ + return (std::max)(test_relative_error(a.angle(), b.angle()), test_relative_error(a.axis(), b.axis())); +} template<typename Type1, typename Type2> -inline bool test_isApprox(const Type1& a, const Type2& b) +inline bool test_isApprox(const Type1& a, const Type2& b, typename Type1::Scalar* = 0) // Enabled for Eigen's type only { return a.isApprox(b, test_precision<typename Type1::Scalar>()); } +// get_test_precision is a small wrapper to test_precision allowing to return the scalar precision for either scalars or expressions +template<typename T> +typename NumTraits<typename T::Scalar>::Real get_test_precision(const T&, const typename T::Scalar* = 0) +{ + return test_precision<typename NumTraits<typename T::Scalar>::Real>(); +} + +template<typename T> +typename NumTraits<T>::Real get_test_precision(const T&,typename internal::enable_if<internal::is_arithmetic<typename NumTraits<T>::Real>::value, T>::type* = 0) +{ + return test_precision<typename NumTraits<T>::Real>(); +} + +// verifyIsApprox is a wrapper to test_isApprox that outputs the relative difference magnitude if the test fails. +template<typename Type1, typename Type2> +inline bool verifyIsApprox(const Type1& a, const Type2& b) +{ + bool ret = test_isApprox(a,b); + if(!ret) + { + std::cerr << "Difference too large wrt tolerance " << get_test_precision(a) << ", relative error is: " << test_relative_error(a,b) << std::endl; + } + return ret; +} + // The idea behind this function is to compare the two scalars a and b where // the scalar ref is a hint about the expected order of magnitude of a and b. // WARNING: the scalar a and b must be positive @@ -326,17 +520,17 @@ inline bool test_isUnitary(const MatrixBase<Derived>& m) // Forward declaration to avoid ICC warning template<typename T, typename U> -bool test_is_equal(const T& actual, const U& expected); +bool test_is_equal(const T& actual, const U& expected, bool expect_equal=true); template<typename T, typename U> -bool test_is_equal(const T& actual, const U& expected) +bool test_is_equal(const T& actual, const U& expected, bool expect_equal) { - if (actual==expected) + if ((actual==expected) == expect_equal) return true; // false: std::cerr - << std::endl << " actual = " << actual - << std::endl << " expected = " << expected << std::endl << std::endl; + << "\n actual = " << actual + << "\n expected " << (expect_equal ? "= " : "!=") << expected << "\n\n"; return false; } @@ -347,11 +541,10 @@ bool test_is_equal(const T& actual, const U& expected) */ // Forward declaration to avoid ICC warning template<typename MatrixType> -void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typename MatrixType::Index rows, typename MatrixType::Index cols, MatrixType& m); +void createRandomPIMatrixOfRank(Index desired_rank, Index rows, Index cols, MatrixType& m); template<typename MatrixType> -void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typename MatrixType::Index rows, typename MatrixType::Index cols, MatrixType& m) +void createRandomPIMatrixOfRank(Index desired_rank, Index rows, Index cols, MatrixType& m) { - typedef typename internal::traits<MatrixType>::Index Index; typedef typename internal::traits<MatrixType>::Scalar Scalar; enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime }; @@ -388,11 +581,10 @@ void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typenam // Forward declaration to avoid ICC warning template<typename PermutationVectorType> -void randomPermutationVector(PermutationVectorType& v, typename PermutationVectorType::Index size); +void randomPermutationVector(PermutationVectorType& v, Index size); template<typename PermutationVectorType> -void randomPermutationVector(PermutationVectorType& v, typename PermutationVectorType::Index size) +void randomPermutationVector(PermutationVectorType& v, Index size) { - typedef typename PermutationVectorType::Index Index; typedef typename PermutationVectorType::Scalar Scalar; v.resize(size); for(Index i = 0; i < size; ++i) v(i) = Scalar(i); @@ -411,12 +603,7 @@ template<typename T> bool isNotNaN(const T& x) return x==x; } -template<typename T> bool isNaN(const T& x) -{ - return x!=x; -} - -template<typename T> bool isInf(const T& x) +template<typename T> bool isPlusInf(const T& x) { return x > NumTraits<T>::highest(); } @@ -437,13 +624,15 @@ template<typename T> struct GetDifferentType<std::complex<T> > // Forward declaration to avoid ICC warning template<typename T> std::string type_name(); -template<typename T> std::string type_name() { return "other"; } -template<> std::string type_name<float>() { return "float"; } -template<> std::string type_name<double>() { return "double"; } -template<> std::string type_name<int>() { return "int"; } -template<> std::string type_name<std::complex<float> >() { return "complex<float>"; } -template<> std::string type_name<std::complex<double> >() { return "complex<double>"; } -template<> std::string type_name<std::complex<int> >() { return "complex<int>"; } +template<typename T> std::string type_name() { return "other"; } +template<> std::string type_name<float>() { return "float"; } +template<> std::string type_name<double>() { return "double"; } +template<> std::string type_name<long double>() { return "long double"; } +template<> std::string type_name<int>() { return "int"; } +template<> std::string type_name<std::complex<float> >() { return "complex<float>"; } +template<> std::string type_name<std::complex<double> >() { return "complex<double>"; } +template<> std::string type_name<std::complex<long double> >() { return "complex<long double>"; } +template<> std::string type_name<std::complex<int> >() { return "complex<int>"; } // forward declaration of the main test function void EIGEN_CAT(test_,EIGEN_TEST_FUNC)(); @@ -550,3 +739,8 @@ int main(int argc, char *argv[]) // remark #1572: floating-point equality and inequality comparisons are unreliable #pragma warning disable 279 383 1418 1572 #endif + +#ifdef _MSC_VER + // 4503 - decorated name length exceeded, name was truncated + #pragma warning( disable : 4503) +#endif |