0

I have recently been implementing one of the vehicle control algorithms that solves the "steering to the point" problem. The algorithm itself involves multiple matrix ODE solving and I wanted to implement my main algorithm class in such a way that it was independent on system (ODE) we wish to control.

The most intuitive approach seems to be:

class EquationBase
{
public:
    virtual ~EquationBase();
    /* Due to supposed bug in odeint this class is not abstract and operator() is not pure virtual */
    virtual void operator() (const state_type &x, state_type &dxdt, const time_type t);
    /* method specific for the considered algorithm, this should be part of the interface */
    virtual void setLambdas(std::vector<double> lambdas); 
};

class VehicleEquation: public EquationBase
{
public:
    VehicleEquation();
    ~VehicleEquation();
    void operator() (const state_type &x, state_type &dxdt, const time_type t) override;
    void setLambdas(std::vector<double> lambdas) override;
private:
    /* here some fields/methods specific for the system */
};

class MyAlgorithm
{
public:
    MyAlgorithm();
    MyAlgorithm(EquationBase *eq);
    void start();
private:
    EquationBase *eqPtr_;
};

Now each system that is a child of EquationBase may be used via eqPtr. Unfortunately, a second argument (ODE System) to the odeint::integrate_adaptive must be an object, not a pointer. To bypass this limitation I introduced a wrapper that contains the actual pointer to the ODE system, but does not need to use virtual functions itself:

class EquationWrapper
{
public:
    void operator() (const state_type &x, state_type &dxdt, const time_type t)
    {
        (*eqPtr_)(x,dxdt,t);
    }
    void setEquation(EquationBase *eqPtr)
    {
        eqPtr_ = eqPtr;
    }
private:
    EquationBase *eqPtr_;
};

class MyAlgorithm
{
public:
    MyAlgorithm();
    /* somewhere here: eqWrapper_.setEquation(eq); */
    MyAlgorithm(EquationBase *eq);
    /* somewhere in the algorithm: odeint::integrate_adaptive( .... , eqWrapper_,  ... ) */
    void start();
private:
    EquationWrapper eqWrapper_;
};

Of course this solution works, but I wish to know whether this is safe, clean (obviously odeint will copy my equation pointer multiple times, but will not delete it unless I declare it explicitly in the wrapper destructor), and is there a better way to achieve the desired behaviour (I thought of templates, but found this even worse)?

Since I did not find a similar problem being considered elsewhere, please refer to my solution, should you need to use odeint in such a way.

pptaszni
  • 5,591
  • 5
  • 27
  • 43

1 Answers1

1

You could also use std::function or boost::function to create polymorphic odes:

using equation = std::function< void( state_type const& , state_type& , time_type ) >;

class VehicleEquation {
    // no virtual or override here
    void operator() (const state_type &x, state_type &dxdt, const time_type t);
    void setLambdas(std::vector<double> lambdas) ;
};

class MyAlgorithm
{
    MyAlgorithm();
    MyAlgorithm(equation eq) : m_eq( eq ) {}
    void start()
    {
         // ...
         integrate_adaptive( stepper , eq , x , t0 , t1 , dt , obs );
         // ...
         // You can not call setLambdas
    }
  private:
    equation m_eq;
};
headmyshoulder
  • 6,240
  • 2
  • 20
  • 27