lanl-ansi / Alpine.jl

A Julia/JuMP-based Global Optimization Solver for Non-convex Programs
https://lanl-ansi.github.io/Alpine.jl/latest/
Other
241 stars 39 forks source link

Quadratic Constraints and Functions are passed to MILP solvers. #220

Closed felipemarkson closed 1 year ago

felipemarkson commented 1 year ago

When you are using an pure MILP solver, like Cbc or HiGHS, Alpine is not applying the appropriate relaxations on quadratic functions.

The same issue is not found on Gurobi because Gurobi can handle with quadratic constraints.

Bellow you can see a minimal reproducible example:

using JuMP
using Cbc, Ipopt, Alpine

# MIP optimizer
cbc = optimizer_with_attributes(
    Cbc.Optimizer,
    MOI.Silent() => true)

# NLP optimizer
ipopt = optimizer_with_attributes(Ipopt.Optimizer,
    MOI.Silent() => true,
    "sb" => "yes",
    "max_iter" => 9999)

# Global optimizer
alpine = optimizer_with_attributes(Alpine.Optimizer,
    "nlp_solver" => ipopt,
    "mip_solver" => cbc)

model = Model(alpine)
@variable(model, x ≥ 0)
@NLconstraint(model, x^2 ≥ 1)
@NLobjective(model, Min, x^3)

optimize!(model)

Here you can see the Error message: image

harshangrjn commented 1 year ago

This issue is related to #177. Please note that Alpine currently only reformulates a nonconvex quadratic constraint, like in x^2 >= 1 into a relaxed quadratic constraint and hands it over to a convex MIP solver. As you mentioned, Alpine does not do any outer-approximation at this point to handle this. Instead, please use Pavito as the underlying mip_solver for Alpine. Patio is an open-source convex MIP solver with which you could also invoke Gurobi, HiGHS or Cbc. Here is an example: https://github.com/lanl-ansi/Alpine.jl/blob/c6da8b92cf34bc1c88c1f488285a90d63fd3df55/test/runtests.jl#L35 and https://github.com/lanl-ansi/Alpine.jl/blob/c6da8b92cf34bc1c88c1f488285a90d63fd3df55/test/test_algorithm.jl#L104

felipemarkson commented 1 year ago

Thanks!

So, I suggest remove MILP solvers from the documentation. Or warning the user about this issue on the documentation as well.

harshangrjn commented 1 year ago

@felipemarkson I agree that the docs should clearly mention this. Regarding the x^2 >= 1 constraint, note that Alpine reformulates this into a convex constraint and applies partitioning to capture the non-convex side of the constraint. This reformulated convex MIP shouldn't have any issue to be be able to solve in Pavito.

felipemarkson commented 1 year ago

Sorry, It was my mistake!

You are right! Using Pavito instead of an pure MILP should work

harshangrjn commented 1 year ago

Here is the script to run your NLP using Pavito and Ipopt within Alpine, which runs fine.

using Alpine
using JuMP
using Ipopt
using Pavito
using HiGHS

function get_highs()
    return JuMP.optimizer_with_attributes(
        HiGHS.Optimizer,
        "log_to_console" => false,
    )
end

function get_pavito(mip_solver, cont_solver)
    return optimizer_with_attributes(
        Pavito.Optimizer,
        MOI.Silent() => true,
        "mip_solver" => mip_solver,
        "cont_solver" => cont_solver
    )
end

function get_ipopt()
    return optimizer_with_attributes(
        Ipopt.Optimizer,
        MOI.Silent() => true,
        "sb" => "yes",
    )
end

mip_solver = get_pavito(get_highs(), get_ipopt())
nlp_solver = get_ipopt()

alpine = JuMP.optimizer_with_attributes(
    Alpine.Optimizer,
    "nlp_solver" => nlp_solver,
    "mip_solver" => mip_solver,
    "presolve_bt" => true,
    "apply_partitioning" => true,
)

model = Model(alpine)
@variable(model, 0 <= x <= 10)
@NLconstraint(model, x^2 ≥ 1)
@NLobjective(model, Min, x^3)

JuMP.optimize!(model)
felipemarkson commented 1 year ago

Thanks! this model works here!

Should I close this issue? Or is it a documentation issue?

harshangrjn commented 1 year ago

Feel free to close it. Have made note for docs update.