首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >约束优化:只适用于继续选择的第二项的条件?

约束优化:只适用于继续选择的第二项的条件?
EN

Stack Overflow用户
提问于 2022-08-26 11:32:31
回答 1查看 53关注 0票数 0

我有一个约束优化问题(特别是OR工具)。我正努力将不同运输供应商发送包裹的成本降到最低。它们中的每一个都有一定的维度约束,但一些航运供应商可以选择发送多个包裹,而且对于第二项产品,他们的价格更低。

如何合并约束(或目标)?对选定的第一个项目收取一个价格,对所有其他项目收取不同的价格?如果有任何方法使其分层,奖金点-例如,为所选的第一个项目设置一个价格,通过第5项的另一个价格,以及对项目6+.的第三个价格。

以下是我的一些代码供参考--如果有什么事情看不见/您将如何改进,请告诉我:

def cost_optimisation():

代码语言:javascript
运行
复制
# 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()

(很明显,???是我开始失去它的地方)

EN

回答 1

Stack Overflow用户

发布于 2022-08-26 13:41:53

测试IntVar值的结构,如if语句中的

代码语言:javascript
运行
复制
if all_courier_sums[courier_num] >= 2:

都不管用。IntVar的值不是在求解器之外定义的,它只是一个容器,它的值将在解决方案期间确定。

首先,添加一个约束以强制all_courier_sums[courier_num]等于该信使的parcel_by_courier之和。

代码语言:javascript
运行
复制
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]

然后,您可以为每个快递员创建一个成本公式,如下所示:

代码语言:javascript
运行
复制
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作为目标。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73500391

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档