Giter VIP home page Giter VIP logo

gurobi.jl's Introduction

Gurobi.jl underwent a major rewrite between versions 0.8.1 and 0.9.0. Users of JuMP should see no breaking changes, but if you used the lower-level C API (e.g., for callbacks), you will need to update your code accordingly. For a full description of the changes, read this discourse post.

To revert to the old API, use:

import Pkg
Pkg.add(Pkg.PackageSpec(name = "Gurobi", version = v"0.8"))

Then restart Julia for the change to take effect.

Gurobi.jl

Gurobi.jl is a wrapper for the Gurobi Optimizer.

It has two components:

The C API can be accessed via Gurobi.GRBxx functions, where the names and arguments are identical to the C API. See the Gurobi documentation for details.

The Gurobi wrapper for Julia is community driven and not officially supported by Gurobi. If you are a commercial customer interested in official support for Julia from Gurobi, let them know!

Installation

Minimum version requirement: Gurobi.jl requires Gurobi version 9.0 or 9.1.

First, obtain a license of Gurobi and install Gurobi solver, following the instructions on Gurobi's website. Then, set the GUROBI_HOME environment variable as appropriate and run Pkg.add("Gurobi"), the Pkg.build("Gurobi"). For example:

# On Windows, this might be
ENV["GUROBI_HOME"] = "C:\\Program Files\\gurobi910\\win64"
# ... or perhaps ...
ENV["GUROBI_HOME"] = "C:\\gurobi910\\win64"
import Pkg
Pkg.add("Gurobi")
Pkg.build("Gurobi")

# On Mac, this might be
ENV["GUROBI_HOME"] = "/Library/gurobi910/mac64"
import Pkg
Pkg.add("Gurobi")
Pkg.build("Gurobi")

Note: your path may differ. Check which folder you installed Gurobi in, and update the path accordingly.

By default, building Gurobi.jl will fail if the Gurobi library is not found. This may not be desirable in certain cases, for example when part of a package's test suite uses Gurobi as an optional test dependency, but Gurobi cannot be installed on a CI server running the test suite. To support this use case, the GUROBI_JL_SKIP_LIB_CHECK environment variable may be set (to any value) to make Gurobi.jl installable (but not usable).

Use with JuMP

We highly recommend that you use the Gurobi.jl package with higher level packages such as JuMP.jl.

This can be done using the Gurobi.Optimizer object. Here is how to create a JuMP model that uses Gurobi as the solver.

using JuMP, Gurobi

model = Model(Gurobi.Optimizer)
set_optimizer_attribute(model, "TimeLimit", 100)
set_optimizer_attribute(model, "Presolve", 0)

See the Gurobi Documentation for a list and description of allowable parameters.

Reusing the same Gurobi environment for multiple solves

When using this package via other packages such as JuMP.jl, the default behavior is to obtain a new Gurobi license token every time a model is created. If you are using Gurobi in a setting where the number of concurrent Gurobi uses is limited (e.g. "Single-Use" or "Floating-Use" licenses), you might instead prefer to obtain a single license token that is shared by all models that your program solves. You can do this by passing a Gurobi Environment object as the first parameter to Gurobi.Optimizer. For example, the follow code snippet solves multiple problems with JuMP using the same license token:

using JuMP, Gurobi

const GRB_ENV = Gurobi.Env()

model1 = Model(() -> Gurobi.Optimizer(GRB_ENV))

# The solvers can have different options too
model2 = Model(() -> Gurobi.Optimizer(GRB_ENV))
set_optimizer_attribute(model2, "OutputFlag", 0)

Accessing Gurobi-specific attributes via JuMP

You can get and set Gurobi-specific variable, constraint, and model attributes via JuMP as follows:

using JuMP, Gurobi

model = direct_model(Gurobi.Optimizer())
@variable(model, x >= 0)
@constraint(model, c, 2x >= 1)
@objective(model, Min, x)
MOI.set(model, Gurobi.ConstraintAttribute("Lazy"), c, 2)
optimize!(model)

MOI.get(model, Gurobi.VariableAttribute("LB"), x)  # Returns 0.0
MOI.get(model, Gurobi.ModelAttribute("NumConstrs")) # Returns 1

Note that we are using JuMP in direct-mode.

A complete list of supported Gurobi attributes can be found in their online documentation.

Callbacks

Here is an example using Gurobi's solver-specific callbacks.

using JuMP, Gurobi, Test

model = direct_model(Gurobi.Optimizer())
@variable(model, 0 <= x <= 2.5, Int)
@variable(model, 0 <= y <= 2.5, Int)
@objective(model, Max, y)
cb_calls = Cint[]
function my_callback_function(cb_data, cb_where::Cint)
    # You can reference variables outside the function as normal
    push!(cb_calls, cb_where)
    # You can select where the callback is run
    if cb_where != GRB_CB_MIPSOL && cb_where != GRB_CB_MIPNODE
        return
    end
    # You can query a callback attribute using GRBcbget
    if cb_where == GRB_CB_MIPNODE
        resultP = Ref{Cint}()
        GRBcbget(cb_data, cb_where, GRB_CB_MIPNODE_STATUS, resultP)
        if resultP[] != GRB_OPTIMAL
            return  # Solution is something other than optimal.
        end
    end
    # Before querying `callback_value`, you must call:
    Gurobi.load_callback_variable_primal(cb_data, cb_where)
    x_val = callback_value(cb_data, x)
    y_val = callback_value(cb_data, y)
    # You can submit solver-independent MathOptInterface attributes such as
    # lazy constraints, user-cuts, and heuristic solutions.
    if y_val - x_val > 1 + 1e-6
        con = @build_constraint(y - x <= 1)
        MOI.submit(model, MOI.LazyConstraint(cb_data), con)
    elseif y_val + x_val > 3 + 1e-6
        con = @build_constraint(y + x <= 3)
        MOI.submit(model, MOI.LazyConstraint(cb_data), con)
    end
    if rand() < 0.1
        # You can terminate the callback as follows:
        GRBterminate(backend(model))
    end
    return
end
# You _must_ set this parameter if using lazy constraints.
MOI.set(model, MOI.RawParameter("LazyConstraints"), 1)
MOI.set(model, Gurobi.CallbackFunction(), my_callback_function)
optimize!(model)
@test termination_status(model) == MOI.OPTIMAL
@test primal_status(model) == MOI.FEASIBLE_POINT
@test value(x) == 1
@test value(y) == 2

See the Gurobi documentation for other information that can be queried with GRBcbget.

Common Performance Pitfall with JuMP

Gurobi's API works differently than most solvers. Any changes to the model are not applied immediately, but instead go sit in a internal buffer (making any modifications appear to be instantaneous) waiting for a call to GRBupdatemodel (where the work is done).

This leads to a common performance pitfall that has the following message as its main symptom:

Warning: excessive time spent in model updates. Consider calling update less
frequently.

This often means the JuMP program was structured in such a way that Gurobi.jl ends up calling GRBupdatemodel each iteration of a loop. Usually, it is possible (and easy) to restructure the JuMP program in a way it stays solver-agnostic and has a close-to-ideal performance with Gurobi.

To guide such restructuring it is good to keep in mind the following bits of information:

  1. GRBupdatemodel is only called if changes were done since last GRBupdatemodel (i.e., the internal buffer is not empty).
  2. GRBupdatemodel is called when JuMP.optimize! is called, but this often is not the source of the problem.
  3. GRBupdatemodel may be called when ANY model attribute is queried even if that specific attribute was not changed, and this often the source of the problem.
  4. The worst-case scenario is, therefore, a loop of modify-query-modify-query, even if what is being modified and what is being queried are two completely distinct things.

As an example, prefer:

# GOOD
model = Model(Gurobi.Optimizer)
@variable(model, x[1:100] >= 0)
# All modifications are done before any queries.
for i = 1:100
    set_upper_bound(x[i], i)
end
for i = 1:100
    # Only the first `lower_bound` query may trigger an `GRBupdatemodel`.
    println(lower_bound(x[i]))
end

to:

# BAD
model = Model(Gurobi.Optimizer)
@variable(model, x[1:100] >= 0)
for i = 1:100
    set_upper_bound(x[i], i)
    # `GRBupdatemodel` called on each iteration of this loop.
    println(lower_bound(x[i]))
end

Using Gurobi v9.0 and you got an error like Q not PSD?

You need to set the NonConvex parameter:

model = Model(Gurobi.Optimizer)
set_optimizer_attribute(model, "NonConvex", 2)

gurobi.jl's People

Contributors

abelsiqueira avatar andrioni avatar antonhinneck avatar blegat avatar cdeil avatar chriscoey avatar cossio avatar daschw avatar dourouc05 avatar englhardt avatar expandingman avatar fa-bien avatar henriquebecker91 avatar iainnz avatar jackdunnnz avatar joaquimg avatar joehuchette avatar joseortiz3 avatar juliatagbot avatar leotac avatar lindahua avatar mattmilten avatar metab0t avatar mlubin avatar odow avatar omalled avatar r-barnes avatar rdeits avatar rschwarz avatar yeesian avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.