第五章证明引擎原理与选择
Proof Orchestration(证明编排)
JasperGold 的 Proof Orchestration 自动管理多个证明引擎的调度和切换,是证明自动化的核心。
为什么需要 Proof Orchestration
不同属性有不同的特征,适合不同的引擎。手动选择引擎需要丰富经验。Proof Orchestration 自动:
- 分析属性特征
- 选择合适的引擎组合(engine mode)
- 在引擎间分配时间和资源
- 检测进展(plateau)并切换策略
Proof Orchestration 如何工作
它同时启动多个引擎(Engine Race),监控各引擎的进展。当一个引擎进入 plateau(长时间没有新进展)时,编排器会:
- 切换到其他引擎
- 调整引擎参数
- 在 ProofGrid 上启动新任务
如何控制 Proof Orchestration
# 设置引擎模式
set_engine_mode {K I N B L P}
# 设置时间限制
set_prove_time_limit 120s
set_prove_per_property_time_limit 30s
引擎算法概览
| 引擎 | 算法 | 适用场景 |
|---|---|---|
| B / BMC | Bounded Model Checking(SAT 有界模型检测) | 查找浅层 bug(短 trace 的反例) |
| I / Interpolation | 基于 Craig Interpolation 的模型检测 | 中等深度属性的完整证明 |
| K / K-Induction | K 归纳法 | 需要归纳证明的属性(如不变量) |
| N | BMC 变体(深界 BMC) | 深界属性查找反例 |
| L / PDR | Property Directed Reachability(IC3/PDR) | 安全属性的完整证明,特别适合控制逻辑 |
| P | BDD 基础引擎 | 小规模复杂属性 |
| MBP | Model Based Projection | 特定类型的高级证明 |
Engine Race
Engine Race 同时启动多个引擎竞争证明同一个属性,第一个完成的引擎获胜。这在 ProofGrid 环境中特别有效:
# ProofGrid 自动启用 Engine Race
set_proofgrid_mode on
Engine Mode 选择指南
| 场景 | 推荐引擎模式 |
|---|---|
| 快速查找 bug(初始验证) | {B N}(BMC 优先) |
| 不变量证明 | {K L I} |
| 复杂控制逻辑 | {L K I B}(PDR 优先) |
| 数据通路 | {B N I}(BMC+Interpolation) |
| 全面证明(回归) | {K I N B L}(全部引擎) |
Bounded Proof Information
当 BMC 引擎达到时间边界仍未找到反例时,产生有界证明(bounded proof)。这意味着:
- 属性在 N 个周期内成立(N 为 trace length)
- 不保证 N+1 周期后仍然成立
- 增大 trace length 或使用 K/L/I 引擎可得到完整证明
处理 State-Space Explosion
状态空间爆炸是形式验证的主要挑战:
- 分模块验证:将大设计拆分为子模块分别验证
- 黑盒化:将不相关模块设为黑盒
- 数据抽象:将宽数据路径抽象为小位宽
- 使用 Proof Accelerators:利用预构建模型
- ProofGrid 分布式证明:在服务器集群上并行
引擎选择决策:不是记名字,是理解特性
新手最常问的问题是"我应该用哪个引擎?"答案不是记住某个引擎名字,而是理解每个引擎擅长什么,然后根据问题特征选择。
核心引擎特性对比
| 引擎 | 代号 | 擅长 | 不擅长 |
|---|---|---|---|
| BMC | B | 找浅层反例(深度 < 50 周期),速度快 | 不能完整证明(只证明到有限深度) |
| K-Induction | K, N | 完整证明属性成立,特别适合数据通路和不变量 | 需要辅助不变量,对深时序属性慢 |
| Interpolation | I | 中等深度证明,不需要用户提供不变量 | 对某些类型属性不完备 |
| Heavyweight Trace | Ht | 深层反例搜索,复杂控制逻辑 | 耗时较长 |
| Heavyweight Proof | Hp | 深度证明,难证明的属性 | 耗时最长 |
| BMC-Motor | Bm | 深 BMC(比普通 BMC 搜得更深) | 仍然是有界的 |
| Triage | Tri | 自动调度其他引擎,先试快的再试深的 | 全自动,不适合精细调优 |
引擎选择策略
1先用默认或 Tri 引擎
不指定引擎模式让工具自动选择,或用 set_engine_mode {Tri} 让 Triage 自动调度。这一步能快速解决 70-80% 的属性。
2对 remaining 属性换引擎
第一轮后剩下的属性,根据类型换引擎:控制逻辑的 fail 用 Ht/Bm 深搜,需要证明的属性用 K/I/N,特别难的用 Hp。
3对特别难的属性手动调优
少量 remaining 属性可能需要:增大时间限制、添加辅助不变量、黑盒化部分逻辑、数据路径抽象。
状态空间爆炸的信号
当你观察到以下现象时,说明遇到了状态空间爆炸:
- trace length 从 20 增加到 30 时,证明时间从 10s 跳到 10 分钟(指数增长)
- 引擎开始报 "out of memory" 或 "time limit exceeded"
- BMC 在深度 15 内很快,加深到 20 就跑不完
经验法则:flop 数是状态空间的粗略指标。500 flop 以下通常容易证明;500-2000 flop 需要调优;2000 flop 以上几乎总是需要抽象和分模块验证。
复杂度控制手段
- 黑盒:不参与当前属性的模块黑盒化(-bbox_m)
- Cutpoint:在信号上插入 cutpoint 切断状态传播
- 数据抽象:将宽数据路径替换为符号变量(PA 自动处理)
- 分模块验证:先在子模块级证明,再到系统级集成
- 假设-保证推理:用 assume 约束子模块接口,验证后在系统级转换为 assert
来源文档
jaspergold_engine_selection.pdf