Eigen::VectorXd and Boost::Odeint, not working - c++

I am testing with Eigen::VectorXd as state_type for boost::odeint. I use this code:
#include <Eigen/Eigen>
#include <boost/numeric/odeint.hpp>
#include <boost/numeric/odeint/external/eigen/eigen_algebra.hpp>
#include <iostream>
#include <vector>
template<class T>
struct push_back_state_and_time
{
std::vector<T>& m_states;
std::vector< double >& m_times;
push_back_state_and_time( std::vector<T> &states ,std::vector<double> &times )
: m_states(states) , m_times(times) { }
void operator()(const T &x ,double t )
{
m_states.push_back(x);
m_times.push_back(t);
}
};
template<class T>
struct write_state
{
void operator() ( const T &x, const double t ) {
std::cout << t << "\t";
for(size_t i = 0; i < x.size(); ++i)
std::cout << x[i] << "\t";
std::cout << std::endl;
};
};
template<class T>
class odeClass {
private:
double Ka, Kel, Vd;
public:
odeClass(double ka, double kel, double vd) : Ka(ka), Kel(kel), Vd(vd) {};
void operator() (const T &x, T &dxdt, const double t) {
dxdt[0] = - Ka * x[0];
dxdt[1] = Ka * x[0] - Kel * x[1];
};
};
void testODE_Eigen() {
double Ka = 0.195, Vd = 13.8, Kel = 0.79 / Vd;
Eigen::VectorXd x(2);
x << 40 / Vd, 0.0;
odeClass<Eigen::VectorXd> myClass(Ka, Kel, Vd);
boost::numeric::odeint::runge_kutta4<Eigen::VectorXd, double, Eigen::VectorXd, double, boost::numeric::odeint::vector_space_algebra> stepper;
size_t steps = integrate_adaptive( stepper, myClass, x ,0.0 ,100.0 ,0.5 ,write_state<Eigen::VectorXd>() );
}
void testODE_Vector() {
double Ka = 0.195, Vd = 13.8, Kel = 0.79 / Vd;
std::vector<double> x = { 40 / Vd, 0.0 };
odeClass<std::vector<double>> myClass(Ka, Kel, Vd);
boost::numeric::odeint::runge_kutta4<std::vector<double>> stepper;
size_t steps = integrate_adaptive( stepper, myClass, x ,0.0 ,100.0 ,0.5 ,write_state<std::vector<double>>() );
}
int main()
{
testODE_Eigen();
return 0;
}
When running the function testODE_Vector();, it works perfectly, but when runningtestODE_Eigen();` I get the first integration step, one assertion stop: "Assertion failed: index >= 0 && index < size(), file C:\Eigen-3.3.7\Eigen\src\Core\DenseCoeffsBase.h, line 408.", and a windows message saying that the application has stop working, with no clue, if a use Code::Blocks. If I run the same on Visual Studio 2017 console application, I get one error saying Cannot write on a memory address without printing anything.
Any clues?
Thank you.

It looks like you are failing an assertion inside the Eigen library you are using. With a message like Assertion failed: index >= 0 && index < size() the library is probably trying to iterate over a vector internally and checks that the vector is valid before trying to access it. I would check the objects you are passing in and make sure they are valid.
It looks like one of the main differences in the two function testODE_Vector() and testODE_Eigen() is the way that you create that x. I'm not sure what this line
x << 40 / Vd, 0.0; is intended to do, but I would start there and verify that the value of x is right before it's passed into integrate_adaptive

My answer is a little late but in case someone else runs into this issue, here's what I found.
The issue seems to be that OdeInt can't handle properly the dynamic size with Eigen vectors and matrices. Therefore when creating dxdt, it creates an empty dynamic matrix or vector. This leads to an issue in your operator overload, where you try to access an element of dxdt where it contains none.
A quick fix I found was to use the resize() function (or conservativeResize()) to make sure dxdt has the proper size:
void operator() (const T &x, T &dxdt, const double t) {
dxdt.resize(x.size())
dxdt[0] = - Ka * x[0];
dxdt[1] = Ka * x[0] - Kel * x[1];
};
Note that if you want to use matrices instead of vectors you will have to use x.rows() and x.cols() instead of x.size().

Related

Implementing a European Option class

I need implement the class Option_Pricer that encapsulates all the functions relevant to price both call and put options. The teacher is giving me a code listing (.cpp file) that I have to turn into a class. All the functions that I used in my class are therefore coming from the teacher. I simply have to implement them as a class.
Here is what I have done so far: I have split the code into two different files. One is called option_pricer.hpp and is used as an header for the main file option_pricer.cpp.
//option_pricer.hpp
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
class Option_Pricer {
private:
void init();
public:
double S;
double K;
double r;
double v;
double T;
double x;
double j;
public:
//Constructors
call_price();
put_price();
norm_pdf();
norm_cdf();
d_j() const;
// Assignment operator
call_price& operator = (const call_price& call);
put_price& operator = (const put_price& put);
};
Here is the main file:
//option_pricer.cpp
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
#include "option_pricer.hpp"
double Option_Pricer::norm_pdf(const double& x) const {
return (1.0/(pow(2*M_PI,0.5)))*exp(-0.5*x*x);
}
double Option_Pricer::norm_cdf(const double& x) const {
double k = 1.0/(1.0 + 0.2316419*x);
double k_sum = k*(0.319381530 + k*(-0.356563782 + k*(1.781477937 + k*(-1.821255978 + 1.330274429*k))));
if (x >= 0.0) {
return (1.0 -(1.0/(pow(2*M_PI,0.5)))*exp(-0.5*x*x) * k_sum);
}
else {
return 1.0 - norm_cdf(-x);
}
}
double Option_Pricer::d_j(const int& j, const double& S, const double& K, const double& r, const double& v, const double& T) const {
return (log(S/K) + (r + (pow(-1,j 1))*0.5*v*v)*T)/(v*(pow(T,0.5)));
}
double Option_Pricer::call_price(const double& S, const double& K, const double& r, const double& v, const double& T) const {
return S * norm_cdf(d_j(1, S, K, r, v, T))-K*exp(-r*T) * norm_cdf(d_j(2, S, K, r, v, T));
}
double Option_Pricer::put_price(const double& S, const double& K, const double& r, const double& v, const double& T) const {
return -S*norm_cdf(-d_j(1, S, K, r, v, T))+K*exp(-r*T) * norm_cdf(-d_j(2, S, K, r, v, T));
}
int main() {
Option_Pricer p;
p.S = 100.0;
p.K = 100.0;
p.r = 0.05;
p.v = 0.2;
p.T = 1.0;
double call_price = p.call_price();
double call_put = p.put_price();
// Finally we output the parameters and prices
std::cout << "Underlying: " << p.S << std::endl;
std::cout << "Strike: " << p.K << std::endl;
std::cout << "Risk-Free Rate: " << p.r << std::endl;
std::cout << "Volatility: "<< p.v << std::endl;
std::cout << "Maturity: " << p.T << std::endl;
std::cout << "Call price: " << call_price << std::endl;
std::cout << "Put price: " << call_put << std::endl;
return 0;
}
However, as you can guess, my code isn't compiling really well. My most common error is the following:
option_pricer.cpp:7:8: error: no declaration matches ‘double Option_Pricer::norm_pdf(const double&) const’
7 | double Option_Pricer::norm_pdf(const double& x) const {
| ^~~~~~~~~~~~~
I don't understand how I should call the norm_pdf from outside of the header (same question for norm_cdf and d_j).
I'm fairly new to C++ (was using Python before) and therefore don't understand yet how am I supposed to access the variables (S, K,...) from outside of my class.
Help will be appreciated! Thank you!
You need to make and understand the distinction between a class and an object. Very simply, an object is a collection of values in memory, and a class is a description of those values and of code that will use data organized according to the class description.
So, since Option_Pricer is a class, it doesn't make sense to say Option_Pricer.S = 100.0; in your main() method. You need to create an object of type Option_Pricer, and then fill that object's memory region with the values you want. A common method for doing that - especially in your case where you are simply initializing the object with numeric data - is to create and use a constructor, although you could modify your init() method to take arguments and set values and that would be fine too. You can even set the values one-by-one as you have done, since you made the values public, but you have to modify the object, not the class.
Ex.
int main()
{
Option_Pricer p(100.0, 100.0, 0.5, 0.2, 1.0);
double call_price = p.call_price();
// or
Option_Pricer p2;
p2.init(100.0, 100.0, 0.5, 0.2, 1.0);
double call_price2 = p2.call_price();
// or, if you like typing or want the meaning of the numbers to be super clear
Option_Pricer p3;
p3.S = 100.0;
p3.K = 100.0;
p3.r = 0.05;
p3.v = 0.2;
p3.T = 1.0;
// ...
This doesn't address everything that's wrong with your code, but I'd start by addressing the above. I think the problems that others are pointing out will be easier to sort out once you get the concept of an object squared away.

Eigen Vectors as ODEINT integrate parameters

I am trying to port the Harmonic Oscillator tutorial from ODEINT to Eigen, so that I could use VectorXd for state vectors. I cannot, however, make it compile.
I've been following some questions, for instance this is the closest except that I don't use any stepper here.
This is the code:
#include <iostream>
#include <vector>
#include <Eigen/Dense>
#include <boost/numeric/odeint.hpp>
typedef Eigen::VectorXd state_type;
// was vector<double>
const double gam = 0.15;
/* The rhs of x' = f(x) defined as a class */
class harm_osc
{
public:
void operator() ( const state_type &x , state_type &dxdt , const double /* t */ )
{
dxdt(0) = x(1);
dxdt(1) = -x(0) - gam*x(1);
// dxdt[0] = x[1];
// dxdt[1] = -x[0] - gam*x[1];
}
};
/* The rhs of x' = f(x) */
void harmonic_oscillator(const state_type &x, state_type &dxdt, const double /* t */ )
{
dxdt(0) = x(1);
dxdt(1) = -x(0) - gam*x(1);
// dxdt[0] = x[1];
// dxdt[1] = -x[0] - gam*x[1];
}
void printer(const state_type &x , const double t)
{
// std::cout << t << "," << x[0] << "," << x[1] << std::endl;
std::cout << t << "," << x(0) << "," << x(1) << std::endl;
};
int main(int argc, const char * argv[])
{
state_type x(2);
x(0) = 1.0;
x(1) = 0.0;
// x[0] = 1.0;
// x[1] = 0.0;
std::cout << ">>>> FUNCTION" << std::endl;
// boost::numeric::odeint::integrate(harmonic_oscillator, x, 0.0, 10.0, 0.1, printer);
// boost::numeric::odeint::runge_kutta4<state_type, double, state_type, double, boost::numeric::odeint::vector_space_algebra> stepper();
boost::numeric::odeint::integrate<double, decltype(harmonic_oscillator), state_type, double, decltype(printer)>(harmonic_oscillator, x, 0.0, 10.0, 0.1, printer);
std::cout << ">>>> CLASS" << std::endl;
x(0) = 1.0;
x(1) = 0.0;
// x[0] = 1.0;
// x[1] = 0.0;
harm_osc ho;
boost::numeric::odeint::integrate<double, decltype(harmonic_oscillator), state_type, double, decltype(printer)>(ho, x, 0.0, 10.0, 0.1, printer);
return 0;
}
The compiler complains about No matching function for call to 'begin' in range_algebra.hpp from ODEINT in both class and function versions of integrate. As a matter of fact, Eigen matrices have no begin/end.
I've tried to play with the template parameters (as you see) with no avail.
Any hint?
Assertion failed using Eigen from repo
Using the latest Eigen from the repo (not the latest stable version), I can, as suggested, compile it and run. However, it fails an assertion in the integrate call tree:
Assertion failed: (index >= 0 && index < size()), function operator(), file eigen/include/eigen3/Eigen/src/Core/DenseCoeffsBase.h, line 427.
The call that fails is dxdt(0) = x(1); and subsequently in DenseCoeffsBase.h:
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Scalar&
operator()(Index index)
{
eigen_assert(index >= 0 && index < size()); // <---- INDEX IS 0, SIZE IS 0
return coeffRef(index);
}
Is it possible that ODEINT is trying to default-construct a VectorXd? I followed the path to my ODE call and dxdt is actually NULL:
(lldb) e dxdt
(state_type) $1 = {
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > = {
m_storage = {
m_data = 0x0000000000000000
m_rows = 0
}
}
}
What is worse is that when using resizeLike to allow resizing dxdt, in the second step (so the first real computation of integrate) I have a x with NULL values:
(lldb) e dxdt
(state_type) $0 = {
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > = {
m_storage = {
m_data = 0x0000000000000000
m_rows = 0
}
}
}
(lldb) e x
(state_type) $1 = {
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > = {
m_storage = {
m_data = 0x0000000000000000
m_rows = 0
}
}
}
I found that ODEINT actually works fine with Eigen... only it is not documented, as far as I can see.
Digging around ODEINT's code, I have found a promising eigen.hpp header deep in the external directory.
And lo and behold, it works flawlessly:
#include <fstream>
#include <iostream>
#include <vector>
#include <boost/numeric/odeint/external/eigen/eigen.hpp>
#include <Eigen/Eigenvalues>
#define FMT_HEADER_ONLY
#include "fmt/core.h"
#include "fmt/format.h"
#include "fmt/format-inl.h"
#include "fmt/printf.h"
using namespace std;
int main(int argc, char *argv[])
{
Eigen::VectorXd v;
v.resize(2);
typedef Eigen::VectorXd state_type;
const double gam = 0.15;
v(0) = 1.0;
v(1) = 1.1;
auto harmonic_oscillator = [&](const state_type &x, state_type &dxdt, const double t)
{
dxdt[0] = x[1];
dxdt[1] = -x[0] - gam*x[1];
};
auto printer = [&](const state_type &x, const double t)
{
fmt::print(out, "time: {} state: {}\n", t, x);
};
odeint::integrate(harmonic_oscillator, v, 0.0 , 10.0 , 0.01, printer);
return 0;
}
Hope it helps others.

passed parameters to boost odeint in C++

This answer is helpful, but I would like to know how to pass multiple parameters of different types to the ODE model, perhaps in a struct. For my immediate use case, I need to be able to pass one std::array<double, 6>, two std::vector<std::vector<double>> and two two double scalars for a total of four parameters to be passed. In the linked example, as well as in harmonic_oscillator.cpp, there is only a single double passed parameter. Thanks.
Here's an example of the struct I would need passed to the ODE force model and used within the rate equations.
struct T
{
std::array<double, 6> IC;
double S;
double M;
std::vector<std::vector<double>> C;
std::vector<std::vector<double>> WT;
};
I believe I've come up with a struct solution that works, but am not sure if it has any variable/memory scope no-no's. Here's an example:
#include <vector>
#include <boost/numeric/odeint.hpp>
// define structure
struct T
{
std::array<double, 6> IC;
double S;
};
// force model
class harm_osc
{
struct T T1;
public:
harm_osc(struct T G) : T1(G) {}
void operator() ( const std::vector< double > &x , std::vector< double > &dxdt , const double /* t */ )
{
dxdt[0] = x[1];
dxdt[1] = -x[0] - T1.IC[0]*x[1] + T1.S;
}
};
// print integrated state solution
void write_solution( const std::vector< double > &x , const double t )
{
printf("%-6.2f %-6.2f %-6.2f\n", t, x[0], x[1]);
}
// problem setup
int main()
{
std::vector< double > x(2);
x[0] = 1.0;
x[1] = 0.0;
struct T T2;
T2.IC = {0.15, 0.15, 0.15, 0.15, 0.15, 0.15};
T2.S = 0.0;
harm_osc ho(T2);
boost::numeric::odeint::integrate(ho, x, 0.0, 10.0, 0.1, write_solution);
}

c++ error C2064 for nested bind in C++ template

If I compile the code below, I get an:
microsoft visual studio 12.0\vc\include\xrefwrap(58): error C2064: term does not evaluate to a function taking 2 arguments
In the call to accumulate algorithm, if I change the code to function<double(double, Position const&) > f = bind(sum, placeholders::_1, bind(mem_fn(&Position::getBalance), placeholders::_2));double sum = accumulate(balances.begin(), balances.end(), 0., f); everything compiles fine. I also tried to use a non member function, but it doesn't work neither.
class Position
{
private:
double m_balance;
public:
Position(double balance) :
m_balance(balance)
{}
double getBalance() const
{
return m_balance;
}
};
static double sum(double v1, double v2)
{
return v1 + v2;
}
int main(int argc, char ** argv)
{
std::vector< Position > balances;
for (size_t i = 0; i < 10; i++)
{
balances.push_back(Position(i));
}
double sum = accumulate(balances.begin(), balances.end(), 0., bind(sum, placeholders::_1, bind(mem_fn(&Position::getBalance), placeholders::_2)));
cout << sum << endl;
return 0;
}
This will fix it:
double sum = accumulate(balances.cbegin(),
balances.cend(),
0.0 ,
std::bind(std::plus<>(),
placeholders::_1,
std::bind(&Position::getBalance, placeholders::_2)));
or we could be kind to our fellow programmers:
auto add_balance = [](auto x, auto& position) {
return x + position.getBalance();
};
double sum = accumulate(balances.cbegin(),
balances.cend(),
0.0 ,
add_balance);
Or of course we can inline the lambda. There's no performance difference. Which one seems clearer will be a matter of personal preference.
double sum = accumulate(balances.cbegin(),
balances.cend(),
0.0 ,
[](auto x, auto& position)
{
return x + position.getBalance();
});
Or we can write a complex functor to do a similar job. This was the pre-lambda way:
template<class Op>
struct PositionOp
{
using mfp_type = double (Position::*)() const;
PositionOp(Op op, mfp_type mfp) : op(op), mfp(mfp) {}
template<class T>
auto operator()(T x, const Position& pos) const {
return op(x, (pos.*mfp)());
}
Op op;
mfp_type mfp;
};
template<class Op>
auto position_op(Op op, double (Position::*mfp)() const)
{
return PositionOp<Op>(op, mfp);
}
...
double sum = accumulate(balances.cbegin(),
balances.cend(),
0.0 ,
position_op(std::plus<>(), &Position::getBalance));
... but I hope you'll agree that this is ghastly.

Using dopri5 with odeint boost library

system of equations
Hi. I want to evolve those equations in time from zero to 10^16 and initial condotions x(0)=10^8 and y(0)= 0.5. Because of the dependence of the equations on x in the denominator I think using odeint with runge_kutta_dopri5 is a good choice because of the adaptive step control. The thing is I have little idea how to do this in practice cause i have little experience in c++ and odeint. I searched a lot about using odeint but the examples where not helpful for me. Also i want to stop the calculations when x reaches zero i saw this https://stackoverflow.com/questions/33334073/stop-integration-in-odeint-with-stiff-ode
based on examples i wrote this so far with no luck
#include <iostream>
#include <vector>
#include <cmath>
#include <boost/array.hpp>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
const double b = 43.0e17;
typedef boost::array< double , 2 > state_type;
void binary(const state_type &x , state_type &dxdt , double t )
{
dxdt[0] = -b*(64.0/5)*(1 + (73.0/24)*pow(x[1],2)
+ 37.0/96)*pow(x[1],4) )/pow(x[0],3)*pow(1-pow(x[1],2),7.0/2);
dxdt[1] = -b*(304.0/96)*x[1]*(1 + (121.0/304)*pow(x[1],2))
/pow(x[0],4)*pow((1 - pow(x[1],2)),5.0/2);
}
void write_binary( const state_type &x , const double t )
{
cout << t << '\t' << x[0] << '\t' << x[1] << '\t' << x[2] << endl;
}
//I dont know what this does but the examples used it
struct streaming_observer
{
std::ostream& m_out;
streaming_observer( std::ostream &out ) : m_out( out ) { }
template< class State , class Time >
void operator()( const State &x , Time t ) const
{
m_out << t;
for( size_t i=0 ; i<x.size() ; ++i ) m_out << "\t" << x[i] ;
m_out << "\n";
}
};
//This was a first try with a given stepper but i want to replace it
int main(int argc, char **argv)
{
state_type x = { 20.871e8 , 0.5 }; // initial conditions
integrate( binary , x , 0.0 , 1000.0 , 0.1 , write_binary );
}
When I compiled it a run it I got this error
Internal Program Error - assertion (i < N) failed in const T& boost::array::operator[](boost::array::size_type) const [with T = double; long unsigned int N = 2ul; boost::array::const_reference = const double&; boost::array::size_type = long unsigned int]:
/usr/include/boost/array.hpp(129): out of range
Aborted (core dumped)
How can i get this work?
the write_binary function writes over the array bounds and causes the assertion. x[2] is not valid.