【Coq学习】Formal Reasoning About Programs 阅读笔记第八章

第八章 操作语义 Operational Semantics

补充:

一个计算机语言的操作语义描述一段合理的程序是怎样被理解为一系列计算机步骤的,这些步骤就是这个程序的意义;也就是将语言成分 所对应的计算机操作 作为语言成分的语义

操作语义一般指结构化操作语义(SOS,Structural Operational Semantics),又称“小步语义” ,其显著特征是:在程序运行过程中,程序短语不断地被替换成所计算的值。这种状态转换可用相应的公理和推导规则来描述。SOS 已被广泛用于程序分析和形式化验证等领域 。

与 SOS 对应的另一种操作语义为自然语义,亦称“大步语义”,它较 SOS 隐藏了更多执行细节,只包含初始和最终状态,没有中间状态。自然语义也用公理和推导规则描述计算, 只是它不能用于不确定的程序和交叉存取的表达式计算。自然语义已被用于定义SML 、Eiffel 和 Java 等语言的语义。

From:

程序设计语言语义_百度百科

操作语义_维基百科


 

 

 

 

 

 

From:

华盛顿大学课程ppt


本章关于估值映射的符号还是延用第四章介绍过的:

From:

【Coq学习】Formal Reasoning About Programs 阅读笔记第三章第四章_Present*的博客-CSDN博客

前两章我们一直是手工定义变迁系统来解释具体系统的语义,这章我们考虑将程序编译为其他语言。那这里的其他语言具体指什么呢?为了最大限度地利用我们的正确性证明,我们应该将转换后的语言和传递给编译器的程序语法连接起来。因此,这就涉及到操作语义的知识。本章要学习的操作语义(Operational semantics)从程序的句法(program syntax)自动定义变迁系统或其他关系特征(relational characterization)的一系列技术。在这一章中,我们将在如下定义的源语言上演示不同的操作语义技术:

8.1 大步语义 Big-Step Semantics

大步操作语义(big-step operational semantics)解释了运行程序直到完成的含义。对于我们上面给的源语言的例子,我们定义一个记为的关系,表示给定变量的估值映射v和命令c,运行命令c后将变量的估值映射改为v'。这种关系很容易用如下的推理规则来定义:

请注意,这个定义非常类似于第四章4.3节用高级编程语言编写的递归解释器(recursive interpreter),尽管我们用的是关系语言(the language of relations)而不是函数式编程(functional programming)来编写。例如考虑序列执行“;”( sequence)的简单情况:我们首先使用原始估值映射v在第一个子命令c1上“调用解释器”,“递归调用”的结果是一个新的估值映射v1,然后我们将其输入到另一个c2上的“递归调用”中,它返回的结果就是最后的结果。

为什么要把这个解释器写成关系式而不是函数式程序呢? 答案是,像我们这样的Coq用户甚至是非形式化的数学,在这种情况下,我们必须非常小心地确保我们所有的递归定义都是well-founded。这种关系的递归版本显然不是well-founded,因为它将在一个不终止的While循环上永远运行。此外,将nondeterminism融入到关系型的风格中也更容易,我们将在8.4节讨论。

大步语义很容易应用于具体的程序,例如,可以将阶乘的程序定义为:output <- 1; while input do (output <- output * input; input <- input - 1)

定理8.1:当input=2时,执行阶乘的程序factorial,存在一个估值映射v使得v(output)=2。证明方法是重复应用大步语义的推理规则。 

若将factorial_loop定义为while input do (output <- output * input; input <- input - 1),我们甚至可以利用一个引理证明阶乘的程序factorial对所有的输入都会返回正确结果

引理8.2:如果执行factorial_loop之前input的估值映射值为n并且output的估值映射值为o,那么存在v'使得执行factorial_loop后output的估值映射值为n!*o。

引理8.3:证明阶乘的程序factorial对所有的输入都会返回正确结果。

本书中的大多数程序证明都建立了安全属性(safety properties)或变迁系统的不变量。然而,这最后两个使用大步语义的例子也建立了程序终止(program termination),使我们向活性属性(liveness properties)的世界前进了几步。

补充:

1. Safety 安全性
程序运行中不会进入错误的状态,比如对于分布式数据库来说,不管是网络问题还是整个集群的大部分节点都挂了,系统可以不响应,但是不能响应错误的信息,比如数据明明没有完成持久化但是却给client返回了成功持久化的信息。违反了安全性就意味了对系统的破坏已经发生了,系统自身很难消除破坏造成的影响。

2. Liveness 活性
程序运行中预期状态最终会达到
没有死锁的系统可以认为是一种具有活性的系统,比如多个进程共同访问一块共享区域,同一时刻只有一个进程能够访问,那么在一个时刻如果某个进程被阻塞,那么预期在将来是可以访问到该共享区域的,而不是出现绝对访问不到的情况。同样,当你访问一个系统的时候,如果系统是正常工作的,则理论上最终会收到响应。

区分安全性和活性属性的一个优点是可以帮助我们处理困难的系统模型。对于分布式算法,在系统模型的所有可能情况下,要求始终保持安全属性是基本要求。也就是说,即使所有节点崩溃,或者整个网络出现故障,算法仍然必须确保它不会返回错误的结果(即保证安全性得到满足)

但是,对于活性属性,我们可以提出一些注意事项:例如,只有在大多数节点没有崩溃的情况下,只有当网络最终从中断中恢复时,我们才可以保证请求最终会收到响应。部分同步模型的定义要求任何网络中断的时间段只会持续一段有限的时间,然后得到了修复,系统最终返回到同步状态。

原文链接:safety 和 liveness

8.2 小步语义 Small-Step Semantics

通常,将系统的执行分解成小的连续步骤比一次执行整个程序更方便。也许最引人注目的例子来自并发程序,它很难直接给出大步骤语义。另一个标准的例子是非终止程序。我们希望能够为这些程序建立不变量,同样的,我们需要一个语义来帮助我们说明不变量的含义。

标准的解决方案是小步操作语义(small-step operational semantics),这可能是当代研究中最常见的形式化程序语义的方法。现在我们定义一个单步的关系(v, c)-> (v', c'),这意味着一个执行步骤将第一个状态转换为第二个状态,每个状态都是由一个估值映射v和一个当前命令c组成的二元组。下面的推理规则给出了细节:

接下来还是先看一个将小步语义用在阶乘程序上的例子。定理8.4

 

8.2.1 大步和小步的等价性 Equivalence of Big-Step and Small-Step

不同的定理有时候用不同的语义更容易证明,因此在形式上建立大步语义和小步语义之间的直观联系是有帮助的。

引理8.5:对第一个假设的自反传递闭包关系进行归纳

 定理8.6:证明从大步语义到小步语义的等价性,同样是通过归纳法对大步语义进行推导,同时结合使用上一个引理。

 引理8.7:证明我们在任何大步语义的推导开头可以添加一个小步语义。

 引理8.8:证明我们在任何大步语义的推导开头可以添加任意数量的小步语义。

 定理8.9:证明了小步语义到大步语义的等价性。

 

结合定理8.6和定理8.9,则证明了大步语义和小步语义的相互等价性。

8.2.2 从小步语义构建变迁系统 Transition Systems from Small-Step Semantics

小步语义与我们的变迁系统的定义是自然匹配的。我们可以从任何估值映射和命令出发定义一个变迁系统,其中V是估值映射的集合,C是命令的集合。

 然后我们就能把之前第六章学的所有关于不变量的知识和它们的证明方法都用上了。

例如,考虑如下程序:

定理8.10:给一个偶数n,对于以估值映射和程序P作为初始状态的变迁系统,性质“估值映射会将变量a映射为一个偶数”是这个变迁系统的一个不变量。

要证明上述定理,首先,我们需要强化不变量。我们通过小步语义计算所有可以从P到达的命令的集合P,这个集合是有限的。

我们的强化不变量如下:

我们通过添加了两个条件来增强约束:(1)我们不会偏离预期的可达命令集,(2)变量n也保持偶数。

通过对变迁关系->的不断倒推,可以通过invariant_induction证明强化不变量。

8.3 上下文小步语义 Contextual Small-Step Semantics

读者可能已经注意到小步语义的某些规则有些乏味,如像下面这个:

这是一致性规则 "congruence rule" 的一个示例,它展示了如何将一个步骤(step)从一个小组命令(command)提升到一个更大的命令中,而不影响更大命令的其他子命令。这种规则允许将单个步骤的执行扩展到包含该步骤的更大的上下文中。这个规则确保整个命令的执行结果与其子命令的执行结果保持一致。

使用 "congruence rule" 可能会引入很多重复的逻辑和规则,因此,我们考虑采用 "contextual small-step semantics",这是一种更高级的方法,可以减少冗余并更好地捕捉语言的语义。通过上下文小步骤语义,可以更自然地描述命令之间的关系,而不需要编写大量的 "congruence rule"。这是一种更高级和更抽象的语义定义方法。

上下文小步语义的第一步是定义一个估值映射上下文的集合(define a set of evaluation contexts),它形式化了在一个大的命令中允许执行小步骤的位置,例如:

第二步,定义插入一个估值映射上下文的操作符(the operator of plugging an evaluation context),例如:

对于上述例子而言,有趣的估值映射上下文情况是允许我们下降到左子命令(descend into the left subcommand),因为旧的一致性规则是递归地调用该位置的步骤关系(step relation)。

第三步,一套简化的基本步骤规则(basic step rules),其中去掉了一致性规则,其余和之前定义小步语义时的一模一样。

由于丢掉了一条一致性规则,为了让新规则达到和原本的小步语义一样的覆盖效果,新增一个关系记为,表示可能在一个更大的命令中对当前活跃的子命令(at the active subcommand within a larger command)应用上面简化的step rules

至此,上下文小步语义的定义完成。下面把刚定义的上下文小步语义用在之前的例子上,看看上下文小步语义的作用,特别是演示如何将任意命令表示为插入另一个命令的映射上下文

利用上下文小步语义的证明过程展示如下:图中的等号是上面定义插入操作符的等号。

8.3.1 有无估值映射上下文小步语义的等价性 Equivalence of Small-Step, With and Without Evaluation Contexts

 定理8.12证明从小步语义出发,能得到上下文小步语义。

两个帮助后续证明的引理:

 

定理8.15证明从上下文小步语义出发,能得到小步语义。至此,完成了小步语义与上下文小步语义的等价性证明。

 

 

8.3.2 估值映射上下文的好处:增加并发性  Evaluation Contexts Pay Off: Adding Concurrency

为了展示上下文小步语义的便利,还拿之前的例子来看,增加一个并发程序的命令:

 

为了表明并发结构中的任何一个命令都允许下一步执行,对估值映射上下文也做相应的扩展:

 

相应地,需要增加一条基本的步骤规则,表明一个并发程序已结束:

 

以上就是新的并发程序需要做的全部工作。所有之前证明的关于上下文步骤的定理仍然成立!在下面的Coq代码中,和之前相同的证明脚本建立了定理的新版本,并不涉及需要额外做的新的证明工作。在严格的证明中,如此轻松就能获得并发性,这是很罕见的!这就是上下文小步语义带来的好处。

 

8.4 确定性 Determinism

对并行性的最后一个扩展是在语义中故意引入了不确定性:一个起始状态可以步进到多个不同的下一个状态。 然而,原始语言的三种语义是确定的,我们可以证明这一点。

定理8.16证明大步语义的确定性:

定理8.17证明小步语义的确定性:

定理8.18证明上下文小步语义的确定性:

至此本章结束,停止对操作语义有用属性的介绍。本书的其余部分都是基于小步语义,要么是基于估值映射上下文,要么不是。后面学习新的编程语言时,本书将介绍如何对它们进行操作语义建模。几乎每一种新的证明技巧都被描述为一种基于小步语义建立变迁系统不变量的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值