Closed jbcaillau closed 3 months ago
Qu'est-ce que j'ai encore fait ! Je vais checker ça asap.
Ok I see what happened. I fix this.
Actually, the solve
function from OptimalControl.jl
had init=nothing
as default value:
function solve(ocp::OptimalControlModel, description::Symbol...;
display::Bool=__display(),
init=nothing,
kwargs...)
#
method = getFullDescription(description, available_methods())
# print chosen method
display ? println("Method = ", method) : nothing
# if no error before, then the method is correct: no need of else
if :direct ∈ method
return CTDirect.solve(ocp, clean(method)...; display=display, init=init, kwargs...)
end
end
I have changed the default value to: CTBase.OCPInit()
. However, I am not sure that it is what we want.
In CTDirect.jl
, in the solve function, we have:
"""
$(TYPEDSIGNATURES)
Solve an optimal control problem OCP by direct method
"""
function solve(ocp::OptimalControlModel,
description...;
init=OCPInit(),
grid_size::Integer=__grid_size_direct(),
display::Bool=__display(),
print_level::Integer=__print_level_ipopt(),
mu_strategy::String=__mu_strategy_ipopt(),
kwargs...)
# build init data if needed
if !(init isa OCPInit)
init = OCPInit(init)
end
# build discretized OCP
docp = directTranscription(ocp, description, init=init, grid_size=grid_size)
# solve DOCP and retrieve OCP solution
ocp_solution = solve(docp; display=display, print_level=print_level, mu_strategy=mu_strategy, kwargs...)
return ocp_solution
end
and from a DOCP
:
"""
$(TYPEDSIGNATURES)
Solve a discretized optimal control problem DOCP
"""
function solve(docp::DOCP;
init=nothing,
display::Bool=__display(),
print_level::Integer=__print_level_ipopt(),
mu_strategy::String=__mu_strategy_ipopt(),
kwargs...)
# solve DOCP with NLP solver
print_level = display ? print_level : 0
if init == nothing
docp_solution = ipopt(getNLP(docp), print_level=print_level, mu_strategy=mu_strategy, sb="yes"; kwargs...)
else
# build init data if needed
if !(init isa OCPInit)
init = OCPInit(init)
end
docp_solution = ipopt(getNLP(docp),x0=DOCP_initial_guess(docp, init), print_level=print_level, mu_strategy=mu_strategy, sb="yes"; kwargs...)
end
# return solution for original OCP
return OCPSolutionFromDOCP(docp, docp_solution)
end
So, when we solve from an OCP
we are never in the case where init=nothing
. However, if we solve from a DOCP
, it possible. What is not clear is that we can provide an init when we do the transcription but it is not used if we do not provide an init to the solve.
"""
$(TYPEDSIGNATURES)
Discretize an optimal control problem into a nonlinear optimization problem (ie direct transcription)
"""
function directTranscription(ocp::OptimalControlModel,
description...;
init=OCPInit(),
grid_size::Integer=__grid_size_direct())
docp = DOCP(ocp, grid_size)
# build init data if needed
if !(init isa OCPInit)
init = OCPInit(init)
end
# set initial guess and bounds
x0 = DOCP_initial_guess(docp, init)
docp.var_l, docp.var_u = variables_bounds(docp)
docp.con_l, docp.con_u = constraints_bounds(docp)
# call NLP problem constructor
docp.nlp = ADNLPModel!(x -> DOCP_objective(x, docp),
x0,
docp.var_l, docp.var_u,
(c, x) -> DOCP_constraints!(c, x, docp),
docp.con_l, docp.con_u,
backend = :optimized)
return docp
end
Maybe the right thing inside the DOCP
solve:
if isnothing(init) && isnothing(getInit(docp))
# we let the NLP solver provide the init
docp_solution = ipopt(getNLP(docp), print_level=print_level, mu_strategy=mu_strategy, sb="yes"; kwargs...)
else
if isnothing(init) && !isnothing(getInit(docp))
init = getInit(docp)
end
if !(init isa OCPInit)
init = OCPInit(init)
end
docp_solution = ipopt(getNLP(docp),x0=DOCP_initial_guess(docp, init), print_level=print_level, mu_strategy=mu_strategy, sb="yes"; kwargs...)
end
Ok I didn't understand that the init is inside the model so we provide it if the solve method has no init. I propose something else.
Ok it is not so simple since ADNLPModel
needs an initial guess.
I think we have to manage how we want. If we want to let the solver provide the init, we should separate in DOCP
the init from the ADNLPModel
, passing to ADNLPModel
either the init if it is not nothing or a dummy init if init is nothing. I don't know if the ipopt
function needs an init or not inside the nlp
argument.
OK finalement c'est cohérent. Si on veut résoudre un docp on peut ne pas fournir d'init car le docp en a une. Dans ce cas par défaut init est nothing. Pour le reste il faut en fournir une et si l'utilisateur ne la donne pas on crée l'init par défaut. Du coup dans OptimalControl dans le solve on ne doit pas avoir nothing par défaut. Donc tout va bien. Il faudrait juste placer la construction d'init par défaut dans CTBase.jl.
Just in passing:
Ok thanks @PierreMartinon.
We have a file with the default values given by functions which return the default value. The functions can have inputs: https://github.com/control-toolbox/CTBase.jl/blob/main/src/default.jl
I have created the function which returns the default init in OptimalControl.jl
:
This should be put in CTBase.jl
.
Then, in the solver I have:
@ocots @PierreMartinon hi, just had a quick look at your answers - thanks. so, are we back into a stable state with
solve(ocp)
back to normal (without init)?ocp
, docp
(from ADNLPModels
)?Continued here https://github.com/control-toolbox/CTDirect.jl/issues/115
@ocots @PierreMartinon hi, can't solve anymore with
v0.7.7
andjulia 1.10.3
(see below). Any clue?