Metadata-Version: 2.4
Name: aps-kernel
Version: 1.7.1
Summary: Deterministic CP-SAT scheduling kernel, independent schedule validator, and headless CLI — APS standard edition
Author: APS Contributors
License: MIT
Project-URL: Homepage, https://aps.zhinengti.online
Project-URL: Documentation, https://github.com/123aiot/aps/tree/main/docs
Project-URL: Source, https://github.com/123aiot/aps
Project-URL: Changelog, https://github.com/123aiot/aps/blob/main/CHANGELOG.md
Keywords: aps,scheduling,production-planning,cpsat,ortools,finite-capacity,manufacturing,aps-kernel
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Manufacturing
Classifier: Intended Audience :: Science/Research
Classifier: Natural Language :: Chinese (Simplified)
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: ortools>=9.10
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Dynamic: license-file

# aps-kernel — Metis 谋序（APS 标准版）

> **运筹帷幄，谋定后动** —— 同衡·谋序·同枢，智造同频。
> One Truth. One Plan. One Rhythm.

可嵌入的**确定性**排产内核：CP-SAT 精确求解、**独立复核器**、
工序-资源适配数据模型、设备槽位与班次日历、ε-约束 trade-off、headless CLI。

> **标准版 vs 专业版**：本包只含可嵌入内核（无 UI / 无服务 / 无 LLM）。
> 甘特图前端、Web 控制台、AI 编排层、多租户 RLS、审批与 IM 通道
> 属专业版（Docker 镜像 + docker compose）。

🌐 官网：https://aps.zhinengti.online
家族：Nereus 同衡（数字孪生）· Metis 谋序（智能排产）· Hermes 同枢（物流调度）

---

## ⭐ 求解能力（横向基准，非自说自话）

在 **16 个标准 FJSP 实例**（ft/la/abz/orb/swv/ta/yn，来源 `job_shop_lib` MIT，
含**文献公认最优值**）上的实测：

| 实例 | 工单×机器 | SPT 基线 | 规则链 | **CP-SAT** | 文献最优 | vs 最优 |
|---|---|---|---|---|---|---|
| ft06 | 6×6 | 94 | 92 | **55** | 55 | **+0.0% OPTIMAL** |
| ft10 | 10×10 | 1530 | 1310 | **930** | 930 | **+0.0% OPTIMAL** |
| ft20 | 20×5 | 1513 | 1565 | **1165** | 1165 | **+0.0% OPTIMAL** |
| la01-05 | 10×5 | ~1000 | ~940 | **最优** | — | **+0.0% OPTIMAL** |
| abz5/6 | 10×10 | ~1700 | ~1600 | **1234/943** | 同 | **+0.0% OPTIMAL** |
| orb01 | 10×10 | 1489 | 1631 | 1082 | 1059 | +2.2% FEASIBLE |
| swv01/02 | 20×10 | ~2100 | ~2100 | 1495/1562 | 1407/1475 | +6% FEASIBLE |
| ta01/02 | 15×15 | ~2100 | ~2040 | 1233/1248 | 1231/1244 | +0.3% FEASIBLE |
| yn1 | 20×20 | 1547 | 1509 | 944 | 884 | +6.8% FEASIBLE |

**11/16 达到文献最优**，其余为大规模实例（20 秒预算不足，已如实标 gap）。
**全部 11/11 独立复核通过。**

```bash
python benchmarks/run_standard_bench.py --time-limit 30
```

---

## 当前状态

**v1.7.1** —— 工序依赖接线（P7-6）+ 固定准备 `setup_seconds` 建模 + 复核器第 11 项。514 tests passed

| 模块 | 状态 | 关键能力 |
|---|---|---|
| 数据模型 P0 | ✅ | 工序-资源适配、**空适配 ≠ 全设备可用**、槽位 |
| 输入校验 P0 | ✅ | 三项 P0 准则 + 5 类检查 |
| 规则引擎 P1 | ✅ | **7 条规则**（CR/EDD/SPT/WKWR/ATC/加权优先级/**FIFO**）+ 8 条链 |
| 日历与齐套 P2 | ✅ | 三日历求交、**班次×资源×位置**、工单级齐套布尔判定 |
| 换型规则链 P2 | ✅ | frePPLe 语义、**无匹配 = 硬约束禁止**、参数配置化、**非对称 A→B≠B→A**、矩阵格式 |
| CP-SAT 求解 P3 | ✅ | **字典序三级目标**、容量池用 `AddCumulative`、冻结窗口 |
| 独立复核器 P4 | ✅ | **11 项真检查**（含日历可行、模具互斥、技能资格、**依赖满足**）、用输入重算不信任求解器 |
| Provenance P4 | ✅ | 快照 hash + 配置/源码/求解器版本 |
| CLI + 基准 P5 | ✅ | `solve` / `benchmark` / `explain` / `chains` / `health` / **`lotting`** |
| 冲突诊断 | ✅ | `aps explain` —— 最小冲突集 + 排不下原因 |
| ε-约束 trade-off | ✅ | 钉住交期预算，问 makespan 能压到多少 |
| **数据体检** | ✅ | `aps health` —— 四张底账逐项核对 + 可执行率估计 |
| **设备负载均衡旋钮** | ✅ | ε-约束第 3 个旋钮：钉住设备负荷不均衡度 |
| **工装模具约束** | ✅ | 跨设备 NoOverlap —— 冲压/注塑的头号约束，「机床等模具」不再是隐患 |
| **并行工序** | ✅ | 同 `seq` 的工序可同时执行（双人工位装配 / 多工位并行检测）|
| **序列相关换型** | ✅ | 换型**真实占用产能**（贪心+CP-SAT+复核器三方一致）；A→B 与 B→A 可不同 |
| **换型矩阵格式** | ✅ | 直接贴工厂的换型矩阵表（行业通用格式），支持非对称与「禁止该换型」|
| **拆批合批** | ✅ | 求解前预处理；工时按数量缩放；最小批量约束；合批守交期红线 |
| **人员技能资格** | ✅ | 工序声明技能 → 资源必须**持证**（1.6.0）。无证资源自动跳过；缺证时警告点名技能而非静默 |
| **工序依赖** | ✅ | `predecessors` + `min_lag_minutes`（1.7.0）：跨工单拓扑就绪门 + 并行组内分层 + 前道完工地板；pred 未排 ⟹ 约束不生效（与 CP-SAT presence 语义一致） |
| **固定准备时间** | ✅ | `setup_seconds`（1.7.0）：装夹/调机首件确认每单必付，占用区间 `[start−P, end]` 两求解器+复核器三方同口径 |

---

## 三个设计立场

### 1. 诚实高于漂亮

`OPTIMAL` 只在**真正证明最优**时才标；`FEASIBLE` 必带真实 gap；
超时回退贪心解时 `diagnostics["solver_fallback"]` 明确标注来源；
**全部未排时标 `INFEASIBLE` 而非 `OPTIMAL`**（避免"看起来排好了"）。

> 这直接对应论文《Formalize, Don't Optimize》的三个统计口径：
> **返回结果率 / 验证通过率 / 已返回中通过比例** —— 分母不同，不可混比。

### 2. 复核器是必需品，不是锦上添花

`validator.independent_validate()` 用**输入数据重算**（时长、槽位、日历、
换型、设备资格、技能资格、**依赖满足**），**不信任求解结果自报的值**。这不是防御性冗余 ——

> 开发中它抓到过**槽位重叠 48 处而求解器报 `OPTIMAL`**、
> **makespan = 2.3e18 的垃圾值**（`UNKNOWN` 时仍读未赋值变量）。

### 3. 基准必须公平

所有基线必须在**相同约束集**下比较。曾实现一个无视日历/工序先后的 SPT 基线，
得出「SPT 比 CP-SAT 还优」的**颠倒结论**（vsSPT = -203%）。

> 非法基线比没有基线更糟 —— 它会得出完全相反的结论。

---

## 🏗 分层架构：本包的位置

博客园《CP-SAT 排产、排程、排班》：

> 「APS（长周期规划）+ RTS/RTD（实时派工）**双层架构是业界最佳实践**」
> 「前一天做的排程，第二天全乱套」—— 排程 ≠ 派工 是经典误区

```
┌─────────────────────────────────────────────────┐
│  上层（aps-platform / 本包之外）                  │
│  · MRP / 采购 / 库存                              │
│  · APS 长周期计划（天/周）                        │
│  · RTS / RTD 实时派工（分钟级）  ← 不在本包        │
│  · MES 执行回写 / 甘特图 UI                       │
└─────────────────────────────────────────────────┘
                ↕ ScheduleInput / ScheduleResult
┌─────────────────────────────────────────────────┐
│  aps-kernel（本包）—— 求解内核，不含流程            │
│  ✅ 数据模型 / 输入校验                            │
│  ✅ 规则引擎（7 规则 + 8 链）                     │
│  ✅ CP-SAT 精确求解 + 贪心兜底                    │
│  ✅ 冻结窗口（支持增量重排）                      │
│  ✅ 独立复核器（11 项）                          │
│  ✅ ε-约束 trade-off / 冲突诊断 / 基准            │
│  ❌ 不做派工、不做 UI、不做持久化、不含 LLM         │
└─────────────────────────────────────────────────┘
```

⚠️ **为什么派工不在本包**：派工是**高频决策**（分钟级刷新），
需要实时状态推送与人工干预；本包是**低频决策**（计划级），
追求确定性与可审计。把两者混在一个包里会同时失去两者。

⚠️ **本包负责「证明这个计划可执行」，不负责「生成甘特图」**：

> 「排产的难点从来不是生成一个计划，而是**证明这个计划在约束下可执行**。」
> —— 《LLM 不会给你最优排产，求解器会》

---

## 版本与兼容性

| | |
|---|---|
| 当前 | **1.7.1** —— 功能优先迭代期，API 会随功能演进 |
| 含义 | ⚠️ **1.0.0 的 API 冻结承诺已于 2026-10-17 取消**，现按功能优先迭代 |
| 变更记录 | [CHANGELOG.md](CHANGELOG.md) —— 含破坏性变更与迁移动作 |

---

## 快速开始

```bash
pip install aps-kernel

# 0) ⭐ 上线前先体检（核对工时/BOM/日历/换型矩阵四张底账）
aps health input.json --bom bom.json --inventory stock.json

# 1) 看内置规则链
aps chains

# 2) 求解（贪心，快）
aps solve input.json --chain default

# 3) 求解（CP-SAT，可证 OPTIMAL）
aps solve input.json --solver cpsat --time-limit 30

# 4) 排不下时诊断原因（最小冲突集）
aps explain input.json

# 5) 基准验证（规则链 vs SPT vs CP-SAT）
aps benchmark --sizes 5,8,10 --chains default
```

> `aps health` 的退出码可直接接 CI：`0` 可上线 / `1` 需补数 / `2` 阻断。

```python
from aps_kernel import schedule, solve, CpSatOptions, independent_validate

# 贪心（快，不证明最优）
result = schedule(data, chain="default")

# CP-SAT（可证 OPTIMAL）
result, stats = solve(
    data, options=CpSatOptions(time_limit_seconds=30, workers=8),
)

# 独立复核 —— 不信任求解器自报
checks = independent_validate(data, result)
assert all(ok for _, ok, _ in checks)
```

---

## 已知局限（诚实列出）

| 局限 | 说明 |
|---|---|
| ~~`Job.due_date` 只能表达天~~ | ✅ 已修复（v0.10.0）：改为 `date | datetime` 联合类型，支持小时级交期。用 `due_offset_from_horizon()` 计算偏移（**不要**用 `.days * 1440`，会丢小时） |
| 交期需**整日或整时** | 建议传 `datetime`；传 `date` 时按当天 00:00 算，不是「当天结束」—— 与部分 APS 的约定不同，转换时请留意 |
| 大规模 gap 仍大 | 20 工单以上、30 秒预算只能到 FEASIBLE。**根因已定位**：
| 字典序前两级在「证明贪心已最优」上耗掉 27.5 秒。已加**下界剪枝**
| （贪心已达理论下界时跳过该级），n=10 改善 3.9% → 7.5%；
| n≥15 的 makespan 级本身在 30 秒内证不了最优（gap 60%+），
| 这是 CP-SAT 的固有限制（Chalmers 论文：57/100 实例可证最优） |
| ~~换型为**静态规则**，非序列相关~~ | ✅ 已修复（v1.4.0/1.5.0）：换型时间**真实占用产能**（此前只记录不预留，计划现场执行不了）；A→B 与 B→A 可不同（换下的模具比装上的更重是物理现实）。仍不支持「A→B→C 链式换型」的组合优化 |
| ~~缺**拆批合批**~~ | ✅ 已修复（v1.5.0）：`split_input` / `merge_compatible_jobs`。**工时按数量线性缩放**（不缩放时拆 4 批 makespan 120→480）。合批守交期红线，默认关闭 |
| 换型建模假设「同槽位同组成块」 | CP-SAT 的换型约束是**充分非必要**的（排除交错排法），非等价改写。换型极贵时该假设成立，但这是真实限制 |
| 模具**无寿命/维护周期**建模 | 现只有「同一时刻一台机」，没有「这副模还能用几次」 |
| 技能只有**资格过滤**，无池容量 | 1.6.0 起「无证资源不排工序」，但「几人持证 = 几个并行额度」尚未建模（`Resource.skills` 是集合，无数量）。多工种共享同一设备的并发上限需专业版 |
| 无持久化状态 | 每次求解无状态，冻结窗口需由调用方传入 |
| 合成 demo 交期偏宽 | demo 默认交期 = horizon+5 天 ≫ makespan → 拖期恒为 0；验证拖期逻辑需改用紧交期 |
| 体检的**可执行率是估计值** | 基于静态校验，不检查「现场是否会临时变更」。cp_sat_demo 实测 44%，本估计通常偏乐观 |

---

## 安装与依赖

- Python ≥ 3.11
- 运行时依赖：`ortools >= 9.12`、`PyYAML`
- **仅发 wheel**（`py3-none-any`），不发 sdist

## License

MIT
