# 排产算法 · CP-SAT / HYBRID v1(SC-03,工序级模型) > 代码:`server/engines/cp_engine.py` > 测试:`tests/golden/test_cp_engine.py`、`tests/golden/test_cp_operation_level.py` > 工厂:`get_engine("CP"|"HYBRID")` --- ## 1. 范围 | 引擎 | 管线 | | --- | --- | | CP | CP-SAT 工序级选线+排序(Interval/NoOverlap/换型/冻结窗)→ 班次占槽 | | HYBRID | RULE 策略序/选线 hint → CP-SAT 改良 → 班次占槽 | 诚实留痕:`engineType` + `solverMeta`(backend / model / pipeline / warmStart / status / gap / wallTimeSec / operationSlots / totalChangeoverMin / frozenCount)。 --- ## 2. 工序级模型摘要(方向 D) 决策与约束(对应 plan.md §9.2a 约束目录): | 约束 | 建模 | | --- | --- | | 选线(C5) | 每订单恰好一条可行产线(OptionalBoolVar 互斥);只保留全线工序均有可用工位的产线 | | 工序区间(C1) | 每订单每道工序一个 `OptionalIntervalVar`(准备 + 数量×单件/效率),按工艺路线 `start[i+1] >= end[i] + 转移/等待` 串联 | | 工位/设备独占(C2) | 同工位/设备上全部工序 `AddNoOverlap`(跨订单聚合);同线不同工位允许并行(流水语义) | | 换型矩阵(C10) | 产线工序序列用 next-link 单链路径建模:相邻订单首工序间 `start >= 前序首工序 end + setup(族→族)`;同族/无前序为 0 | | 冻结窗(C11) | `freezeWindowHours` 内已发布/`isFrozen` 工单作为 `FixedSizeIntervalVar` 障碍加入 NoOverlap;新排订单首工序不早于冻结窗末端 | | 目标(C8/C9) | 加权延期最小化(客户等级 + 急单权重),与前版一致 | 其他说明: - 无工艺路线或缺工位的产线不作为 CP 候选(物化阶段照常报 `NO_LINE`/`NO_WORKSTATION`,诚实留痕)。 - 二级资源当前采用「容量互斥」:同工位 NoOverlap;`Cumulative`(班组/工装等聚合容量)为后续扩展点。 - 换型 setup 落在相邻订单的首工序之间(与 RuleEngine 物化把跨族分钟叠到首道工序的语义一致);`solverMeta.operationSlots` 中 `changeoverMin` 标注在首工序槽位。 - 工序级 Interval 与物化的班次占槽是两个层面:CP 决定选线与开工序,物化仍按班次日历落槽(`placement=shift-slot`)。 --- ## 3. solverMeta 新增字段 | 字段 | 内容 | | --- | --- | | `model` | `"operation-level+no-overlap+changeover+freeze"` | | `operationSlots` | 每个订单每道工序:lineId / workstationId / sequenceNo / operationId / startMin / endMin / durationMin / setupMin / changeoverMin / isFrozen | | `totalChangeoverMin` | 本版累计换型分钟(跨族 setup 求和) | | `frozenCount` | 冻结窗内固定障碍工单数 | --- ## 4. 降级策略 | 场景 | CP | HYBRID | | --- | --- | --- | | 缺 ortools | `ENGINE_UNAVAILABLE` 空版本 | `DEGRADED_RULE` 物化 RULE 序 | | 求解无可行解 | 保留启发式序 | 保留 warm 强制线 | --- ## 5. 未做 - LNS 大邻域 / 插单局部修复 - GA / NSGA-II 多目标 - 班组/工装 Cumulative 聚合容量进 CP - 换型矩阵与冻结工单之间的跨窗 setup(冻结障碍不参与换型路径) 见 [roadmap.md](./roadmap.md)。