我有一个产品列表(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的乘积)。
答案 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))