垃圾箱包装

时间:2018-11-21 12:39:50

标签: python algorithm optimization linear-programming bin-packing

我有一个产品列表(i),每个都有给定的重量和体积。优化分两步进行,其中我无法解决第二步。

第一个优化:最大限度地减少使用(已解决)的垃圾箱数量

  • 最小化用于包装产品列表的垃圾箱数量。我有固定的垃圾箱,具有最大的体积和重量限制。 Python代码:

    prob = pp.LpProblem("algorithm",pp.LpMinimize) #pp=pulp solver
    
    Y_max=10  #bins will not exceed this number
    #Y_min = minimum number of bins (calculated)
    # j = index of jth bin
    # i = index of ith product
    
    w=weights #list of weights w_i for product i
    v=volumes #list of volumes v_i for product i
    W=W_max #maximum weight of a bin
    V=V_max #maximum volume of a bin
    #len(order) = number of products
    
    x=pp.LpVariable.dicts("x_i,j", ((i, j) for i in range(len(order)) for j in range(Y_max)),0,1,pp.LpBinary) #variable indicating if product i is placed in bin j
    y=pp.LpVariable.dicts("y_j", ((j,0) for j in range(Y_max)),0,1,pp.LpBinary) #variable indicating if bin j is used or unused
    Y=pp.LpVariable('Y')
    
    prob +=Y , 'objective function'    
    prob += pp.lpSum([y[j,0] for j in range(Y_max)]) == Y, ""
    
    for i in range(len(order)):
        prob += pp.lpSum([x[i,j] for j in range(Y_max)]) == 1,''  #product i can only be placed in 1 bin
    
    for j in range(Y_max):
        prob += pp.lpSum([x[i,j]*w[i] for i in range(len(order))]) <= W*y[j,0],""  #weight constraint
    
    for j in range(Y_max):
        prob += pp.lpSum([x[i,j]*v[i] for i in range(len(order))]) <= V*y[j,0],""  #volume constraint
    
    for j in range(Y_max):
        for i in range(len(order)):
            prob += x[i,j] <= y[j,0],"" #products i may not be placed in bin j if bin j is unnused. 
    
    prob += pp.lpSum([y[j,0] for i in range(len(order))]) >=Y_min,""
    pp.LpSolverDefault.msg = 1
    prob.solve()`
    

第二优化:最小化垃圾箱行驶到的区域数量(如何在线性优化中求解?)

  • 每种产品来自两个区域(区域1或区域2)中的1个。我们有这些区域z_i的列表(例如,区域1 <==> 1,区域2 <==> 0)。

  • 在箱数不超过最小箱数(在第一次优化中确定)的约束下,我可以在箱上拆分产品,以使每个箱箱行进到的区域数最小化?

  • 第一次优化的体积和重量约束仍然适用。

理想情况下,垃圾箱永远不会移动到两个区域,但是在某些情况下,它被迫这样做。 (例如,第一次优化会导致1个垃圾箱包含区域1和区域2的乘积)。

1 个答案:

答案 0 :(得分:0)

以下是执行此操作的一种方法-不一定是最简洁或最有效的。类似于@juvian

提出的建议

如果您逐渐减小每个垃圾箱的体积,则会发现它虽然很大,但可以容纳少量的垃圾箱,每个垃圾箱只能访问一个区域。随着垃圾箱变小,您不得不将垃圾箱移动到多个区域,而随着垃圾箱再次变小,就不得不使用更多的垃圾箱。

关于目标函数的通知: prob += Y + pp.lpSum([two_zones[j] for j in range(Y_max)])/(Y_max+1)

我们将次要目标(具有来自两个区域的产品的垃圾箱数量)除以最大垃圾箱数量+1。这样,我们始终将垃圾箱数量的主要目标放在优先位置-即使每个垃圾箱中都有来自在不同的区域中,第二个总和最多为Y_max,因此,如果将其除以Y_max + 1,将得到小于1.0的值,因此希望将已用垃圾箱的数量减少1。要确定目标优先级时常用的技术。

import numpy as np 
import pulp as pp

prob = pp.LpProblem("algorithm",pp.LpMinimize) #pp=pulp solver

Y_max = 5 #bins will not exceed this number
#Y_min = minimum number of bins (calculated)
# j = index of jth bin
# i = index of ith product

# Some dummy data
n_prod = 10

np.random.seed(0)
w = np.random.uniform(2.5, 10, n_prod)  # product weights
v = np.random.uniform(0.1, 1, n_prod) # product volumes
W = 25 #maximum weight of a bin
V = 1.5  #maximum volume of a bin
z = np.random.randint(0, 2, n_prod) # product zones

x=pp.LpVariable.dicts("x_i,j", ((i, j) for i in range(n_prod) for j in range(Y_max)), cat='Binary') #variable indicating if product i is placed in bin j
y=pp.LpVariable.dicts("y_j", range(Y_max), cat='Binary') #variable indicating if bin j is used or unused
Y=pp.LpVariable('Y') # No. bins used
two_zones = pp.LpVariable.dicts("two_zones,j", range(Y_max), cat='Binary')
has_zone_0 = pp.LpVariable.dicts("has_zone_0,j", range(Y_max), cat='Binary')
has_zone_1 = pp.LpVariable.dicts("has_zone_1,j", range(Y_max), cat='Binary')

# Primary objective: minm No. bins, Secondary minimize bins that visit two zones
prob += Y + pp.lpSum([two_zones[j] for j in range(Y_max)])/(Y_max+1), 'objective function'    

prob += pp.lpSum([y[j] for j in range(Y_max)]) == Y, 'set Y to No. bins'

for i in range(n_prod):
    prob += pp.lpSum([x[i,j] for j in range(Y_max)]) == 1,'each product in 1 bin %s' % i

for j in range(Y_max):
    prob += pp.lpSum([x[i,j]*w[i] for i in range(n_prod)]) <= W*y[j], 'weight constraint %s' % j

    prob += pp.lpSum([x[i,j]*v[i] for i in range(n_prod)]) <= V*y[j], 'volume constraint %s' % j

    for i in range(n_prod):
        prob += x[i,j] <= y[j], 'products only placed in used bin  %s_%s' % (j, i)

        prob += has_zone_0[j] >= x[i,j]*(z[i] == 0), 'set has_zone_0 flag %s_%s' % (j, i)
        prob += has_zone_1[j] >= x[i,j]*(z[i] == 1), 'set has_zone_1 flag %s_%s' % (j, i)

    prob += two_zones[j] >= has_zone_0[j] + has_zone_1[j] - 1, 'set two_zones flag %s' % j

prob.solve()

has_zone_0_soln = np.array([has_zone_0[j].varValue for j in range(Y_max)])
has_zone_1_soln = np.array([has_zone_1[j].varValue for j in range(Y_max)])
two_zones_soln = np.array([two_zones[j].varValue for j in range(Y_max)])
y_soln = np.array([y[j].varValue for j in range(Y_max)])

# Print some output:
print("Status:" + str(pp.LpStatus[prob.status]))
print('z: ' + str(z))
print('Y: ' + str(Y.varValue))
print('y_soln: ' + str(y_soln))
print('Objective: ' + str(pp.value(prob.objective)))
print('has_zone_0_soln: ' + str(has_zone_0_soln))
print('has_zone_1_soln: ' + str(has_zone_1_soln))
print('two_zones_soln: ' + str(two_zones_soln))
相关问题