Gurobi Notes (Python version)
Author: 有何不可
Reference book: GUROBI OPTIMIZER REFERENCE MANUAL,(提取码:s4kv )
Updated time: 2019/4/4
gurobipy lib
1 | # import gurobipy lib |
Model
A model consists of a set of variables, a linear, quadratic, or piecewise-linear objective function on those variables, and a set of constraints.
Common Optimization Model
- Linear Program (LP)
A model with a linear objective function, linear constraints, and continuous variables. - Quadratic Program (QP)
The objective is quadratic. - Quadratically-Constrained Program (QCP)
The objective is quadratic, any of the constraints are quadratic. - Second-Order Cone Program (SOCP)
- Mixed Integer Program (MIP)
the model contains any integer variables, semi-continuous variables, semi-integer variables, Special Ordered Set (SOS) constraints, or general constraints. - Mixed Integer Linear Programs (MILP)
- Mixed Integer Quadratic Programs (MIQP)
- Mixed Integer Quadratically-Constrained Programs (MIQCP)
- Mixed Integer Second-Order Cone Programs (MISOCP)
The Gurobi Optimizer handles all of these models.
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.
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.
Lazy Updates
The Gurobi optimizer employs a lazy update approach, so changes to attributes don’t take effect until the next call to Model.update, Model.optimize, Model.write on the associated model.
Model File Formats
The Gurobi optimizer works with a variety of file formats.
The MPS
, REW
, LP
, RLP
, ILP
, OPB
formats are used to hold optimization models.
The MST
format is used to hold MIP start data. Importing this data into a MIP model allows the MIP model to start with a known feasible solution.
The HNT
format is used to hold MIP hints. Importing this data into a MIP model guides the MIP search towards a guess at a high-quality feasible solution.
The ORD
format is used to hold MIP variable branching priorities. Importing this data into a MIP model affects the search strategy.
The BAS
format holds simplex basis information. Importing this data into a continuous models allows the simplex algorithm to start from the given simplex basis.
The SOL
format holds a solution vector. It can be written once the model has been optimized.
The PRM
format holds parameter values. Importing this data into a model changes the values of the referenced parameters.
1 | # Initiate a model |
Academic license - for non-commercial use only
Var(Gurobi variable object)
Before starting, we should point out one important thing about the variables in a mathematical programming model: their computed solution values will only satisfy bounds to tolerances, meaning that a variable may violate its stated bounds. Mathematical programming is fundamentally built on top of linear algebra and in particular on the numerical solution of systems of linear equations. These linear systems are solved using finite-precision arithmetic, which means that small errors are unavoidable. For some models, large errors are unavoidable too.
Variable Types
In gurobi, the available variables types includes:
- Continuous
- General integer
- Binary
- Semi-continuous
- Semi-integer.
Create Decision variables
In Gurobi, we can create a variable object by adding a variable to a model rather than by using a Var constrcutor.
There are two ways to create variables, as follow, and the Model.addVars
refers the tupledict section1
2
3
4# Add a decision variable to a model
Model.addVar(lb=0.0, ub=GRB.INFINITY, obj=0.0, vtype=GRB.CONTINUOUS, name="", column=None)
# Add multiple decision variables to a model
Model.addVars(*indices, lb=0.0, ub=GRB.INFINITY, obj=0.0, vtype=GRB.CONTINUOUS, name="")
About “name” : the variable x
in Python is used to operate. In name="x"
, the `x’ is used to replace the CX(e.g. C0, C1…) in order to represent the expression in the way of user.
1 | # Create decision variables |
==> Model no updated: <gurobi.Var *Awaiting Model Update*> <gurobi.Var *Awaiting Model Update*> <gurobi.Var *Awaiting Model Update*>
==> Model updated: <gurobi.Var x> <gurobi.Var y> <gurobi.Var z>
=========================
==> x_tudict: {'x1': <gurobi.Var x1>, 'x2': <gurobi.Var x2>, 'x3': <gurobi.Var x3>}
==> expr0: <gurobi.LinExpr: x1 + 2.0 x2 + x3>
1 | # Get attribute of variable |
==> Get attrs: [(1.0, 1e+100), (0.0, 1e+100)]
=========================
==> attr_lb: 5.0
==> attr_ub: 100.0
Gurobi constraint
Constr(Gurobi constraint object)
In Gurobi, we can create a constraint object by adding a constraint to a model rather than by using a Constr constrcutor.
There are two ways, as follow,1
2
3
4# Add a constraint to a model.
Model.addConstr(lhs, sense=None, rhs=None, name="" )
# Add multiple constraints to a model.
Model.addConstrs(generator, name="")
1 | # Add a linear constraint to a model |
1 | # Add constraints to a model |
==> c0: <gurobi.Constr c0> c1: <gurobi.Constr c1>
=========================
==> RHS: 4.0
QConstr(Gurobi quadratic constraint object)
Add a quadratic constraint to a model, as follow,1
2# Add a quadratic constraint to a model.
Model.addQConst(lhs, sense=None, rhs=None, name="")
Important note:
The algorithms that Gurobi uses to solve quadratically constrained problems can only handle certain types of quadratic constraints. Constraints of the following forms are always accepted:
$$ x^TQx + q^Tx <= b $$
$$ x^Tx <= y^2 $$
$$ x^Tx <= yz $$
1 | # Add quadratic constraints to a model |
==> qc0: <gurobi.QConstr qc0>
GenConstr(Gurobi general constraint object)
General constraints are always associated with a particular model. You add a general constraint to a model either by using Model.addGenConstr
, or by using Model.addConstr
or Model.addConstrs plus a general constraint helper function
).
Refer the TempConstr section to add a general constraint to a model.
TempConstr(Gurobi temporary constraint object)
Objects of this class are created as intermediate results when building constraints using overloaded operators.
The TempConstr object allows you to create several different types of constraints:
- Linear Constraint
- Ranged Linear Constraint
- Quadratic Constraint
- Absolute Value Constraint
- Logical Constraint
- Min or Max Constraint
- Indicator Constraint
1 | # Create a TempConstr object |
SOS(Gurobi SOS constraint object)
SOS constraints are always associated with a particular model. You create an SOS object by adding an SOS constraint to a model (using Model.addSOS
), rather than by using an SOS constructor. Similarly, SOS constraints are removed using the Model.remove
method.
An SOS constraint can be of type 1 or 2 (GRB.SOS_TYPE1
or GRB.SOS_TYPE2
). A type 1 SOS constraint is a set of variables where at most one variable in the set may take a value other than zero. A type 2 SOS constraint is an ordered set of variables where at most two variables in the set may take non-zero values. If two take non-zero values, they must be contiguous in the ordered set.
1 | # Add an SOS constraint to the model. |
Gurobi expression
LinExpr(Gurobi linear expression object)
Build linear expression, there are two ways, as follow,1
2
3
4
5
6
7
8# Method 1
LinExpr(arg1=0.0, arg2=None)
# Method 2
quicksum(list)
# Mothod 3
tupledict.sum()
# Method 4 -- overloaded operators
Lin_expr = x1 + 2*x2 + 5*x3 + 2.5
The cost of building expressions depends heavily on the approach you use, you should be aware of a few efficiency issues when building large expressions:
- Avoid using Python
sum
function. - Avoid using
expr+= x
in a loop. - Use the
quicksum
function when build a large expression. - The two most efficient ways to build large linear expressions are
addTerms
or theLinExpr()
constructor.
1 | # Build linear expressions |
==> expr1: <gurobi.LinExpr: 3.0>
==> expr2: <gurobi.LinExpr: 2.0 x + y + z>
==> expr3: <gurobi.LinExpr: 3.0 + 2.0 x + y + z>
==> expr4: <gurobi.LinExpr: 4.0 x + 12.0 y>
==> expr5: <gurobi.LinExpr: 0.5 x + 1.2 y + 2.5 z>
==> expr6: <gurobi.LinExpr: x + y + z>
1 | # LinExpr |
==> expr1: <gurobi.LinExpr: 3.0 + 3.0 x>
==> expr1: <gurobi.LinExpr: 13.0 + 3.0 x>
==> expr1: <gurobi.LinExpr: 13.0 + 3.0 x + 6.0 y + 9.0 z>
==> expr7: <gurobi.LinExpr: 13.0 + 3.0 x + 6.0 y + 9.0 z>
==> expr7 items: 3
1 | # LinExpr.getConstant() |
==> 13.0
==> 3.0 6.0 9.0
==> <gurobi.Var x> <gurobi.Var y> <gurobi.Var z>
==> expr8: <gurobi.LinExpr: 13.0 + 3.0 x + 9.0 z>
QuadExpr(Gurobi quadratic expression object)
A quadratic expression consists of a linear expression plus a list of coefficient-variable-variable triples that capture the quadratic terms. Quadratic expressions are used to build quadratic objective functions and quadratic constraints. Expressions can be built from constants, variables, or from other expressions.
The cost of building expressions depends heavily on the approach you use, you should be aware of a few efficiency issues when building large expressions:
- Avoid using the Python
sum
function.. - Avoid using
expr = expr + x*x
in a loop. - Use the
quicksum
function when build a large expression. - The most efficient way to build a large quadratic expression is with a single call to
addTerms
.
Build a quadratic expression, as follow,
QuadExpr(expr=None)
variables + overloadedoperators
1 | # Build quadratic expressions |
==> qexpr1: <gurobi.QuadExpr: 1.0> item_num: 0
==> qexpr2: <gurobi.QuadExpr: y + z + [ x * y ]> item_num: 1
==> qexpr3: <gurobi.QuadExpr: 3.0 + [ x ^ 2 + y ^ 2 + z ^ 2 ]> item_num: 3
1 | # Quad.addTerms(coeffs, vars, vars2=None) |
==> <gurobi.QuadExpr: 1.0 + [ 2.0 x * y + 3.0 y * z + 1.5 z * x ]>
GenExpr(Gurobi general expression object)
Objects of this class are created by a set of general constraint helper functions
functions(i.e. max_()
,min_()
,and_()
,or_()
).
GenExpr object is used in conjunction with overloaded operators to build TempConstr
objects, which are then passed to addConstr
or addConstrs
to build general constraints.
1 | # Create a GenExpr |
==> <class 'gurobipy.GenExpr'>
==> <class 'gurobipy.GenExpr'>
==> <class 'gurobipy.GenExpr'>
==> <class 'gurobipy.GenExpr'>
==> <class 'gurobipy.GenExpr'>
Callbacks(Gurobi callback class)
A callback is a user function that is called periodically by the Gurobi optimizer in order to allow the user to query or modify the state of the optimization.
More precisely, if you pass a function that takes two arguments (model
and where
) as the argument to Model.optimize
, your function will be called during the optimization. Your callback function can then call Model.cbGet
to query the optimizer or details on the state of the optimization.
The Gurobi callback class provides a set of constants that are used within the user callback function. The first set of constants in this class list the options for the where
argument to the user callback function. The where
argument indicates from where in the optimization process the user callback is being called. The other set of constants in this class list the options for the what
argument to Model.cbGet
. The what
argument is used by the user callback to indicate what piece of status information it would like to retrieve.
When solving a model using multiple threads, note that the user callback is only ever called from a single thread, so you don’t need to worry about the thread safety of your callback.
tuplelist & tupledict
tuplelist(Gurobi tuple list)
This is a sub-class of the Python list class that is designed to efficiently support a usage pattern that is quite common when building optimization models. The tuplelist is a Python list and the elements of the list is Python tuple. All tuples in a tuplelist must be the same length.
In particular, if a tuplelist is populated with a list of tuples, the select
function on this class efficiently selects tuples whose values match specified values in specified tuple fields.
You generally build tuplelist objects in the same way you would build standard Python lists. For example, you can use the +=
operator to append a new list of items to an existing tuplelist, or the +
operator to concatenate a pair of tuplelist objects. You can also call the append
, extend
, insert
, pop
, and remove
functions.
To access the members of a tuplelist, you also use standard list functions.
Note that tuplelist objects build and maintain a set of internal data structures to support efficient select operations. If you wish to reclaim the storage associated with these data structures, you can call the clean
function.
A tuplelist is designed to store tuples containing scalar values (int, float, string, …) to a list, namely [(int, float, string), (int, float, string), (int, float, string)]
rather than tuples containing tuples, namely [(int, float, string), (tuple )]
1
2
3
4
5
6# list: Initial list of member tuples.
tuplelist(list)
# Returns a tuplelist containing all member tuples that match the specified pattern.
tuplelist.select(pattern)
# Discards internal data structure associated with a tuplelist object.
tuplelist.clean()
1 | # Create tuplelist |
==> tulist1 len: 4
==> tulist1: <gurobi.tuplelist (4 tuples, 3 values each):
( 1 , 2 , z )
( z , h , f )
( 1 , 6 , z )
( A , 2 , 5 )
>
==> (1, 2, 'z') 2
=========================
==> tulist2: <gurobi.tuplelist (2 tuples, 3 values each):
( 1 , 2 , z )
( 1 , 6 , z )
>
tupledict(Gurobi tuple dict)
This is a sub-class of the Python dict class that is designed to efficiently support a usage pattern that is quite common when building optimization models. In particular, a tupledict is a Python dict where the keys are stored as a Gurobi tuplelist, and where the values are typically Gurobi Var objects.
Objects of this class make it easier to build linear expressions on sets of Gurobi variables, using tuplelist.select()
syntax and semantics.
You typically build a tupledict by calling Model.addVars
. Once you’ve created a tupledict object d
, you can use d.sum()
to create a linear expression that captures the sum of the variables in the tupledict. You can also use a command like d.sum(1, ’*’, 5)
to create a sum over a subset of the variables in tupledict. You can also use d.prod(coeff)
to create a linear expression where the coefficients are pulled from the argument dict.
To access the members of a tupledict, you can use standard dict indexing.
Note that a tupledict key must be a tuple of scalar values (int, float, string, ...)
. Thus, you can use (1, 2.0, ’abc’)
as a key, but you can’t use ((1, 2.0), ’abc’)
.
Note that tupledict objects build and maintain a set of internal data structures to support efficient select operations. If you wish to reclaim the storage associated with these data structures,
you can call the clean
function.1
2
3
4
5
6
7
8
9
10
11
12#
tupledict(args, kwargs)
#
tupledict.sum()
tupledict.sum(pattern)
#
tupledict.sum(pattern)
# Returns a linear expression that contains one term for each tuple
# that is present in both the tupledict and in the argument dict.
tupledict.prod (coeff, pattern)
# Discards internal data structure associated with a tupledict object.
tupledict.clean()
1 | # Create tupledict |
==> tudict1: {(1, 2): 'zhf', (1, 'z'): [2010, 1218], ('w', 'z'): ('zhf', 'wjq')}
==> keys: <gurobi.tuplelist (3 tuples, 2 values each):
( 1 , 2 )
( 1 , z )
( w , z )
>
==> values: ['zhf', [2010, 1218], ('zhf', 'wjq')]
=========================
==> tudict2: {(1, 2): <gurobi.Var tudict2[1,2]>, (1, 3): <gurobi.Var tudict2[1,3]>, (2, 3): <gurobi.Var tudict2[2,3]>}
==> tudict3: {(1, 2): <gurobi.Var C11>, (1, 3): <gurobi.Var C12>, (2, 3): <gurobi.Var C13>}
==> keys: <gurobi.tuplelist (3 tuples, 2 values each):
( 1 , 2 )
( 1 , 3 )
( 2 , 3 )
>
==> values: [<gurobi.Var tudict2[1,2]>, <gurobi.Var tudict2[1,3]>, <gurobi.Var tudict2[2,3]>]
1 | # Create LinExpr |
==> tudict_expr1: <gurobi.LinExpr: tudict2[1,2] + tudict2[1,3] + tudict2[2,3]>
==> tudict_expr5: <gurobi.LinExpr: C11 + C12 + C13>
==> tudict_expr2: <gurobi.LinExpr: tudict2[1,2] + tudict2[1,3]>
==> tudict_expr3: <gurobi.LinExpr: tudict2[1,3] + tudict2[2,3]>
==> tudict_expr4: <gurobi.LinExpr: tudict2[2,3]>
1 | # tupledict.select(pattern) |
==> ['zhf', [2010, 1218], ('zhf', 'wjq')]
==> ['zhf', [2010, 1218]]
==> [[2010, 1218], ('zhf', 'wjq')]