The tupledict class
The final important preliminary we would like to discuss is the
tupledict
class. This is a custom sub-class of the Python
dict
class that allows you to efficiently work with subsets of
Gurobi variable objects. To be more specific, you can use the
sum
and prod
methods on a tupledict
object to
easily and concisely build linear expressions. The keys for a
tupledict
are stored as a tuplelist
, so the same
select
syntax can be used to choose subsets of entries.
Specifically, by associating a tuple with each Gurobi variable, you
can efficiently create expressions that contain a subset of matching
variables. For example, using the sum
method on a
tupledict
object, you could easily build an expression that
captures the sum over all Gurobi variables for which the first field
of the corresponding tuple is equal to 3 (using x.sum(3, '*')
).
While you can directly build your own tupledict
, the Gurobi
interface provides an addVars
method that adds one Gurobi
decision variable to the model for each tuple in the input
argument(s) and returns the result as a tupledict
.
Let us give a simple example. We'll begin by
constructing a list of tuples, and then we'll create a set of Gurobi
variables that are indexed using this list:
gurobi> l = list([(1, 2), (1, 3), (2, 3), (2, 4)]) gurobi> d = model.addVars(l, name="d") gurobi> model.update()The
addVars
method will create variables d(1,2)
,
d(1,3)
, d(2,3)
, and d(2,4)
. Note that the
name
argument is used to name the resulting variables, but it
only gives the prefix for the name - the names are subscripted by the
tuple keys (so the variables would be named d[1,2]
,
d[1,3]
, etc.). The final call to update
synchronizes
certain internal data structures; this detail can be safely ignored
for now.
You can then use this tupledict
to build linear expressions.
For example, you could do:
gurobi> sum(d.select(1, '*'))The
select
method returns a list of Gurobi variables where the
first field of the associated tuple is 1. The Python sum
statement then creates a linear expression that captures the sum of
these variables. In this case, that expression would be
d(1,2) + d(1,3)
. Similarly, sum(d.select('*', 3))
would
give d(1,3) + d(2,3)
. As with a tuplelist
, you use a
'*'
string to indicate that any value is acceptable in that
position in the tuple.
The tupledict
class includes a method that simplifies the
above. Rather than sum(d.select('*', 3))
, you can use
d.sum('*', 3)
instead.
The tupledict
class also includes a prod
method, for
cases where you need to build a linear expression with coefficients that aren't all
1.0
. Coefficients are provided through a dict
argument.
They are indexed using the same tuples as the tupledict
. For
example, given a dict
named coeff
with two entries:
coeff(1,2)
= 5 and coeff(2,3)
= 7, a call to
d.prod(coeff)
would give the expression
5 d(1,2) + 7 d(2,3)
. You can also include a filter, so
d.prod(coeff, 2, '*')
would give just 7 d(2,3)
.
Note that tupledict
is a sub-class of dict
, so you can
use the standard dict
methods to access or modify a
tupledict
:
gurobi> print(d[1,3]) <gurobi.Var d[1,3]> gurobi> d[3, 4] = 0.3 gurobi> print(d[3, 4]) 0.3 gurobi> print(d.values()) dict_values([<gurobi.Var d[1,2]>, 0.3, <gurobi.Var d[1,3]>, <gurobi.Var d[2,3]>, <gurobi.Var d[2,4]>])In our upcoming network flow example, once we've built a
tupledict
that contains a variable for each valid
commodity-source-destination combination on the network (we'll call it
flows
), we can create a linear expression that captures the
total flow on all arcs that empty into a specific destination city as
follows:
gurobi> inbound = flows.sum('*', '*', 'New York')
We now present an example that illustrates the use of all of the concepts discussed so far.