类编译器架构与模型转换
OSPF 可以用类编译器架构组织“业务表达 → 数学表示 → 后端执行 → 业务结果”。这个类比解释职责分离,不意味着建模就是编译文本,也不意味着求解等于代码生成。
1. 前端、中间表示与后端
| 层次 | 保存的内容 | 主要职责 |
|---|---|---|
| 业务前端 | 实体、参数、规则身份、单位和上下文 | 将业务定义绑定为数学表达 |
| 符号与建模层 | 变量、表达式、函数符号、约束、目标 | 组合、检查和组织数学语义 |
| 求解层表示 | 目标模型类别所需的域与关系 | 显式转换、辅助结构、可执行模型描述 |
| 后端适配 | 具体求解器对象和配置 | 能力匹配、模型装载、求解和状态读取 |
| 结果映射 | 原始身份与转换映射 | 将解和诊断返回业务对象 |
中间表示不一定只有一种。线性稀疏系数、二次项和原生 CP 关系具有不同结构,不能要求所有模型都先变成线性矩阵。
2. 内部 DSL 不需要重复解析宿主代码
Kotlin/Rust 程序已经由宿主编译器处理语法。建模 DSL 通常通过对象与运算构造表达,不必再从源码字符串做词法分析。
模型层仍需要语义检查:引用是否属于本轮模型,类型和取值域是否一致,表达是否线性,所需逻辑或全局约束是否有合适执行路径。这些检查与宿主程序能否编译是不同问题。
符号表达式承载运算结构,但业务单位、权限和来源仍需要额外绑定。
3. 贯穿例子:产量不足惩罚
概述、概念与变量
生产上下文计划整数产量
中间值与原始目标
不足量定义为:
总成本是生产成本与不足惩罚之和:
产量域已经给出容量约束。这里
转换后的约束
引入连续辅助变量
并最小化
但这不是函数图像的无条件等价表达:转换模型允许非最优点中
结果
对
4. 转换如何保持来源
一个函数符号可能生成多行约束与多列辅助变量。转换需要记录原始符号、变量和约束到这些元素的对应关系。公共报告使用业务身份,不依赖易变的行列序号。
数值解映射与诊断映射不同:前者提取原始变量并求值中间量;后者解释某些底层约束为何出现以及属于哪条业务规则。底层 IIS 映射回名字后,仍不自动成为原始约束粒度的极小冲突。
5. 等价、松弛与近似
精确转换应说明保留的是可行域投影、目标值还是最优解。引入辅助变量后,原空间与扩展空间维度不同,不能直接比较集合相等。
松弛通常扩大可行域,可能用于给出界;它的可行解未必满足原问题。分段近似改变函数,需要声明区间和误差。表达式化简只是在构建阶段改写表示,不是求解最优化问题。
若后端不支持某个语义,应选择经声明的转换路线或明确拒绝,不能悄悄删项、放松整数域或换成近似后仍称为原模型。
6. 后端无关与能力边界
后端无关表示业务规则不直接依赖厂商对象,不表示所有后端能力完全相同。目标类别、变量域、逻辑关系、时间控制与诊断能力都需要匹配。
远端执行可以传递版本化模型表示,但不能把进程内对象地址当成跨机器身份。模型、参数、转换策略和求解配置应分别管理;见远端求解。
7. 与其他章节的关系
领域语言解释表达的组成,DDD解释业务所有权,本章解释表达的转换与执行。形式化设计与形式化验证进一步讨论转换正确性,临界约束分析使用反向证据映射解释目标边界。