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

Alpine cannot use the same Gurobi environment for multiple solves #211

Closed Shuvomoy closed 1 year ago

Shuvomoy commented 1 year ago

Consider the following code where I am trying to use the same Gurobi environment for multiple soves as found in the Gurobi.jl documentation here. I am trying to do this, because otherwise there are too many Academic license - for non-commercial use only.

## Load packages
using Alpine
using JuMP
using Gurobi
using Ipopt

## Alpine optimization model
function nlp(; solver=nothing)

    d = 10

    m = Model(solver)

    # declare the variable 
    @variable(m, 0 <= x[1:d])

    # add objective
    @NLobjective(m, Max, x[1] * x[d] - x[2] * x[d-1])

    # add the constraints

    @constraint(m, sum(x[i] for i in 1:d) <= 10)

    for i in 1:d-1
        @constraint(m, x[i] * x[i+1] <= 2)
    end

    @constraint(m, sum(x[i] * x[i+1] for i in 1:d-1) == 1)

    return m

end

# Set NLP local solver

ipopt = JuMP.optimizer_with_attributes(Ipopt.Optimizer, 
MOI.Silent() => true)

## Set MIP solver
gurobi = JuMP.optimizer_with_attributes(() -> Gurobi.Optimizer(GRB_ENV),  # 💀 done in order to suppress `Academic license - for non-commercial use only` multiple times
                                        MOI.Silent() => true, 
                                        "Presolve" => 0)

# Set Alpine as the global solver
const alpine = JuMP.optimizer_with_attributes(Alpine.Optimizer, 
                                              "nlp_solver"   => ipopt, # knitro,  
                                              "mip_solver"   => gurobi,
                                              "presolve_bt"  => true,
                                              "disc_ratio"   => 10,
                                              "apply_partitioning" => true,
                                              "log_level" => 100
                                              )

m = nlp(solver = alpine)

JuMP.optimize!(m)

The error is:

MathOptInterface.OptimizerWithAttributes(Ipopt.Optimizer, Pair{MathOptInterface.AbstractOptimizerAttribute, Any}[MathOptInterface.Silent() => true])

ERROR: Unsupported MIP solver MathOptInterface.OptimizerWithAttributes(var"#17#18"(), Pair{MathOptInterface.AbstractOptimizerAttribute, Any}[MathOptInterface.Silent() => true, MathOptInterface.RawOptimizerAttribute("Presolve") => 0]); use a Alpine-supported MIP solver
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:35
  [2] fetch_mip_solver_identifier(m::Alpine.Optimizer; override::String)
    @ Alpine ~/.julia/packages/Alpine/RIjEU/src/utility.jl:494
  [3] fetch_mip_solver_identifier
    @ ~/.julia/packages/Alpine/RIjEU/src/utility.jl:464 [inlined]
  [4] load!(m::Alpine.Optimizer)
    @ Alpine ~/.julia/packages/Alpine/RIjEU/src/algorithm.jl:90
  [5] optimize!(m::Alpine.Optimizer)
    @ Alpine ~/.julia/packages/Alpine/RIjEU/src/algorithm.jl:137
  [6] optimize!
    @ ~/.julia/packages/MathOptInterface/LqT2k/src/Bridges/bridge_optimizer.jl:376 [inlined]
  [7] optimize!
    @ ~/.julia/packages/MathOptInterface/LqT2k/src/MathOptInterface.jl:87 [inlined]
  [8] optimize!(m::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{Alpine.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}})
    @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/LqT2k/src/Utilities/cachingoptimizer.jl:316
  [9] optimize!(model::Model; ignore_optimize_hook::Bool, _differentiation_backend::MathOptInterface.Nonlinear.SparseReverseMode, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ JuMP ~/.julia/packages/JuMP/60Bnj/src/optimizer_interface.jl:185
 [10] optimize!(model::Model)
    @ JuMP ~/.julia/packages/JuMP/60Bnj/src/optimizer_interface.jl:155
 [11] top-level scope
    @ ~/Desktop/alpine_test.jl:105

After talking with @blegat , it appears that the issue lies in Alpine.jl and not in Gurobi.jl. @harshangrjn, what can I do to use the same Gurobi environment for multiple solves?

harshangrjn commented 1 year ago

@ccoffrin @odow Do you have any suggestions for this based on your experiences to handle Gurobi's environment issue?

ccoffrin commented 1 year ago

As I understand this issue, it has to do with how in Alpine you conduct the check, "do I support this MIP solver?". In Juniper we don't run into this because we accept any MIP or NLP solver that follow's MOI's API for these classes of problems.

Actually, I don't remember why this check is in Alpine. Maybe now it can be removed? If not, @odow can guide us on the best approach for checking the solver's type.

odow commented 1 year ago

Yeah this is a duplicate of #178. It's probably easiest to just accept any solver the user throws at you and hope they choose carefully

harshangrjn commented 1 year ago

Thanks @ccoffrin and @odow. It's probably easiest to leave it to the user and reduce other solver related issues like this one. Will update accordingly.

blegat commented 1 year ago

I agree, the only place where checks are needed is when Alpine sets solvers specific attributes to Ipopt but it should accept any solver as input

harshangrjn commented 1 year ago

@Shuvomoy This issue has been resolved in v0.4.3. Also the way Gurobi is invoked in the same environment is updated here: https://github.com/lanl-ansi/Alpine.jl/blob/9844e7deec33b1df4708f66335231e6fa0d85bb2/examples/optimizers.jl#L2

Shuvomoy commented 1 year ago

Great, thanks @harshangrjn