Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MOI.ScalarNonlinearFunction #346

Merged
merged 5 commits into from
Jun 2, 2023
Merged

Add support for MOI.ScalarNonlinearFunction #346

merged 5 commits into from
Jun 2, 2023

Conversation

odow
Copy link
Member

@odow odow commented Dec 8, 2022

x-ref: jump-dev/MathOptInterface.jl#2059

The most-basic example is working:

julia> import Ipopt

julia> const MOI = Ipopt.MOI
MathOptInterface

julia> model = Ipopt.Optimizer()
Ipopt.Optimizer

julia> x = MOI.add_variable(model)
MathOptInterface.VariableIndex(1)

julia> MOI.add_constraint(
           model,
           MOI.ScalarNonlinearFunction{Float64}(:^, Any[x, 2]), 
           MOI.LessThan(1.0))
MathOptInterface.ConstraintIndex{MathOptInterface.ScalarNonlinearFunction{Float64}, MathOptInterface.LessThan{Float64}}(1)

julia> MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)

julia> f = MOI.ScalarNonlinearFunction{Float64}(:exp, Any[x])
MathOptInterface.ScalarNonlinearFunction{Float64}(:exp, Any[MathOptInterface.VariableIndex(1)])

julia> MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)

julia> MOI.optimize!(model)
This is Ipopt version 3.14.4, running with linear solver MUMPS 5.4.1.

Number of nonzeros in equality constraint Jacobian...:        0
Number of nonzeros in inequality constraint Jacobian.:        1
Number of nonzeros in Lagrangian Hessian.............:        2

Total number of variables............................:        1
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:        0
Total number of inequality constraints...............:        1
        inequality constraints with only lower bounds:        0
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        1

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  1.0000000e+00 0.00e+00 1.00e+00  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1  7.1653131e-01 0.00e+00 7.03e-01  -1.7 3.33e-01    -  1.00e+00 1.00e+00f  1
   2  2.8647417e-01 5.63e-01 2.00e-01  -1.7 9.17e-01    -  1.00e+00 1.00e+00f  1
   3  3.0881253e-01 3.81e-01 9.91e-02  -1.7 4.99e-01    -  1.00e+00 5.50e-01h  1
   4  3.8678069e-01 0.00e+00 4.85e-02  -1.7 2.25e-01    -  1.00e+00 1.00e+00f  1
   5  3.6927833e-01 0.00e+00 2.77e-04  -2.5 1.39e-01    -  1.00e+00 1.00e+00h  1
   6  3.6803998e-01 0.00e+00 1.14e-05  -3.8 8.84e-03    -  1.00e+00 1.00e+00h  1
   7  3.6788138e-01 0.00e+00 1.66e-07  -5.7 8.73e-04    -  1.00e+00 1.00e+00h  1
   8  3.6787944e-01 0.00e+00 2.47e-11  -8.6 1.07e-05    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 8

                                   (scaled)                 (unscaled)
Objective...............:   3.6787944185279176e-01    3.6787944185279176e-01
Dual infeasibility......:   2.4747093263499664e-11    2.4747093263499664e-11
Constraint violation....:   0.0000000000000000e+00    0.0000000000000000e+00
Variable bound violation:   0.0000000000000000e+00    0.0000000000000000e+00
Complementarity.........:   2.5258713785469758e-09    2.5258713785469758e-09
Overall NLP error.......:   2.5258713785469758e-09    2.5258713785469758e-09


Number of objective function evaluations             = 9
Number of objective gradient evaluations             = 9
Number of equality constraint evaluations            = 0
Number of inequality constraint evaluations          = 9
Number of equality constraint Jacobian evaluations   = 0
Number of inequality constraint Jacobian evaluations = 9
Number of Lagrangian Hessian evaluations             = 8
Total seconds in IPOPT                               = 0.005

EXIT: Optimal Solution Found.

julia> @test isapprox(MOI.get(model, MOI.VariablePrimal(), x), -1; atol = 1e-6)
Test Passed

julia> @test isapprox(MOI.get(model, MOI.ObjectiveValue()), exp(-1); atol = 1e-6)
Test Passed

@codecov
Copy link

codecov bot commented Dec 12, 2022

Codecov Report

Patch coverage: 100.00% and project coverage change: +0.43 🎉

Comparison is base (e5fd613) 93.58% compared to head (3cb938f) 94.02%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #346      +/-   ##
==========================================
+ Coverage   93.58%   94.02%   +0.43%     
==========================================
  Files           4        4              
  Lines         858      921      +63     
==========================================
+ Hits          803      866      +63     
  Misses         55       55              
Impacted Files Coverage Δ
src/MOI_wrapper.jl 93.08% <100.00%> (+0.92%) ⬆️

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@@ -5,6 +5,16 @@

include("utils.jl")

const _PARAMETER_OFFSET = 0x00f0000000000000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a messy piece of logic to copy in each NLP solver. It's fine for now, but can this eventually go into MOI.Nonlinear.Model or some other abstraction layer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes... it's unfortunately messy. I haven't thought about ways to abstract this because I think we'd need to see a couple of implementations first.

if model.nlp_model !== nothing
backend = MOI.Nonlinear.SparseReverseMode()
evaluator = MOI.Nonlinear.Evaluator(model.nlp_model, backend, vars)
model.nlp_data = MOI.NLPBlockData(evaluator)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we now delete the code to set nlp_data as an attribute?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. So we didn't discuss the deprecation plan in today's call. My suggestion is that we leave all of the current infrastructure in-place. So if you use @NLconstraint it'll go via NLPBlock, and if you use @constraint it'll go via ScalarNonlinearFunction.

On the documentation front in JuMP, we'd just delete the mentions of @NL macros, but perhaps leave them in the reference docstrings with a compat annotationn/warning.

@odow odow force-pushed the od/nlp-expr branch 4 times, most recently from 779c3ba to 2e54f8f Compare May 9, 2023 05:29
@odow odow changed the title WIP: explore refactoring to accept ScalarNonlinearFunction Add support for MOI.ScalarNonlinearFunction Jun 2, 2023
@odow odow merged commit 3af5728 into master Jun 2, 2023
@odow odow deleted the od/nlp-expr branch June 2, 2023 04:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants