完成仿真系统IR-schema规定
This commit is contained in:
1 parent
03b86f52ba
commit
ce353d2dd2
8 files changed
+5949
-4
No files matched your search
@@ -0,0 +1,262 @@
|
||||
# 全系统数值中间表示(System Numeric IR)规范 v2.0
|
||||
|
||||
状态:C-01 已实现并冻结 v2.0 数据合同;当前编译结果为 `reference_only`,原生 kernel 与执行器属于 C-02/C-03 及后续工作。
|
||||
|
||||
适用范围:后端 `GenericFluidSystem` 编译后的整个仿真系统。
|
||||
|
||||
机器可读定义:`schemas/system-numeric-ir-v2.schema.json`。
|
||||
|
||||
## 1. 定位与边界
|
||||
|
||||
System Numeric IR(以下简称 IR)描述“一个已经解析并编译好的系统,数值求解时需要哪些数据、按什么关系执行”。它是系统级合同,不是单个部件的文件。
|
||||
|
||||
```text
|
||||
XML / 建模 JSON
|
||||
→ 模型解析和连接检查
|
||||
→ GenericFluidSystem 对象图
|
||||
→ System IR v2.0
|
||||
→ 参考执行器 / 未来原生执行器
|
||||
```
|
||||
|
||||
XML 保存用户建立了哪些元件、参数和连线;IR 在此基础上补充求解器真正需要的槽位编号、状态降维、方程块、执行阶段、闭合范围、事务回滚、事件、Jacobian 和输出投影。因此二者看起来相似,但用途和层级不同。
|
||||
|
||||
本版本只完成“完整、确定、可校验的数据合同”和从现有系统生成该合同的编译器。它没有替换当前默认 Python 求解路径,不改变现有仿真结果。IR 中禁止保存 Python 函数、闭包、模型对象、对象地址和运行期临时状态。
|
||||
|
||||
## 2. 三个权威来源
|
||||
|
||||
三份实现共同定义 v2.0:
|
||||
|
||||
- `app/simulation/ir/schema.py`:Python 不可变数据类型、枚举、规范序列化和签名算法;
|
||||
- `schemas/system-numeric-ir-v2.schema.json`:跨语言 JSON 结构合同;
|
||||
- `app/simulation/ir/validation.py`:仅靠 JSON Schema 无法表达的引用、覆盖、拓扑和数值语义校验。
|
||||
|
||||
生产者必须同时满足机器 Schema 和语义校验。字段有增删时必须同步修改三处以及合同测试,不能只更新文档。
|
||||
|
||||
## 3. 版本、兼容性和严格读取
|
||||
|
||||
版本不是顶层整数,而是 `version` 对象:
|
||||
|
||||
```json
|
||||
{
|
||||
"$type": "schema_version",
|
||||
"schema_id": "system-numeric-ir",
|
||||
"major": 2,
|
||||
"minor": 0
|
||||
}
|
||||
```
|
||||
|
||||
- `major` 改变表示不兼容的字段或执行语义变化;读取方必须拒绝未知主版本。
|
||||
- `minor` 用于同一主版本内向前演进;当前读取方拒绝负数和高于自身能力的次版本。
|
||||
- JSON Schema 对所有合同对象使用 `additionalProperties: false`,v2.0 读取方不会静默忽略未知字段或枚举值。
|
||||
- 原生二进制 ABI 不写入 `SystemIR`,而由独立的 `IRNativeBuildIdentity.abi_version` 管理,当前值为 `1`。
|
||||
- 压力流量中的 `causal_plans.source_schema_version == 1` 只表示其来源是既有 causal IR v1;它不是完整系统 IR 的版本,也不能携带 v1 的 Python 回调。
|
||||
|
||||
## 4. 线格式和顶层结构
|
||||
|
||||
每个 dataclass 序列化后都带有稳定的 `$type`;操作对象还带有 `opcode`。顶层 `$type` 为 `system_ir`,其字段完整集合如下:
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| `version` | IR schema 身份与版本 |
|
||||
| `model_id` / `model_version` | 输入系统的稳定身份和调用方提供的模型版本 |
|
||||
| `compiler_id` / `compiler_version` | 产生 IR 的编译器身份,当前为 `generic-fluid-system` / `2.0.0` |
|
||||
| `numeric_dtype` | 主数值类型,v2.0 只接受 `float64` |
|
||||
| `buffers` / `values` | 连续缓冲区及每一个数值槽位的元数据 |
|
||||
| `kernels` / `components` | kernel 声明与元件实例绑定 |
|
||||
| `mediums` | 介质实现、介质常量和使用该介质的元件 |
|
||||
| `ports` / `connections` | 端口变量和系统拓扑 |
|
||||
| `state_reducer` | 求解器状态与元件局部状态/导数的线性映射 |
|
||||
| `causal_plans` / `pressure_flow` | 因果子计划和完整压力流量方程计划 |
|
||||
| `stream_plans` / `thermofluid` | stream SCC/DAG 与热流体外层闭合计划 |
|
||||
| `stages` / `blocks` | 无回调操作阶段与复合/迭代执行块 |
|
||||
| `entry_points` | `rhs`、`events`、`jacobian`、`outputs` 四个入口 |
|
||||
| `transaction` | 试算快照、流量恢复和参考缓存诊断 |
|
||||
| `modes` / `events` | 离散模式、根函数、reset 与缓存失效 |
|
||||
| `jacobian` | 固定 CSR 结构、着色和局部有限差分计划 |
|
||||
| `outputs` | 结果元数据和投影 |
|
||||
| `capabilities` | 系统和元件的原生可执行能力及缺口 |
|
||||
| `required_features` | 读取/执行该程序必须理解的功能 ID |
|
||||
|
||||
所有列表的顺序都是合同的一部分。引用统一采用数组索引或稳定 ID,不能依赖哈希表遍历顺序。
|
||||
|
||||
## 5. 规范序列化与内容签名
|
||||
|
||||
`canonical_json_bytes()` 是跨平台唯一线表示:
|
||||
|
||||
- UTF-8,ASCII 转义开启,JSON 键排序,无无意义空白;
|
||||
- 字符串先做 Unicode NFC 规范化;
|
||||
- tuple 写成 JSON array,不接受 list、dict、set 或任意对象;
|
||||
- 浮点数写成 IEEE-754 binary64 大端十六进制对象,例如 `{"$float64":"3ff0000000000000"}`;
|
||||
- `-0.0` 统一为 `+0.0`,NaN 和正负无穷直接拒绝;
|
||||
- 枚举写成规范字符串,整数和布尔值保持其 JSON 类型。
|
||||
|
||||
`SystemIR.structural_signature` 是上述完整 `SystemIR` 内容字节的 SHA-256 小写十六进制值。它准确回答“这份 IR 内容是否完全相同”,包含参数值和所有计划,因此不声称不同表达形式的数学系统会得到同一签名。操作系统、机器路径、构建时间、编译器和 native flags 不进入这个签名。
|
||||
|
||||
## 6. 缓冲区、槽位和值
|
||||
|
||||
槽位引用的格式为 `{"$type":"slot_ref","buffer":"...","index":N}`。v2.0 恰好声明以下 16 类缓冲区,每类一次:
|
||||
|
||||
| dtype | 缓冲区 |
|
||||
| --- | --- |
|
||||
| `float64` | `time`、`state_input`、`derivative_output`、`local_state`、`local_derivative`、`algebraic`、`signal`、`parameter`、`constant`、`work_float`、`event_output`、`jacobian_value`、`result_output`、`runtime_input` |
|
||||
| `int32` | `mode`、`work_int` |
|
||||
|
||||
`time` 的长度必须为 1;`int32` 初值必须在有符号 32 位范围内。每个缓冲区内索引为 `[0, size)`,而且每一个实际槽位必须恰好有一个 `IRValueSpec`。值描述包含稳定 ID、语义、角色、物理量、单位、缩放、可选上下界和可选所属元件。缩放必须为正有限数,边界必须有序且有限。
|
||||
|
||||
缓冲区是执行器唯一的数值寻址合同。名称用于诊断,不允许执行器重新用名称查找取代槽位访问。
|
||||
|
||||
## 7. Kernel 与元件绑定
|
||||
|
||||
`IRKernelSpec` 声明模型类型、模型版本、实现版本、能力、支持的 phase 以及参数/状态/mode/workspace 数量。phase 枚举为:
|
||||
|
||||
`primal`、`residual`、`derivative`、`property`、`event`、`reset`、`jacobian`、`output`。
|
||||
|
||||
phase 在 C-01 中只是稳定的功能标签。不同模型在同一 phase 下可能有不同输入输出数量,所以不能在 phase 上填写虚假的统一 arity。当前每个 `IRKernelCallOperation` 自身的有序 `read_slots`、`write_slots` 和 `equation_indices` 才是该次调用的权威依赖合同。C-02 将在此基础上冻结每个 `kernel_id + phase` 的纯数值调用签名并验证所有调用实例一致。
|
||||
|
||||
`IRComponentInstance` 把一个元件实例绑定到 kernel,并明确列出参数、局部状态、局部导数、mode、端口、输出和两类 workspace。绑定数量必须与 kernel 声明一致;端口和输出必须与其反向所属关系精确一致。
|
||||
|
||||
当前编译器把所有既有 Python kernel 标记为 `reference_only`。为便于结构审计,reference kernel 调用声明了保守读集合:可能多读,但不能漏掉模型对象当前可见的数值输入。Python 内部隐藏缓存仍不是原生槽位,因而任何含这类依赖的程序都不得宣称 `native`。
|
||||
|
||||
## 8. 介质、端口和连接
|
||||
|
||||
介质记录稳定 `medium_id`、名称、实现及其版本、常量槽位和使用它的元件索引。介质参数必须位于 `constant` 缓冲区。
|
||||
|
||||
端口分为 `physical` 与 `signal`:
|
||||
|
||||
- 物理端口必须声明正流方向,当前统一为 `intoComponent`;
|
||||
- signal 端口不得声明物理流向;
|
||||
- 变量角色与连接规则固定对应:`effort → equal`、`flow → sumToZero`、`stream → streamMix`、`signal → directed`。
|
||||
|
||||
连接必须引用两个已声明、不同、同 kind/同 domain 的端口,并精确覆盖两个端口的全部同名变量合同。物理端口和 signal 输入最多被一条连接占用;signal 输出允许扇出到多个输入。禁止重复端点对和悬空索引。
|
||||
|
||||
## 9. 状态降维与导数汇总
|
||||
|
||||
`IRStateReducer` 使求解器的 `state_input` 与各元件 `local_state` 分离。`state_reducer.initial_state` 是状态初值的语义描述,必须与 `state_input` 缓冲区的初值逐项完全相同,避免消费者面对两个不同初值:
|
||||
|
||||
- `state_scatter` 用 CSR 矩阵把求解器状态散射到有序局部状态槽位;
|
||||
- `derivative_gather` 把有序局部导数汇总为 `derivative_output`;
|
||||
- `initial_state` 与 `absolute_tolerances` 按求解器状态顺序定义。
|
||||
|
||||
这能显式表达共享机械坐标和气动储能状态的降维关系。例如同一气动储能状态可以按体积权重散射到多个局部状态,而不是由执行器临时按对象身份猜测。两个矩阵必须满足 CSR 不变量、维度和值数量合同,并覆盖全部组件状态/导数绑定。
|
||||
|
||||
## 10. 压力—流量计划与因果元数据
|
||||
|
||||
`IRPressureFlowPlan` 包含:
|
||||
|
||||
- `unknowns`:未知量的元件、端口、变量角色、槽位、缩放和边界;
|
||||
- `equations`:元件或连接拥有的方程、关系、涉及槽位、残差槽位和缩放;
|
||||
- `blocks`:未知量/方程的方块分解及每块 Jacobian CSR 结构;
|
||||
- `scopes`:全网、敏感物理岛或方程块作用域及求解限制;
|
||||
- `global_scope_index` 和 `secondary_scope_indices`:第一次全网求解与后续局部重算范围;
|
||||
- `pressure_lower_bound`:全局压力下界。
|
||||
|
||||
全局 scope 必须覆盖完整网络;每个 scope 的未知量和方程必须等于它包含的 blocks 之并集;secondary scope 唯一且不能包含 global scope。每条方程必须拥有唯一的 residual 槽位,防止两个残差互相覆盖。`sparse_pattern_trusted=false` 时必须给出回退原因,可信结构则不得携带回退原因。
|
||||
|
||||
`IRCausalPlan` 保存当前 causal IR v1 编译得到的无回调元数据,包括作用域、规范/兼容/重置槽位、外部 effort、effort 阶段和 flow 阶段。它只作为 v2 压力流量计划的一部分,不代替完整系统计划。
|
||||
|
||||
## 11. 操作、阶段、执行块和四个入口
|
||||
|
||||
v2.0 的无回调 opcode 为:
|
||||
|
||||
`fill`、`copy`、`scatter`、`linear_combination`、`state_map`、`kernel_call`、`effort_broadcast`、`flow_assign`、`check_finite`。
|
||||
|
||||
`IRStage` 给出 stage kind、操作序列以及声明的读/写集合;声明集合必须与操作读写并集完全一致。`IRExecutionBlock` 可以按顺序引用 stage 或其他 block;引用图必须无环。`fixed_point` 和 `stream_scc` block 必须声明监控槽位、绝对/相对容差、最大迭代、松弛、回滚槽位和失败策略,其他 block 禁止携带收敛合同。
|
||||
|
||||
四个入口必须恰好各一个,且入口输入统一按 `time`、完整 `state_input`、完整 `runtime_input` 排列:
|
||||
|
||||
| 入口 | 必须到达的结果阶段 | 精确输出缓冲区 | 不允许夹带 |
|
||||
| --- | --- | --- | --- |
|
||||
| `rhs` | `derivative_reduce` | 全部 `derivative_output` | event、Jacobian、output、reset |
|
||||
| `events` | `event` | 按事件顺序的全部 `event_output` 根槽位 | derivative reduce、Jacobian、output、reset |
|
||||
| `jacobian` | `jacobian` | 按 CSR 顺序的全部 `jacobian_value` | event、output、reset |
|
||||
| `outputs` | `output` | 按结果顺序的全部 `result_output` | event、Jacobian、reset |
|
||||
|
||||
入口可以复用前置 primal 阶段,但不能把四个入口合并成“每次 RHS 都把事件、Jacobian 和全部输出计算一遍”。入口执行不得写入 `state_input`、`parameter`、`constant` 或 `mode` 等持久输入。
|
||||
|
||||
## 12. Stream、热流体闭合和事务
|
||||
|
||||
`IRStreamPlan` 显式列出 stream 节点、强连通分量(SCC)、SCC 间缩点 DAG 和拓扑顺序。每个 SCC 对应一个 `stream_scc` block,循环只在 SCC 内迭代;监控槽位必须覆盖该 SCC 节点。
|
||||
|
||||
`IRThermofluidPlan` 覆盖全部物理端口,关联 stream plan、全局元件集合、敏感元件、secondary 压力 scope、最大迭代和流量相对容差。是否使用保守全网求解及原因必须成对出现,避免执行器静默扩大作用域。
|
||||
|
||||
`IRTransactionPlan` 冻结一次试探计算需要快照和恢复的端口变量,并单列实际活动气动端口上的 `m_flow`。当前目标系统中的这部分数量为 232;机械模型对象里没有作为活动端口变量出现的隐藏 `m_flow` 字段不会被误算进该集合。所有失败试算必须恢复快照;正常成功返回即为隐式提交,不另设可被误排序的 commit opcode。
|
||||
|
||||
`cache_component_indices`、`cache_attribute_ids` 和 `diagnostic_owner_ids` 只记录当前 Python 参考路径中仍需关注的隐藏副作用,供 C-02/C-03 清除和 Shadow 诊断;它们不是原生内存布局。存在 opaque Python cache 属性的系统不能标记为 `native`。
|
||||
|
||||
## 13. 模式、事件和 Reset
|
||||
|
||||
每个 `IRModeSpec` 记录 int32 mode 槽位、所属元件、合法值及初值。模式槽位必须全部且只被一个 mode 说明,组件 mode 绑定与 owner 关系必须双向覆盖。
|
||||
|
||||
每个 `IREventSpec` 记录稳定事件 ID、事件类型、owner、根槽位、触发方向、终止性、优先级、mode guard、reset steps、失效缓存种类以及是否重启积分器。reset 只能引用 `reset` stage,事件根槽位必须精确覆盖 `event_output` 缓冲区。
|
||||
|
||||
当前 IR 已能表达现有元件暴露的事件和模式结构;仍隐藏在 Python 信号求解或机械密集输出逻辑中的行为属于 `reference_only` 能力缺口,必须在 C-02/C-08 显式化后才能原生执行。
|
||||
|
||||
## 14. Jacobian 合同
|
||||
|
||||
`IRJacobianPlan` 包含固定 CSR pattern、与非零项一一对应的 `value_slots`、颜色组、填充值步骤、解析 value 索引和局部有限差分列。
|
||||
|
||||
CSR 必须满足:`row_pointers` 长度为行数加一、首项为 0、单调不减、末项等于非零项数量;每行列索引递增、唯一且在范围内。颜色组中的列不能共享同一潜在非零行,列不能重复着色。解析项和有限差分项不得重复或越界;每个有限差分列只能填写该列在 CSR 中确实存在的 value 索引,步长必须为正有限数。Jacobian 入口的执行步骤必须与 `fill_steps` 完全一致。
|
||||
|
||||
结构可以保守地多报潜在非零项,但不能漏报可能依赖。结构、模式布局或 kernel 实现改变会自然改变整份 IR 内容签名。
|
||||
|
||||
## 15. 输出合同
|
||||
|
||||
每个 `IROutputSpec` 包含稳定 output ID、所属元件、scope、可选端口名、内部名、显示标签、类别、物理量、单位、局部顺序、来源槽位、结果槽位以及线性 scale/offset。
|
||||
|
||||
`output_id` 和 `result_output` 槽位在全系统唯一。`order` 只在 `(component_index, scope, port_name)` 内排序,因此不同元件出现相同 `order` 是合法的;全局最终列顺序由 `outputs` 数组顺序确定。组件的 `output_indices` 必须精确反向覆盖其所有输出。
|
||||
|
||||
## 16. 能力报告与拒绝规则
|
||||
|
||||
能力级别只有:
|
||||
|
||||
- `native`:所有 kernel phase、状态、事件、事务和缓存都满足原生合同;
|
||||
- `reference_only`:数学/结构已描述,但至少一个阶段仍依赖 Python 参考实现;
|
||||
- `unsupported`:当前 IR 无法安全表达或执行,必须带 error 级能力问题。
|
||||
|
||||
每个元件必须恰好有一条 capability,列出支持 phase 与缺失 feature。系统为 `native` 时所有元件和 kernels 都必须是 native,且不能依赖 opaque Python cache;系统含任意 reference-only 元件时不能伪装为 native。能力问题具有 code、severity、scope ID 和消息,相同 code/scope 不得重复。
|
||||
|
||||
当前 `compile_system_ir()` 的输出明确为 `reference_only`,原因是 C-02 的纯数值 kernel 签名与 C-03 的扁平参考执行器尚未完成。这不是 IR 编译失败,也不允许 native loader 越过能力报告运行。标为 native 的系统还必须覆盖所有实际调用 phase,并且不得要求 `reference_kernel_dispatch`。
|
||||
|
||||
## 17. 原生构建产物键
|
||||
|
||||
二进制缓存身份与 IR 内容签名严格分离。`native_artifact_key(program, build)` 对以下信息再次做规范序列化和 SHA-256:
|
||||
|
||||
- `program.structural_signature`;
|
||||
- native ABI 版本;
|
||||
- target triple;
|
||||
- 编译器 ID 与版本;
|
||||
- 有序编译 flags;
|
||||
- 浮点策略;
|
||||
- kernel 库 SHA-256 签名。
|
||||
|
||||
ABI 必须等于当前支持值,字符串不能为空,flags 不能含空项,kernel 库签名必须为 64 位小写十六进制。这样相同 IR 在 Windows/Linux 上具有相同内容签名,但得到不同且安全的 native artifact key。
|
||||
|
||||
## 18. 编译、校验和消费流程
|
||||
|
||||
当前公开入口为:
|
||||
|
||||
```python
|
||||
from app.simulation.ir import compile_system_ir, require_valid_system_ir
|
||||
|
||||
program = compile_system_ir(system, model_version="...")
|
||||
require_valid_system_ir(program)
|
||||
payload = program.canonical_json_bytes()
|
||||
signature = program.structural_signature
|
||||
```
|
||||
|
||||
`compile_system_ir()` 接收已完成解析和系统构建的 `GenericFluidSystem`,不直接解析 XML。消费者必须先验证,再根据 `capabilities.system_level` 选择参考路径或未来原生路径;不得把“JSON Schema 能读取”误当成“具备 native 执行能力”。
|
||||
|
||||
静态校验采用 fail-closed 策略,覆盖:版本与 required feature、全部槽位、数值范围、组件/kernel arity、端口/连接、介质、状态映射、压力流量方程与 scope、阶段读写、block 无环、四入口切片、stream/热流体、事务、mode/event/reset、Jacobian、输出及能力一致性。`require_valid_system_ir()` 聚合错误后拒绝程序。
|
||||
|
||||
## 19. C-01 验收边界与后续工作
|
||||
|
||||
C-01 的完成标准是:
|
||||
|
||||
- 能从当前目标复杂模型和历史 0.81 s 模型生成完整系统级结构;
|
||||
- 同一系统重复编译得到字节完全相同的 canonical JSON 和签名;
|
||||
- 换行方式、Python 哈希种子和目标平台不会污染 IR 内容身份;
|
||||
- 故意破坏引用、覆盖、CSR、事务、入口或能力合同会被拒绝;
|
||||
- IR 中没有 callback、对象地址或任意 Python 对象;
|
||||
- 默认 Python 仿真路径保持不变。
|
||||
|
||||
C-01 不等于已经拥有可运行的 C 后端。下一步 C-02 要冻结每个 kernel 的纯数值签名、隐藏缓存和错误码;C-03 要用扁平 Python 执行器逐槽 Shadow 对照;完成这两项后,才可以建立 C ABI、原生执行器并逐步把 capability 从 `reference_only` 提升为 `native`。
|
||||
Reference in new issue
Block a user