Skip to content

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

Open

Description

@ds283

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

  1. ds283 commented on Nov 29, 2019

    @ds283
    ContributorAuthor

    Probably relevant: boostorg/multiprecision#159

  2. ds283 commented on Dec 1, 2019

    @ds283
    ContributorAuthor

    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions