【发布时间】:2015-01-08 20:19:27
【问题描述】:
我在优化方面相对较新,我正在尝试优化一个关于仓库位置的问题(来自 Coursera 的课程,2 年前)。问题是,它已经 6 个多小时了,它仍然在一个有 100 个仓库和 1000 个客户的实例上运行。
问题如下。我有一组可以打开或不打开的仓库。打开它们每个都有成本 s_w。此外,它们都有一个最大容量 cap_w。 另一方面,有一堆客户端,它们都必须连接到一个(并且只有一个)开放仓库。他们每个人都有一个需求 d_c,对于每个客户,每个仓库都有一个运输成本 t_wc。 我想要的,显然是最小化总成本。
所以,我有一个大小等于仓库总数的数组,称为 x。每个 x[w] 是一个整数 {0,1},定义仓库 w 是否打开。 我还有一个由 0 和 1 组成的矩阵,用于定义为每个客户提供哪个仓库。因此,行数与客户数相同,列数与仓库数相同。该矩阵称为 y。 y[c][w] 如果 waregouse w 交付客户 c,则为 1,否则为 0。
到目前为止一切顺利。这应该是一个 MIP 问题。 为了编写代码,我使用 PuPL lib(https://pythonhosted.org/PuLP/pulp.html) 和 GLPK 来解决它。
现在,这是我的模型:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pulp import *
def solveIt(inputData):
# parse the input
lines = inputData.split('\n')
parts = lines[0].split()
warehouseCount = int(parts[0])
customerCount = int(parts[1])
warehouses = []
for i in range(1, warehouseCount+1):
line = lines[i]
parts = line.split()
warehouses.append((int(parts[0]), float(parts[1])))
customerDemands = []
customerCosts = []
lineIndex = warehouseCount+1
for i in range(0, customerCount):
customerDemand = int(lines[lineIndex+2*i])
customerCost = map(float, lines[lineIndex+2*i+1].split())
customerDemands.append(customerDemand)
customerCosts.append(customerCost)
x = [LpVariable("x"+str(w),0,1,cat='Integer') for w in range(0,warehouseCount)]
y = [[LpVariable("y"+str(c)+","+str(w),0,1,cat='Integer') for w in range(0,warehouseCount)] for c in range(0,customerCount)]
prob = LpProblem("Warehouse Location",LpMinimize)
#Constraints
# y_cw <= x_w makes sure that no client is delivered by a closed warehouse
for w in range(0,warehouseCount):
for c in range(0,customerCount):
prob += y[c][w] <= x[w]
#A client is served by exactly one warehouse
for c in range(0,customerCount):
affineExpression = []
for w in range(0,warehouseCount):
affineExpression.append((y[c][w],1))
prob += LpAffineExpression(affineExpression) == 1
#For each warehouse, the sum of demand of all the clients it serves is lower than its capacity
for w in range(0,warehouseCount):
affineExpression = []
for c in range(0,customerCount):
affineExpression.append((y[c][w],customerDemands[c]))
prob += LpAffineExpression(affineExpression) <= warehouses[w][0]
#Objective
#The sum of all the warehouses opening plus the transportation costs has to be minimal
affineExpression = []
for w in range(0,warehouseCount):
affineExpression.append((x[w],warehouses[w][1]))
for c in range(0,customerCount):
affineExpression.append((y[c][w],customerCosts[c][w]))
prob += LpAffineExpression(affineExpression)
print "#######################START SOLVING"
status = prob.solve(GLPK(mip=1,msg = 1))
print LpStatus[status]
for w in range(0,warehouseCount):
print value(x[w])
solution = []
for c in range(0,customerCount):
string = ""
whichOne = -1
for w in range(0,warehouseCount):
string += str(value(y[c][w])) + " "
if value(y[c][w]) == 1:
whichOne = w
solution.append(w)
print string+ " "+str(whichOne)
# calculate the cost of the solution
obj = sum([warehouses[x][1]*x[w] for x in range(0,warehouseCount)])
for c in range(0, customerCount):
obj += customerCosts[c][solution[c]]
# prepare the solution in the specified output format
outputData = str(obj) + ' ' + str(0) + '\n'
outputData += ' '.join(map(str, solution))
return outputData
我知道我构建矩阵的方式不是最优的,但它确实不会花费太长时间。 它开始解决,在某个时候我达到了 GLPK 所说的点:
OPTIMAL SOLUTION FOUND
Integer optimization begins...
我相信这意味着它解决了 LP,现在它得到整数......但它已经像 6 小时左右并且它一直在进步,并且仍然是,但没有完成。 在较小的情况下,它工作得很好。
我想我的问题是……我的模型有问题吗?我忘记了一些优化?或者这个问题有那么大吗?
另外,关于计算机,它的性能很差:Intel Atom 和 1GB 的 RAM...
感谢您的帮助!
编辑: 这是日期:https://github.com/ddeunagomez/DiscreteOptimization/blob/master/04_warehouse_location/warehouse/data/wl_100_1 格式为:
NumberOfWarehouses NumberOfCustomers
CapacityWarehouse1 OpeningCostWarehouse1
CapacityWarehouse2 OpeningCostWarehouse2
.....
CapacityWarehouseN OpeningCostWarehouseN
DemandCustomer1
TransportCostW1_C1 TransportCostW2_C1 ....... TransportCostWN_C1
DemandCustomer2
TransportCostW1_C2 TransportCostW2_C2 ....... TransportCostWN_C2
.....
DemandCustomerN
TransportCostW1_CM TransportCostW2_CM ....... TransportCostWN_CM
【问题讨论】:
-
输入数据是什么?
-
这实际上是一个大问题(就变量的数量而言),我怀疑 glpk 在这里是否有效。您可以尝试的一件事是选择一组仓库来打开,看看 glpk 需要多长时间才能找到客户到仓库的最佳分配。对于这种规模的问题,我也会尝试本地搜索。
-
您好,感谢您的回答。实际上数据文件太大了,我不能在 Stackoverlow 上发布它......有没有办法在这里上传文件?谢谢
-
哦,我也考虑过本地搜索...但我不确定该怎么做。尝试所有仓库组合(这里是 100 个!),并为每个尝试分配客户并在本地尝试改进每个客户或类似的东西?容量限制实际上是对我个人而言最困难的限制。再次感谢!!
-
我见过的一个求解器使用满足的 MIP 约束的数量作为评分函数。通过选择一个约束来执行局部搜索,考虑该约束中的每个变量,并确定如果该变量被翻转,分数将如何变化。然后你做你的基本爬山——也许随机倒退以摆脱局部最大值等。或者也许使用 obj.函数 + c*作为评分函数满足的约束数。
标签: python optimization linear-programming glpk