Kevin
Kevin

Reputation: 301

JuMP nonlinear optimization constraints broken to O(1e-9)

I'm running nonlinear optimization using the Ipopt optimizer in JuMP. My objective/cost function relies on the constraints being adhered to strictly. However on some iterations the constraint are being broken.

Specifically, my constraints are s.t. the values should be between 0 and 1/0.6 = 1.6666666....

However, in some iterations, the variables have values like:

-7.761358324221462e-9 or 1.6666666718748067

crashing the program.

Is this a bug? Is it a problem with JuMP or Ipopt? Is there a workaround?

Code:

using JuMP
using Ipopt

model = Model(Ipopt.Optimizer)
@variable(model, 0.0 <= ξ[1:6] <= 1.0/0.6)
set_start_value.(ξ, ξ₀)

@constraint(model, dot(ξ, T) == 1)

register(model, :objtv, 6, MyNonLinearObjectiveFn; autodiff=true)
@NLobjective(model, Min, objtv(ξ...))

optimize!(model)

Upvotes: 3

Views: 528

Answers (2)

stefan
stefan

Reputation: 929

To add to the answer of Przemyslaw and repeat what Miles said in the Julia discourse, setting the bound_relax_factor to 0 should help to ensure variable value are almost always within or at bounds.

"almost" because Ipopt may choose to relax variable bounds (or constraint sides) during solve again. There is a message "Slack too small, adjusting variable bound" in the log that indicates that this happened. So you want to handle this case in your code and not just "crash".

Upvotes: 0

Przemyslaw Szufel
Przemyslaw Szufel

Reputation: 42244

When working with real numbers using a computer you can never get full precision. Basically what one does in such situation is to apply rounding after getting a solution from the solver (eg. rounding to an integer or a rational number in your case - eg. try something like rationalize(1.6666666718748067, tol=1e-6) since 1e-6 is the default tolerance in Ipopt).

Having that said, you can try playing with Ipopt's precision/tolerance options such as (your code is not complete so I cannot test on your case):

set_optimizer_attribute(model, "constr_viol_tol", 1e-10)
set_optimizer_attribute(model, "acceptable_tol", 1e-10)

You can find more options having _tol suffix in Ipopt documentation and see how they influence the precision of your solution: see https://coin-or.github.io/Ipopt/OPTIONS.html

Upvotes: 2

Related Questions