OR-tools中多批次生产产量分配至订单的实现技巧咨询
问题描述
需要履行订单并明确交付日期,允许分多次交付,将生产批次(含部分批次)分配至已知订单,核心规则为同产品的生产产量按订单顺序填充(即优先满足先出现的订单,产能不足时再用后续批次补充)。最终需通过OR-tools返回各订单对应的生产批次(含关联生产日)及分配的产量。
订单数据示例
orders = { 0 : [50,45,65], # 键:产品编号;值:订单需求量列表(按顺序) 1 : [155,15,80,25] }
生产批次数据示例
已通过OR-tools定义变量形式的生产批次列表list_production,每个批次包含产品编号、产量、关联NewIntervalVar的生产日,示例如下:
# 格式:[产品编号, 产量, 生产日] list_production = [ [0, 30, 1], [1, 100, 1], [1, 90, 2], [0, 40, 2], [0, 60, 3], [1, 40, 3], [1, 35, 3] ]
注:该列表整体产品编号无序,但同产品的生产日变量已满足时间先后顺序约束。
实现技巧与方法
1. 按产品分组生产批次
先将无序的生产批次按产品编号分组,利用同产品生产日已有的顺序约束,得到每个产品对应的有序批次列表:
from collections import defaultdict # 按产品编号分组,自动保留同产品的生产日顺序 product_batches = defaultdict(list) for batch in list_production: product_id, qty, day = batch product_batches[product_id].append( (qty, day) )
2. 建模顺序填充约束
针对每个产品的订单序列和批次列表,创建分配变量并添加三类约束:
- 批次产能约束:单个批次分配给所有订单的总量不能超过自身产量
- 订单需求约束:所有批次分配给单个订单的总量必须等于该订单的需求量
- 顺序填充约束:确保先填满前面的订单,再用剩余产能分配给后续订单
以下是OR-tools的具体实现代码:
from ortools.linear_solver import pywraplp # 初始化求解器 solver = pywraplp.Solver.CreateSolver('SCIP') all_assign_vars = {} # 存储所有产品的分配变量 for product_id in orders: reqs = orders[product_id] batches = product_batches[product_id] num_orders = len(reqs) num_batches = len(batches) # 计算累计需求和累计批次产量,用于顺序约束 cum_reqs = [0] for r in reqs: cum_reqs.append(cum_reqs[-1] + r) cum_batches = [0] for qty, _ in batches: cum_batches.append(cum_batches[-1] + qty) # 创建分配变量:assign[j][i] = 第j个批次分配给第i个订单的数量 assign = [] for j in range(num_batches): row = [] for i in range(num_orders): var = solver.IntVar(0, batches[j][0], f'assign_p{product_id}_b{j}_o{i}') row.append(var) assign.append(row) all_assign_vars[product_id] = assign # 约束1:批次产能不超 for j in range(num_batches): solver.Add(sum(assign[j]) <= batches[j][0]) # 约束2:订单需求被完全满足 for i in range(num_orders): solver.Add(sum(assign[j][i] for j in range(num_batches)) == reqs[i]) # 约束3:顺序填充——前i个订单必须用完前j个批次的产能后,才能用后续批次给第i+1个订单分配 for i in range(num_orders): for j in range(num_batches): # 前j个批次的总产能 <= 前i个订单的总需求 → 该批次不能分配给第i+1及之后的订单 if cum_batches[j+1] <= cum_reqs[i]: for k in range(i+1, num_orders): solver.Add(assign[j][k] == 0) # 前i个订单的总需求 <= 前j-1个批次的总产能 → 该批次不能分配给第i及之前的订单 elif cum_reqs[i] <= cum_batches[j]: for k in range(i+1): solver.Add(assign[j][k] == 0)
3. 提取并输出结果
求解完成后,遍历分配变量,整理每个订单对应的批次信息:
status = solver.Solve() if status in (pywraplp.Solver.OPTIMAL, pywraplp.Solver.FEASIBLE): for product_id in all_assign_vars: reqs = orders[product_id] batches = product_batches[product_id] assign = all_assign_vars[product_id] print(f"=== 产品{product_id}的订单分配结果 ===") for i in range(len(reqs)): print(f"订单{i}(需求:{reqs[i]}):") for j in range(len(batches)): qty_assigned = assign[j][i].solution_value() if qty_assigned > 0: print(f" 批次{j}:分配产量{qty_assigned},生产日{batches[j][1]}")
内容的提问来源于stack exchange,提问作者Vincente
相关产品推荐
相关产品推荐

