Iterators and Ranges

| Home | Libraries | People | FAQ | More

### Iterators and Ranges

#### Examples

odeint supports iterators that iterate along an approximate solution of an ordinary differential equation. Iterators offer you an alternative to the integrate functions. Furthermore, many of the standard algorithms in the C++ standard library and Boost.Range can be used with the odeint's iterators.

Several iterator types are provided, in consistence with the integrate functions. Hence there are `const_step_iterator`, `adaptive_step_iterator`, `n_step_iterator` and `times_iterator` -- each of them in two versions: either with only the `state` or with a `std::pair<state,time>` as value type. They are all single pass iterators. In the following, we show a few examples of how to use those iterators together with std algorithms.

    runge_kutta4< state_type > stepper;
    state_type x = {{ 10.0 , 10.0 , 10.0 }};
    double res = std::accumulate( make_const_step_iterator_begin( stepper , lorenz() , x , 0.0 , 1.0 , 0.01 ) ,
                                  make_const_step_iterator_end( stepper , lorenz() , x ) ,
                                  0.0 ,
                                  []( double sum , const state_type &x ) {
                                      return sum + x[0]; } );
    cout << res << endl;

In this example all x-values of the solution are accumulated. Note, how dereferencing the iterator gives the current state `x` of the ODE (the second argument of the accumulate lambda). The iterator itself does not occur directly in this example but it is generated by the factory functions `make_const_step_iterator_begin` and `make_const_step_iterator_end`. odeint also supports Boost.Range, that allows to write the above example in a more compact form with the factory function `make_const_step_range`, but now using `boost::accumulate` from __bost_range:

    runge_kutta4< state_type > stepper;
    state_type x = {{ 10.0 , 10.0 , 10.0 }};
    double res = boost::accumulate( make_const_step_range( stepper , lorenz() , x , 0.0 , 1.0 , 0.01 ) , 0.0 ,
                                    []( double sum , const state_type &x ) {
                                        return sum + x[0]; } );
    cout << res << endl;

The second iterator type is also a iterator with const step size. But the value type of this iterator consists here of a pair of the time and the state of the solution of the ODE. An example is

    runge_kutta4< state_type > stepper;
    state_type x = {{ 10.0 , 10.0 , 10.0 }};
    double res = boost::accumulate( make_const_step_time_range( stepper , lorenz() , x , 0.0 , 1.0 , 0.01 ) , 0.0 ,
                                    []( double sum , const std::pair< const state_type &, double > &x ) {
                                        return sum + x.first[0]; } );
    cout << res << endl;

The factory functions are now `make_const_step_time_iterator_begin`, `make_const_step_time_iterator_end` and `make_const_step_time_range`. Note, how the lambda now expects a `std::pair` as this is the value type of the `const_step_time_iterator`'s.

Next, we discuss the adaptive iterators which are completely analogous to the const step iterators, but are based on adaptive stepper routines and thus adjust the step size during the iteration. Examples are

    auto stepper = make_controlled( 1.0e-6 , 1.0e-6 , runge_kutta_cash_karp54< state_type >() );
    state_type x = {{ 10.0 , 10.0 , 10.0 }};
    double res = boost::accumulate( make_adaptive_range( stepper , lorenz() , x , 0.0 , 1.0 , 0.01 ) , 0.0 ,
                                    []( double sum , const state_type& x ) {
                                        return sum + x[0]; } );
    cout << res << endl;

    auto stepper = make_controlled( 1.0e-6 , 1.0e-6 , runge_kutta_cash_karp54< state_type >() );
    state_type x = {{ 10.0 , 10.0 , 10.0 }};
    double res = boost::accumulate( make_adaptive_time_range( stepper , lorenz() , x , 0.0 , 1.0 , 0.01 ) , 0.0 ,
                                    []( double sum , const pair< const state_type& , double > &x ) {
                                        return sum + x.first[0]; } );
    cout << res << endl;

| Note
'adaptive_iterator`and` adaptive_time_iterator' can only be used with Controlled Stepper or Dense Output Stepper.

In general one can say that iterating over a range of a `const_step_iterator` behaves like an `integrate_const` function call, and similarly for `adaptive_iterator` and `integrate_adaptive`, `n_step_iterator` and `integrate_n_steps`, and finally `times_iterator` and `integrate_times`.

Below we list the most important properties of the exisiting iterators:

#### const_step_iterator

- Definition: `const_step_iterator< Stepper , System , State >`
- `value_type` is `State`
- `reference_type` is `State const&`
- Factory functions
  - `make_const_step_iterator_begin( stepper , system , state , t_start , t_end , dt )`
  - `make_const_step_iterator_end( stepper , system , state )`
  - `make_const_step_range( stepper , system , state , t_start , t_end , dt )`
- This stepper works with all steppers fulfilling the Stepper concept or the DenseOutputStepper concept.
- The value of `state` is the current state of the ODE during the iteration.

#### const_step_time_iterator

- Definition: `const_step_time_iterator< Stepper , System , State >`
- `value_type` is `std::pair< State , Stepper::time_type >`
- `reference_type` is `std::pair< State const& , Stepper::time_type > const&`
- Factory functions
  - `make_const_step_time_iterator_begin( stepper , system , state , t_start , t_end , dt )`
  - `make_const_step_time_iterator_end( stepper , system , state )`
  - `make_const_step_time_range( stepper , system , state , t_start , t_end , dt )`
- This stepper works with all steppers fulfilling the Stepper concept or the DenseOutputStepper concept.
- This stepper updates the value of `state`. The value of `state` is the current state of the ODE during the iteration.

#### adaptive_step_iterator

- Definition: `adaptive_iterator< Stepper , System , State >`
- `value_type` is `State`
- `reference_type` is `State const&`
- Factory functions
  - `make_adaptive_iterator_begin( stepper , system , state , t_start , t_end , dt )`
  - `make_adaptive_iterator_end( stepper , system , state )`
  - `make_adaptive_range( stepper , system , state , t_start , t_end , dt )`
- This stepper works with all steppers fulfilling the ControlledStepper concept or the DenseOutputStepper concept.
- For steppers fulfilling the ControlledStepper concept `state` is modified according to the current state of the ODE. For DenseOutputStepper the state is not modified due to performance optimizations, but the steppers itself.

#### adaptive_step_time_iterator

- Definition: `adaptive_iterator< Stepper , System , State >`
- `value_type` is `std::pair< State , Stepper::time_type >`
- `reference_type` is `std::pair< State const& , Stepper::time_type > const&`
- Factory functions
  - `make_adaptive_time_iterator_begin( stepper , system , state , t_start , t_end , dt )`
  - `make_adaptive_time_iterator_end( stepper , system , state )`
  - `make_adaptive_time_range( stepper , system , state , t_start , t_end , dt )`
- This stepper works with all steppers fulfilling the ControlledStepper concept or the DenseOutputStepper concept.
- For steppers fulfilling the ControlledStepper concept `state` is modified according to the current state of the ODE. For DenseOutputStepper the state is not modified due to performance optimizations, but the stepper itself.

#### n_step_iterator

- Definition: `n_step_iterator< Stepper , System , State >`
- `value_type` is `State`
- `reference_type` is `State const&`
- Factory functions
  - `make_n_step_iterator_begin( stepper , system , state , t_start , dt , num_of_steps )`
  - `make_n_step_iterator_end( stepper , system , state )`
  - `make_n_step_range( stepper , system , state , t_start , dt , num_of_steps )`
- This stepper works with all steppers fulfilling the Stepper concept or the DenseOutputStepper concept.
- The value of `state` is the current state of the ODE during the iteration.

#### n_step_time_iterator

- Definition: `n_step_time_iterator< Stepper , System , State >`
- `value_type` is `std::pair< State , Stepper::time_type >`
- `reference_type` is `std::pair< State const& , Stepper::time_type > const&`
- Factory functions
  - `make_n_step_time_iterator_begin( stepper , system , state , t_start , dt , num_of_steps )`
  - `make_n_step_time_iterator_end( stepper , system , state )`
  - `make_n_step_time_range( stepper , system , state , t_start , dt , num_of_steps )`
- This stepper works with all steppers fulfilling the Stepper concept or the DenseOutputStepper concept.
- This stepper updates the value of `state`. The value of `state` is the current state of the ODE during the iteration.

#### times_iterator

- Definition: `times_iterator< Stepper , System , State , TimeIterator >`
- `value_type` is `State`
- `reference_type` is `State const&`
- Factory functions
  - `make_times_iterator_begin( stepper , system , state , t_start , t_end , dt )`
  - `make_times_iterator_end( stepper , system , state )`
  - `make_times_range( stepper , system , state , t_start , t_end , dt )`
- This stepper works with all steppers fulfilling the Stepper concept, the ControlledStepper concept or the DenseOutputStepper concept.
- The value of `state` is the current state of the ODE during the iteration.

#### times_time_iterator

- Definition: `times_time_iterator< Stepper , System , State , TimeIterator>`
- `value_type` is `std::pair< State , Stepper::time_type >`
- `reference_type` is `std::pair< State const& , Stepper::time_type > const&`
- Factory functions
  - `make_times_time_iterator_begin( stepper , system , state , t_start , t_end , dt )`
  - `make_times_time_step_iterator_end( stepper , system , state )`
  - `make_times_time_range( stepper , system , state , t_start , t_end , dt )`
- This stepper works with all steppers fulfilling the Stepper concept, the ControlledStepper concept or the DenseOutputStepper concept.
- This stepper updates the value of `state`. The value of `state` is the current state of the ODE during the iteration.