control-toolbox / OptimalControl.jl

Model and solve optimal control problems in Julia
http://control-toolbox.org/OptimalControl.jl/
MIT License
62 stars 6 forks source link

Open contributions #286

Open ocots opened 1 month ago

ocots commented 1 month ago

It could be great to encourage contributions. We need:

How to contribute

Let us consider you want to add a method to solve an optimal control problem. First, you need to define a method which takes an optimal control problem as input and returns a solution. More precisely, the signature should be of the form:

using CTBase: OptimalControlModel, OptimalControlSolution

mysolve(
    ocp::OptimalControlModel, 
    description::Symbol...;
    kwargs...
)::OptimalControlSolution

API

The types OptimalControlModel and OptimalControlSolution are mutable structs:

However, it is better not to access fields directly in the case of a change in the api. Hence, it would be better to access data of the model from the getters.

To construct an OptimalControlSolution, please use the following constructors:

where Fixed means that there are no variables in the problem and NonFixed the contrary.

Customize the signature of your solver

Actually, you can customize the keyword arguments. For the other arguments, they must be ocp::OptimalControlModel, description::Symbol.... However, for the keyword arguments, you can set you own. Imagine your solver needs an initial guess, then, you can decide to define:

using CTBase: OptimalControlModel, OptimalControlSolution

mysolve(
    ocp::OptimalControlModel, 
    description::Symbol...;
    init,                                          # initial guess
    kwargs...
)::OptimalControlSolution

Note that we provide a default valuer for the initial guess: CTBase.__ocp_init(). It is simply nothing. Hence, you can choose to set the default value and define:

using CTBase: OptimalControlModel, OptimalControlSolution, __ocp_init

mysolve(
    ocp::OptimalControlModel, 
    description::Symbol...;
    init::__ocp_init(),                      # initial guess
    kwargs...
)::OptimalControlSolution

The two required methods

The first method which is required is mysolve. The second method must be named available_methods. This method returns a list of descriptions that correspond to possibilities offered by your solver. Imagine you use ADNLPModels.jl to modelise the optimisation problem (if you transform the optimal control problem to an optimisation problem) and you use either Ipopt or MadNLP to solve the optimisation problem. In this case, you can define:

function available_methods()
    # available methods by order of preference
    algorithms = ()
    algorithms = add(algorithms, (:adnlp, :ipopt))
    algorithms = add(algorithms, (:adnlp, :madnlp))
    return algorithms
end

Note that :adnlp is not strictly necessary since there is no alternative but it permits to prepare future possibilities or to explicit a little bit more the method.

Note that the descriptions are added by order of priority. If the user makes:

mysolve(ocp, :adnlp)

then, the chosen method is (:adnlp, :ipopt). The user may not give a complete description. The following are equivalent:

mysolve(ocp)
mysolve(ocp, :adnlp)
mysolve(ocp, :adnlp, :ipopt)

To recap, you need to define:

Initial guess

To be completed

Add you method to OptimalControl

To be completed

ocots commented 3 weeks ago

See

ocots commented 2 weeks ago

It could be nice to make a template.