Getting duals for nonlinear programming problem

Hi Guys!

I’m having problems getting the dual variables for a nonlinear problem, with Ipopt as the solver…

I just found this post here of 2015, but not working here and a bit old:
https://github.com/JuliaOpt/JuMP.jl/issues/456

Any updates on the topic?

Have you tried? Works for me:

julia> using  JuMP, Ipopt

julia> m=Model(solver=IpoptSolver())
Feasibility problem with:
 * 0 linear constraints
 * 0 variables
Solver is Ipopt

julia> @variable(m, 0 <= x <= π / 2)
x

julia> c = @constraint(m, x >= π / 3)
x >= 1.0471975511965976

julia> @NLobjective(m, Min, sin(x))

julia> solve(m)
This is Ipopt version 3.12.8, running with linear solver mumps.
... lines omitted ...

julia> getdual(c)
0.5000000071047659

julia> cos(π/3)
0.5000000000000001

If you’re having problems, try posting a small reproducible example (How to create a Minimal, Reproducible Example - Help Center - Stack Overflow).

Hi Orscar!

Thanks.

Your example works here as well…

Now I realized that my problem is that Ipopt is letting down while solving the problem…

Best,

Just to leave a note. The code can be renewed to

julia> import JuMP, Ipopt

julia> begin
           model = JuMP.Model(Ipopt.Optimizer)
               JuMP.set_silent(model)
           JuMP.@variable(model, 0 <= x <= 1. * π)
           JuMP.@constraint(model, c, x >= π / 3)
           JuMP.@objective(model, Min, sin(x))
           JuMP.optimize!(model)
       end

julia> JuMP.solution_summary(model; verbose = true)
solution_summary(; result = 1, verbose = true)
├ solver_name          : Ipopt
├ Termination
│ ├ termination_status : LOCALLY_SOLVED
│ ├ result_count       : 1
│ └ raw_status         : Solve_Succeeded
├ Solution (result = 1)
│ ├ primal_status        : FEASIBLE_POINT
│ ├ dual_status          : FEASIBLE_POINT
│ ├ objective_value      : -2.89073e-08
│ ├ dual_objective_value : -3.14159e+00
│ ├ value
│ │ └ x : 3.14159e+00
│ └ dual
│   └ c : 1.19568e-09
└ Work counters
  ├ solve_time (sec)   : 4.48600e+00
  └ barrier_iterations : 8

julia> JuMP.set_start_value(x, (π/3 + π/2) / 2)

julia> JuMP.optimize!(model)

julia> JuMP.solution_summary(model; verbose = true)
solution_summary(; result = 1, verbose = true)
├ solver_name          : Ipopt
├ Termination
│ ├ termination_status : LOCALLY_SOLVED
│ ├ result_count       : 1
│ └ raw_status         : Solve_Succeeded
├ Solution (result = 1)
│ ├ primal_status        : FEASIBLE_POINT
│ ├ dual_status          : FEASIBLE_POINT
│ ├ objective_value      : 8.66025e-01
│ ├ dual_objective_value : 5.23599e-01
│ ├ value
│ │ └ x : 1.04720e+00
│ └ dual
│   └ c : 5.00000e-01
└ Work counters
  ├ solve_time (sec)   : 0.00000e+00
  └ barrier_iterations : 7

Note that if the starting points was JuMP.set_start_value(x, π/2 - 0.05), then Ipopt would fail to converge to the π / 3 local minimum, which is not as expected. This suggests that the outcomes (the resulting local minimum) might differ, if you write an algorithm yourself.

I don’t know how Ipopt compute the Lagrangian multiplier of x >= b, e.g. (b = pi / 3).

I guess that it will first reformulate this constraint as x == y + b, where y >= 0 is an additional ancillary variable. Then it can associate a multiplier m, which is free, to x == y + b.
If the final solution suggests that y == 0 (or almost zero), then it can returns the value of m, as the multiplier of x >= b. Otherwise, if y > 0 strictly, then it can returns 0, as the multiplier of x >= b.

If there is anyone who knows this interior-point-method procedure, please tell me🙂

Hi @WalterMadelim, we generally discourage commenting on long dead posts. If we updated every post from 2018 that’d be too much work and people will get unexpected emails.

Your idea for the dual is more or less correct. Theres a paper on Ipopt if you want to go find the details.

1 Like