Provide the user_data to the callbacks
@odow
When I created the C / Julia interface for Uno, I checked a few times the interfaces of other nonlinear solvers (Ipopt, KNITRO, GALAHAD) and I noticed that in Ipopt.jl we never provide a way to pass user_data.
This means that model::Optimizer is passed as a closure, and the same applies to model::AbstractNLPModel in NLPModelsIpopt.jl.
In UnoSolver.jl, I added an option to pass user_data / user_model when creating the internal solver model (Ipopt.IpoptProblem in this repository).
If user_data is nothing, we keep the current signature; otherwise, we pass user_data / user_model as the first argument to all Julia callbacks.
This is what we expect in the signatures of the NLP API in MathOptInterface.jl or NLPModels.jl.
I also think it is a clean way to pass a list of parameters to an objective or constraints. For example, if we have a complex physical problem, we would like to store them in a Julia structure and pass this structure as an argument to the Julia functions. I find it neater than using closures.
The current PR is non-breaking because, by default, user_data / user_model is nothing.
I would like to have your point of view (as well as that of other users) before I add unit tests for coverage.
Ipopt.jl: https://github.com/jump-dev/Ipopt.jl/blob/master/ext/IpoptMathOptInterfaceExt/MOI_wrapper.jl#L1242-L1264
UnoSolver.jl: https://github.com/cvanaret/Uno/blob/main/interfaces/Julia/ext/UnoSolverMathOptInterfaceExt/MOI_wrapper.jl#L1294-L1301
Codecov Report
:x: Patch coverage is 75.00000% with 6 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 99.48%. Comparing base (3a7aed2) to head (bd966d0).
| Files with missing lines | Patch % | Lines |
|---|---|---|
| src/C_wrapper.jl | 75.00% | 6 Missing :warning: |
Additional details and impacted files
@@ Coverage Diff @@
## master #514 +/- ##
===========================================
- Coverage 100.00% 99.48% -0.52%
===========================================
Files 5 5
Lines 1154 1170 +16
===========================================
+ Hits 1154 1164 +10
- Misses 0 6 +6
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
I'm not really in favour of this. What's the problem with a closure?
Do you have a worked example of code that would be improved with this?
Can't this just be achieved with:
prob = Ipopt.CreateIpoptProblem(
n,
x_L,
x_U,
m,
g_L,
g_U,
nnzJ,
nnzH,
x -> eval_f(user_data, x),
(args...) -> eval_g(user_data, args...),
(args...) -> eval_grad_f(user_data, args...),
(args...) -> eval_jac_g(user_data, args...),
(args...) -> eval_h(user_data, args...),
)
I don't really want to make changes to the C API, and adding multiple ways of doing something has a long-term maintenance cost.
You can convince me of the need for this at JuMP-dev
Conclusion is that we need an example of why we need this. It might have something to do with Enzyme.