简体   繁体   English

混合整数编程-仓库位置(Python + GLPK)

[英]Mixed Integer Programming - Warehouse Location (Python + GLPK)

I am relatively new in optimizationa nd I am trying to optimize a problem (from a pas class in Coursera, 2 years ago) about Warehouse Location. 我在优化方面相对较新,并且正在尝试优化有关仓库位置的问题(来自2年前Coursera的一次课程)。 The problem is, its been more than 6 hours and its still running on an instance with 100 warehouses and 1000 customers. 问题是,它已经超过6个小时,并且仍在具有100个仓库和1000个客户的实例上运行。

The problem is the following. 问题如下。 I have a set of warehouses that I can either open or not. 我有一套可以打开或不打开的仓库。 Opening each of them has a cost s_w. 打开它们中的每一个的成本为s_w。 Also, they all have a maximum capcity, cap_w. 而且,它们都具有最大容量cap_w。 On the other side, there is a bunch of clients, all of them have to be connected to one (and only one) open warehouse. 另一方面,有一堆客户,所有客户都必须连接到一个(只有一个)开放式仓库。 Each of them has a demand d_c and for each of the clients, there is a transportation cost from each warehouse t_wc. 他们每个人都有需求d_c,对于每个客户,每个仓库都有运输成本t_wc。 What I want, is obviouly, to minimize the total cost. 我要的是使总成本最小化。

So, I have an array of size equal to the total number of warehouses called x. 因此,我有一个数组的大小等于称为x的仓库总数。 Each x[w] is a integer {0,1} defining if warehouse w is open or not. 每个x [w]是整数{0,1},定义仓库w是否开放。 I also have a matrix of 0s and 1s defining which warehouse delivers each customer. 我还有一个0和1的矩阵,定义哪个仓库交付每个客户。 there is, therefore as many rows as customers and as many columns as warehouses. 因此,存在与客户一样多的行,而与仓库一样多的列。 The matrix is called y. 该矩阵称为y。 y[c][w] is 1 if waregouse w delivers customer c, 0 otherwise. 如果商品w交付客户c,则y [c] [w]为1,否则为0。

So far so good. 到现在为止还挺好。 This is supossed to be an MIP problem. 推测这是一个MIP问题。 To code it, I do it un Python using the PuPL lib( https://pythonhosted.org/PuLP/pulp.html ) and the GLPK to solve it. 为了进行编码,我使用PuPL lib( https://pythonhosted.org/PuLP/pulp.html )和GLPK在Python上完成它来解决它。

Now, here is my model: 现在,这是我的模型:

#!/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

I know the way I build the matrix is not optimal, but it really isnt taking too long. 我知道我构建矩阵的方法不是最佳的,但实际上并不需要花费太长时间。 It started solving and at some point I reached a point where GLPK said: 它开始解决,在某个时候我到达了GLPK说的一点:

OPTIMAL SOLUTION FOUND
Integer optimization begins...

I believe that means it solved the LP, and now its getting it integer... but its been like 6 hours or so and its been progressing, and still is, but doesn't finish. 我相信这意味着它解决了LP,现在使它变成整数了……但是它大约需要6个小时左右,并且一直在进步,现在还在,但是还没有结束。 In smaller instances, it worked fine. 在较小的情况下,它可以正常工作。

My question, I guess is... Is there something wrong with my model? 我的问题是,我的模型有问题吗? Some optimizations I forgot? 我忘记了一些优化? OR is this problem just that huge? 还是这个问题那么大?

Also, about the computer, its quite a poor one: Intel Atom and 1GB of RAM only... 另外,关于计算机,它的性能相当差:仅Intel Atom和1GB RAM ...

Thank you for your help! 谢谢您的帮助!

EDIT: Here is the date: https://github.com/ddeunagomez/DiscreteOptimization/blob/master/04_warehouse_location/warehouse/data/wl_100_1 the format is: 编辑:这是日期: 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

This is not really a huge problem in the scheme of things -- there is specialized code to solve much larger warehouse location instances than this one, and good off-the-shelf solvers like CPLEX could solve it easily too. 这在事物方案中并不是一个真正的大问题-有专门的代码可以解决比此更大的仓库位置实例,而且像CPLEX这样的优质现货解决程序也可以轻松解决它。 I don't know how efficient GLPK/PuPL are, but it could well be that they just take too long using straightforward LP/branch-and-bound (which is what they are doing). 我不知道GLPK / PuPL的效率如何,但是很可能使用简单的LP /分支绑定(它们正在做的事情)花费的时间太长。

One thing you could try is to allow the y variables to be continuous (0 <= y <= 1) instead of binary. 您可以尝试做的一件事是允许y变量连续(0 <= y <= 1)而不是二进制。 This will most likely speed up the run times because the solver won't have to branch on them. 这很可能会加快运行时间,因为求解程序无需在其上进行分支。 The physical interpretation is that some customers can have their demands split between multiple warehouses. 实际解释是,某些客户可以将他们的需求分配到多个仓库之间。 In practice, very few of them will probably be split in most solutions. 实际上,在大多数解决方案中,它们中可能很少。 If the capacities are large enough to be non-binding, then none of the demands will be split, and you'll always get binary solutions even though you allow y to be continuous. 如果容量足够大以至于无法绑定,那么任何需求都不会分裂,即使允许y连续,您也将始终获得二进制解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM