“SMT 驱动的验证器通常先用 wp 生成验证条件,再化简并求解背景理论公式;不变量发现、理论编码和求解分别有自己的可靠性边界。精化演算则反向使用谓词变换器,从规格逐步选择能建立目标的程序构造…”
命令作为谓词变换器 ​
把命令
则在本页约定下,
含义是:任何足以保证规格命令
这与行为精化相接,但谓词变换器还编码终止是 partial 还是 total correctness;选择
健康谓词变换器通常还要求 strictness、conjunctivity 等性质。demonic command 对任意后置集取逆像并要求所有可能结果满足,因此保存任意 meet;angelic nondeterminism 则更接近保存 join。选择哪些健康条件决定该演算对应哪类程序语义。
abort、magic 与 skip 是边界命令:abort 无法保证后置,magic 无需执行即可满足任意后置,skip 保持状态。混淆 abort 和 magic 会让不可实现规格看似最强实现。
规格语句 ​
规格语句
例如“输入
若后置关系无可实现状态,规格 miraculous;若前置为 false,任何实现都 vacuously 满足。演算需排除或显式处理这些退化规格,不能把逻辑蕴含通过当成可部署程序。
feasibility 条件要求允许初态至少有一个后继满足关系。对 total correctness,规格还要求实现终止;把非终止作为“没有坏后继”会错误满足任意后置。
非确定规格可以有多个合法结果。实现选择其中一个通常是 refinement;若环境而非实现控制选择,消除某些分支可能违反输入接受义务。接口需区分输入 nondeterminism 与内部实现 freedom。
赋值精化轨迹 ​
目标规格为从 y:=x+1,其
代入后置
若选 y:=x,代入得到
对数组更新 A[i]:=v,后置替换不是文本替换所有
并行赋值 x,y:=y,x 同时读取旧值;若按两个顺序赋值精化,会得到两个变量都等于旧
顺序、选择与循环规则 ​
顺序组合满足
非确定 demonic choice 要对所有选择保证后置,因此 wp 取合取;angelic choice 只需存在成功选择,取析取。把两者混用会把实现控制权与环境控制权倒置。
循环精化需要 invariant
只给出一个看起来递减的整数不够,还需证明循环期间非负且每次执行确实严格下降。
guarded command if G_i -> S_i fi 的 demonic 语义要求所有为真 guard 分支都满足后置,并要求至少一个 guard 为真以避免 abort。把 guard 合取成互斥不是演算自动性质;重叠 guard 正是 nondeterminism 来源。
循环 invariant 可先从规格中推导而不是猜测:计算希望保持的抽象关系,再选择实现体。若 invariant 太弱,退出推不出后置;若太强,初始化失败。
单调性与逐步推导 ​
健康谓词变换器通常对后置条件单调:
精化的传递性允许链
每步只承担局部证明义务,最终由传递性得到程序满足初始规格。若中间步骤改变状态空间或数据表示,还需 coupling invariant/refinement mapping。
数据精化例:抽象集合用无序数学 set 表示,实现用无重复排序数组。coupling invariant 连接数组元素集合与抽象 set;insert 操作需证明数组更新后仍有序无重复,且抽象投影恰好多一个元素。
若实现保留 tombstone 或额外容量,它们是具体状态细节;finalization/observation 映射必须隐藏它们。只证明元素数相同不能推出成员集合相同。
边界 ​
演算证明功能正确性,不自动给时间、空间、数值稳定性或并发公平保证;这些需加入规格或独立分析。
从数学关系推导代码还要连接语言溢出、异常和 I/O。精确整数演算得出的赋值在固定宽度机器上可能不保持同一后置。
性能 refinement 需要另加 cost semantics。功能行为集合缩小的实现可能从常数时间变成指数时间,仍满足基础精化关系;实时系统若把 deadline 当保证,就必须把时间纳入观察。
机械演算可以生成大量 verification conditions,最终仍需求解器或证明助理检查。未解决义务不能以“设计直觉清楚”视为已精化。
参考资料
- Ralph-Johan Back and Joakim von Wright, Refinement Calculus: A Systematic Introduction, Springer, 1998, Chs. 1–8。
- Carroll Morgan, Programming from Specifications, 2nd ed., Prentice Hall, 1994, Chs. 1–9。
- Edsger W. Dijkstra, A Discipline of Programming, Prentice Hall, 1976, Chs. 1–4。