Closed ocots closed 3 months ago
Did you try it ? The arguments are different, so Julia should be able to match the proper method (?)
I haven't try but yes I think that with multiple dispatch it will work fine. Otherwise, we have to prefix the method solve
.
Ok, I tried with CTdirect, we need to prefix
using CTDirect
using NonlinearSolve
include("ocp.jl") # defines ocp1
sol = solve(ocp1)
fails with
WARNING: both NonlinearSolve and CTDirect export "solve"; uses of it in module Main must be qualified
Calling CTDirect.solve(ocp1) works fine.
That's why we need to share the same function. I think we should take a look at the CommonSolve.jl package.
That's why we need to share the same function. I think we should take a look at the CommonSolve.jl package.
Did you try it ? Their documentation is ... quite brief. And not that clear. Maybe we should look for an example.
@PierreMartinon First example:
Note. I don't know why I have exported MySolve
. This is useless I guess.
With another package that export a solve
function. Note that the solve
function extends the one from CommonSolve
.
With CommonSolve.jl
:
Thanks, I'll have a look. I just finished the package extensions for CTDirect.
@ocots Ok, halfway done I guess. I managed to redefine CommonSolve.solve and use it to solve a DOCP, but the export is not done properly, ie I have to prefix and call
CommonSolve.solve(docp)
I tried the export both in the extension and CTDirect, do you know what I'm missing ?
module CTSolveExt
using CTDirect
using CTBase
using CommonSolve
using DocStringExtensions
using NLPModelsIpopt
using HSL
"""
$(TYPEDSIGNATURES)
Solve a discretized optimal control problem DOCP
"""
function CommonSolve.solve(docp::DOCP;
init=nothing,
display::Bool=CTDirect.__display(),
print_level::Integer=CTDirect.__print_level_ipopt(),
mu_strategy::String=CTDirect.__mu_strategy_ipopt(),
linear_solver::String=CTDirect.__linear_solver(),
kwargs...)
# Linear solver
if (linear_solver == "ma27") || (linear_solver == "ma57") || (linear_solver == "ma77") || (linear_solver == "ma86") || (linear_solver == "ma97")
if !LIBHSL_isfunctional()
linear_solver = "mumps"
end
end
if linear_solver == "spral"
if !haskey(ENV, "OMP_CANCELLATION") || !haskey(ENV, "OMP_PROC_BIND")
linear_solver = "mumps"
end
end
# solve DOCP with NLP solver
print_level = display ? print_level : 0
if init == nothing
# use initial guess embedded in the DOCP
docp_solution = ipopt(getNLP(docp), print_level=print_level, mu_strategy=mu_strategy, sb="yes", linear_solver=linear_solver; kwargs...)
else
# use given initial guess
docp_solution = ipopt(getNLP(docp), x0=CTDirect.DOCP_initial_guess(docp, OptimalControlInit(init)), print_level=print_level, mu_strategy=mu_strategy, sb="yes", linear_solver=linear_solver; kwargs...)
end
# return DOCP solution
return docp_solution
end
export solve
end
Ok, it works now oO FWIW I used in CTDirect
using CommonSolve: solve
export solve
Now I have to do the same with solve(ocp), that actually calls solve(docp) internally...
Since you redefine it into an extension it changes some things. I have to think about it. I don't know the answer.
I think that the solve function must be defined into CTDirect.jl and this function may call an internal one defined in both CTDirect.jl and the extension. In CTDirect.jl this internal function should have as arguments args...; kwargs...
and return an error. In the extension the internal function is redefine with the right signature and do the job.
The export is only in CTDirect.jl.
Like the Flow function here:
https://github.com/control-toolbox/CTFlows.jl/blob/main/src%2FCTFlows.jl#L26
The export in the extension can indeed be removed.
Apparently the fact that we redefine the solve function from CommonSolve is incompatible with declaring an 'empty' solve in CTDirect. I get a compilation error if I try.
In the other extension CTDirectExt I did use empty functions in CTDirect. Insome cases I got the precompilation error when redefining methods. As a result I had to change the signatures for the read/load functions, which is a bit ugly.
save_OCP_solution() = error("placeholder for save")
#load_OCP_solution() = error("placeholder for load") # precompilation error (overwriting method)
function load_OCP_solution end #ok for precompilation
export_OCP_solution() = error("placeholder for export")
function read_OCP_solution end
By the way, people seem to disagree on how exactly the 'empty' functions should be written. I guess the feature is still new.
That's why I said to define an internal function which redefined in the extension. The solve function is defined once.
I think that it has been done by @PierreMartinon.
If we use
NonlinearSolve
to solve nonlinear equations andOptimalControl
to solve an OCP in the same script, then there an ambiguity with bothsolve
method. We need to overload thesolve
fromCommonSolve
I guess.