TLA+ 《Specifying Systems》翻译初稿——Section 3.1 The First specification(第一个规约)

本节详细介绍了异步接口规约的写作过程,及作者对规约某些设定的现实考量。
本节要点有:

  • 通过   EXTENDS  N a t u r a l s \text{ \small{EXTENDS }}Naturals 这样的语句引入模块;
  • 通过   CONSTANT  D a t a \text{ \small{CONSTANT }}Data 这样的方式引入规约入参;
  • 通过   VARIABLES  v a l , r d y , a c k \text{ \small{VARIABLES }}val,rdy,ack 这种方式声明状态变量;
  • 类型不变量、状态函数、状态谓词的定义;
  • 关于类型定义、初始谓词、动作等书写格式的约定: , \land,\lor 缩进对齐,如 I n i t v a l D a t a r d y { 0 , 1 } a c k = r d y \begin{aligned}Init \triangleq &\land val \in Data \\ &\land rdy\in \{0,1\} \\&\land ack=rdy\end{aligned}
  • 动作的书写约定:首先是动作的“使能”条件,然后是对状态变量的新值进行赋值,最后所有不变的变量用   UNCHANGED  v \text{ \small{UNCHANGED }} v 这种方式表示,如: S e n d r d y = a c k v a l D a t a r d y = 1 r d y   UNCHANGED  a c k \begin{aligned}Send \triangleq &\land rdy=ack \\ &\land val' \in Data \\ &\land rdy'=1-rdy \\&\land \text{ \small{UNCHANGED }}ack\end{aligned}
  • 最后,完整的规约如下 S p e c I n i t [ N e x t ] v a l , r d y , a c k Spec \triangleq Init \land \square[Next]_{\langle val,rdy,ack \rangle}

现在让我们在模块 A s y n c h I n t e r f a c e AsynchInterface 中定义异步接口,因为规约中会用到自然数减法,因此通过   EXTENDS  N a t u r a l s \text{ \small{EXTENDS }}Naturals 语句引入 N a t u r a l s Naturals 模块,以包含减法运算符“ - ”的定义。接下来,我们来确定 v a l val 的可能取值,即什么数值才允许被发送。我们当然也可以写没有任何取值限制的规约,如发送方先发送 37 37 ,接着发送 15 \sqrt{-15} ,然后再发 N a t Nat (完整的自然数集)。但是,任何真实的设备都只能发送一组受限制的值,我们可以选择一些特定的集合,例如 32 32 位数字集,不过,无论用于发送 32 32 位数字还是 128 128 位数字,该协议都是相同的。因此,我们在允许发送任何内容和仅发送 32 32 位数字集这两个极端之间进行折衷,设定只有数据集 D a t a Data 中的数据才可以被发送,常量 D a t a Data 是规约的一个参数。由下列语句声明:
  CONSTANT  D a t a \text{ \small{CONSTANT }}Data 我们的3个变量声明如下:   VARIABLES  v a l , r d y , a c k \text{ \small{VARIABLES }}val,rdy,ack 关键字   VARIABLE \text{ \small{VARIABLE}}   VARIABLES \text{ \small{VARIABLES}} 含义相同,区别只在定义的变量数,   CONSTANT \text{ \small{CONSTANT}}   CONSTANTS \text{ \small{CONSTANTS}} 也是如此。

变量 r d y rdy 可以取任意的值,例如 1 / 2 -1/2 ,即存在将 1 / 2 -1/2 赋值给 r d y rdy 的状态。在讨论规约时,我们通常会说 r d y rdy 只能取值0或1,我们真正的意思是,在满足规约的任何行为的每种状态下, r d y rdy 的值都等于0或1。不必理解完整的规约也可以理解这一点。通过告诉读者变量在满足规约的行为中可以取哪些值,可以使规约更易于理解。我们可以用注释来做到这一点,但是我更喜欢使用这样的定义: T y p e I n v a r i a n t ( v a l D a t a ) ( r d y { 0 , 1 } ) ( a c k { 0 , 1 } ) TypeInvariant \triangleq (val \in Data)\land (rdy\in \{0,1\})\land (ack \in \{0,1\})

我称集合 { 0 , 1 } \{0,1\} r d y rdy 的类型,称 T y p e I n v a r i a n t TypeInvariant 为类型不变量。让我们更精确地定义类型和其他一些术语:

  • 状态函数是一个普通表达式(一个没有 ' \square 的表达式),可以包含变量和常量。
  • 状态谓词是布尔值状态函数。
  • 规约 S p e c Spec I n v Inv 不变量是状态谓词,使得 S p e c       I n v Spec \implies Inv 是一个定理。
  • 变量 v v 在规约 S p e c Spec 中具有类型 T T 当且仅当 v T v\in T S p e c Spec 的不变量。

如下书写方式可以使 T y p e I n v a r i a n t TypeInvariant 的定义更易于阅读: T y p e I n v a r i a n t v a l D a t a r d y { 0 , 1 } a c k { 0 , 1 } \begin{aligned}TypeInvariant \triangleq &\land val \in Data \\ &\land rdy\in \{0,1\} \\&\land ack \in \{0,1\}\end{aligned} 上式中每个合取词都以一个 \land 开头,且都必须完全处于 \land 的右边。(该合取词可能占据多行。)对于析取词,我们使用相同的方式。在使用此“项目符号列表”(bulleted-list)表示法时,所有的 \land \lor 都必须精确对齐(即使在ASCII版本中),上式中这种缩进很重要,我们可以因此不用括号,这种书写方式在合取词和析取词嵌套的时候特别有用。

公式 T y p e I n v a r i a n t TypeInvariant 不会出现在规约中,因为规约会蕴含 T y p e I n v a r i a n t TypeInvariant 为不变量,因此不必显式定义它。实际上,它的不变性将被断言为一个定理。

初始谓词很简单直接,开始时, v a l val 可以等于 D a t a Data 的任一元素, r d y rdy a c k ack 也可以要么均为0,要么均为1: I n i t v a l D a t a r d y { 0 , 1 } a c k = r d y \begin{aligned}Init \triangleq &\land val \in Data \\ &\land rdy\in \{0,1\} \\&\land ack=rdy\end{aligned} 现在开始定义“下一个状态动作” N e x t Next 。协议的步骤要么是发送值,要么是接收值,我们定义 S e n d Send R c v Rcv 两个动作来分别表示它们。 N e x t Next 步骤(满足 N e x t Next 动作的步骤)要么是 S e n d Send 步骤,要么是 R c v Rcv 步骤,因此它是 S e n d R c v Send \land Rcv 步骤。这样,我们将 N e x t Next 定义为 S e n d R c v Send \land Rcv 。下面让我们分别定义 S e n d Send R c v Rcv

我们认为,在一个状态下,动作 S e n d Send 被“使能”,则意味着此时可以执行一个“ S e n d Send ”步骤了。上述示例行为也可以看出这一点: S e n d Send 被使能当且仅当 r d y rdy 等于 a c k ack 。通常,我们关于动作的第一个问题是它何时被使能?因此,动作的定义通常从其使能条件开始。因此, S e n d Send 定义中的第一个合取词是 r d y = a c k rdy=ack ,下一个合取词告诉我们变量 v a l val r d y rdy a c k ack 的新值是什么。 v a l val 的新值 v a l val' 可以是 D a t a Data 的任何元素,即任意满足 v a l D a t a val' \in Data 的值。 r d y rdy 的值从0变为1或从1变为0,因此 r d y rdy' 等于 1 r d y 1-rdy (因为 1 = 1 0 1 = 1-0 0 = 1 1 0 = 1-1 ), a c k ack 的值保持不变。

TLA+定义   UNCHANGED  v \text{ \small{UNCHANGED }} v 来表示表达式 v v 在新旧状态下都具有相同的值。更准确地说,   UNCHANGED  v \text{ \small{UNCHANGED }} v 等价于 v = v v'=v ,其中 v v' 是通过给 v v 的所有变量加 ' 得到的表达式。因此,我们这样定义 S e n d Send : S e n d r d y = a c k v a l D a t a r d y = 1 r d y   UNCHANGED  a c k \begin{aligned}Send \triangleq &\land rdy=ack \\ &\land val' \in Data \\ &\land rdy'=1-rdy \\&\land \text{ \small{UNCHANGED }}ack\end{aligned} (我可以用 a c k = a c k ack'=ack 代替   UNCHANGED  a c k \text{ \small{UNCHANGED }}ack ,但我更喜欢后者。)

一个 R c v Rcv 步骤被使能当且仅当 r d y rdy a c k ack 的值不相等,这个步骤会改变 a c k ack 的值,但 v a l val r d y rdy 保持不变,也即( v a l val r d y rdy )“对”保持不变。TLA+使用“ \langle ”和“ \rangle ”包裹有序元组,所以 R c v Rcv 断言 v a l , r d y \langle val,rdy \rangle 保持不变。(在ASCII版本中,这对括号被记作<<和>>。)因此 R c v Rcv 定义如下: R c v r d y a c k a c k = 1 a c k   UNCHANGED  v a l , r d y \begin{aligned}Rcv \triangleq &\land rdy\neq ack \\ &\land ack' =1-ack \\ &\land \text{ \small{UNCHANGED }}\langle val,rdy \rangle\end{aligned}

就像在小时时钟示例中一样,完整的规约 S p e c Spec 应该允许重叠步骤,在这种情况下,所有这三个变量保持不变,即 S p e c Spec 允许 v a l , r d y , a c k \langle val,rdy,ack\rangle 保持不变。 S p e c Spec 的定义是 S p e c I n i t [ N e x t ] v a l , r d y , a c k Spec \triangleq Init \land \square[Next]_{\langle val,rdy,ack \rangle}

模块 A s y n c h I n t e r f a c e AsynchInterface 还声明了 T y p e I n v a r i a n t TypeInvariant 不变量,完整的规约如下图3.1显示:
在这里插入图片描述

发布了4 篇原创文章 · 获赞 1 · 访问量 5514

猜你喜欢

转载自blog.csdn.net/robinhzp/article/details/103875657