如何在使用继承和虚拟运算符()的系统中使用 odeint 求解器

How to use odeint solver with system using inheritance and virtual operator()

我最近一直在实施一种解决 "steering to the point" 问题的车辆控制算法。该算法本身涉及多矩阵 ODE 求解,我想以独立于我们希望控制的系统 (ODE) 的方式实现我的主要算法 class。

最直观的方法似乎是:

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_;
};

现在每个作为 EquationBase 子系统的系统都可以通过 eqPtr 使用。不幸的是,odeint::integrate_adaptive 的第二个参数(ODE 系统)必须是对象,而不是指针。为了绕过这个限制,我引入了一个包装器,其中包含指向 ODE 系统的实际指针,但不需要使用虚函数本身:

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_;
};

当然这个解决方案有效,但我想知道这是否安全、干净(显然 odeint 会多次复制我的方程式指针,但不会删除它,除非我在包装器析构函数中明确声明它),并且有没有更好的方法来实现所需的行为(我想到了模板,但发现这更糟)?

由于我没有发现其他地方正在考虑类似的问题,如果您需要这样使用odeint,请参考我的解决方案。

您还可以使用 std::functionboost::function 来创建多态性代码:

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;
};