C API Overview#
Environments#
The first step in using the Gurobi C optimizer is to create an
environment, using the GRBloadenv
call. The environment acts
as a container for all data associated with a set of optimization runs.
You will generally only need one environment in your program, even if
you wish to work with multiple optimization models. Once you are done
with an environment, you should call GRBfreeenv
to release the
associated resources.
For more advanced use cases, you can use the GRBemptyenv
routine 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. A model consists of a set of variables, a linear, quadratic, or piecewise-linear objective function on those variables, and a set of constraints. Each variable has an associated lower bound, upper bound, type (continuous, binary, integer, semi-continuous, or semi-integer), and linear objective coefficient. Each linear 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 and constraints.
An optimization model may be specified all at once, through the
GRBloadmodel
routine, or built incrementally, by first calling
GRBnewmodel
and then calling GRBaddvars
to add
variables and GRBaddconstr
, GRBaddqconstr
,
GRBaddsos
, or any of the
GRBaddgenconstr* methods to add
constraints. Models are dynamic entities; you can always add or delete
variables or constraints.
See Build a model
for general guidance or mip1_c.c
for a specific example.
Specific variables and constraints are referred to throughout the Gurobi C interface using their indices. Variable indices are assigned as variables are added to the model, in a contiguous fashion. The same is true for constraints. In adherence to C language conventions, indices all start at 0.
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 GRBoptimize
to
compute a solution. By default, GRBoptimize
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 as a set of attributes of the model.
The C interface contains an extensive set of routines for querying these
attributes.
The Gurobi algorithms keep careful track of the state of the model, so
calls to GRBoptimize
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 GRBreset
.
After a MIP model has been solved, you can call GRBfixmodel
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_c.c).
Multiple Scenarios: Allows you to find solutions to multiple, related models (refer to example multiscenario_c.c).
Multiple Objectives: Allows you to specify multiple objective functions and control the trade-off between them (refer to example multiobj_c.c).
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 GRBcomputeIIS
to compute an Irreducible Inconsistent Subsystem (IIS). This routine can
be used for both continuous and MIP models, but you should be aware that
the MIP version can be quite expensive. This routine populates a set of
IIS attributes.
To attempt to repair an infeasibility, call GRBfeasrelax
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 array (the LB attribute) can.
The Gurobi C interface contains an extensive set of routines for querying or modifying attribute values. The exact routine to use for a particular attribute depends on the type of the attribute. As mentioned earlier, attributes can be either variable attributes, constraint attributes, or model attributes. Variable and constraint attributes are arrays, and use a set of array attribute routines. Model attributes are scalars, and use a set of scalar routines. Attribute values can additionally be of type char, int, double, or string (really char *).
Scalar model attributes are accessed through a set of GRBget*attr()
routines (e.g., GRBgetintattr
). In addition, those model
attributes that can be set directly by the user (e.g., the objective
sense) may be modified through the GRBset*attr()
routines (e.g.,
GRBsetdblattr
).
Array attributes are accessed through three sets of routines. The first
set, the GRBget*attrarray()
routines (e.g.,
GRBgetcharattrarray
) return a contiguous sub-array of the
attribute array, specified using the index of the first member and the
length of the desired sub-array. The second set, the
GRBget*attrelement()
routines (e.g.,
GRBgetcharattrelement
) return a single entry from the
attribute array. Finally, the GRBget*attrlist()
routines (e.g.,
GRBgetdblattrlist
) retrieve attribute values for a list of
indices.
Array attributes that can be set by the user are modified through the
GRBset*attrarray()
, GRBset*attrelement()
, and
GRBset*attrlist()
routines.
The full list of Gurobi 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 constraints themselves, and to the quadratic and piecewise-linear portions of the objective function.
The constraint matrix can be modified in a few ways. The first is to
call GRBchgcoeffs
to change individual matrix coefficients.
This routine 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 constraints (through
GRBdelconstrs
) or variables (through GRBdelvars
).
The non-zero values associated with the deleted constraints or variables
are removed along with the constraints or variables themselves.
Quadratic objective terms are added to the objective function using the
GRBaddqpterms
routine. You can add a list of quadratic terms
in one call, or you can add terms incrementally through multiple calls.
The GRBdelq
routine allows you to delete all quadratic terms
from the model. Note that quadratic models will typically have both
quadratic and linear terms. Linear terms are entered and modified
through the Obj attribute, in the same way that they are handled
for models with purely linear objective functions.
If your variables have piecewise-linear objectives, you can specify them
using the GRBsetpwlobj
routine. Call this routine 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 GRBupdatemodel
. The second is
by a call to GRBoptimize
. The third is by a call to
GRBwrite
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 then, you’ll get
an INDEX_OUT_OF_RANGE
error instead.
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 the GRBset*param()
routines (e.g., GRBsetintparam
).
Current values can be retrieved with the GRBget*param()
routines
(e.g., GRBgetdblparam
). Parameters can be of type int,
double, or char * (string). You can also read a set of parameter
settings from a file using GRBreadparams
, or write the set of
changed parameters using GRBwriteparams
.
Refer to the example params_c.c 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 GRBtunemodel
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 each model gets its own copy of the
environment when it is created. Parameter changes to the original
environment therefore have no effect on existing models. Use
GRBgetenv
to retrieve the environment associated with a
particular model if you want to change a parameter for that model.
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 GRBloadenv
when you create your environment.
You can modify the LogFile parameter if you wish to
redirect the log to a different file after creating the environment. 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 Gurobi
callback function. The GRBsetcallbackfunc
routine allows you
to install a function that the Gurobi optimizer will call regularly
during the optimization process. You can call GRBcbget
from
within the callback to obtain additional information about the state of
the optimization.
Refer to the example callback_c.c
which is discussed in Callbacks.
Modifying Solver Behavior - Callbacks#
Callbacks can also be used to modify the behavior of the Gurobi
optimizer. If you call routine GRBterminate
from within a
callback, for example, the optimizer will terminate at the earliest
convenient point. Routine GRBcbsolution
allows you to inject a
feasible solution (or partial solution) during the solution of a MIP
model. Routines GRBcbcut
and GRBcblazy
allow you to
add cutting planes and lazy constraints during a MIP optimization,
respectively (refer to the example tsp_c.c).
Routine GRBcbstoponemultiobj
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#
Most of the Gurobi C library routines return an integer error code. A zero return value indicates that the routine completed successfully, while a non-zero value indicates that an error occurred. The list of possible error return codes can be found in the Error Codes table.
When an error occurs, additional information on the error can be
obtained by calling GRBgeterrormsg
.