微步和宏步语义等价性证明及通用递归程序最弱前置条件形式化
1. 语义证明相关内容
在语义证明过程中,有两个重要的谓词。一个谓词描述了结构化操作语义(SOS)规则从非空暂停集产生空暂停集的所有条件;另一个内部移动谓词涵盖了SOS规则从非空暂停集产生非空暂停集的条件。这里需注意,在后面这两个情况中,使用
InHS(H, S)
作为假设而非
H ≠ []
,这只是在相关索引方面的细微差别,因为
InHS(H, S) ⇔(H |NP(S) 1 ≠ [])
成立。
在证明相关定理时,虽难度不大,但会产生大量子目标。在对程序应用归纳策略并展开定义后,得到约150个子目标是很常见的。因此,需要采用能尽快减少子目标数量的策略,形如
(tac THEN NO_TAC) ORELSE ALL_TAC
的策略就很方便。其含义是先应用策略
tac
来解决部分子目标,对于未被
tac
解决的子目标,会应用预定义的HOL策略
NO_TAC
,这会引发异常,而预定义的HOL策略
ALL_TAC
会捕获该异常,使得被
tac
解决的子目标消失,其他子目标保持不变。
除了处理大量子目标的好策略,还需要证明一组引理来解决诸如添加/减去偏移量或切片暂停集等技术问题。
基于暂停集编码的SOS规则形式为
(S, Φ) ▷H D −−→H′
,表示语句
S
在条件
Φ
启用下,从暂停集
H
转移到暂停集
H′
,并执行
D
中包含的数据操作。具体规则如下:
-
原子语句
:
(nothing, true) ▷H {} −−→{}
(ℓ: pause, true) ▷H {} −−→(ℓ∈H ⇒{}| {ℓ})
(emit x, true) ▷H {emit x} −−−−−−−→{}
(emit next(x), true) ▷H {emit next(x)} −−−−−−−−−−−−→{}
(y := τ, true) ▷H {y := τ} −−−−−−−→{}
(next(y) := τ, true) ▷H {next(y) := τ} −−−−−−−−−−−−→{}
- 条件语句 :
(S1, Φ) ▷H D −−→H1
(if σ then S1 else S2 end, Φ ∧σ ∧¬ (InHS(H, S1) ∨InHS(H, S2))) ▷H D −−→H1
(S2, Φ) ▷H D −−→H2
(if σ then S1 else S2 end, Φ ∧¬σ ∧¬ (InHS(H, S1) ∨InHS(H, S2))) ▷H D −−→H2
(S1, Φ) ▷H D −−→H1
(if σ then S1 else S2 end, Φ ∧InHS(H, S1)) ▷H D −−→H1
(S2, Φ) ▷H D −−→H2
(if σ then S1 else S2 end, Φ ∧InHS(H, S2)) ▷H D −−→H2
- 顺序语句 :
(S1, Φ1) ▷H D1 −−−→H1
(S1; S2, Φ1 ∧¬InHS(H, S2) ∧InHS(H1, S1)) ▷H D1 −−−→H1
(S1, Φ1) ▷H D1 −−−→H1
(S2, Φ2) ▷{} D2 −−−→H2
(S1; S2, Φ1 ∧Φ2 ∧¬InHS(H, S2) ∧¬InHS(H1, S1)) ▷H D1 ∪D2 −−−−−−−→H2
(S2, Φ2) ▷H D2 −−−→H2
(S1; S2, Φ2 ∧InHS(H, S2)) ▷H D2 −−−→H2
- 同步并发语句 :
(S1, Φ1) ▷H D1 −−−→H1
(S1 ∥S2, Φ1 ∧InHS(H, S1) ∧¬InHS(H, S2)) ▷H D1 −−−→H1
(S2, Φ2) ▷H D2 −−−→H2
(S1 ∥S2, Φ2 ∧¬InHS(H, S1) ∧InHS(H, S2)) ▷H D2 −−−→H2
(S1, Φ1) ▷H D1 −−−→H1
(S2, Φ2) ▷H D2 −−−→H2
(S1 ∥S2, Φ1 ∧Φ2 ∧(InHS(H, S1) = InHS(H, S2))) ▷H D1 ∪D2 −−−−−−−→H1 ∪H2
- 循环语句 :
(S, Φ) ▷H D −−→H′
(do S while σ, Φ ∧(H′ ≠ {})) ▷H D −−→H′
(S, Φ1) ▷H D −−→{}
(S, Φ2) ▷{} D′ −−−→H′
(do S while σ, Φ1 ∧σ ∧Φ2) ▷H D ∪D′ −−−−−−→H′
(S, Φ) ▷H D −−→{}
(do S while σ, Φ ∧¬σ) ▷H D −−→{}
- 挂起语句 :
(S, Φ) ▷H D −−→H′
([weak] suspend S when σ, Φ ∧¬InHS(H, S)) ▷H D −−→H′
(S, Φ) ▷H D −−→H′
([weak] suspend S when σ, Φ ∧¬σ ∧InHS(H, S)) ▷H D −−→H′
(suspend S when σ, σ ∧InHS(H, S)) ▷H {} −−→H
(S, Φ) ▷H D −−→H′
(weak suspend S when σ, Φ ∧σ ∧InHS(H, S)) ▷H D −−→H
- 中止语句 :
(S, Φ) ▷H D −−→H′
([weak] abort S when σ, Φ ∧¬InHS(H, S)) ▷H D −−→H′
(S, Φ) ▷H D −−→H′
([weak] abort S when σ, Φ ∧¬σ ∧InHS(H, S)) ▷H D −−→H′
(abort S when σ, σ ∧InHS(H, S)) ▷H {} −−→{}
(S, Φ) ▷H D −−→H′
(weak abort S when σ, Φ ∧σ ∧InHS(H, S)) ▷H D −−→{}
- 选择语句 :
(S1, Φ) ▷H D −−→H1
(choose S1 S2 end, Φ ∧¬(InHS(H, S1) ∨InHS(H, S2))) ▷H D −−→H1
(S2, Φ) ▷H D −−→H2
(choose S1 S2 end, Φ ∧¬(InHS(H, S1) ∨InHS(H, S2))) ▷H D −−→H2
(S1, Φ) ▷H D −−→H1
(choose S1 S2 end, Φ ∧InHS(H, S1)) ▷H D −−→H1
(S2, Φ) ▷H D −−→H2
(choose S1 S2 end, Φ ∧InHS(H, S2)) ▷H D −−→H2
- 异步并发语句 :
(S1, Φ1) ▷H D1 −−−→H1
(S1 S2, Φ1 ∧InHS(H, S1) ∧¬InHS(H, S2)) ▷H D1 −−−→H1
(S2, Φ2) ▷H D2 −−−→H2
(S1 S2, Φ2 ∧¬InHS(H, S1) ∧InHS(H, S2)) ▷H D2 −−−→H2
(S1, Φ1) ▷H D1 −−−→H1
(S2, Φ2) ▷H D2 −−−→H2
(S1 S2, Φ1 ∧Φ2 ∧¬InHS(H, S1) ∧¬InHS(H, S2)) ▷H D1 ∪D2 −−−−−−−→H1 ∪H2
(S1, Φ1) ▷H D1 −−−→H1
(S2, Φ2) ▷H D2 −−−→H2
(S1 S2, Φ1 ∧Φ2 ∧InHS(H, S1) ∧InHS(H, S2)) ▷H D1 ∪D2 −−−−−−−→H1 ∪H2
(S1, Φ1) ▷H D1 −−−→H1
(S1 S2, Φ1 ∧InHS(H, S1) ∧InHS(H, S2)) ▷H D1 −−−→H1 ∪(H ∩labels (S2))
(S2, Φ2) ▷H D2 −−−→H2
(S1 S2, Φ2 ∧InHS(H, S1) ∧InHS(H, S2)) ▷H D2 −−−→(H ∩labels (S1)) ∪H2
2. 通用递归程序最弱前置条件形式化
最弱前置条件(wp)由E. W. Dijkstra提出,在软件开发的各个领域都很有用。此前有很多尝试使用计算机辅助推理系统(如HOL、Isabelle、Ergo、PVS和Alf)来支持wp和精化演算,但只有Laibinis和Wright处理了通用递归问题。
这里使用Coq支持的内涵类型理论对通用递归程序的wp进行形式化,这种嵌入方式被称为“计算嵌入”。计算嵌入的重要性在于它是深度嵌入和浅度嵌入之间的桥梁。wp被定义为从语句项到谓词变换器的函数,在展开
wp (c)
的定义之前,通过访问
c
的语法结构,能享受到深度嵌入的好处,可验证元级操作(如程序转换);展开
wp
后,
wp (c)
成为
c
的语义,借助计算机制处理展开过程,能专注于语义而无需担心语法细节,享受浅度嵌入的好处,因此计算嵌入能让我们轻松在深度和浅度嵌入之间切换。
所研究的语言是通用递归的,包含无参数递归过程
proc p ≡ c
,执行从过程体
c
开始,遇到递归调用
pcall p
时,会将其替换为过程体
c
并继续执行。
一个简单的
wp (proc p ≡ c)
定义可能是:
wp (proc p ≡c) def =⇒ n<ω wp proc p ≡c n
其中扩展操作
proc p ≡c n
定义为:
proc p ≡c 0 def =⇒assert(false)
proc p ≡c n+1 def =⇒c p/ proc p ≡c n
但这个定义存在问题,因为
wp proc p ≡c n
不是结构递归的,其参数
proc p ≡c n
在结构上比左边的参数
proc p ≡c
更大,所以会被只接受结构递归函数的Coq函数定义机制拒绝。
为解决这个问题,引入了环境的概念,环境类型
Σ
定义为:
Σ def =⇒ID →PT
它是从标识符到谓词变换器的函数,这里过程名用标识符表示。空环境
ε : Σ
定义为:
ε def =⇒λ p. λ P. F
其中
p
是过程名,
P
是谓词,
F
是假谓词,定义为:
F def =⇒λ s. False
F
在任何程序存储上都不成立。
操作
σ [p →pt]
用于向环境
σ
中添加映射
p →pt
:
σ [p →pt] (p) def =⇒pt if p = p
σ [p →pt] (p) def =⇒σ (p) if p ≠ p
编程语言的语法定义如下:
| 语句形式 | 规则 |
| ---- | ---- |
|
i := e
|
C fmt: i : ID, e : E, i := e : C
|
|
assert(e)
|
s assert: e : E, assert(e) : C
|
|
c1; c2
|
s seq: c1 : C, c2 : C, c1; c2 : C
|
|
if e then c1 else c2
|
s ifs: e : E, c1 : C, c2 : C, if e then c1 else c2 : C
|
|
proc p ≡c
|
s proc: p : ID, c : C, proc p ≡c : C
|
|
pcall p
|
s pcall: p : ID, pcall p : C
|
定义
wpc (σ, c)
来计算命令
c
在环境
σ
下的谓词变换器,通过使用环境
σ
,
wpc (σ, c)
可以用结构递归定义,正常的
wp
定义为
wp (c) def =⇒wpc (ε, c)
。
wpc (σ, c)
的定义如下:
wpc (σ, i := e) def =⇒λ P, s. ∃v . [[e]]s = v ∧P s v i
wpc (σ, assert(e)) def =⇒λ P, s. [[e]]s = true ∧P (s)
wpc (σ, c1; c2) def =⇒λ P, s. wpc (σ, c1) (wpc (σ, c2) (P )) (s)
wpc (σ, if e then c1 else c2) def =⇒λ P, s .([[e]]s = true ∧wpc (σ, c1) (P ) (s)) ∨
([[e]]s = false ∧wpc (σ, c2) (P ) (s))
wpc (σ, proc p ≡c) def =⇒λ P, s. ∃n . λ pt. wpc σ p →pt
, c n (P ) (s)
wpc (σ, pcall p) def =⇒λ P, s. σ (p) (P ) (s)
在后续内容中,还会定义操作语义,并证明
wp
与操作语义的等价性,以及
wp
的三个主要健康条件:严格性、单调性和可结合性。
3. 相关概念定义
-
谓词和谓词变换器
:
-
谓词类型
PD定义为:
-
谓词类型
PD def =⇒PS →Prop
其中 `Prop` 是命题类型,`PS` 是程序存储类型。
- 谓词变换器类型 `PT` 定义为:
PT def =⇒PD →PD
- 谓词变换器的变换器类型 `PTT` 定义为:
PTT def =⇒PT →PT
-
偏序关系
:
-
谓词之间的偏序
≼P定义为:
-
谓词之间的偏序
P1 ≼P P2 def =⇒∀s . P1 (s) ⇒P2 (s)
- 谓词变换器之间的偏序 `≼pt` 定义为:
pt1 ≼pt pt2 def =⇒∀P . pt1 (P) ≼P pt2 (P)
- 环境之间的偏序 `≼σ` 定义为:
σ1 ≼σ σ2 def =⇒∀p . σ1 (p) ≼pt σ2 (p)
- 谓词变换器的变换器之间的偏序 `≼ptt` 定义为:
ptt1 ≼ptt ptt2 def =⇒∀pt . mono(pt) ⇒ptt1 (pt) ≼pt ptt2 (pt)
- 等价关系 :
P1 ≈P P2 def =⇒P1 ≼P P2 ∧P2 ≼P P1
pt1 ≈pt pt2 def =⇒pt1 ≼pt pt2 ∧pt2 ≼pt pt1
ptt1 ≈ptt ptt2 def =⇒ptt1 ≼ptt ptt2 ∧ptt2 ≼ptt ptt1
-
单调性谓词
:
- 谓词变换器的单调性谓词定义为:
mono(pt) def =⇒∀P1, P2. P1 ≼P P2 ⇒pt (P1) ≼P pt (P2)
- 环境的单调性谓词定义为:
mono(σ) def =⇒∀p . mono(σ (p))
下面是这些概念关系的mermaid流程图:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(谓词PD):::process -->|映射| B(谓词变换器PT):::process
B -->|映射| C(谓词变换器的变换器PTT):::process
D(偏序关系):::process --> E(≼P):::process
D --> F(≼pt):::process
D --> G(≼σ):::process
D --> H(≼ptt):::process
I(等价关系):::process --> J(≈P):::process
I --> K(≈pt):::process
I --> L(≈ptt):::process
M(单调性谓词):::process --> N(mono(pt)):::process
M --> O(mono(σ)):::process
综上所述,在语义证明和通用递归程序最弱前置条件形式化方面,我们已经介绍了相关的概念、规则和定义,后续还将进一步深入探讨操作语义以及
wp
与操作语义的关系等内容。
微步和宏步语义等价性证明及通用递归程序最弱前置条件形式化
4. 操作语义定义
为了证明
wp
与操作语义的等价性,需要先定义操作语义。操作语义描述了程序在执行过程中的具体行为。
在通用递归程序的语境下,操作语义主要关注程序状态的变化。程序状态可以用程序存储
s
来表示,它包含了程序中变量的当前值。
操作语义的核心是定义程序语句的执行规则。对于不同类型的语句,其执行规则也不同:
-
赋值语句
:
i := e
的执行规则是计算表达式
e
在当前程序存储
s
下的值
v
,然后将变量
i
的值更新为
v
,得到新的程序存储
s'
。
-
断言语句
:
assert(e)
的执行规则是检查表达式
e
在当前程序存储
s
下的值是否为
true
,如果是,则程序继续执行;否则,程序终止。
-
顺序语句
:
c1; c2
的执行规则是先执行语句
c1
,得到新的程序存储
s'
,然后在
s'
的基础上执行语句
c2
。
-
条件语句
:
if e then c1 else c2
的执行规则是检查表达式
e
在当前程序存储
s
下的值,如果为
true
,则执行语句
c1
;否则,执行语句
c2
。
-
递归过程
:
proc p ≡ c
的执行规则是将过程名
p
与过程体
c
关联起来。当遇到递归调用
pcall p
时,将其替换为过程体
c
并继续执行。
操作语义可以用状态转移系统来表示,其中状态是程序存储,转移是语句的执行。状态转移系统可以用以下表格来总结:
| 语句类型 | 执行规则 |
| ---- | ---- |
|
i := e
| 计算
[[e]]s = v
,更新
s
为
s'
,其中
s'[i] = v
|
|
assert(e)
| 检查
[[e]]s = true
,是则继续,否则终止 |
|
c1; c2
| 先执行
c1
得到
s'
,再在
s'
上执行
c2
|
|
if e then c1 else c2
| 若
[[e]]s = true
,执行
c1
;否则执行
c2
|
|
proc p ≡ c
| 关联
p
与
c
,
pcall p
替换为
c
执行 |
下面是操作语义状态转移的mermaid流程图:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(初始状态 s):::process -->|i := e| B(计算 [[e]]s = v):::process
B --> C(更新 s 为 s',s'[i] = v):::process
A -->|assert(e)| D(检查 [[e]]s = true):::process
D -->|是| E(继续执行):::process
D -->|否| F(程序终止):::process
A -->|c1; c2| G(执行 c1 得到 s'):::process
G --> H(在 s' 上执行 c2):::process
A -->|if e then c1 else c2| I(检查 [[e]]s = true):::process
I -->|是| J(执行 c1):::process
I -->|否| K(执行 c2):::process
A -->|proc p ≡ c| L(关联 p 与 c):::process
L -->|pcall p| M(替换为 c 执行):::process
5. 操作语义与 wp 的关系
证明
wp
与操作语义的等价性是形式化工作的重要部分。等价性证明可以分为两个方向:
-
从操作语义到
wp
:证明如果程序从初始状态
s
开始执行,最终能到达满足谓词
P
的状态,那么初始状态
s
满足
wp (c) (P)
。
- 对于赋值语句
i := e
:
- 操作语义:计算
[[e]]s = v
,更新
s
为
s'
,其中
s'[i] = v
。
-
wp
定义:
wpc (σ, i := e) = λ P, s. ∃v . [[e]]s = v ∧ P (s [v/i])
。
- 证明思路:假设程序从
s
执行
i := e
后到达
s'
满足
P
,即
P (s'[i])
。根据操作语义,
s'[i] = v
且
[[e]]s = v
,所以
s
满足
wpc (σ, i := e) (P)
。
- 对于其他类型的语句,也可以采用类似的方法进行证明。
-
从
wp
到操作语义
:证明如果初始状态
s
满足
wp (c) (P)
,那么程序从
s
开始执行,最终能到达满足谓词
P
的状态。
- 对于赋值语句
i := e
:
-
wp
定义:
wpc (σ, i := e) = λ P, s. ∃v . [[e]]s = v ∧ P (s [v/i])
。
- 操作语义:计算
[[e]]s = v
,更新
s
为
s'
,其中
s'[i] = v
。
- 证明思路:假设
s
满足
wpc (σ, i := e) (P)
,即存在
v
使得
[[e]]s = v
且
P (s [v/i])
。根据操作语义,程序从
s
执行
i := e
后到达
s'
,其中
s'[i] = v
,所以
s'
满足
P
。
通过以上两个方向的证明,可以得出
wp
与操作语义是等价的。
6. wp 的健康条件证明
除了证明
wp
与操作语义的等价性,还需要证明
wp
的三个主要健康条件:严格性、单调性和可结合性。
-
严格性
:
wp
对于空谓词应该返回空谓词。即
wp (c) (λ s. False) = λ s. False
。
- 证明思路:根据
wpc
的定义,对于不同类型的语句,分别证明当
P = λ s. False
时,
wpc (σ, c) (P) = λ s. False
。
- 例如,对于赋值语句
i := e
:
wpc (σ, i := e) (λ s. False) = λ s. ∃v . [[e]]s = v ∧ (λ s. False) (s [v/i])
= λ s. ∃v . [[e]]s = v ∧ False
= λ s. False
-
单调性
:如果
P1 ≼P P2,那么wp (c) (P1) ≼P wp (c) (P2)。-
证明思路:根据
wpc的定义和偏序关系≼P的定义,对于不同类型的语句,分别证明当P1 ≼P P2时,wpc (σ, c) (P1) ≼P wpc (σ, c) (P2)。 -
例如,对于赋值语句
i := e:
-
证明思路:根据
假设 P1 ≼P P2,即 ∀s . P1 (s) ⇒ P2 (s)。
wpc (σ, i := e) (P1) = λ s. ∃v . [[e]]s = v ∧ P1 (s [v/i])
wpc (σ, i := e) (P2) = λ s. ∃v . [[e]]s = v ∧ P2 (s [v/i])
对于任意 s,若 wpc (σ, i := e) (P1) (s) 成立,即存在 v 使得 [[e]]s = v 且 P1 (s [v/i]) 成立。
因为 P1 ≼P P2,所以 P2 (s [v/i]) 也成立,即 wpc (σ, i := e) (P2) (s) 成立。
所以 wpc (σ, i := e) (P1) ≼P wpc (σ, i := e) (P2)。
-
可结合性
:
wp (c1; c2) (P) = wp (c1) (wp (c2) (P))。-
证明思路:根据
wpc的定义,对于顺序语句c1; c2,证明wpc (σ, c1; c2) (P) = wpc (σ, c1) (wpc (σ, c2) (P))。
-
证明思路:根据
wpc (σ, c1; c2) (P) = λ s. wpc (σ, c1) (wpc (σ, c2) (P)) (s)
= wpc (σ, c1) (wpc (σ, c2) (P))
7. 总结
本文围绕微步和宏步语义等价性证明以及通用递归程序最弱前置条件形式化展开了深入研究。
- 在语义证明方面,介绍了基于暂停集编码的SOS规则,通过合理的策略处理大量子目标,并证明了相关定理。
- 在通用递归程序最弱前置条件形式化方面,引入了计算嵌入的概念,解决了简单定义
wp
时的结构递归问题。通过定义环境和
wpc
操作,实现了
wp
的形式化。
- 进一步定义了操作语义,并证明了
wp
与操作语义的等价性,以及
wp
的严格性、单调性和可结合性三个健康条件。
这些工作为软件开发中的形式化验证提供了重要的理论基础和方法支持,有助于提高软件的可靠性和正确性。未来的研究可以进一步拓展到更复杂的程序语言和应用场景,探索如何更好地利用形式化方法解决实际问题。
超级会员免费看
23

被折叠的 条评论
为什么被折叠?



