boost error: expression cannot be used as a function - c++

I am trying to use the boost RK4 integration together with the rigid body dynamics library.
I am getting a strange error I dont recognize, that I think has to do with the operator() override but I am not sure based on this post.
My code is similar to this example. Which makes me think that either I am missing something obvious. I think that it may be a compiler problem.
This is my class I use to convert from RBDL to boost.
class rbdlToBoost {
public:
rbdlToBoost(Model* model) : model(model)
{
q = VectorNd::Zero(model->dof_count);
qd = VectorNd::Zero(model->dof_count);
qdd = VectorNd::Zero(model->dof_count);
tau = VectorNd::Zero(model->dof_count);
}
//3c. Boost uses this 'operator()' function to evaluate the state
// derivative of the pendulum.
void operator() (const state_type &x, state_type &dxdt, const double t)
{
//do stuff
}
private:
Model* model;
VectorNd q, qd, qdd, tau;
};
This is my main I am using to test the integration. This is a minimal example I put together.
#include "rbdl/Model.h"
#include "rbdl/Dynamics.h"
#include "rbdl_model_tests/DynamicTesting.h"
int main(int argc, char const *argv[])
{
int nPts = 100;
double t0 = 0;
double t1 = 3;
double t = 0; //time
double ts = 0; //scaled time
double dtsdt = M_PI/(t1-t0); //dertivative scaled time
double tp = 0;
double dt = (t1-t0)/((double)nPts);
//Integration settings
double absTolVal = 1e-10;
double relTolVal = 1e-6;
double a_x = 1.0 , a_dxdt = 1.0;
Model* model = NULL;
model = new Model();
rbdlToBoost rbdlBoostModel(model);
state_type xState(2);
int steps = 0;
xState[0] = -M_PI/4.0;
xState[1] = 0;
controlled_stepper_type controlled_stepper(
default_error_checker< double , range_algebra , default_operations >
( absTolVal , relTolVal , a_x , a_dxdt )
);
integrate_adaptive(
controlled_stepper ,
model , xState , tp , t , (t-tp)/10 );//This seems to be the problem
tp = t;
return 0;
}
I am getting this error:
~/catkin_ws/src/ambf_control_system/rbdl_model_tests/src/tempDyn.cpp:37:47: required from here
/usr/include/boost/numeric/odeint/stepper/controlled_runge_kutta.hpp:481:12: error: expression cannot be used as a function
sys( x , m_dxdt.m_v ,t );

It turns out it was a simple fix
I just had to change.
I was passing in the wrong variable into the function. I had to pass in my custom class variable (rbdlBoostModel) not my RBDL model (model).
integrate_adaptive(
controlled_stepper ,
model , xState , tp , t , (t-tp)/10 );//This seems to be the problem
to
integrate_adaptive(
controlled_stepper ,
rbdlBoostModel , xState , tp , t , (t-tp)/10 );

Related

Do controlled error steppers in boost odeint support complex data types?

I encountered a problem with the odeint library using a controlled error stepper together with a complex state type. The code from the example with the complex stuart landau equation, I modified such that it includes an adaptive integrator. The code looks like this now:
#include <iostream>
#include <complex>
#include <boost/array.hpp>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
//[ stuart_landau_system_function
typedef complex< double > state_type;
struct stuart_landau
{
double m_eta;
double m_alpha;
stuart_landau( double eta = 1.0 , double alpha = 1.0 )
: m_eta( eta ) , m_alpha( alpha ) { }
void operator()( const state_type &x , state_type &dxdt , double t ) const
{
const complex< double > I( 0.0 , 1.0 );
dxdt = ( 1.0 + m_eta * I ) * x - ( 1.0 + m_alpha * I ) * norm( x ) * x;
}
};
//]
struct streaming_observer
{
std::ostream& m_out;
streaming_observer( std::ostream &out ) : m_out( out ) { }
template< class State >
void operator()( const State &x , double t ) const
{
m_out.precision(10);
m_out << t;
m_out << "\t" << x.real() << "\t" << x.imag() ;
m_out << "\n";
}
};
int main( int argc , char **argv )
{
//[ stuart_landau_integration
state_type x = complex< double >( 1.0 , 0.0 );
bulirsch_stoer< state_type > stepper( 1E-12 , 1E-12 , 1 , 1 );
const double dt = 0.1;
//]
integrate_adaptive( stepper , stuart_landau( 2.0 , 1.0 ) , x , 0.0 , 10.0 , dt , streaming_observer( cout ) );
return 0;
}
However, if I change the definition of the stepper to
bulirsch_stoer< state_type, complex< double > > stepper( 1E-12 , 1E-12 , 1 , 1 );
compilation fails.
My question is: Are complex data types not supported in controlled error steppers? If so, is there a method to circumvent the problem, which arises. Or, is it possible to define an own vector algebra for the complex data type?
The odeint library does support complex data types, including controlled steppers.
As an example, to obtain a controlled stepper in the case of the 4th/5th order Dormand-Prince method you can do this:
runge_kutta_dopri5< state_type > stepper;
auto c_stepper = make_controlled(1.E-12, 1.E-12, stepper);
integrate_adaptive(c_stepper, stuart_landau( 2.0 , 1.0 ) , x , 0.0 , 10.0 , dt , streaming_observer( cout ) );
Where state_type is typedef'd as
typedef complex< double > state_type;
The Bulirsch-Stoer algorithm that is implemented in odeint, however, is already inherently a controlled stepper. It is therefore not possible to apply make_controlled or other strategies to create controlled steppers in this case. There is no such template in the odeint library because it would not make sense.
The first code that you posted already integrates the ODE, with complex values and with a controlled stepper. It is not clear what you are trying to achieve by changing the stepper to
bulirsch_stoer< complex<double>, complex<double> > stepper( 1E-12 , 1E-12 , 1 , 1 );

Solving differential Equation using BOOST Libraries

I have to find next state of my robot which can be found though solving differential equations. In MATLAB i used ode45 function and on c++ i found on internet that i have to use some method like stepper runga kutta dopri5. I tried to understand its implementation and somehow got an idea. Now my states are X,Y and theta and to find next states my differential equations are
Xdot=v*cos(theta)
Ydot=v*sin(theta)
thetadot=w
Now there is a public function stepper.do_step_impl(System,state,...etc) where what i understood is that system represents a function whose parameters could be &state,dstate and t. Now here is my problem. My differential equations have variables v and w which i need in my System function but according to my understanding System function could have only fixed parameters i.e State, dstate and t. How do i put v and w in it? I hope someone understands my question. Kindly help. Below is my code
using namespace boost::numeric::odeint;
typedef std::vector< double > state_type;
void pdot_w( const state_type &state, state_type &dstate, const double t )
{
double p_robot_xdot = v*cos(state[2]);
double p_robot_ydot = v*sin(state[2]);
double thetadot = w;
dstate[0] = p_robot_xdot;
dstate[1] = p_robot_ydot;
dstate[2] = thetadot;
}
runge_kutta_dopri5<state_type> stepper;
stepper.do_step(pdot_w, state , 0, 0.01 );
The answer depends on how you want to pass the parameters v and w to the integrator.
One approach in C++11 is to use a lambda. Your function and a call to the stepper would look like this (depending on context, the capture [] may need to be more explicit):
void pdot_w(const state_type &state,
state_type & dstate,
const double t,
const double v,
const double w) {
dstate[0] = v * cos(state[2]);
dstate[1] = v * sin(state[2]);
dstate[2] = w;
}
runge_kutta_dopri5<state_type> stepper;
/* v = 4 and w = 5 example */
stepper.do_step([](const state_type & state, state_type & d_state, const double t) {
return pdot_w(state, d_state, t, 4, 5);
}, state,
0, 0.01);

R interacting with c++ by means of Rcpp to solve large ODE systems

I'm trying to speedup my R code performing some computationally expensive task with C++ and Rcpp. My problem involves approximately a system of 100 equations, so any hint to speed up the computation is welcome.
What I need is to import a matrix MX created in R into a C++ script. The C++ script have to use rows of MX as x0 (x initial values) in a systems of ODE.
To simplify the explanation of my problem, the code below is based on the Lorenz systems.
As it is clear from the quality of my code, I'm new to C++ (and Rcpp).
For clarity, I don't post all my test code that are terrible, bu I really need your help to try solve this problem.
Any help will be really, really appreciated!
Thanks in advance.
#include <boost/array.hpp>
#include <boost/numeric/odeint.hpp>
#include <Rcpp.h>
// [[Rcpp::depends(BH)]]
// [[Rcpp::plugins(cpp11)]]
using namespace std;
using namespace boost::numeric::odeint;
double theta [] = {10.000,28,2.5};
typedef boost::array< double , 3 > state_type;
void lorenz( const state_type &x , state_type &dxdt , double t ) {
dxdt[0] = theta[0] * ( x[1] - x[0] );
dxdt[1] = theta[1] * x[0] - x[1] - x[0] * x[2];
dxdt[2] = -theta[2] * x[2] + x[0] * x[1];
}
struct foo { std::vector<double> a, b, c; };
struct foo f;
//observer should be a function that append a single output row for each input row of mx corresponding to the last integration step.
void append_lorenz(const state_type &x , const double t ) {
f.a.push_back(x[0]);
f.b.push_back(x[1]);
f.c.push_back(x[2]);
}
using namespace Rcpp;
// [[Rcpp::export]]
DataFrame callMain(NumericMatrix mx){
int n = mx.nrow();
NumericMatrix total(mx);
for(int i = 0; i < n; ++i) {
// state_type x should be mx rows
state_type x = total.row(i); // initial conditions
const double dt =0.1;
integrate(lorenz , x , 0.0 , 1.0 , dt , append_lorenz );
}
return DataFrame::create(Named("a") = f.a, Named("b") = f.b, Named("c") = f.c);
}
/*** R
mx=matrix(1:9,3,3)
res <- callMain(mx)
print((res))
*/
the error I get is:
error: conversion from ‘Rcpp::Matrix<14>::Row {aka Rcpp::MatrixRow<14>}’ to non-scalar type ‘state_type {aka boost::array}’ requested
state_type x = total.row(i); // initial conditions
I think the error message is clear enough.
state_type x = total.row(i);
There is no conversion between Rcpp object and boost::array, you need to develop your own.

Comparison of odeint's runge_kutta4 with Matlab's ode45

I would like to use runge_kutta4 method in the odeint C++ library. I've solved the problem in Matlab. My following code in Matlab to solve x'' = -x - g*x', with initial values x1 = 1, x2 = 0, is as follows
main.m
clear all
clc
t = 0:0.1:10;
x0 = [1; 0];
[t, x] = ode45('ODESolver', t, x0);
plot(t, x(:,1));
title('Position');
xlabel('time (sec)');
ylabel('x(t)');
ODESolver.m
function dx = ODESolver(t, x)
dx = zeros(2,1);
g = 0.15;
dx(1) = x(2);
dx(2) = -x(1) - g*x(2);
end
I've installed the odeint Library. My code for using runge_kutta4 is as follows
#include <iostream>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
/* The type of container used to hold the state vector */
typedef std::vector< double > state_type;
const double gam = 0.15;
/* The rhs of x' = f(x) */
void lorenz( const state_type &x , state_type &dx , double t )
{
dx[0] = x[1];
dx[1] = -x[0] - gam*x[1];
}
int main(int argc, char **argv)
{
const double dt = 0.1;
runge_kutta_dopri5<state_type> stepper;
state_type x(2);
x[0] = 1.0;
x[1] = 0.0;
double t = 0.0;
cout << x[0] << endl;
for ( size_t i(0); i <= 100; ++i){
stepper.do_step(lorenz, x , t, dt );
t += dt;
cout << x[0] << endl;
}
return 0;
}
The result is in the following picture
My question is why the result varies? Is there something wrong with my C++ code?
These are the first values of both methods
Matlab C++
-----------------
1.0000 0.9950
0.9950 0.9803
0.9803 0.9560
0.9560 0.9226
0.9226 0.8806
0.8806 0.8304
0.8304 0.7728
0.7728 0.7084
0.7083 0.6379
Update:
The problem is that I forgot to include the initial value in my C++ code. Thanks for #horchler for noticing it. After including the proper values and using runge_kutta_dopri5 as #horchler suggested, the result is
Matlab C++
-----------------
1.0000 1.0000
0.9950 0.9950
0.9803 0.9803
0.9560 0.9560
0.9226 0.9226
0.8806 0.8806
0.8304 0.8304
0.7728 0.7728
0.7083 0.7084
I've updated the code to reflect these modifications.
The runge_kutta4 stepper in odeint is nothing like Matlab's ode45, which is an adaptive scheme based on the Dormand-Prince method. To replicate Matlab's results, you should probably try the runge_kutta_dopri5 stepper. Also, make sure that your C++ code uses the same absolute and relative tolerances as ode45 (defaults are 1e-6 and 1e-3, respectively). Lastly, it looks like you may not be saving/printing your initial condition in your C++ results.
If you're confused at why ode45 is not taking fixed steps even though you specified t = 0:0.1:10;, see my detailed answer here.
If you must use the fixed steprunge_kutta4 stepper, then you'll need to reduce the integration step-size in your C++ code to match Matlab's output.
The Matlab ode45 function already includes error control and I think also interpolation (dense output). to compare with boost.odeint you should use the same functionality there. Boost.odeint provides integrate functions that perform step-size control and dense output if the used stepper algorithm provides this functionality. The following code piece shows how you this is used with the default error control parameters from Matlab given by horchler:
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
/* The type of container used to hold the state vector */
typedef std::vector< double > state_type;
const double gam = 0.15;
/* The rhs of x' = f(x) */
void damped_osc( const state_type &x , state_type &dx , const double t )
{
dx[0] = x[1];
dx[1] = -x[0] - gam*x[1];
}
void print( const state_type &x, const double t )
{
cout << x[0] << endl;
}
int main(int argc, char **argv)
{
cout.precision(16); // full precision output
const double dt = 0.1;
typedef runge_kutta_dopri5<state_type> stepper_type;
state_type x(2);
x[0] = 1.0;
x[1] = 0.0;
integrate_const(make_dense_output<stepper_type>( 1E-6, 1E-3 ),
damped_osc, x, 0.0, 10.0, dt , print);
return 0;
}
Please note that the results might still not be exactly the same (as in all 16 digits) because the error control in Boost.odeint might not be impemented exactly as in Matlab's ode45.

Error Passing `const` as `this` argument of `const double` discards qualifiers

I have to work within some libraries and no matter what i do i keep getting the following error with this code.
passing `const amko::problem::launch' as 'this'argument of 'const double amko::problem::launch::ratio(double, double)' discards qualifiers
namespace amko { namespace problem {
launch::launch():base( 0.0, 20.0, 1 ) {}
base_ptr launch::clone() const
{
return base_ptr(new launch(*this));
}
const double launch::ratio( const double a, const double b)
{
const double area = a*b;
const double circumference = 2*a+2*b;
const double ratio = circumference/area;
return ratio;
}
void launch::objfun_impl(fitness_vector &f, const decision_vector &xv) const
{
amko_assert(f.size() == 1 && xv.size() == get_dimension());
const double x = xv[0];
const double y = launch::ratio(x,5);
f[0] = y;
}
while the following piece of code worked just fine.
namespace amko { namespace problem {
initialValueProblem::initialValueProblem():base( 0.0, 20.0, 1 ) {}
base_ptr initialValueProblem::clone() const
{
return base_ptr(new initialValueProblem(*this));
}
Eigen::VectorXd initialValueProblem::computeDerivative( const double time, const Eigen::VectorXd& state )
{
Eigen::VectorXd stateDerivative( 1 );
stateDerivative( 0 ) = state( 0 ) - std::pow( time, 2.0 ) + 1.0;
return stateDerivative;
}
void initialValueProblem::objfun_impl(fitness_vector &f, const decision_vector &xv) const
{
amko_assert(f.size() == 1 && xv.size() == get_dimension());
const double x = xv[0];
double intervalStart = 0.0;
double intervalEnd = 10.0;
double stepSize = 0.1;
Eigen::VectorXd initialState_;
initialState_.setZero( 1 );
initialState_( 0 ) = x;
numerical_integrators::EulerIntegratorXd integrator( boost::bind( &initialValueProblem::computeDerivative,
const_cast<initialValueProblem*>( this ), _1, _2 ), intervalStart, initialState_ );
Eigen::VectorXd finalState = integrator.integrateTo( intervalEnd, stepSize );
f[0] = fabs( finalState( 0 ) - 11009.9937484598 );
}
Thank you!
launch::objfun_impl is a const member function, it cannot change members or call other functions that do. That means it can't call non-const non-static member functions such as launch::ratio.
Because launch::ratio doesn't appear to access members at all, just its arguments, the simplest fix is to make it a static member function by changing the prototype inside the class definition:
static /* <- ADDED static HERE */ double launch::ratio(const double a, const double b);
The problem is that your ratio member function is not const, even though you are not modifying any member of the object (why is it a member function at all?). Inside objfun_impl you are calling ratio. Now, objfun_impl is const, and thus promises not to modify the object, but calling ratio would break that promise.