Gurobi.jl icon indicating copy to clipboard operation
Gurobi.jl copied to clipboard

Document how to use C API

Open dsigler1234 opened this issue 4 years ago • 3 comments

Hello,

I am attempting to get the lower bound from an integer program using the Gurobi C API. Here is my example

using JuMP, Gurobi

const GRB_ENV = Gurobi.Env()

model = Model(() -> Gurobi.Optimizer(GRB_ENV))
@variable(model, 0 <= y <= 2.5,Int)
@objective(model, Max, y)
optimize!(model)

p = Ref{Cdouble}()
Gurobi.GRBgetdblattr(model, "ObjBound", p)

When I run this code I get the following error:

ERROR: LoadError: MethodError: no method matching unsafe_convert(::Type{Ptr{Nothing}}, ::Model)
Closest candidates are:
  unsafe_convert(::Union{Type{Ptr{Nothing}}, Type{Ptr{Base.Libc.FILE}}}, ::Base.Libc.FILE) at libc.jl:94
  unsafe_convert(::Type{Ptr{T}}, ::StaticArrays.SizedArray) where T at /home/dsigler/.julia/packages/StaticArrays/xV8rq/src/SizedArray.jl:129
  unsafe_convert(::Type{Ptr{T}}, ::Ptr{Tuple{Vararg{T, N}}}) where {N, T} at refpointer.jl:176
  ...
Stacktrace:
 [1] GRBgetdblattr(model::Model, attrname::String, valueP::Base.RefValue{Float64})
   @ Gurobi ~/.julia/packages/Gurobi/HtUHB/src/gen90/libgrb_api.jl:70
 [2] top-level scope
   @ /lustre/eaglefs/scratch/dsigler/ADMM.jl/experimental/ParConsensusADMM/examples/LB_gurobi_test.jl:14
 [3] include(fname::String)
   @ Base.MainInclude ./client.jl:444
 [4] top-level scope
   @ REPL[1]:1
in expression starting at /lustre/eaglefs/scratch/dsigler/ADMM.jl/experimental/ParConsensusADMM/examples/LB_gurobi_test.jl:14

I am not sure if my code is incorrect or if there is a bug here. Any help you can provide would be much appreciated.

dsigler1234 avatar May 25 '21 23:05 dsigler1234

Use objective_bound(model) from JuMP instead.

Using the C API is an advanced an largely undocumented feature. You need to use JuMP in direct mode:

using JuMP, Gurobi
const GRB_ENV = Gurobi.Env()
model = direct_model(Gurobi.Optimizer(GRB_ENV))
@variable(model, 0 <= y <= 2.5, Int)
@objective(model, Max, y)
optimize!(model)
grb = backend(model)
p = Ref{Cdouble}()
Gurobi.GRBgetdblattr(grb, "ObjBound", p)

odow avatar May 25 '21 23:05 odow

I'll leave this issue open as a reminder we need to better document this.

odow avatar May 25 '21 23:05 odow

Sounds good! Thanks for your help.

dsigler1234 avatar May 26 '21 02:05 dsigler1234

Hi, @odow

I wonder is there a convenient way to call the general constraints from Gurobi, e.g.,

julia> import MathOptInterface as MOI

julia> import Gurobi

julia> const GRB_ENV = Gurobi.Env()
Set parameter Username
Academic license - for non-commercial use only - expires 2024-08-09
Gurobi.Env(Ptr{Nothing} @0x000001fe29b2f6d0, false, 0)

julia> o = Gurobi.Optimizer(GRB_ENV);

julia> x,sin_x = MOI.add_variable(o),MOI.add_variable(o) # input 5
(MOI.VariableIndex(1), MOI.VariableIndex(2))

julia> error_code = Gurobi.GRBaddgenconstrSin(o, "sin_constr", 1, 2, "") # input 6
10006 # probably means GRB_ERROR_INDEX_OUT_OF_RANGE

Can we just model as usual (up to input 5) conveniently with the help of MOI, and we insert such a C-API portion as in input 6?

To be more specific, the intention is to build a constraint sin_x = sin(x), which is natively supported by Gurobi (see Approach 2, https://www.gurobi.com/documentation/current/examples/gc_pwl_func_c_c.html).

Thanks!

WalterMadelim avatar Oct 30 '23 02:10 WalterMadelim

For the columns, you need to use a 0-indexed Cint.

import MathOptInterface as MOI
import Gurobi
model = Gurobi.Optimizer()
x, sin_x = MOI.add_variables(model, 2)
Gurobi.GRBaddgenconstrSin(
    model,
    "sin_constr",
    Cint(Gurobi.column(model, x) - 1),
    Cint(Gurobi.column(model, sin_x) - 1),
    "",
)

odow avatar Oct 30 '23 02:10 odow

I've added a minimal amount of documentation here: https://github.com/jump-dev/Gurobi.jl/pull/526

odow avatar Oct 30 '23 02:10 odow