Java API Overview#
Environments#
The first step in using the Gurobi Java interface is to create an
environment object. Environments are represented using the
GRBEnv
class. An environment acts as the container for all
data associated with a set of optimization runs. You will generally only
need one environment object in your program.
For more advanced usecases, you can use an empty environment to create an uninitialized environment and then, programmatically, set all required options for your specific requirements. For further details see the Environment section.
Models#
You can create one or more optimization models within an environment.
Each model is represented as an object of class GRBModel
.
A model consists of a set of decision variables (objects of class
GRBVar
), a linear or quadratic objective function on these
variables (specified using GRBModel.setObjective
), and a
set of constraints on these variables (objects of class
GRBConstr
, GRBQConstr
, GRBSOS
,
or GRBGenConstr
). Each variable has an associated lower
bound, upper bound, and type (continuous, binary, etc.). Each linear or
quadratic constraint has an associated sense (less-than-or-equal,
greater-than-or-equal, or equal), and right-hand side value. Refer to
this section in the Reference
Manual for more information on variables, constraints, and objectives.
Linear constraints are specified by building linear expressions (objects
of class GRBLinExpr
), and then specifying relationships
between these expressions (for example, requiring that one expression be
equal to another). Quadratic constraints are built in a similar fashion,
but using quadratic expressions (objects of class
GRBQuadExpr
) instead.
An optimization model may be specified all at once, by loading the model
from a file (using the appropriate GRBModel
constructor),
or built incrementally, by first constructing an empty object of class
GRBModel
and then subsequently calling
GRBModel.addVar
or GRBModel.addVars
to add
additional variables, and GRBModel.addConstr
,
GRBModel.addQConstr
, GRBModel.addSOS
, or any
of the GRBModel.addGenConstr*
methods to add additional constraints. Models are dynamic entities; you
can always add or remove variables or constraints.
See Build a model
for general guidance or Mip1.java
for a specific example.
We often refer to the class of an optimization model. A model with a linear objective function, linear constraints, and continuous variables is a Linear Program (LP). If the objective is quadratic, the model is a Quadratic Program (QP). If any of the constraints are quadratic, the model is a Quadratically-Constrained Program (QCP). We will sometimes refer to a few special cases of QCP: QCPs with convex constraints, QCPs with non-convex constraints, bilinear programs, and Second-Order Cone Programs (SOCP). If the model contains any integer variables, semi-continuous variables, semi-integer variables, Special Ordered Set (SOS) constraints, or general constraints, the model is a Mixed Integer Program (MIP). We’ll also sometimes discuss special cases of MIP, including Mixed Integer Linear Programs (MILP), Mixed Integer Quadratic Programs (MIQP), Mixed Integer Quadratically-Constrained Programs (MIQCP), and Mixed Integer Second-Order Cone Programs (MISOCP). The Gurobi Optimizer handles all of these model classes.
Solving a Model#
Once you have built a model, you can call GRBModel.optimize
to compute a solution. By default,
optimize
will use the
concurrent optimizer to solve LP models, the
barrier algorithm to solve QP models with convex objectives and QCP
models with convex constraints, and the branch-and-cut algorithm
otherwise. The solution is stored in a set of attributes of the model.
These attributes can be queried using a set of attribute query methods
on the GRBModel
, GRBVar
,
GRBConstr
, GRBQConstr
, GRBSOS
,
and GRBGenConstr
, and classes.
The Gurobi algorithms keep careful track of the state of the model, so
calls to GRBModel.optimize
will only perform further
optimization if relevant data has changed since the model was last
optimized. If you would like to discard previously computed solution
information and restart the optimization from scratch without changing
the model, you can call GRBModel.reset
.
After a MIP model has been solved, you can call
GRBModel.fixedModel
to compute the associated fixed
model. This model is identical to the original, except that the integer
variables are fixed to their values in the MIP solution. If your model
contains SOS constraints, some continuous variables that appear in these
constraints may be fixed as well. In some applications, it can be useful
to compute information on this fixed model (e.g., dual variables,
sensitivity information, etc.), although you should be careful in how
you interpret this information.
Multiple Solutions, Objectives, and Scenarios#
By default, the Gurobi Optimizer assumes that your goal is to find one proven optimal solution to a single model with a single objective function. Gurobi provides the following features that allow you to relax these assumptions:
Solution Pool: Allows you to find more solutions (refer to example Poolsearch.java).
Multiple Scenarios: Allows you to find solutions to multiple, related models (refer to example Multiscenario.java).
Multiple Objectives: Allows you to specify multiple objective functions and control the trade-off between them (refer to example Multiobj.java).
Infeasible Models#
You have a few options if a model is found to be infeasible. You can try
to diagnose the cause of the infeasibility, attempt to repair the
infeasibility, or both. To obtain information that can be useful for
diagnosing the cause of an infeasibility, call
GRBModel.computeIIS
to compute an Irreducible Inconsistent
Subsystem (IIS). This method can be used for both continuous and MIP
models, but you should be aware that the MIP version can be quite
expensive. This method populates a set of IIS attributes.
To attempt to repair an infeasibility, call
GRBModel.feasRelax
to compute a feasibility relaxation for
the model. This relaxation allows you to find a solution that minimizes
the magnitude of the constraint violation.
You will find more information about this feature in section
Relaxing for feasibility. Examples are discussed in
Diagnose and cope with infeasibility.
Querying and Modifying Attributes#
Most of the information associated with a Gurobi model is stored in a set of attributes. Some attributes are associated with the variables of the model, some with the constraints of the model, and some with the model itself. To give a simple example, solving an optimization model causes the X variable attribute to be populated. Attributes such as X that are computed by the Gurobi optimizer cannot be modified directly by the user, while others, such as the variable lower bound (the LB attribute) can.
Attributes are queried using GRBVar.get
,
GRBConstr.get
, GRBQConstr.get
,
GRBSOS.get
, GRBGenConstr.get
, or
GRBModel.get
, and modified using GRBVar.set
,
GRBConstr.set
, GRBQConstr.set
,
GRBGenConstr.set
, or GRBModel.set
. Attributes
are grouped into a set of enums by type (GRB.CharAttr
,
GRB.DoubleAttr
, GRB.IntAttr
,
GRB.StringAttr
). The get()
and set()
methods are
overloaded, so the type of the attribute determines the type of the
returned value. Thus, constr.get(GRB.DoubleAttr.RHS)
returns a
double, while constr.get(GRB.CharAttr.Sense)
returns a char.
If you wish to retrieve attribute values for a set of variables or
constraints, it is usually more efficient to use the array methods on
the associated GRBModel
object. Method
GRBModel.get
includes signatures that allow you to query or
modify attribute values for one-, two-, and three-dimensional arrays of
variables or constraints.
The full list of attributes can be found in the Attributes section.
Additional Model Modification Information#
Most modifications to an existing model are done through the attribute interface (e.g., changes to variable bounds, constraint right-hand sides, etc.). The main exceptions are modifications to the constraint matrix and to the objective function.
The constraint matrix can be modified in a few ways. The first is to
call the chgCoeff
method on a
GRBModel
object to change individual matrix coefficients.
This method can be used to modify the value of an existing non-zero, to
set an existing non-zero to zero, or to create a new non-zero. The
constraint matrix is also modified when you remove a variable or
constraint from the model (through the GRBModel.remove
method). The non-zero values associated with the deleted constraint or
variable are removed along with the constraint or variable itself.
The model objective function can also be modified in a few ways. The
easiest is to build an expression that captures the objective function
(a GRBLinExpr
or GRBQuadExpr
object), and
then pass that expression to method GRBModel.setObjective
.
If you wish to modify the objective, you can simply call
GRBModel.setObjective
again with a new GRBLinExpr
or GRBQuadExpr
object.
For linear objective functions, an alternative to GRBModel.setObjective
is to use
the Obj variable attribute to modify individual linear objective
coefficients.
If your variables have piecewise-linear objectives, you can specify them using
the GRBModel.setPWLObj
method. Call this method once for each
relevant variable. The Gurobi simplex solver includes algorithmic support for
convex piecewise-linear objective functions, so for continuous models you
should see a substantial performance benefit from using this feature. To clear
a previously specified piecewise-linear objective function, simply set the
Obj attribute on the corresponding variable to 0.
Some examples are discussed in Modify a model.
Lazy Updates#
One important item to note about model modification in the Gurobi optimizer is that it is performed in a lazy fashion, meaning that modifications don’t affect the model immediately. Rather, they are queued and applied later. If your program simply creates a model and solves it, you will probably never notice this behavior. However, if you ask for information about the model before your modifications have been applied, the details of the lazy update approach may be relevant to you.
As we just noted, model modifications (bound changes, right-hand side
changes, objective changes, etc.) are placed in a queue. These queued
modifications can be applied to the model in three different ways. The
first is by an explicit call to GRBModel.update
. The second
is by a call to GRBModel.optimize
. The third is by a call
to GRBModel.write
to write out the model. The first case
gives you fine-grained control over when modifications are applied. The
second and third make the assumption that you want all pending
modifications to be applied before you optimize your model or write it
to disk.
Why does the Gurobi interface behave in this manner? There are a few reasons. The first is that this approach makes it much easier to perform multiple modifications to a model, since the model remains unchanged between modifications. The second is that processing model modifications can be expensive, particularly in a Compute Server environment, where modifications require communication between machines. Thus, it is useful to have visibility into exactly when these modifications are applied. In general, if your program needs to make multiple modifications to the model, you should aim to make them in phases, where you make a set of modifications, then update, then make more modifications, then update again, etc. Updating after each individual modification can be extremely expensive.
If you forget to call update, your program won’t crash. Your query will simply return the value of the requested data from the point of the last update. If the object you tried to query didn’t exist, Gurobi will throw an exception with error code NOT_IN_MODEL.
The semantics of lazy updates have changed since earlier Gurobi versions. While the vast majority of programs are unaffected by this change, you can use the UpdateMode parameter to revert to the earlier behavior if you run into an issue.
Managing Parameters#
The Gurobi optimizer provides a set of parameters that allow you to control many of the details of the optimization process. Factors like feasibility and optimality tolerances, choices of algorithms, strategies for exploring the MIP search tree, etc., can be controlled by modifying Gurobi parameters before beginning the optimization. Parameters can be of type int, double, or string.
The simplest way to set parameters is through the
GRBModel.set
method on the model object. Similarly,
parameter values can be queried with GRBModel.get
.
Parameters can also be set on the Gurobi environment object, using
GRBEnv.set
. Note that each model gets its own copy of the
environment when it is created, so parameter changes to the original
environment have no effect on existing models.
You can read a set of parameter settings from a file using
GRBEnv.readParams
, or write the set of changed parameters
using GRBEnv.writeParams
.
Refer to the example Params.java which is considered in Change parameters.
We also include an automated parameter tuning tool that explores many
different sets of parameter changes in order to find a set that improves
performance. You can call GRBModel.tune
to invoke the
tuning tool on a model. Refer to the
parameter tuning tool section for more information.
The full list of Gurobi parameters can be found in the Parameters section.
Memory Management#
Users typically do not need to concern themselves with memory management in Java, since it is handled automatically by the garbage collector. The Gurobi Java interface utilizes the same garbage collection mechanism as other Java programs, but there are a few specifics of our memory management that users should be aware of.
In general, Gurobi objects live in the same Java heap as other Java
objects. When they are no longer referenced, they become candidates for
garbage collection, and are returned to the pool of free space at the
next invocation of the garbage collector. Two important exceptions are
the GRBEnv
and GRBModel
objects. A
GRBModel
object has a small amount of memory associated with it in
the Java heap, but the majority of the space associated with a model
lives in the heap of the Gurobi native code library (the Gurobi DLL in
Windows, or the Gurobi shared library in Linux or Mac). The Java heap
manager is unaware of the memory associated with the model in the native
code library, so it does not consider this memory usage when deciding
whether to invoke the garbage collector. When the garbage collector
eventually collects the Java GRBModel
object, the memory associated
with the model in the Gurobi native code library will be freed, but this
collection may come later than you might want. Similar considerations
apply to the GRBEnv
object.
If you are writing a Java program that makes use of multiple Gurobi
models or environments, we recommend that you call
GRBModel.dispose
when you are done using the associated
GRBModel
object, and GRBEnv.dispose
when you are done
using the associated GRBEnv
object and after you have called
GRBModel.dispose
on all of the models created using that
GRBEnv
object.
Native Code#
As noted earlier, the Gurobi Java interface is a thin layer that sits on
top of our native code library (the Gurobi DLL on Windows, and the
Gurobi shared library on Linux or Mac). Thus, an application that uses
the Gurobi Java library will load the Gurobi native code library at
runtime. In order for this happen, you need to make sure that two things
are true. First, you need to make sure that the native code library is
available in the search path of the target machine (PATH
on Windows,
LD_LIBRARY_PATH
on Linux, or DYLD_LIBRARY_PATH
on Mac). These
paths are set up as part of the installation of the Gurobi Optimizer,
but may not be configured appropriately on a machine where the full
Gurobi Optimizer has not been installed. Second, you need to be sure
that the Java JVM and the Gurobi native library use the same object
format. In particular, you need to use a 64-bit Java JVM to use the
64-bit Gurobi native library.
Monitoring Progress - Logging and Callbacks#
Progress of the optimization can be monitored through Gurobi logging. By
default, Gurobi will send output to the screen. A few simple controls
are available for modifying the default logging behavior. If you would
like to direct output to a file as well as to the screen, specify the
log file name in the GRBEnv
constructor. You can modify
the LogFile parameter if you wish to redirect the log to
a different file after creating the environment object. The frequency of
logging output can be controlled with the
DisplayInterval parameter, and logging can be turned off
entirely with the OutputFlag parameter. A detailed
description of the Gurobi log file can be found in the
Logging section.
More detailed progress monitoring can be done through the
GRBCallback
class. The GRBModel.setCallback
method allows you to receive a periodic callback from the Gurobi
optimizer. You do this by sub-classing the GRBCallback
abstract class, and writing your own Callback()
method on this
class. You can call GRBCallback.getDoubleInfo
,
GRBCallback.getIntInfo
,
GRBCallback.getStringInfo
, or
GRBCallback.getSolution
from within the callback to obtain
additional information about the state of the optimization.
Refer to the example Callback.java
which is discussed in Callbacks.
In addition, you can add a logging callback function to an environment
object (GRBEnv.setLogCallback
) or a model object
(GRBModelEnv.setLogCallback
).
The callback function will receive each log line produced by the
environment or model object.
Modifying Solver Behavior - Callbacks#
Callbacks can also be used to modify the behavior of the Gurobi
optimizer. The simplest control callback is
GRBCallback.abort
, which asks the optimizer to terminate at
the earliest convenient point. Method
GRBCallback.setSolution
allows you to inject a feasible
solution (or partial solution) during the solution of a MIP model.
Methods GRBCallback.addCut
and
GRBCallback.addLazy
allow you to add cutting planes and
lazy constraints during a MIP optimization, respectively (refer to
the example Tsp.java). Method
GRBCallback.stopOneMultiObj
allows you to interrupt
the optimization process of one of the
optimization steps in a multi-objective MIP problem without stopping the
hierarchical optimization process.
Batch Optimization#
Gurobi Compute Server enables programs to offload optimization
computations onto dedicated servers. The Gurobi Cluster Manager adds a
number of additional capabilities on top of this. One important one,
batch optimization, allows you to build an optimization model with
your client program, submit it to a Compute Server cluster (through the
Cluster Manager), and later check on the status of the model and
retrieve its solution. You can use a Batch object
to
make it easier to work with batches. For details on batches, please
refer to the Batch Optimization section.
Error Handling#
All of the methods in the Gurobi Java library can throw an exception of
type GRBException
. When an exception occurs, additional
information on the error can be obtained by retrieving the error code
(using method GRBException.getErrorCode
), or by retrieving
the exception message (using method GRBException.getMessage
from the
parent class). The list of possible error return codes can be found in
the Error Codes table.