Skip to content

滤棒智能排产CP-SAT建模说明

About 3045 wordsAbout 10 min

aps

2026-09-02

当前阶段仅输出建模与实现设计,不修改生产代码。

1. 建模目标

根据已生效的卷包智能排产明细 t_schedule_plan_detail,计算各滤棒物料在不同日期的需求,并生成滤棒设备生产计划。

滤棒计划必须满足:

  1. 卷包开始生产前,所需滤棒已经生产完成。
  2. 滤棒生产完成后必须存放指定时长,达到可用状态后才能供应卷包。
  3. 满足滤棒设备能力、工厂日历、开台计划、物料适配及换牌时间约束。
  4. 首版不考虑现有库存,期初可用库存按 0 建模。
  5. 在满足卷包需求的前提下,尽量晚生产、减少库存等待和换牌损耗。
  6. 滤棒排产不能修改卷包计划,只能根据卷包计划生成上游供应计划。

2. 数据关系

2.1 卷包需求来源

从指定的卷包排产版本读取:

t_schedule_plan_version
        │
        └── t_schedule_plan_detail
                ├── mat_id
                ├── plan_qty
                ├── plan_date
                └── plan_start_time

一次滤棒排产只能关联一个确定的卷包排产版本,不能把不同版本的明细混合计算。

滤棒排产版本应保存:

source_pack_schedule_plan_version_id

用于追踪滤棒计划依据的卷包版本。

2.2 卷烟与滤棒映射

通过 t_filter_cost 建立转换关系:

卷烟成品物料 mat_id
        │
        ├── filter_mat_id        滤棒物料
        ├── unit_consume_qty     标准单耗
        ├── switch_consume       是否使用统计单耗
        └── statistic_consume    统计单耗

有效单耗定义为:

if switch_consume = 1 and statistic_consume > 0:
    effective_consume = statistic_consume
else:
    effective_consume = unit_consume_qty

单耗缺失、非正或单位不一致时,应在进入求解器前终止,并返回配置错误。

2.3 滤棒存放时间

新增滤棒存放时间配置,至少包含:

model_site_id
work_shop_id
filter_mat_id
storage_hours
enable

配置读取顺序:

  1. 滤棒物料级配置;
  2. 工厂或车间默认配置;
  3. 均未配置时返回错误,不允许默认按 0 小时处理。

3. 卷包需求转换

3.1 单条明细转换

当前卷包 CP-SAT 明细的 plan_qty 按“箱”处理。

对于卷包明细 ii:

  • 卷包计划量:PiP_i,单位为箱;
  • 对应滤棒物料:f(i)f(i);
  • 单箱滤棒消耗:CiC_i,单位为万支/箱。

滤棒需求为:

Di=Pi×CiD_i = P_i \times C_i

单位为万支。

这里不再执行 planQty / 5。如果后续需要兼容其他排产分支,应先在输入适配层统一转换成“箱”,不能把单位换算散落在求解代码中。

3.2 日需求聚合

同一天可能有多个卷烟牌号使用同一种滤棒。

对滤棒物料 ff 和生产日期 dd:

Df,d=∑i∈I(f,d)DiD_{f,d} = \sum_{i \in I(f,d)} D_i

需求截止时间取当天相关卷包明细最早的开台时间:

Tf,ddue=min⁡i∈I(f,d)planStartTimeiT_{f,d}^{due} = \min_{i \in I(f,d)} planStartTime_i

因此形成如下需求事件:

滤棒物料 | 需求日期   | 需求截止时间     | 需求量
F01      | 2026-09-10 | 2026-09-10 07:30 | 120万支
F01      | 2026-09-11 | 2026-09-11 07:30 | 100万支

使用累计需求而不是逐条绑定,可以让前一天的剩余滤棒继续覆盖后续需求。

4. 时间模型

4.1 时间粒度

首版使用小时桶建模。

每个时间桶来自滤棒车间工厂日历:

bucket.start_time
bucket.end_time
bucket.machine_id
bucket.available_capacity

非工作时间不生成生产变量。

如果换牌时间不是整小时,应按照实际分钟数扣减相邻时间桶的有效能力,不能直接忽略或简单四舍五入。

4.2 存放后的可用时间

滤棒物料 ff 的存放时长为 LfL_f。

时间桶 bb 的产量统一视为在桶结束时完成,其可用时间为:

Tf,bavailable=Tbend+LfT_{f,b}^{available} = T_b^{end} + L_f

只有满足以下条件的产量才能供应截止时间 tt 的卷包需求:

Tf,bavailable≤tT_{f,b}^{available} \le t

该处理相对保守,但可以避免把仍在生产或仍在存放的滤棒提前计入库存。

5. 决策变量

定义:

xf,m,b∈{0,1}x_{f,m,b} \in \{0,1\}

表示滤棒物料 ff 是否在设备 mm 的时间桶 bb 上生产。

qf,m,b∈Z≥0q_{f,m,b} \in \mathbb{Z}_{\ge 0}

表示对应时间桶的滤棒产量。

为避免 CP-SAT 使用浮点数,所有产量应统一放大成整数。例如以 0.01 万支 为最小单位:

scaledQty = round(quantityWanZhi × 100)

所有需求、产能和求解结果必须使用相同缩放比例。

6. 硬约束

6.1 设备物料适配

只有 t_filter_equ_capacity 存在有效能力配置时,设备才能生产该滤棒:

qf,m,b=0if capacityf,m is unavailableq_{f,m,b}=0 \quad \text{if } capacity_{f,m} \text{ is unavailable}

6.2 单机互斥

同一设备、同一时间桶最多生产一种滤棒:

∑fxf,m,b≤1\sum_f x_{f,m,b} \le 1

6.3 设备能力

0≤qf,m,b≤Capacityf,m,b×xf,m,b0 \le q_{f,m,b} \le Capacity_{f,m,b} \times x_{f,m,b}

其中 Capacity 根据设备小时能力和时间桶有效工作时长计算。

6.4 工厂日历

生产变量只能建立在滤棒设备有效开台时间内。

休息日、停机班次和非工作时段的能力为 0。

6.5 换牌时间

设备从滤棒 f1f_1 切换到 f2f_2 时,需要满足:

Start(f2)≥End(f1)+ChangeTime(f1,f2)Start(f_2) \ge End(f_1) + ChangeTime(f_1,f_2)

换牌时间来自 t_filter_change_brand_time。

相同滤棒连续生产不产生换牌时间。

6.6 累计供应保障

定义截止时刻 tt 前已经完成存放的累计产量:

Af(t)=∑m,b:Tf,bavailable≤tqf,m,bA_f(t) = \sum_{m,b: T_{f,b}^{available}\le t} q_{f,m,b}

定义截止时刻 tt 前的累计需求:

Df(t)=∑d:Tf,ddue≤tDf,dD_f(t) = \sum_{d: T_{f,d}^{due}\le t} D_{f,d}

首版期初库存为 0,因此必须满足:

Af(t)≥Df(t)A_f(t) \ge D_f(t)

该约束需要在每个需求截止时刻建立,而不是只在排产周期结束时检查。

6.7 总量约束

首版不考虑安全库存,也不允许无意义超产:

∑m,bqf,m,b=∑dDf,d\sum_{m,b} q_{f,m,b} = \sum_d D_{f,d}

如果未来增加最小批量或整托盘约束,可以将等式改为允许少量尾差,并单独最小化超产量。

7. 自动向前扩展排产窗口

由于期初库存为 0,月初卷包需求通常需要在上月末提前生产。

例如:

卷包需求时间:09-01 07:30
滤棒存放时间:8小时

则滤棒必须在以下时间前完成生产:

08-31 23:30

排产起点不能固定为计划月份第一天。

窗口计算流程:

  1. 找到所有需求中最早的截止时间。
  2. 减去对应滤棒的存放时间。
  3. 按滤棒设备日历向前累计可用产能。
  4. 如果前置产能不足,继续向前加载工作日。
  5. 直到各滤棒理论产能和设备总产能能够覆盖前置需求。
  6. 若已经没有更早日历或设备始终无能力,返回无解诊断。

上月末生成的明细仍归属于本次滤棒排产版本,通过明细日期体现实际生产时间。

8. 优化目标

采用分层优化,避免不同目标的权重互相覆盖。

第一层:满足卷包生产

正式求解中累计供应保障为硬约束,不允许缺料。

第二层:尽量晚生产

在不缺料的前提下,最大化生产时间位置,使滤棒尽量靠近需求时间完成存放。

等价于最小化提前库存时间:

min⁡∑f,m,bqf,m,b×HoldingTimef,b\min \sum_{f,m,b} q_{f,m,b} \times HoldingTime_{f,b}

第三层:减少换牌

min⁡∑Changeoverm,b\min \sum Changeover_{m,b}

优先让同一种滤棒连续生产,减少换牌损耗。

第四层:设备优先级

根据 t_filter_equ_group_brand_priority,优先把滤棒安排到推荐设备。

第五层:设备负荷平衡

在不影响前四层目标的前提下,减少设备间负荷差异,避免部分设备长期满负荷而其他设备空闲。

9. 无解诊断模型

正式模型无解时,不保存排产结果。

诊断模型在累计保障约束中增加缺口变量:

Af(t)+Shortagef(t)≥Df(t)A_f(t) + Shortage_f(t) \ge D_f(t)

其中:

Shortagef(t)≥0Shortage_f(t) \ge 0

诊断模型第一目标为:

min⁡∑f,tShortagef(t)\min \sum_{f,t} Shortage_f(t)

为优先保障较早的卷包计划,应让越早的需求缺口惩罚越大。

诊断结果至少输出:

滤棒物料
需求日期
卷包开台时间
累计需求量
可用产量
缺口量
最晚应完成生产时间
主要原因

主要原因包括:

  • 卷烟物料未配置滤棒单耗;
  • 滤棒未配置存放时间;
  • 没有可生产该滤棒的设备;
  • 工厂日历没有足够工作时间;
  • 存放提前期不足;
  • 设备总产能不足;
  • 换牌时间导致可用产能不足。

10. 实现思路

10.1 输入装载层

建立独立的滤棒排产上下文装载器,负责:

  1. 加载指定卷包排产版本;
  2. 查询卷包日进度明细;
  3. 批量加载 t_filter_cost;
  4. 转换并聚合滤棒日需求;
  5. 加载滤棒存放时间;
  6. 加载设备能力、机组优先级和换牌矩阵;
  7. 加载滤棒车间日历;
  8. 计算自动向前扩展后的排产窗口;
  9. 完成单位转换和输入校验。

所有数据库查询和业务单位转换应在该层完成,求解器只接收已经标准化的整数模型。

10.2 问题模型层

建立独立的 FilterScheduleProblem,包含:

sourcePackVersionId
scheduleStartTime
scheduleEndTime
filterMaterials
demandEvents
machines
timeBuckets
capacityMap
changeoverMap
storageHoursMap
machinePriorityMap

不要让 CP-SAT 代码直接查询数据库。

10.3 求解层

滤棒 CP-SAT 可以沿用卷包求解器的组织方式:

ProblemBuilder
VariableBuilder
ConstraintBuilder
ObjectiveBuilder
SolutionMapper
FeasibilityAnalyzer

可以复用卷包排产中的设计思想,但首版不应为了代码复用而重构现有卷包 CP-SAT。滤棒使用独立类和独立模型,稳定后再评估是否抽取公共时间桶、日历和换牌组件。

10.4 结果转换层

将相邻设备、相同滤棒的连续小时桶合并为一条滤棒排产明细:

manageAreaId
filterMatId
planQty
planDate
planStartTime
planEndTime
actualStartTime
actualEndTime
workHours

同时保存对应需求身份或滤棒订单计划明细 ID,保证能够解释这批滤棒服务于哪些日期的卷包需求。

10.5 版本一致性

滤棒计划生成后,应记录源卷包版本。

如果源卷包版本被作废、重新发布或日进度发生变化,滤棒版本应标记为“需求已变化”,必须重新排产,不能继续作为有效供应计划。

11. 后续库存扩展

首版:

InitialInventoryf=0InitialInventory_f = 0

未来接入库存后,累计保障约束扩展为:

InitialUsableInventoryf+FutureMaturedInventoryf(t)+Af(t)≥Df(t)InitialUsableInventory_f + FutureMaturedInventory_f(t) + A_f(t) \ge D_f(t)

其中:

  • InitialUsableInventory:排产开始时已经完成存放的库存;
  • FutureMaturedInventory(t):当前尚未完成存放、但会在时刻 tt 前成熟的库存;
  • A_f(t):本次滤棒排产产生的可用量。

因此首版模型不需要推翻,只需增加两类外部供应事件。

12. 验收场景

  1. 9 月 10 日卷包生产 100 箱,单耗 0.05 万支/箱,应生成 5 万支滤棒需求。
  2. 两个卷烟牌号映射到同一种滤棒时,应合并成一个累计需求。
  3. 存放时间为 8 小时,09-10 07:30 的需求只能由 09-09 23:30 前完成的产量覆盖。
  4. 09-09 提前生产的剩余量可以继续覆盖 09-10、09-11 的需求。
  5. 09-01 的需求可以自动在 08-31 或更早日期排产。
  6. 未完成存放的产量不能计入可用量。
  7. 缺少单耗、存放配置或设备能力时,不进入求解器。
  8. 正式模型无解时不保存结果,诊断模型能够给出具体物料、截止时间和缺口。
  9. 滤棒排产始终读取同一个明确的卷包版本。
  10. 首版所有需求均由本次排产生产,库存贡献固定为 0。

求求了,快滚去学习!!!

求求了求求了,快去学习吧!

【LeetCode】贪心算法
【LeetBook】数组和字符串

不知道方向的时候,可以多看看书,书会给你指明下一步该干什么,加油!