Repository navigation
boost::multi precision and boost::find_if fails with odeint::make_adaptive_range and (at least) Boost 1.70 #245
Description
Summary
For some years I have been successfully using odeint-v2 and boost::multiprecision for extended-precision arithmetic.
Recently MacPorts upgraded their version of Boost from 1.66 to 1.70. Since this happened, code using boost::find_if in conjunction with a boost::multiprecision state type will no longer compile.
I've attached a minimal example exhibiting the error, which is the standard find_crossing.cpp example generalised to use boost::multiprecision::cpp_dec_float_50.
The same error occurs using the mpfr library as the backend to boost::multiprecision::number, which is the arrangement used in my production code. Also, in production we are using odeint-v2 obtained direct from this GitHub repository at commit hash db8b39a rather than the version bundled with Boost 1.70. None of these details seem to make a difference.
On compilation the example attached above gives
$ clang++ -std=c++11 -ftemplate-backtrace-limit=0 -I/opt/local/include find_if_multiprecision.cpp
In file included from find_if_multiprecision.cpp:24:
In file included from /opt/local/include/boost/numeric/odeint.hpp:27:
In file included from /opt/local/include/boost/numeric/odeint/stepper/euler.hpp:25:
In file included from /opt/local/include/boost/numeric/odeint/algebra/range_algebra.hpp:28:
In file included from /opt/local/include/boost/numeric/odeint/algebra/norm_result_type.hpp:20:
/opt/local/include/boost/numeric/odeint/algebra/detail/extract_value_type.hpp:47:68: error: no type named 'type' in 'boost::numeric::odeint::detail::extract_value_type<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<50, int, void>, boost::multiprecision::et_on>, void>'
typedef typename extract_value_type< typename S::value_type >::type type;Backtrace details
As far as I can tell, this is the error I am encountering in production code. Most of the template backtrace is identical:
/opt/local/include/boost/numeric/odeint/algebra/detail/extract_value_type.hpp:47:68: error: no type named 'type' in 'boost::numeric::odeint::detail::extract_value_type<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<50, int, void>, boost::multiprecision::et_on>, void>'
typedef typename extract_value_type< typename S::value_type >::type type;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
...
typedef typename extract_value_type< typename S::value_type >::type type;
^
/opt/local/include/boost/numeric/odeint/algebra/norm_result_type.hpp:28:30: note: in instantiation of template class ...
typedef typename detail::extract_value_type< S >::type type;
^
/opt/local/include/boost/numeric/odeint/algebra/array_algebra.hpp:276:21: note: in instantiation of template class ...
return algebra.norm_inf( x_err );
^
/opt/local/include/boost/numeric/odeint/stepper/controlled_runge_kutta.hpp:768:50: note: in instantiation of function template specialization ...
value_type max_rel_err = m_error_checker.error( m_stepper.algebra() , in , dxdt_in , m_xerr.m_v , dt );
^
/opt/local/include/boost/numeric/odeint/stepper/dense_output_runge_kutta.hpp:338:29: note: in instantiation of function template specialization ...
res = m_stepper.try_step( system , get_current_state() , get_current_deriv() , m_t ,
^
/opt/local/include/boost/numeric/odeint/iterator/impl/adaptive_iterator_impl.hpp:230:25: note: in instantiation of function template specialization ...
stepper.do_step( this->m_system );
^
/opt/local/include/boost/iterator/iterator_facade.hpp:556:13: note: in instantiation of member function ...
f.increment();
^
/opt/local/include/boost/iterator/iterator_facade.hpp:666:35: note: in instantiation of function template specialization ...
iterator_core_access::increment(this->derived());
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:1011:31: note: in instantiation of member function ...
for (; __first != __last; ++__first)In my production code I have a slightly longer backtrace that includes
/opt/local/include/boost/iterator/iterator_facade.hpp:666:35: note: in instantiation of function template specialization 'boost::iterators::iterator_core_access::increment<boost::numeric::odeint::adaptive_time_iterator ... requested here
iterator_core_access::increment(this->derived());
^
/opt/local/include/boost/range/concepts.hpp:138:17: note: in instantiation of member function 'boost::iterators::detail::iterator_facade_base<boost::numeric::odeint::adaptive_time_iterator ... requested here
++i;
^
/opt/local/include/boost/concept/usage.hpp:16:43: note: in instantiation of member function 'boost::range_detail::IncrementableIteratorConcept<boost::numeric::odeint::adaptive_time_iterator ... requested here
~usage_requirements() { ((Model*)0)->~Model(); }
^
/opt/local/include/boost/concept/detail/general.hpp:39:42: note: in instantiation of member function 'boost::concepts::usage_requirements<boost::range_detail::IncrementableIteratorConcept<boost::numeric::odeint::adaptive_time_iterator ... requested here
static void failed() { ((Model*)0)->~Model(); }
^
/opt/local/include/boost/range/concepts.hpp:136:13: note: in instantiation of member function 'boost::concepts::requirement<boost::concepts::failed ************ ... requested here
BOOST_CONCEPT_USAGE(IncrementableIteratorConcept)
^
/opt/local/include/boost/concept/usage.hpp:29:7: note: expanded from macro 'BOOST_CONCEPT_USAGE'
BOOST_CONCEPT_ASSERT((boost::concepts::usage_requirements<model>)); \
^
/opt/local/include/boost/concept/assert.hpp:43:5: note: expanded from macro 'BOOST_CONCEPT_ASSERT'
BOOST_CONCEPT_ASSERT_FN(void(*)ModelInParens)
^
/opt/local/include/boost/concept/detail/general.hpp:71:51: note: expanded from macro 'BOOST_CONCEPT_ASSERT_FN'
&::boost::concepts::requirement_<ModelFnPtr>::failed> \
^From the line iterator_core_access::increment(this->derived()); the backtraces agree.
Issue occurs with multiple compilers
I've checked that I encounter the error with both Apple Clang
$ clang++ --version
Apple LLVM version 10.0.1 (clang-1001.0.46.4)and the Intel compiler
$ icpc --version
icpc (ICC) 19.0.4.233 20190416
Activity
ds283 commentedon Nov 29, 2019
Probably relevant: boostorg/multiprecision#159
ds283 commentedon Dec 1, 2019
I eventually had time to look into this. I believe I understand the issue, but having got to the key point it turned out the problem had already been written up at the other odeint-v2 repository belonging to boost.org:
boostorg/odeint#40
To summarise the outcome of the ticket linked above, it is commit boostorg/multiprecision@2f1cb02 that is to blame. The problem is that the
boost::multiprecision::number::value_typemember type it introduces resolves toboost::multiprecision::numberfor non-complex types, setting up an infinite recursion in the odeint-v2 metafunctionextract_value_type<>.I've confirmed that my codes build correctly with the immediately-prior commit boostorg/multiprecision@3390855 but fail with boostorg/multiprecision@2f1cb02 itself. For now, this means the workaround is to revert to commit boostorg/multiprecision@3390855 of
Boost::Multiprecision(or earlier).To make progress we probably need some input from the maintainers as to how they wish to modify
extract_value_type<>to avoid this infinite loop.