ODEint: adaptive integration with arbitrary precision

你说的曾经没有我的故事 提交于 2020-01-24 09:47:27

问题


Is it possible for ODEint to use adaptive integration routines with arbitrary precision arithmetic? For example, I'd like to use the Boost multiprecision libraries with the integrate_adaptive() function with a controlled stepper. The ODEint documentation gives examples for using arbitrary precision arithmetic for integrate_const(), but I can't modify them to use the adaptive integrator.

I've also tried using iterators (e.g. make_adaptive_time_iterator...) but run into similar problems. For concreteness this is a simple code I am looking to get working:

#include <iostream>

//[ mp_lorenz_defs
#include <boost/numeric/odeint.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>

using namespace std;
using namespace boost::numeric::odeint;

typedef boost::multiprecision::cpp_dec_float_50 value_type;
//typedef double value_type;

typedef boost::array< value_type , 3 > state_type;
//]

//[ mp_lorenz_rhs
struct lorenz
{
    void operator()( const state_type &x , state_type &dxdt , value_type t ) const
    {
        const value_type sigma( 10 );
        const value_type R( 28 );
        const value_type b( value_type( 8 ) / value_type( 3 ) );

        dxdt[0] = sigma * ( x[1] - x[0] );
        dxdt[1] = R * x[0] - x[1] - x[0] * x[2];
        dxdt[2] = -b * x[2] + x[0] * x[1];
    }
};
//]

int main( int argc , char **argv )
{
    //[ mp_lorenz_int
    state_type x = {{ value_type( 10.0 ) , value_type( 10.0 ) , value_type( 10.0 ) }};

    auto stepper = make_controlled( 1.0e-16 , 1.0e-16 , runge_kutta_cash_karp54< state_type >() );


    cout.precision(50);
    integrate_adaptive( stepper ,
           lorenz() , x , value_type( 0.0 ) , value_type( 0.1 ) , value_type( value_type( 1.0 ) / value_type( 2000.0 ) ) );
    //]
    cout << x[0] << endl;

    return 0;
}

Compiling this returns the error:

Lorenz_mp2.cpp:52:19: error: no matching function for call to 'make_controlled'
        auto stepper = make_controlled( value_type(1.0e-16) , value_type(1.0e-16) , runge_kutta_cash_karp54< state_type >() );

If I change the typedef for value_type to double it compiles and runs fine.


回答1:


Using adaptive integrators with arbitrary precision is possible with odeint. Your code is almost correct, you only forgot to also configure the value_type (used for the internal constants of the stepper, and for the "time" variable t) to be the arbitrary precision type. If you check back in the docs (http://headmyshoulder.github.io/odeint-v2/doc/boost_numeric_odeint/tutorial/using_arbitrary_precision_floating_point_types.html) you'll see that this is done by a second template argument to the stepper. So the correct stepper definition within make_controlled should be:

runge_kutta_cash_karp54< state_type , value_type >()

With this, it should compile and run with arbitrary precision.

Independent of this issue, I would like to add that using conversion from double to a multi_prec type is potentially problematic. For example, 0.1 can not be accurately represented as a double (http://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/). Hence you will end up with a multi_prec value that is not exactly 0.1. I'd advice to always convert from Integers and for example express 0.1 as value_type(1)/value_type(10).



来源:https://stackoverflow.com/questions/36301615/odeint-adaptive-integration-with-arbitrary-precision

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!