Open contributions
Opened this issue · 2 comments
It could be great to encourage contributions. We need:
- a tutorial explaining how to contribute
- some CI to make some tests to decide acceptation
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:
mysolve
available_methods
Initial guess
To be completed
Add you method to OptimalControl
To be completed
It could be nice to make a template.