2015-11-24 3 views
0

Я недавно реализовал один из алгоритмов управления транспортным средством, который решает проблему «рулевого управления». Сам алгоритм включает в себя решение множественной матрицы ODE, и я хотел реализовать свой основной класс алгоритма таким образом, чтобы он был независим от системы (ODE), которую мы хотим контролировать.Как использовать odeint solver с системой с использованием наследования и виртуального оператора()

Наиболее интуитивный подход, кажется:

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. К сожалению, второй аргумент (ODE System) для odeint :: integrate_adaptive должен быть объектом, а не указателем. Чтобы обойти это ограничение, я ввел оболочку, которая содержит фактический указатель на систему ОДУ, но не нужно использовать виртуальные функции самостоятельно:

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

Конечно, это решение работает, но я хотел бы знать, является ли это безопасно , clean (очевидно, odeint скопирует мой указатель на уравнение несколько раз, но не удалит его, если я не объявлю его явно в деструкторе оболочки), и есть ли лучший способ добиться желаемого поведения (я думал о шаблонах, но нашел это даже хуже)?

Поскольку я не нашел аналогичную проблему в другом месте, обратитесь к моему решению, если вам нужно использовать odeint таким образом.

ответ

1

Вы также можете использовать 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; 
};