Python API Overview#
Global Functions#
For convenience when using Gurobi interactively through the Python
interpreter, we provide a set of Global Functions. The most important of these functions is probably the
read
function, which allows you to
read and solve a model from file.
Another useful global function is disposeDefaultEnv
, which
disposes of the default environment. Other global functions allow you to
read, modify, or write Gurobi parameters (readParams
,
setParam
, and writeParams
).
Models#
Most actions in the Gurobi Python interface are performed by calling
methods on Gurobi objects. The most commonly used object is the
Model
. A model consists of a set of decision variables
(objects of class Var
or MVar
), a linear or
quadratic objective function on these variables (specified using
Model.setObjective
), and a set of constraints on these
variables (objects of class Constr
, MConstr
,
QConstr
, MQConstr
, SOS
,
GenConstr
, or MGenConstr
). 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
for more information on variables, constraints, and objectives.
An optimization model may be specified all at once, by loading the model
from a file (using the previously mentioned read
function),
or it may be built incrementally, by first constructing an empty object
of class Model
and then subsequently calling
Model.addVar
, Model.addVars
, or
Model.addMVar
to add additional variables, and
Model.addConstr
, Model.addConstrs
,
Model.addLConstr
, Model.addQConstr
,
Model.addSOS
, or any of the
Model.addGenConstr*
methods to add
additional constraints.
See Build a model
for general guidance or mip1_remote.py
for a specific example.
Linear constraints are specified by building linear expressions (objects
of class LinExpr
or MLinExpr
), 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 QuadExpr
or
MQuadExpr
) instead. General constraints are built using a
set of dedicated methods, or a set of
general constraint helper functions plus
overloaded operators.
Nonlinear constraints are specified by building nonlinear expressions (objects
of class NLExpr
or MNLExpr
) and specifying a chosen
resultant variable which takes the value of the expression. That resultant
variable can then participate in other constraints. In the Python API, nonlinear
expressions are built using operator overloading. In general, calling any
nonlinear function, or creating any expression which is not strictly linear
or quadratic (in terms of the model variables) results in a nonlinear expression.
Models are dynamic entities; you can always add or remove variables or constraints.
We often refer to the class of an optimization model. At the highest level, a model can be continuous or discrete, depending on whether the modeling elements present in the model require discrete decisions to be made. Among continuous models…
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 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 any of the constraints are non-linear (chosen from among the available general constraints), the model is a Non-Linear Program (NLP).
A model that contains any integer variables, semi-continuous variables, semi-integer variables, Special Ordered Set (SOS) constraints, or general constraints, is discrete, and is referred to as a Mixed Integer Program (MIP). The special cases of MIP, which are the discrete versions of the continuous models types we’ve already described, are…
Mixed Integer Linear Programs (MILP)
Mixed Integer Quadratic Programs (MIQP)
Mixed Integer Quadratically-Constrained Programs (MIQCP)
Mixed Integer Second-Order Cone Programs (MISOCP)
Mixed Integer Non-Linear Programs (MINLP)
The Gurobi Optimizer handles all of these model classes. Note that the boundaries between them aren’t as clear as one might like, because we are often able to transform a model from one class to a simpler class.
Environments#
Environments play a much smaller role in the Gurobi Python interface than they do in our other language APIs, mainly because the Python interface has a default environment. Unless you explicitly pass your own environment to routines that require an environment, the default environment will be used.
The main situation where you may want to create your own environment is
when you want precise control over when the resources associated with an
environment (specifically, a licensing token or a Compute Server) are
released. If you use your own environment to create models (using
read
or the Model
constructor), then the
resources associated with the environment will be released as soon as your
program no longer references your environment or any models created with
that environment.
Note that you can manually remove the reference to the default
environment, thus making it available for garbage collection, by calling
disposeDefaultEnv
. After calling this, and after all models
built within the default environment are garbage collected, the default
environment will be garbage collected as well. A new default environment
will be created automatically if you call a routine that needs one.
For more advanced use cases, 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.
Solving a Model#
Once you have built a model, you can call Model.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,
which can be subsequently queried (we will return to this topic
shortly).
The Gurobi algorithms keep careful track of the state of the model, so
calls to Model.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 Model.reset
.
After a MIP model has been solved, you can call Model.fixed
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.py).
Multiple Scenarios: Allows you to find solutions to multiple, related models (refer to example multiscenario.py).
Multiple Objectives: Allows you to specify multiple objective functions and control the trade-off between them (refer to example multiobj.py).
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
Model.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 Model.feasRelaxS
or Model.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 can be accessed in two ways in the Python interface. The
first is to use the getAttr()
and setAttr()
methods, which are
available on variables (Var.getAttr
/ Var.setAttr
),
matrix variables (MVar.getAttr
/ MVar.setAttr
),
linear constraints (Constr.getAttr
/
Constr.setAttr
), matrix constraints
(MConstr.getAttr
/ MConstr.setAttr
), quadratic
constraints (QConstr.getAttr
/ QConstr.setAttr
),
matrix constraints (MQConstr.getAttr
/
MQConstr.setAttr
), SOSs (SOS.getAttr
), general
constraints (GenConstr.getAttr
/
GenConstr.setAttr
), and models (Model.getAttr
/
Model.setAttr
). These are called with the attribute name as
the first argument (e.g., var.getAttr("x")
or
constr.setAttr("rhs", 0.0)
). The full list of available attributes
can be found in the Attributes section of this
manual.
Attributes can also be accessed more directly: you can follow an object
name by a period, followed by the name of an attribute of that object.
Note that upper/lower case is ignored when referring to attributes.
Thus, b = constr.rhs
is equivalent to b = constr.getAttr("rhs")
,
and constr.rhs = 0.0
is equivalent to
constr.setAttr("rhs", 0.0)
.
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 Model.chgCoeff
method. 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 Model.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 LinExpr
, MLinExpr
, QuadExpr
, or
MQuadExpr
object), and then pass that expression to method
Model.setObjective
. If you wish to modify the objective, you
can simply call Model.setObjective
again with a new LinExpr
or
QuadExpr
object.
For linear objective functions, an alternative to Model.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 Model.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 Model.update
. The second is
by a call to Model.optimize
. The third is by a call to
Model.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 are set
using method Model.setParam
. Current values may also be
retrieved with Model.getParamInfo
. You can also access
parameters more directly through the Model.Params
class. To set the
MIPGap parameter to 0.0 for model m
, for example,
you can do either m.setParam('MIPGap', 0)
or
m.Params.MIPGap = 0
.
Refer to the example params.py which
is considered in Change parameters.
You can read a set of parameter settings from a file using
Model.read
, or write the set of changed parameters using
Model.write
.
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 Model.tune
to invoke the tuning
tool on a model. Refer to the parameter tuning tool
section for more information.
One thing we should note is that changing a parameter for one model has
no effect on the parameter value for other models. Use the global
setParam
method to set a parameter for all loaded models.
The full list of Gurobi parameters can be found in the Parameters section.
Monitoring Progress - Logging#
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. You can set the LogFile parameter if you wish to also direct the Gurobi log to a file. Printing of log messages to the screen (standard output) can be suppressed using the LogToConsole parameter. The frequency of logging output can be controlled with the DisplayInterval parameter, and logging can be turned off entirely with the OutputFlag parameter.
Log output is also sent to a Python logger named gurobipy
, at level
INFO
. You can use the Python logging
module to connect to
this log. Messages are always sent to the logger, unless
OutputFlag is set to 0.
If you want log messages to be sent to the Python logger but not printed to
standard output, you should leave OutputFlag at its default
value and set LogToConsole to 0. To suppress all Gurobi log
messages on standard output, you must set this parameter when starting the
environment. The following example demonstrates proper usage, along with a call
to logging.basicConfig
to emit Gurobi log messages through the Python
logger:
import logging
import gurobipy as gp
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
env = gp.Env(params={"LogToConsole": 0})
model = gp.Model(env=env)
...
model.optimize()
Monitoring Progress - Callbacks#
More detailed progress monitoring can be done through a callback
function. If you pass a function taking two arguments, model
and
where
, to Model.optimize
, your function will be called
periodically from within the optimization. Your callback can then call
Model.cbGet
to retrieve additional information on the state
of the optimization. You can refer to the
Callbacks section for additional information.
Refer to the example callback.py
which is discussed in Callbacks.
Modifying Solver Behavior - Callbacks#
Callbacks can also be used to modify the behavior of the Gurobi
optimizer. The simplest control callback is Model.terminate
,
which asks the optimizer to terminate at the earliest convenient point.
Method Model.cbSetSolution
allows you to inject a feasible
solution (or partial solution) during the solution of a MIP model.
Methods Model.cbCut
and Model.cbLazy
allow you to
add cutting planes and lazy constraints during a MIP optimization,
respectively (refer to the example tsp.py).
Method Model.cbStopOneMultiObj
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 Python library can throw an exception
of type GurobiError
. When an exception occurs, additional
information on the error can be obtained by retrieving the errno
or
message
members of the GurobiError
object. A list of possible
values for the errno
field can be found in the
Error Code table.