TLA+ 《Specifying Systems》翻译初稿——Section 3.2 Another specification(另一个规约)

本节描述了异步接口的另一种写作方式,引入了记录的概念及其书写格式,在描述 n e x t s t a t e next-state 动作时引入了两种书写方式,并引入两个代指符号。

  • 记录:类似C/C++语言的结构,Python的字典。
  • 记录的书写方式 [ r . v a l d , r . r d y 1 c h a n . r d y , r . a c k c h a n . a c k ] [r.val \mapsto d,r.rdy\mapsto 1-chan.rdy,r.ack\mapsto chan.ack]
  • n e x t s t a t e next-state 动作: S e n d ( d ) c h a n . r d y = c h a n . a c k c h a n = [ r . v a l d , r . r d y 1 c h a n . r d y , r . a c k c h a n . a c k ] \begin{aligned} Send(d) \triangleq & \land chan.rdy=chan.ack\\ & \land chan'=[r.val \mapsto d,r.rdy\mapsto 1-chan.rdy,r.ack \mapsto chan.ack]\end{aligned} S e n d ( d ) c h a n . r d y = c h a n . a c k c h a n = [ c h a n  EXCEPT  ! . v a l = d , ! . r d y = 1 @ ] \begin{aligned}Send(d) \triangleq &\land chan.rdy = chan.ack \\ &\land chan'=[chan \text{\footnotesize{ EXCEPT }} !.val=d,!.rdy=1-@ ]\end{aligned} 其中 ! ! 指代新记录, @ @ 指代旧记录中的原值。

模块 A s y n c h I n t e r f a c e AsynchInterface 是对异步接口及其握手协议的详细描述,不过,目前它对调用该接口的其他系统不大友好,让我们以某种形式重写这个接口规约,以更方便地将其用作更大的规约的一部分。

原始规约的第一个问题是它使用三个变量来描述单个接口,其他系统可能调用接口的多个不同实例,为避免变量激增,我们用单个变量 c h a n chan c h a n n e l channel 的缩写)替换三个变量 v a l val r d y rdy a c k ack 。数学家可以通过将 c h a n chan 的值设为有序三元组(例如用 [ c h a n = 1 / 2 , 0 , 1 ] [chan = \langle -1/2,0,1 \rangle] 代替 v a l = 1 / 2 r d y = 0 , a c k = 1 val = -1/ 2,rdy = 0,ack = 1 。)不过程序员在编码过程中发现,使用这样的元组经常会出错,因为很容易忘记 a c k ack 是由第二个还是第三个元素表示。因此,TLA+除了提供更常规的数学符号外,还提供“记录”( r e c o r d record )。

让我们用 v a l val r d y rdy a c k ack 字段将通道的状态表示为记录。如果 r r 是记录,则 r . v a l r.val 是其 v a l val 字段。我们可以定义类型不变量,声明 c h a n chan 的值是所有此类记录 r r 的集合的元素:其中 r . v a l r.val 是集合 D a t a Data 的元素, r . r d y r.rdy r . a c k r.ack 是集合 { 0 , 1 } \{0,1\} 的元素,该集合记做: [ v a l : D a t a , r d y { 0 , 1 } , a c k { 0 , 1 } ] [val:Data,rdy:\{0,1\},ack:\{0,1\}]

记录的字段是不保序的,因此我们以何种顺序书写它们都无关紧要。同一组记录也可以写为 [ a c k { 0 , 1 } , v a l : D a t a , r d y { 0 , 1 } ] [ack:\{0,1\},val:Data,rdy:\{0,1\}]

在初始态, c h a n chan 可以等于该集合中 a c k ack r d y rdy 字段相等的任何元素,因此初始谓词是类型不变量和条件 c h a n . a c k = c h a n . r d y chan.ack=chan.rdy 的合取。

调用该接口的系统可能执行以下操作:发送数值 d d 并执行其他一些依赖于 d d 的变更操作。我们想将这种操作表示为一个动作,该动作是两个单独动作的合取:一个描述 d d 的发送,另一个描述其他变更。因此,我们定义发送数据值 d d 的动作为 S e n d ( d ) Send(d) ,而不是定义为发送一些未指定数值的动作 S e n d Send 。“下一个状态”动作由 S e n d ( d ) Send(d) 步骤(对于 D a t a Data 集中的某个 d d )或 R c v Rcv 步骤满足。( R c v Rcv 步骤收到的值等于 c h a n . v a l chan.val 。)我们说 S e n d ( d ) Send(d) 步骤是一个关于 D a t a Data 中某个 d d 的步骤,则意味着存在 D a t a Data 中一个 d d 使得该步骤满足 S e n d ( d ) Send(d) ——换句话说,是个 d D a t a : S e n d ( d ) \exists d \in Data:Send(d) 步骤,因此我们定义 N e x t ( d D a t a : S e n d ( d ) ) R c v Next \triangleq(\exists d \in Data:Send(d)) \lor Rcv S e n d ( d ) Send(d) 动作声明 c h a n chan' 等于记录 r r ,其中 r . v a l = d r . r d y = 1 c h a n . r d y r . a c k = c h a n . a c k r.val= d\qquad r.rdy= 1- chan.rdy \qquad r.ack= chan.ack 该记录在TLA+中记做: [ r . v a l d , r . r d y 1 c h a n . r d y , r . a c k c h a n . a c k ] [r.val \mapsto d,r.rdy\mapsto 1-chan.rdy,r.ack\mapsto chan.ack] (该符号在ASCII版本中记做“|->”。)由于记录的字段是无序的,因此也可以将该记录记做: [ r . a c k c h a n . a c k , r . v a l d , r . r d y 1 c h a n . r d y ] [r.ack\mapsto chan.ack,r.val \mapsto d,r.rdy\mapsto 1-chan.rdy] S e n d ( d ) Send(d) 的使能条件是 r d y rdy a c k ack 值相等,因此我们可以这样定义:
S e n d ( d )    c h a n . r d y = c h a n . a c k    c h a n = [ r . v a l d , r . r d y 1 c h a n . r d y , r . a c k c h a n . a c k ] \begin{array}{l} Send(d) \triangleq\\ \qquad \land \;chan.rdy=chan.ack\\ \qquad\land \; chan'=[r.val \mapsto d,r.rdy\mapsto 1-chan.rdy,r.ack \mapsto chan.ack]\end{array}

这样定义 S e n d ( d ) Send(d) 就很完美了,不过我更喜欢下面稍微不同的这个,我们可以说 c h a n chan' 的值和 c h a n chan 的值相等,除了 v a l val 等于 d d r d y rdy 等于 1 c h a n . r d y 1-chan.rdy 之外。在TLA+中,我们可以将之记做 [ c h a n  EXCEPT  ! . v a l = d , ! . r d y = 1 c h a n . r d y ] [chan \text{\footnotesize{ EXCEPT }} !.val=d,!.rdy=1-chan.rdy] ! ! 代表新记录,用  EXCEPT  \text{\footnotesize{ EXCEPT }} 表达式描述对 c h a n chan 的修改,则该表达式读作:“新纪录 ! ! c h a n chan 相等,除了 ! . v a l !.val 等于 d d ,且 ! . r d y !.rdy 等于 1 c h a n . r d y 1-chan.rdy ”,
在表达式 ! . r d y = 1 c h a n . r d y !.rdy=1-chan.rdy 中,用符号 @ @ 表示 c h a n . r d y chan.rdy ,我们可以将之改写为: [ c h a n  EXCEPT  ! . v a l = d , ! . r d y = 1 @ ] [chan \text{\footnotesize{ EXCEPT }} !.val=d,!.rdy=1-@ ] 通常,对于任何记录 r r ,表达式 [ r  EXCEPT  ! . c 1 = e 1 , , ! . c n = e n ] [r \text{\footnotesize{ EXCEPT }} !.c_{1}=e_{1},\ldots,!.c_{n}=e_{n}]
是通过对 i 1.. n i\in 1..n 中的每个 i i e i e_{i} 替换 r . c i r.c_{i} 而获得的记录。用 @ @ 代替 e i e_{i} ,我们得到定义: S e n d ( d ) c h a n . r d y = c h a n . a c k c h a n = [ c h a n  EXCEPT  ! . v a l = d , ! . r d y = 1 @ ] \begin{aligned} Send(d) \triangleq &\land chan.rdy = chan.ack \\ &\land chan'=[chan \text{\footnotesize{ EXCEPT }} !.val=d,!.rdy=1-@ ]\end{aligned} R c v Rcv 的定义很简单直接,当 c h a n . r d y chan.rdy 不等于 c h a n . a c k chan.ack 时,可以接收一个值,且收到该值后要转置 c h a n . a c k chan.ack R c v c h a n . r d y c h a n . a c k c h a n = [ c h a n  EXCEPT  ! . a c k = 1 @ ] \begin{aligned} Rcv \triangleq &\land chan.rdy \neq chan.ack \\ &\land chan'=[chan \text{\footnotesize{ EXCEPT }} !.ack=1-@ ] \end{aligned} 完整的规约如下图3.2:
在这里插入图片描述

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

猜你喜欢

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