PSORLab / EAGO.jl

A development environment for robust and global optimization
MIT License
140 stars 16 forks source link

EAGO.Optimizer not solving correctly with user-defined subroutines #59

Closed ca0h closed 3 years ago

ca0h commented 3 years ago

Cannot reproduce the following example after updating JuMP to v0.21

https://github.com/PSORLab/EAGO-notebooks/blob/master/notebooks/nlpopt_interval_bnb.ipynb

Julia: v1.4 or v1.5 JuMP: v0.21.4 EAGO: 0.4.2 or 0.5.2

MWE:

using EAGO, IntervalArithmetic, JuMP

struct IntervalExt <: EAGO.ExtensionType end

import EAGO.lower_problem!
function lower_problem!(t::IntervalExt, x::EAGO.Optimizer)

    # retrieve bounds at current node
    n = x._current_node
    lower = n.lower_variable_bounds
    upper = n.upper_variable_bounds

    # define X for node and compute interval extension
    x_value = Interval.(lower, upper)
    F = sin(x_value[1])x_value[2]^2-cos(x_value[3])/x_value[4]

    x._lower_objective_value = F.lo
    x._lower_solution = IntervalArithmetic.mid.(x_value)
    x._lower_feasibility = true
    x._cut_add_flag = false

    return
end

import EAGO.upper_problem!
function EAGO.upper_problem!(t::IntervalExt, x::EAGO.Optimizer)

    # retrieve bounds at current node
    n = x._current_node
    lower = n.lower_variable_bounds
    upper = n.upper_variable_bounds

    # compute midpoint value
    x_value = 0.5*(upper + lower)
    f_val = sin(x_value[1])*x_value[2]^2-cos(x_value[3])/x_value[4]
    x._upper_objective_value = f_val
    x._upper_solution = x_value
    x._upper_feasibility = true

    return
end

import EAGO: preprocess!, postprocess!, cut_condition
function EAGO.preprocess!(t::IntervalExt, x::Optimizer)
    x._preprocess_feasibility = true
    return
end
function EAGO.postprocess!(t::IntervalExt, x::Optimizer)
    x._postprocess_feasibility = true
    return
end
EAGO.cut_condition(t::IntervalExt, x::Optimizer) = false

m = JuMP.Model(EAGO.Optimizer)
JuMP.set_optimizer_attribute(m, "branch_variable", Bool[true; true; true; true])
JuMP.set_optimizer_attribute(m, "verbosity",        10)
JuMP.set_optimizer_attribute(m, "time_limit",       10.0)
JuMP.set_optimizer_attribute(m, "obbt_depth",       0)
JuMP.set_optimizer_attribute(m, "dbbt_depth",       0)
JuMP.set_optimizer_attribute(m, "cp_depth",         0)

# Adds variables and bounds
x_L = [-10, -1, -10, 2]
x_U = [10, 1, 10, 20]
@variable(m, x_L[i] <= x[i=1:4] <= x_U[i])

# Solves the problem
JuMP.optimize!(m)
mewilhel commented 3 years ago

It looks like you missed transitioning one important attribute from keyword arguments to the set_optimizer_attribute. You just need to specify that EAGO should use the new IntervalExt Extension type rather than it's default. This is done using the following line of code:

JuMP.set_optimizer_attribute(m, "ext_type", IntervalExt())

Also, thanks for the updated version of the interval branch and bound example! I'll update the notebooks to the more modern JuMP syntax shortly.

ca0h commented 3 years ago

Problem solved! Thanks a lot!