Uppaal 4.0:小型教程

Uppaal 4.0:小型教程

Uppaal 4.0 : Small Tutorial

1 引言

本文档旨在供初次接触Uppaal和验证的人使用。在完成本教程后,具有有限形式化方法知识的学生或工程师应能够将Uppaal应用于实际目的。

第2节介绍了Uppaal,第3节是教程部分。

【译者注:官网及更详细的教程

2 Uppaal

Uppaal是一个用于实时系统验证(validation)(通过图形模拟)和验证(verification)(通过自动模型检查)的工具包。它由两个主要部分组成:图形用户界面和模型检查引擎。用户界面采用Java实现,并在用户的工作站上执行。Uppaal的4.0版本要求计算机上安装有Java Runtime Environment 5或更高版本。引擎部分默认在与用户界面相同的计算机上执行,但也可以在更强大的服务器上运行。

该工具的思想是使用时钟自动机对系统进行建模,进行模拟,然后验证其性质时钟自动机是带有时间(时钟)的有限状态机。系统由由位置组成的进程网络构成。在这些位置之间的转换定义了系统的行为。模拟步骤包括以交互方式运行系统,以检查它是否按预期工作。然后,我们可以请求验证器检查可达性属性,即某个状态是否可达。这称为模型检查,基本上是对系统所有可能的动态行为进行详尽搜索。

更具体地说,引擎使用即时验证结合符号技术,将验证问题简化为解决简单约束系统的问题 [YPD94,LPY95]。为了提高效率,验证器检查简单的不变性和可达性属性。其他属性可以通过使用测试自动机 [JLS96] 或带有调试功能的装饰系统进行检查。

3 学习Uppaal

Uppaal基于时钟自动机,即带有时钟的有限状态机。时钟是处理Uppaal中时间的方式。时间是连续的,时钟测量时间的进度。可以测试时钟的值或将其重置。整个系统的时间将在全局范围内以相同的速度推进。

在Uppaal中,系统由并发进程组成,每个进程都被建模为一个自动机。自动机有一组位置。使用转换来改变位置。为了控制何时执行转换(“触发”它),可以设置一个守卫和一个同步。守卫是对变量和时钟的条件,说明何时启用转换。Uppaal中的同步机制是握手同步:两个进程同时执行握手来同步它们的操作。当执行转换时,有两种可能的操作:变量的赋值或时钟的重置。

以下示例将使您熟悉这个简短的描述。

3.1 概览

Uppaal主窗口(图1)有两个主要部分:菜单和选项卡。
UPPAAL概览

图1:UPPAA概览


菜单在集成帮助中有详细说明,可通过帮助菜单访问。帮助进一步详细描述了使用的语法和GUI,因此本教程将侧重于如何使用该工具。三个选项卡分别访问Uppaal的三个组件,即编辑器、模拟器和验证器。

图1显示了编辑器视图。其思想是定义模板(类似于C++)用于实例化为完整系统的进程。使用模板的动机是系统通常具有几个非常相似的进程。== 控制结构(即位置和边)相同,只有一些常量或变量不同==。因此,模板可以将符号变量和常量作为参数。模板还可以具有本地变量和时钟。启动Uppaal时,在绘图区域预先创建了一个位置。这是自动机的初始位置,因此它内部有一个额外的圆圈。要添加第二个位置,请单击工具栏中的“添加位置”按钮(工具提示将帮助您),然后单击绘图区域,位于初始位置旁边一点。使用“选择工具”为它们命名为"start"和"end"。然后选择“添加边”按钮,单击开始位置,然后单击结束位置。您现在有了第一个自动机,如图2所示。
在这里插入图片描述

图2:你的第一个自动机


编辑器中还有另一个重要的细节,您应该知道。在屏幕底部,有一个可以“拖动”的条形区域。这将打开一个表格,其中包含“位置”和“描述”行,此时可能为空。稍后,它将包含关于模型包含的语法编译错误的非常有用的信息。使用此功能将使查找和修复错误变得更加容易。

现在,单击“模拟器”选项卡以启动模拟器,单击弹出的“是”按钮,您就可以运行您的第一个系统了。

图3显示了模拟器视图。
在这里插入图片描述

图3:图形模拟器的快照


在左侧,您将找到控制部分,您可以选择转换(上部)并处理现有的跟踪(下部)。中间是变量,右侧是系统本身。在系统下方,您将看到各个进程中发生的情况。

要模拟我们的简单系统,请在屏幕左上角的列表中选择一个启用的转换。在我们的示例中,当然只有一个转换。单击“下一步”。右侧的过程视图将更改(指示当前位置的红点将移动),并且模拟跟踪将增长。您会注意到实际上没有更多的转换是可能的,因此系统陷入了死锁

现在,我们已经模拟了我们的系统,并将继续进行验证。单击“验证器”选项卡。显示验证器视图,如图4所示。
在这里插入图片描述

图4:验证器视图快照


上部允许您指定对系统的查询。下部记录与模型检查引擎的通信。

在概览下方的查询字段中输入文本E<>Process.end这是Uppaal表示临时逻辑公式∃⋄Process.end的符号,应理解为“在进程自动机中可以达到位置end”。单击“检查”以让引擎验证。概览中的圆点将变为绿色,表示该属性确实被满足。
【译者注:Uppaal所有CTL公式:在这里插入图片描述

本文档的其余部分旨在通过示例探索Uppaal的一些关键点。

3.2 互斥算法

我们将学习著名的Petterson互斥算法,以了解如何从程序/算法中派生出一个作为自动机的模型,并检查与之相关的属性。

以下是两个进程的C语言算法:
在这里插入图片描述

将构建相应的自动机。请注意,协议是对称的,因此我们可以使用Uppaal的模板来简化模型。首先,重置系统(New system)以清除“Hello World”示例。将默认模板P重命名为mutex。

我们将在此省略在临界区域中的实际工作,因为这里没有兴趣。协议有四个状态,直接来自所述算法,类似于goto标签。使用这些状态,两个进程可以写成如下形式:
在这里插入图片描述

作为自动机,这两个进程将如图5所示。
在这里插入图片描述

图5:mutex自动机


蓝色表达式是对变量的赋值,当执行相应的转换时执行。绿色表达式是守卫,必须为相应的转换启用。【译者注:守卫是对变量和时钟的条件,说明何时启用转换】
【译者注:在这里插入图片描述

您可能会注意到这两个自动机看起来非常相似。唯一的区别是某些值和变量名称。为了节省工作,我们将仅定义一个模板自动机,然后实例化该模板两次。模板可以如图6所示。
在这里插入图片描述

图6:mutex模板


请注意,我们将变量req1和req2替换为占位符req_self和req_other,稍后我们将对其进行实例化。新变量me将指示实例表示哪个进程。为了创建一个模板,您首先从图5中绘制自动机,如前所述。让我们将此模板称为“mutex”,并将其指定在绘图区域正上方的“Name:”字段中。此外,您必须通过在“Name:”字段旁边的“Parameters:”字段中编写它们来指定模板参数me、req_self和req_other。写入以下内容:
const int[1,2] me, int[0,1] &req_self, int[0,1] &req_other

这意味着您为整数类型的实例化定义了三个变量,每个变量都限定为两个值。第一个变量me是一个常量,其他两个必须是具有布尔值(0或1)的变量

现在,您可以从图5中实例化两个类型为P1 = mutex(1, req1, req2);和P2 = mutex(2, req2, req1);的对象。检查表达式(类似于C语法) t u r n : = ( m e = = 1 ? 2 : 1 ) turn := (me == 1 ? 2 : 1) turn:=(me==1?2:1)将如何评估。要创建实例,请打开Project tree中的System declarations标签,并在其中输入上述声明(替换默认行,该行实例化默认模板)。此外,请指定系统现在由P1和P2组成,通过在关键字system后面写入它们,以逗号分隔。System declarations现在包含:
// Place template instantiations here.
P1 = mutex(1, req1, req2);
P2 = mutex(2, req2, req1);
// List one or more processes to be composed into a system.
system P1, P2;

仍然有一些遗漏:还必须声明变量。单击Declarations标签并声明:int[0,1] req1,req2; 和 int[1,2] turn;

现在您已经定义了模板,将其实例化两次,将实例用于系统,并声明了适当的变量。正如您可能已经注意到的,声明的变量是全局的。这对于共享的turn变量很有用名称声明的范围首先是局部的,然后是全局的。在继续之前,进行语法检查(工具菜单或按F7键),并查看您可以在绘图区域下方拖动的列表。它应该为空,否则请修复报告的问题。

现在,单击“模拟器”选项卡,查看两个自动机如何被实例化。特别注意两个自动机的对称名称。您可以通过交互选择转换来模拟系统。尝试同时到达两个进程的临界区域…嗯,您无法这样做,这就是协议的目的。但是使用模拟,我们不能确定这一点。更好的方法是使用验证器。

单击“验证器”选项卡,单击“插入”按钮,单击查询文本区域并编写互斥属性:A[] not (P1.CS and P2.CS)。按下“检查”按钮,完成。应该有一个亮起的绿色按钮,这意味着已验证该属性。如果按钮是红色的,这意味着未验证该属性。属性A[]是一种安全属性:您检查(P1.CS和P2.CS)是否始终为真。另一种类型的属性,E<>,可以用于可达性属性。例如,插入一个新属性E<> P1.CS,检查进程P1是否可以到达临界区域。

如果系统不正确,Uppaal可以返回一个诊断跟踪。首先更改模型,使其有错误。例如,将req_other == 0的守卫更改为req_other == 1。然后转到Options菜单,激活其中一个诊断跟踪选项;选择互斥属性,然后按下“检查”按钮。现在,该属性应该不满足。现在您可以返回到模拟器并查看找到的跟踪。选择跟踪中的第一个条目,然后按下“Replay for this”。

您现在已经对简单的互斥协议进行了建模、模拟和验证。在分发目录的demo文件夹中,有一些其他简单的示例。例如,文件fischer.xml包含另一个互斥协议,以及一些示例查询在fischer.q中。

3.3 Uppaal中的时间

本小节旨在直观解释Uppaal中时间的概念。

Uppaal中的时间模型是连续时间。在技术上,它是通过区域(regions)实现的,因此状态是符号化的,这意味着在一个状态中,我们对时间没有任何具体的值,而是差异[AD94]。为了理解Uppaal中如何处理时间,我们将研究一个简单的例子。我们将使用一个观察者来显示差异。通常,观察者是一个附加的自动机,负责检测事件而不干扰被观察系统。在我们的情况下,时钟的复位(x := 0)委托给观察者来执行。请注意,通过这样做,系统的原始行为 - 在时钟直接在过渡循环到自身上进行复位 - 并未改变。

图7显示了带有观察者的第一个模型。
在这里插入图片描述

图7:第一个涉及到自动机 P1 和观察者 Obs的例子


时间是通过时钟来表示的。在示例中,x是在全局声明部分中声明的时钟,如 clock x;。用于与观察者同步的是一个复位通道,它也在声明部分中声明为 chan reset。在我们的例子中,通道同步是在reset!和reset?之间的握手。因此,在这个例子中,时钟可能在2个时间单位后被复位。观察者检测到这一点并执行复位。

绘制模型,为自动机命名为P1和Obs,在系统中定义它们。在编辑菜单中使用Insert Template创建一个新模板(您可以直接在system语句中写入模板名称,Uppaal将自动为您实例化它们)。请注意,观察者的所取的状态是committed类型。如果您模拟系统,您将看不到太多。为了培养解释所见内容的能力,我们将使用查询并逐渐修改系统。

我们系统的预期行为如图8所示。
在这里插入图片描述

图8:第一个例子的时间行为:这是一个可能的执行


尝试使用以下属性来展示这种行为:

  • A[] Obs.taken imply x>=2:所有时钟值的下降(见曲线)都在2以上。此查询的含义是:对于所有状态,处于位置Obs.taken意味着x>=2。
  • E<> Obs.idle and x>3:这是等待期间的查询,您可以尝试值如30000,结果将相同。这个问题的意思是:是否可以达到一个Obs在位置idle且x>3的状态。

现在,在循环位置添加一个不变式,如图9所示。
在这里插入图片描述

图9:添加不变式:新的行为


这个不变式是一个进展条件:系统不允许停留在状态超过3个时间单位(更准确地说:要求时钟x不大于3),因此转换必须被执行,且在我们的例子中,时钟被复位。

为了看到差异,尝试以下属性:

  • A[] Obs.taken imply (x>=2 and x<=3):显示当x在区间[2,3]内时转换被执行。
  • E<> Obs.idle and x>2:可以在区间(2,3]内取得转换。
  • A[] Obs.idle imply x<=3:显示上限得到了遵守。

之前的属性E<> Obs.idle and x>3不再成立。

现在,删除不变式并将守卫更改为 x >= 2 and x <= 3。您可能认为这与之前相同 - 但实际上并不是!系统不再具有进展条件,只是现在守卫上有了新的条件。图10显示了新的系统。
在这里插入图片描述

图10:无不变量和一个新的防护条件:新的行为


正如您所看到的,系统可能会像以前一样执行相同的转换,但现在存在死锁:如果在3个时间单位后不执行转换,则系统可能会卡住。重试相同的属性,最后一个现在不再成立。实际上,您可以通过以下属性看到死锁:A[] x>3 imply not Obs.taken,即3个时间单位后不能再执行转换。

3.4 Urgent/committed 位置

我们现在将看一下 Uppaal 中不同类型的位置。在前面的例子中,您已经看到了 committed 类型。Uppaal 中有三种不同类型的位置:

  • 带有或没有不变量的普通(normal)位置(例如上面的 x <= 3),
  • 紧急(urgent)位置
  • 在 Obs 自动机中使用的承诺(committed)位置

绘制图11中所示的自动机,并命名它们为 P0、P1 和 P2。
在这里插入图片描述

图11:三种状态的自动机


为每个自动机本地定义时钟 x,以尝试此功能:打开项目树中它们模板的子树。在相关模板下,您将看到一个 Declarations 声明标签。

单击它,然后定义clock x;。对其他两个自动机重复此步骤。

标记为“U”的位置是urgent的,标记为“C”的位置是committed的。在模拟器中尝试它们,并注意在committed状态时,唯一可能的转换始终是从committed状态出发的转换。必须立即离开committed状态。为了看到normal状态和urgent状态之间的区别,请转到验证器并尝试以下属性:

  • E<> P0.S1 and P0.x > 0:在 P0 的 S1 中等待是可能的。
  • A[] P1.S1 imply P1.x==0 在 P1 的 S1 中无法等待。

urgent状态中时间可能不会流逝,但允许与正常状态的交替,正如您在模拟器中所见。因此,urgent位置比committed位置“更宽松”一些。

3.5 验证属性

在上面的例子中,我们多次使用了验证器。现在,我们将更详细地介绍验证器理解的语言。总体而言,验证器中可用的查询有:

  • E<> p:存在一条路径,其中最终成立 p。
  • A[] p:对于所有路径,始终成立 p。
  • E[] p:存在一条路径,其中始终成立 p。
  • A<> p:对于所有路径,最终将成立 p。
  • p --> q:每当成立 p 时,最终将成立 q。

【译者注:E存在,A任意,<>最终,[]始终】

其中 pq 是状态公式,例如(P1.cs and x < 3)。查询语言的完整语法可在在线帮助中找到。请注意有用的特殊形式 A[] not deadlock,用于检查死锁。

3.6 一些建模技巧

Uppaal 提供了紧急通道(使用 urgent chan 定义),这是在启用转换(transition)时必须立即进行的同步,没有延迟在这些过渡上不允许时钟条件。可以通过在变量上设置守卫(即在变量上繁忙等待)来编码“紧急转换(urgent transition)”,使用紧急通道。使用一个带有一个状态循环和一个转换 read! 的虚拟过程。例如,紧急转换可以是 x>0 read?

虽然通道中没有传递值,但这可以通过共享变量轻松编码:全局定义一个变量 x,并将其用于读取和写入。请注意,使用 read! x:=3;read? y:=x; 不够清晰,最好在它们之间使用一个committed位置:首先是 read?过渡到committed位置,然后是设置y:=x的过渡。

自 Uppaal 4 版本以来,广播通信也是可能的:直觉是具有同步标签 e!的边会在通道 e 上发出广播,任何具有同步标签 e? 的启用边将与发出广播的进程同步。有关详细信息,请参阅在线帮助。
整数数组可能很有用,将它们声明为 int a[3]; 可以创建一个从0到2可索引的数组。索引可以是另一个变量 i,通常是 int[0,2] i; 以保持清晰。

为了保持模型的可管理性,必须注意以下几点:

• 时钟数量对复杂性有重要影响,即对验证时间有重要影响,因为它极大地影响状态空间。

• 使用committed位置可以显著减少状态空间,但在使用此功能时必须小心,因为它可能会带走一些相关状态。

• 变量数量同样起着重要作用,更重要的是它们的范围。应当小心确保整数不会使用例如 -32000 到 32000 的所有值。特别是要避免整数上的无限循环,因为值将跨越整个范围。

参考文献

[YPD94] 王毅,保罗·彼得森(Paul Pettersson),马茨·丹尼尔斯(Mats Daniels)。通过约束求解的自动验证实时通信系统。在第7届国际形式描述技术大会论文集中,1994年。

[LPY95] 金·G·拉尔森(Kim G. Larsen),保罗·彼得森,王毅。实时系统的模型检查。在基础计算理论大会论文集中,计算机科学讲座笔记第965卷,1995年8月,第62-88页。

[JLS96] H.E. 詹森(H.E. Jensen),K.G. 拉尔森,A. 斯库(A. Skou)。使用SPIN和Uppaal对避撞协议的建模和分析。在第2届SPIN验证系统国际研讨会论文集中,1996年8月,第1-20页。

[LPY97] Magnus Lindahl,Paul Pettersson,王毅。一个齿轮箱控制器的形式设计与分析:使用Uppaal的工业案例研究。正在准备中,1997年。

[AD94] R. Alur 和 D. Dill。定时自动机的理论,在《理论计算机科学》中,卷125,1994年,第183–235页。

版本历史

  • 2001年3月 由Alexandre David创建的第一个版本。
  • 2001年4月 由Alexandre David进行的更正。修复了需求中的错误,添加了chan声明,在声明中修复了错误:int[0,1] req1,req2, turn; turn 是 int,而不是 int[0,1]!
  • 2001年12月17日 由Alexandre David进行的更新。添加了如何标记初始状态的说明(因为新版UPPAAL不再默认使第一个状态成为初始状态)。
  • 2002年10月16日 由Tobias Amnell进行的更新。将屏幕截图更改为最新版本(3.2.11),在开始-结束示例中添加了验证步骤,添加了关于查询语言的部分以及在多个地方进行了文本更新。
  • 2009年11月16日 由Martin Stigge进行的更新。将文档适应到Uppaal 4.0.7版本(语法和屏幕截图)。对互斥示例进行了更详细的版本以减少混淆。在Pontus Ekberg的帮助下进行了一堆小修复和澄清。
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值