如何在使用继承和虚拟运算符()的系统中使用 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::function
或 boost::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;
};
我最近一直在实施一种解决 "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::function
或 boost::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;
};