Update Eigen NumTraits code.

Eigen's requirements have changed in version 3.4.
Also improve testing and better support variable precision types.
This commit is contained in:
jzmaddock
2021-12-09 15:40:48 +00:00
parent 785772b494
commit c5eda8ad18
11 changed files with 321 additions and 24 deletions

View File

@@ -13,14 +13,18 @@
// Generic Eigen support code:
//
namespace Eigen {
template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
struct NumTraits<boost::multiprecision::number<Backend, ExpressionTemplates> >
template <class B1, class B2>
struct NumTraitsImp;
template <class B1>
struct NumTraitsImp<B1, B1>
{
using self_type = boost::multiprecision::number<Backend, ExpressionTemplates> ;
using Real = typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type;
using NonInteger = self_type ; // Not correct but we can't do much better??
using Literal = double ;
using Nested = self_type ;
using self_type = B1;
using Real = typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type;
using NonInteger = self_type; // Not correct but we can't do much better??
using Literal = double;
using Nested = self_type;
enum
{
IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex,
@@ -33,6 +37,7 @@ struct NumTraits<boost::multiprecision::number<Backend, ExpressionTemplates> >
};
static Real epsilon()
{
static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?");
return std::numeric_limits<Real>::epsilon();
}
static Real dummy_precision()
@@ -41,14 +46,17 @@ struct NumTraits<boost::multiprecision::number<Backend, ExpressionTemplates> >
}
static Real highest()
{
static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?");
return (std::numeric_limits<Real>::max)();
}
static Real lowest()
{
static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?");
return (std::numeric_limits<Real>::min)();
}
static int digits10_imp(const std::integral_constant<bool, true>&)
{
static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?");
return std::numeric_limits<Real>::digits10;
}
template <bool B>
@@ -58,13 +66,107 @@ struct NumTraits<boost::multiprecision::number<Backend, ExpressionTemplates> >
}
static int digits10()
{
return digits10_imp(std::integral_constant<bool, std::numeric_limits<Real>::digits10 && (std::numeric_limits<Real>::digits10 != INT_MAX) ? true : false > ());
return digits10_imp(std::integral_constant < bool, std::numeric_limits<Real>::digits10 && (std::numeric_limits<Real>::digits10 != INT_MAX) ? true : false > ());
}
static int digits()
{
// return the number of digits in the component type in case Real is complex
// and we have no numeric_limits specialization.
static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?");
return std::numeric_limits<Real>::digits;
}
static int min_exponent()
{
static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?");
return std::numeric_limits<Real>::min_exponent;
}
static int max_exponent()
{
static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?");
return std::numeric_limits<Real>::max_exponent;
}
static Real infinity()
{
static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?");
return std::numeric_limits<Real>::infinity();
}
static Real quiet_NaN()
{
static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?");
return std::numeric_limits<Real>::quiet_NaN();
}
};
template <class B1, class B2>
struct NumTraitsImp : public NumTraitsImp<B2, B2>
{
//
// This version is instantiated when B1 and B2 are different types, this happens for rational/complex/interval
// types, in which case many methods defer to those of the "component type" B2.
//
using self_type = B1;
using Real = typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type;
using NonInteger = self_type; // Not correct but we can't do much better??
using Literal = double;
using Nested = self_type;
enum
{
IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex,
IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer,
ReadCost = 1,
AddCost = 4,
MulCost = 8,
IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true,
RequireInitialization = 1,
};
static B2 epsilon()
{
return NumTraitsImp<B2, B2>::epsilon();
}
static B2 dummy_precision()
{
return 1000 * epsilon();
}
static B2 highest()
{
return NumTraitsImp<B2, B2>::highest();
}
static B2 lowest()
{
return NumTraitsImp<B2, B2>::lowest();
}
static int digits10()
{
return NumTraitsImp<B2, B2>::digits10();
}
static int digits()
{
return NumTraitsImp<B2, B2>::digits();
}
static int min_exponent()
{
return NumTraitsImp<B2, B2>::min_exponent();
}
static int max_exponent()
{
return NumTraitsImp<B2, B2>::max_exponent();
}
static B2 infinity()
{
return NumTraitsImp<B2, B2>::infinity();
}
static B2 quiet_NaN()
{
return NumTraitsImp<B2, B2>::quiet_NaN();
}
};
template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
struct NumTraits<boost::multiprecision::number<Backend, ExpressionTemplates> > : public NumTraitsImp<boost::multiprecision::number<Backend, ExpressionTemplates>, typename boost::multiprecision::number<Backend, ExpressionTemplates>::value_type>
{};
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
struct NumTraits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > : public NumTraits<typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>
{
};
{};
#define BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(A) \
template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp> \

View File

@@ -3609,4 +3609,73 @@ constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::
} // namespace std
namespace Eigen
{
template <class B1, class B2>
struct NumTraitsImp;
template <boost::multiprecision::expression_template_option ExpressionTemplates>
struct NumTraitsImp<boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates>, boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates> >
{
using self_type = boost::multiprecision::number<boost::multiprecision::gmp_float<0>, ExpressionTemplates>;
using Real = typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type;
using NonInteger = self_type; // Not correct but we can't do much better??
using Literal = double;
using Nested = self_type;
enum
{
IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex,
IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer,
ReadCost = 1,
AddCost = 4,
MulCost = 8,
IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true,
RequireInitialization = 1,
};
static Real epsilon()
{
return boost::math::tools::epsilon<Real>();
}
static Real dummy_precision()
{
return 1000 * epsilon();
}
static Real highest()
{
return boost::math::tools::max_value<Real>();
}
static Real lowest()
{
return boost::math::tools::min_value<Real>();
}
static int digits10()
{
return Real::thread_default_precision();
}
static int digits()
{
return boost::math::tools::digits<Real>();
}
static int min_exponent()
{
return LONG_MIN;
}
static int max_exponent()
{
return LONG_MAX;
}
static Real infinity()
{
return Real();
}
static Real quiet_NaN()
{
return Real();
}
};
}
#endif

View File

@@ -3078,6 +3078,74 @@ inline boost::multiprecision::number<boost::multiprecision::backends::logged_ada
} // namespace boost
namespace Eigen
{
template <class B1, class B2>
struct NumTraitsImp;
template <boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates>
struct NumTraitsImp<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0, AllocateType>, ExpressionTemplates>, boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0, AllocateType>, ExpressionTemplates>>
{
using self_type = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0, AllocateType>, ExpressionTemplates>;
using Real = typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type;
using NonInteger = self_type; // Not correct but we can't do much better??
using Literal = double;
using Nested = self_type;
enum
{
IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex,
IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer,
ReadCost = 1,
AddCost = 4,
MulCost = 8,
IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true,
RequireInitialization = 1,
};
static Real epsilon()
{
return boost::math::tools::epsilon< boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0, AllocateType>, ExpressionTemplates>>();
}
static Real dummy_precision()
{
return 1000 * epsilon();
}
static Real highest()
{
return boost::math::tools::max_value<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0, AllocateType>, ExpressionTemplates>>();
}
static Real lowest()
{
return boost::math::tools::min_value<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0, AllocateType>, ExpressionTemplates>>();
}
static int digits10()
{
return Real::thread_default_precision();
}
static int digits()
{
return boost::math::tools::digits<Real>();
}
static int min_exponent()
{
return mpfr_get_emin();
}
static int max_exponent()
{
return mpfr_get_emax();
}
static Real infinity()
{
return std::numeric_limits<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<50, AllocateType>, ExpressionTemplates>>::infinity();
}
static Real quiet_NaN()
{
return std::numeric_limits<boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<50, AllocateType>, ExpressionTemplates>>::quiet_NaN();
}
};
}
namespace std {
//

View File

@@ -1171,11 +1171,20 @@ test-suite misc :
[ run test_eigen_interop_mpfr_1.cpp mpfr gmp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] [ check-target-builds ../config//has_mpfr : : <build>no ] ]
[ run test_eigen_interop_mpfr_2.cpp mpfr gmp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] [ check-target-builds ../config//has_mpfr : : <build>no ] ]
[ run test_eigen_interop_mpfr_3.cpp mpfr gmp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] [ check-target-builds ../config//has_mpfr : : <build>no ] ]
[ run test_eigen_interop_mpfr_4.cpp mpfr gmp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] [ check-target-builds ../config//has_mpfr : : <build>no ] ]
[ run test_eigen_interop_mpfr_5.cpp mpfr gmp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] [ check-target-builds ../config//has_mpfr : : <build>no ] ]
[ run test_eigen_interop_mpfr_6.cpp mpfr gmp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] [ check-target-builds ../config//has_mpfr : : <build>no ] ]
[ run test_eigen_interop_gmp.cpp gmp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] [ check-target-builds ../config//has_gmp : : <build>no ] ]
[ run test_eigen_interop_gmp_2.cpp gmp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] [ check-target-builds ../config//has_gmp : : <build>no ] ]
[ run test_eigen_interop_mpc.cpp mpc mpfr gmp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] [ check-target-builds ../config//has_mpc : : <build>no ] ]
[ run git_issue_393.cpp : : : release [ check-target-builds ../config//has_eigen : : <build>no ] ]
[ compile git_issue_393.cpp : release [ check-target-builds ../config//has_eigen : : <build>no ] ]
;
alias eigen_tests : test_eigen_interop_cpp_int test_eigen_interop_cpp_dec_float test_eigen_interop_cpp_dec_float_2 test_eigen_interop_cpp_dec_float_3
test_eigen_interop_cpp_bin_float_1 test_eigen_interop_cpp_bin_float_2 test_eigen_interop_cpp_bin_float_3 test_eigen_interop_mpfr_1
test_eigen_interop_mpfr_2 test_eigen_interop_mpfr_3 test_eigen_interop_mpfr_4 test_eigen_interop_mpfr_5 test_eigen_interop_mpfr_6
test_eigen_interop_gmp test_eigen_interop_gmp_2 test_eigen_interop_mpc git_issue_393 ;
#
# This take too long to run as a regular part of the tests:

View File

@@ -549,15 +549,6 @@ void test_float_type()
example15<Num>();
example16<Num>();
example17<Num>();
/*
example18<Num>();
example19<Num>();
example20<Num>();
example21<Num>();
example22<Num>();
example23<Num>();
example24<Num>();
*/
}
template <class Num>
@@ -573,10 +564,6 @@ void test_float_type_2()
example19<Num>();
example20<Num>();
example21<Num>();
//example22<Num>();
//example23<Num>();
//example24<Num>();
}
template <class Num>

View File

@@ -12,5 +12,6 @@ int main()
using namespace boost::multiprecision;
test_integer_type<boost::multiprecision::mpz_int>();
test_integer_type<boost::multiprecision::mpq_rational>();
return 0;
}

View File

@@ -0,0 +1,15 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2018 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/multiprecision/gmp.hpp>
#include "eigen.hpp"
int main()
{
test_float_type<boost::multiprecision::mpf_float_50>();
test_float_type<boost::multiprecision::mpf_float>();
return 0;
}

View File

@@ -11,5 +11,6 @@ int main()
{
using namespace boost::multiprecision;
test_complex_type<mpc_complex>();
test_complex_type<mpc_complex_50>();
return 0;
}

View File

@@ -0,0 +1,15 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2018 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/multiprecision/mpfr.hpp>
#include "eigen.hpp"
int main()
{
using namespace boost::multiprecision;
test_float_type<boost::multiprecision::mpfr_float_50>();
return 0;
}

View File

@@ -0,0 +1,15 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2018 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/multiprecision/mpfr.hpp>
#include "eigen.hpp"
int main()
{
using namespace boost::multiprecision;
test_float_type_2<boost::multiprecision::mpfr_float_50>();
return 0;
}

View File

@@ -0,0 +1,15 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2018 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/multiprecision/mpfr.hpp>
#include "eigen.hpp"
int main()
{
using namespace boost::multiprecision;
test_float_type_3<boost::multiprecision::mpfr_float_50>();
return 0;
}