在Gurobi中添加大小为n的二进制变量

时间:2018-10-20 19:05:17

标签: python gurobi

我正打算在Gurobi(Python界面)中实现设施位置优化模型。我很难翻译模型。数学模型如下所示:

enter image description here

其中dloc,floc是需求(客户)和设施(仓库)位置的(x,y)坐标。 dloc量是常数(即50),与作为决策变量的floc相反:这些量是由求解器计算的。同样,x,y坐标是0到100之间的浮点数。

关键问题之一是我不知道如何添加便利设施变量,其数量可以在0到n之间。

到目前为止我的代码:

from gurobipy import *
import numpy as np
import math


def distance(a, b):
    dx = a[0] - b[0]
    dy = a[1] - b[1]
    return math.sqrt(dx ** 2 + dy ** 2)

customer = np.random.uniform(0,100,[50,2])
print(customer)

m = Model()

n = m.addVar(lb=0.0, ub=GRB.INFINITY,vtype=GRB.INTEGER) #number of candidate facilities

facility={}
for j in range(n):
    facility[j] = m.addVar(vtype=GRB.BINARY, name="facility%d" % j) #certainly this is not correct, as an error is reported as 'Var' object cannot be interpreted as an integer

floc = ? 

因此,我尝试了另一种方法,即手动设置固定数量的候选设施作为临时解决方法:

from gurobipy import *
import numpy as np
import math

customer = np.random.uniform(0,100,[50,2])
print(customer)

m = Model()

###Variable
dc={}
x={}
y={}
assign={}

for j in range(10):
    dc[j] = m.addVar(lb=0,ub=1,vtype=GRB.BINARY, name="DC%d" % j)
    x[j]= m.addVar(lb=0, ub=100, vtype=GRB.CONTINUOUS, name="x%d")
    y[j] = m.addVar(lb=0, ub=100, vtype=GRB.CONTINUOUS, name="y%d")
for i in range(len(customer)):

    for j in range(len(dc)):
        assign[(i,j)] = m.addVar(lb=0,ub=1,vtype=GRB.BINARY, name="Cu%d from DC%d" % (i,j))

###Constraint
for i in range(len(customer)):
    for j in range(len(dc)):
        m.addConstr(((customer[i][0] - x[j])*(customer[i][0] - x[j]) +\
                              (customer[i][1] - y[j])*(customer[i][1] - y[j])) <= 40*40 + 100*100*(1-assign[(i,j)]))

for i in range(len(customer)):
    m.addConstr(quicksum(assign[(i,j)] for j in range(len(dc))) == 1)

for i in range(len(customer)):
    for j in range(len(dc)):
        m.addConstr(assign[(i, j)] <= dc[j])

n=0
for j in dc:
    n=n+dc[j]

m.setObjective(n,GRB.MINIMIZE)

m.optimize()

print('\nOptimal Solution is: %g' % m.objVal)
for v in m.getVars():
    print('%s %g' % (v.varName, v.x))

任何人都可以在Gurobi中演示该模型的翻译,这将有很大的帮助。

1 个答案:

答案 0 :(得分:1)

我认为您对n的定义没有问题。尽管如此,我还是重写了您的代码,以使其更简洁,更易于理解。首先,我们创建给定的集合和常量:

from gurobipy import Model, GRB, quicksum
import numpy as np

m = Model()

demo_coords = np.random.uniform(0, 100, size=(50, 2)) # Just for demonstration

# Sets and Constants
demand = [f"i{k}" for k in range(1, 51)]
facilities = [ f"facility{k}" for k in range(1, 11) ]
dloc = {fac : demo_coords[i] for i, fac in enumerate(demand)}
maxdist = 40
M = 10e6

请注意,dloc是一个字典,因此dloc[i]将为您提供坐标 对于需求点然后dloc[i][0]是x坐标,dloc[i][1]是x坐标 y坐标。

现在,我们可以创建变量并将其存储在gurobi tubledict中:

# Variables
floc = m.addVars(facilities, 2, name="floc")
isopen = m.addVars(facilities, vtype=GRB.BINARY, name="isopen")
assign = m.addVars(demand, facilities, vtype=GRB.BINARY, name="assign")
n = m.addVar(vtype=GRB.INTEGER, name="n")
m.update()

使用m.addConstrs(),约束可以写为

# Constraints
m.addConstrs(((dloc[i][0] - floc[j, 0]) * (dloc[i][0] - floc[j, 0]) \
    + (dloc[i][1] - floc[j, 1])*(dloc[i][1] - floc[j, 1]) \
    <= maxdist**2 + M * (1 - assign[i, j]) \
    for i in demand for j in facilities), name="distance")

m.addConstrs((quicksum(assign[i, j] for j in facilities) == 1\
              for i in demand), name="assignDemand")

m.addConstrs((assign[i, j] <= isopen[j] for i in demand for j in facilities),\
name="closed")

m.addConstr(n == quicksum(isopen[j] for j in facilities), name="numFacilities")

# zip is needed to iterate over all pairs of consecutive facilites
m.addConstrs((isopen[j] >= isopen[jp1] \
    for j, jp1 in zip(facilities, facilities[1:])), name="order")

请注意,虽然在距离约束中写floc[j, 0]并不是问题,但是您不能写dloc[i, 0],因为dloc是python字典,而{{1 }}是元组。

设置目标函数并调用floc

m.optimize()

给我最优解n = 3。