Ipopt.jl icon indicating copy to clipboard operation
Ipopt.jl copied to clipboard

Provide the user_data to the callbacks

Open amontoison opened this issue 2 months ago • 6 comments

@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

amontoison avatar Nov 02 '25 01:11 amontoison

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.

codecov[bot] avatar Nov 02 '25 02:11 codecov[bot]

I'm not really in favour of this. What's the problem with a closure?

odow avatar Nov 02 '25 19:11 odow

Do you have a worked example of code that would be improved with this?

odow avatar Nov 02 '25 19:11 odow

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.

odow avatar Nov 02 '25 21:11 odow

You can convince me of the need for this at JuMP-dev

odow avatar Nov 05 '25 01:11 odow

Conclusion is that we need an example of why we need this. It might have something to do with Enzyme.

odow avatar Nov 19 '25 21:11 odow