This article describes two common data structures in Gurobi: tuplelist
and tupledict
, and to explain to the network flow problem in the case file
Gurobi the tuple
class in Python list
subclass tupledict
is dict
the subclass.
When using Gurobi modeling, it is recommended to use both types, easy to write constraints, and can speed up the read speed of the model. Next will be described in detail:
In this paper, with reference to the Gurobi 9.0.0 directory refman.pdf
The following case the code does not explicitly explainfrom gurobipy import *
tuplelist
Constructor
Passed in the constructor list
object can be converted to tuplelist
Type
l = tuplelist(list)
例子:
l = tuplelist([(1,2),(1,3),(2,4)])
<gurobi.tuplelist (3 tuples, 2 values each):
( 1 , 2 )
( 1 , 3 )
( 2 , 4 )
Filter elements
select(pattern)
Function returns based on a pattern
screening of the tuplelist
object.
> l = tuplelist([(1,2),(1,3),(2,4)])
<gurobi.tuplelist (3 tuples, 2 values each):
( 1 , 2 )
( 1 , 3 )
( 2 , 4 )
> l.select() #返回所有的对象
<gurobi.tuplelist (3 tuples, 2 values each):
( 1 , 2 )
( 1 , 3 )
( 2 , 4 )
# 可使用通配符
> l.select(1,'*') # 返回第一位为1,第二为任意符号的元素
<gurobi.tuplelist (2 tuples, 2 values each):
( 1 , 2 )
( 1 , 3 )
tuplelist
Can also be used in
for determining whether the interior thereof containing the element (rewrite __contains__()
)
> l = tuplelist([(1,2),(1,3),(2,4)])
<gurobi.tuplelist (3 tuples, 2 values each):
( 1 , 2 )
( 1 , 3 )
( 2 , 4 )
# 判断是否有(1,2)
if (1,2) in l:
print("Tuple (1,2) is in tuplelist l")
tupledict
tupledict
Python class is dict
a subclass of the two-part key. key as mentioned above tuplelist
, value of Gurobi variable Var
type
tupledict
Can easily index and index creation expression
Creating tupledict
Constructor
# 一个list,内部一个个元组,按照key,value先排好 dd = [((1,1),'a'), ((1,2),'b'),((2,1),'c'),((2,2),'d')] # 相当于二元变量d_(i,j) d = tupledict(dd) {(1, 1): 'a', (1, 2): 'b', (2, 1): 'c', (2, 2): 'd'}
Batch conversion
multidict(data)
Function provides andict
object typedata
into tupledict. If the value of the data elements includes N, N + 1, the function returns the object, the first object data as the keys, the subsequent value of the N object beatentupledict
.A plurality of sets of data with respect to the input element, and automatically split the keys have the same
tupledict
keys, dict1, dict2 = multidict({'k1':[1,2], 'k2':[3,4], 'k3':[5,6]}) # 生成结果 # 原data中的键 tuplelist类型 keys = ['k1', 'k2', 'k3'] # 第一列元素 dict1 = {'k1': 1, 'k2': 3, 'k3': 5} # 第二列元素 dict2 = {'k1': 2, 'k2': 4, 'k3': 6}
Multivariate decision variables
After you create the model, call the
addVars()
function to create a multi-dimensional decision variables, the decision variables astupledict
the type ofm = Model() x = m.addVars(2,3) # 创建2*3的决策变量 # 使用下标方式进行访问 x[0,0] #<gurobi.Var C0>
Filter elements
- Tuplelist the same, using the select () function can be screened out of the eligible key value
- Like
dict
, the use of[]
access
d = tupledict([((1,1),'a'), ((1,2),'b'),((2,1),'c'),((2,2),'d')])
{(1, 1): 'a', (1, 2): 'b', (2, 1): 'c', (2, 2): 'd'}
# 显示所有元素
d.select()
# pattern筛选元素
d.select(1,'*')
['a', 'b']
# 下标访问
d[1,1]
'a'
Set operations (sum, even by)
tupledict
Objects can be summed sum()
, product operation prod()
. After the operation will generate Gurobi built LinExpr()
expression object, may be added to the model as a constraint.
sum(pattern)
pattern
Similar parameters select
usage, can increase the filtering criteria for the sum
If you do not meet the conditions of the pattern, it returns 0
x = m.addVars(2,2)
expr = x.sum() # LinExpr: x[0,0] + x[0,1] + x[1,0] + x[1,1]
expr = x,sum(1, '*') # LinExpr: x[1,0] + x[1,1]
keys, dict1, dict2 = multidict({'k1':[1,2],
'k2':[3,4],
'k3':[5,6]})
dict1.sum() # LinExpr: 1 + 3 +5 = 9
prod(coeff,pattern)
coeff
A dict
type that specifies the elements to be calculated coefficients. coeff
The key to be calculated and set in the key corresponding to the energy
x = m.addVars(2,2)
coeff = {(0,0):1, (0,1):2,(1,0):3,(1,1):4}
expr = x.prod(coeff) # x[0,0] + 2*x[0,1] + 3*x[1,0] + 4*x[1,1]
expr = x.prod(coeff, 1,"*") # 3*x[1,0] + 4*x[1,1]
Detailed network flow Case
Case source file根目录\example\python\netflow.py
The question relates to two kinds of goods, two shipments, the configuration issue 3 receipt of offers and from the cost of each node, for a maximum amount of inventory throughout the (traffic) as well as of each node, and demand, to meet demand the minimum cost of supply conditions configuration.
The objective function:
Constraint 1: For each product, the maximum does not exceed the maximum capacity of each node
Constraint 2: For each product, to meet the needs of each supply node (in this case the data is supplied to the positive side, the demand side is negative)
The constraint 2 break it, was:
2.1 Constraints: The supply of donor j = j outflow from point
2.2 Constraints: converged load demand point entity j + j needs (negative) = 0
Chinese comments about Paste the code below:
#!/usr/bin/env python3.7
# Copyright 2019, Gurobi Optimization, LLC
# Solve a multi-commodity flow problem. Two products ('Pencils' and 'Pens')
# are produced in 2 cities ('Detroit' and 'Denver') and must be sent to
# warehouses in 3 cities ('Boston', 'New York', and 'Seattle') to
# satisfy demand ('inflow[h,i]').
#
# Flows on the transportation network must respect arc capacity constraints
# ('capacity[i,j]'). The objective is to minimize the sum of the arc
# transportation costs ('cost[i,j]').
import gurobipy as gp
from gurobipy import GRB
# Base data
# 商品种类
commodities = ['Pencils', 'Pens']
# 所有的节点,作为key
nodes = ['Detroit', 'Denver', 'Boston', 'New York', 'Seattle']
arcs, capacity = gp.multidict({
('Detroit', 'Boston'): 100,
('Detroit', 'New York'): 80,
('Detroit', 'Seattle'): 120,
('Denver', 'Boston'): 120,
('Denver', 'New York'): 120,
('Denver', 'Seattle'): 120})
# arcs为tuplelist,表示节点间的连通关系
# capacity为tupledict,表示节点间的流量
# Cost for triplets commodity-source-destination
cost = {
('Pencils', 'Detroit', 'Boston'): 10,
('Pencils', 'Detroit', 'New York'): 20,
('Pencils', 'Detroit', 'Seattle'): 60,
('Pencils', 'Denver', 'Boston'): 40,
('Pencils', 'Denver', 'New York'): 40,
('Pencils', 'Denver', 'Seattle'): 30,
('Pens', 'Detroit', 'Boston'): 20,
('Pens', 'Detroit', 'New York'): 20,
('Pens', 'Detroit', 'Seattle'): 80,
('Pens', 'Denver', 'Boston'): 60,
('Pens', 'Denver', 'New York'): 70,
('Pens', 'Denver', 'Seattle'): 30}
# Demand for pairs of commodity-city
inflow = {
('Pencils', 'Detroit'): 50,
('Pencils', 'Denver'): 60,
('Pencils', 'Boston'): -50,
('Pencils', 'New York'): -50,
('Pencils', 'Seattle'): -10,
('Pens', 'Detroit'): 60,
('Pens', 'Denver'): 40,
('Pens', 'Boston'): -40,
('Pens', 'New York'): -30,
('Pens', 'Seattle'): -30}
# Create optimization model
m = gp.Model('netflow')
# Create variables
# 创建以commodities,arcs为下标的三维决策变量 flow_h,i,j
# obj=cost这种写法在创建变量时,设定好了目标函数
flow = m.addVars(commodities, arcs, obj=cost, name="flow")
# 添加约束1
# Arc-capacity constraints
m.addConstrs(
(flow.sum('*', i, j) <= capacity[i, j] for i, j in arcs), "cap")
# 约束1的等价写法,将生成器改为for循环,逐个添加
# Equivalent version using Python looping
# for i, j in arcs:
# m.addConstr(sum(flow[h, i, j] for h in commodities) <= capacity[i, j],
# "cap[%s, %s]" % (i, j))
# 添加约束2
# Flow-conservation constraints
m.addConstrs(
(flow.sum(h, '*', j) + inflow[h, j] == flow.sum(h, j, '*')
for h in commodities for j in nodes), "node")
# 约束2的等价写法,将生成器改为for循环,逐个添加
# Alternate version:
# m.addConstrs(
# (gp.quicksum(flow[h, i, j] for i, j in arcs.select('*', j)) + inflow[h, j] ==
# gp.quicksum(flow[h, j, k] for j, k in arcs.select(j, '*'))
# for h in commodities for j in nodes), "node")
# Compute optimal solution
m.optimize()
# Print solution
if m.status == GRB.OPTIMAL:
solution = m.getAttr('x', flow)
for h in commodities:
print('\nOptimal flows for %s:' % h)
for i, j in arcs:
if solution[h, i, j] > 0:
print('%s -> %s: %g' % (i, j, solution[h, i, j]))