我有一个约束优化问题(特别是OR工具)。我正努力将不同运输供应商发送包裹的成本降到最低。它们中的每一个都有一定的维度约束,但一些航运供应商可以选择发送多个包裹,而且对于第二项产品,他们的价格更低。。
如何合并约束(或目标)?对选定的第一个项目收取一个价格,对所有其他项目收取不同的价格?如果有任何方法使其分层,奖金点-例如,为所选的第一个项目设置一个价格,通过第5项的另一个价格,以及对项目6+.的第三个价格。
以下是我的一些代码供参考--如果有什么事情看不见/您将如何改进,请告诉我:
def cost_optimisation():
# Instantiate solver
solver = pywraplp.Solver.CreateSolver('SCIP')
# Get data
data = get_model_data()
### VARIABLES ###
# whether a courier can ship a parcel (T or F depending on whether the courier is eligible to ship the parcel)
parcel_by_courier = {}
for parcel_num in data['parcel_range']:
for courier_num in data['courier_range']:
parcel_by_courier[parcel_num, courier_num] = solver.BoolVar(f"parcel_{parcel_num}_courier_{courier_num}")
# the total number of parcels shipped by a courier
all_courier_sums = {}
for courier_num in data['courier_range']:
all_courier_sums[courier_num] = solver.IntVar(0, len(data['parcel_range']), f"{data['courier_names'][courier_num]}_total_parcels_shipped")
print('Number of variables =', solver.NumVariables(), '\n')
### CONSTRAINTS ###
# add constraint that all parcels have to be shipped
for parcel_num in data['parcel_range']:
solver.Add(sum(parcel_by_courier[parcel_num, courier_num] for courier_num in data['courier_range']) == 1)
# add weight & dimension constraints
for parcel_num in data['parcel_range']:
for courier_num in data['courier_range']:
solver.Add(parcel_by_courier[parcel_num, courier_num] * data['parcel_weights'][parcel_num] <= parcel_by_courier[parcel_num, courier_num] * data['courier_weights'][courier_num])
solver.Add(parcel_by_courier[parcel_num, courier_num] * data['parcel_largest_dimensions'][parcel_num] <= parcel_by_courier[parcel_num, courier_num] * data['courier_largest_dimensions'][courier_num])
# add a constraint that couriers can only ship >1 parcel IF "further_item_allowed" = True
for courier_num in data['courier_range']:
solver.Add(sum(parcel_by_courier[parcel_num, courier_num] for parcel_num in data['parcel_range']) <= 1 if data['courier_further_item_allowed'][courier_num] is False else sum(parcel_by_courier[parcel_num, courier_num] for parcel_num in data['parcel_range']) >= 0)
print('Number of constraints =', solver.NumConstraints(), '\n')
### OBJECTIVE ###
# Calculate costs for the objective and run the solver
total_base_item_cost = []
for courier_num in data['courier_range']:
for parcel_num in data['parcel_range']:
if all_courier_sums[courier_num] >= 2:
if ???:
total_base_item_cost.append(data['courier_first_item_pence'][courier_num] * parcel_by_courier[parcel_num, courier_num])
else:
total_base_item_cost.append(data['courier_further_item_pence'][courier_num] * parcel_by_courier[parcel_num, courier_num])
else:
total_base_item_cost.append(data['courier_first_item_pence'][courier_num] * parcel_by_courier[parcel_num, courier_num])
total_cost = sum(total_base_item_cost)
solver.Minimize(total_cost)
status = solver.Solve()
(很明显,???
是我开始失去它的地方)
发布于 2022-08-26 13:41:53
测试IntVar
值的结构,如if语句中的
if all_courier_sums[courier_num] >= 2:
都不管用。IntVar的值不是在求解器之外定义的,它只是一个容器,它的值将在解决方案期间确定。
首先,添加一个约束以强制all_courier_sums[courier_num]
等于该信使的parcel_by_courier
之和。
for courier_num in data['courier_range']:
solver.Add(Sum(parcel_by_courier[parcel_num, courier_num] for parcel_num in data['parcel_range']) == all_courier_sums[courier_num])
为每个信使定义一个变量courier_cost[courier_num]
。
然后,您可以为每个快递员创建一个成本公式,如下所示:
for courier_num in data['courier_range']:
p1 = data['courier_first_item_pence'][courier_num]
p2 = data['courier_further_item_pence'][courier_num]
c1 = solver.IntVar(0, len(data['parcel_range']) * max_cost_per_parcel)
solver.Add(c1 == (p1 * all_courier_sums[courier_num]))
qty2 = solver.IntVar(0, len(data['parcel_range']))
solver.AddMaxEquality(qty2, [0, (all_courier_sums[courier_num] - 1)])
c2 = solver.IntVar(0, len(data['parcel_range']) * max_cost_per_parcel)
solver.Add(c2 == ((p2 - p1) * qty2)
solver.Add(courier_cost[courier_num] == c1 + c2)
注意:我实际上没有检查这个语法。如果它不起作用,将其分解为单个术语的独立变量,并逐项构建表达式。求解者将在内部创建这些额外的变量,即使您没有显式地这样做。
如果有更多的中间价格水平,你可以扩展这里的原则为第4,6或任何价格步骤有。
要获得总成本,必须将变量total_cost
设置为IntVar
。
将其限制为在信使范围内的courier_cost[courier_num]
与courier_num
之和。
然后,您可以使用total_cost作为目标。
https://stackoverflow.com/questions/73500391
复制相似问题