Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

boost::multi precision and boost::find_if fails with odeint::make_adaptive_range and (at least) Boost 1.70 #245

Open
ds283 opened this issue Aug 19, 2019 · 2 comments

Comments

@ds283
Copy link
Contributor

ds283 commented Aug 19, 2019

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
@ds283
Copy link
Contributor Author

ds283 commented Nov 29, 2019

Probably relevant: boostorg/multiprecision#159

@ds283
Copy link
Contributor Author

ds283 commented 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_type member type it introduces resolves to boost::multiprecision::number for non-complex types, setting up an infinite recursion in the odeint-v2 metafunction extract_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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant