Gurobi study notes --tuplelist and tupledict

This article describes two common data structures in Gurobi: tuplelistand tupledict, and to explain to the network flow problem in the case file

Gurobi the tupleclass in Python listsubclass tupledictis dictthe 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 listobject can be converted to tuplelistType

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 patternscreening of the tuplelistobject.

> 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 )

tuplelistCan also be used infor 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

tupledictPython class is dicta subclass of the two-part key. key as mentioned above tuplelist, value of Gurobi variable Vartype

tupledictCan easily index and index creation expression

Creating tupledict

  1. 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'}
  2. Batch conversion

    multidict(data)Function provides an dictobject type datainto 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 beaten tupledict.

    A plurality of sets of data with respect to the input element, and automatically split the keys have the sametupledict

    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}
  3. Multivariate decision variables

    After you create the model, call the addVars()function to create a multi-dimensional decision variables, the decision variables as tupledictthe type of

    m = Model()
    x = m.addVars(2,3) # 创建2*3的决策变量
    # 使用下标方式进行访问
    x[0,0] #<gurobi.Var C0>

Filter elements

  1. Tuplelist the same, using the select () function can be screened out of the eligible key value
  2. 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)

tupledictObjects 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)

patternSimilar parameters selectusage, 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)

coeffA dicttype that specifies the elements to be calculated coefficients. coeffThe 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:

The objective function

Constraint 1: For each product, the maximum does not exceed the maximum capacity of each node

Constraint 1

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)
Constraints 2

The constraint 2 break it, was:

2.1 Constraints: The supply of donor j = j outflow from point
Constraints 2.1

2.2 Constraints: converged load demand point entity j + j needs (negative) = 0
Constraints 2.2

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]))
                

Guess you like

Origin www.cnblogs.com/TianYuanSX/p/12355344.html