840 likes | 1.06k Views
第 9 章 形式化方法. 基本概念 数学预备知识 应用数学符号描述形式化规格说明 形式规格说明语言 Z 规格说明语言 有穷状态机 Petri 网. 基本概念. 根据形式化的程度,可以把软件工程方法划分成非形式化、半形式化和形式化三类。使用自然语言描述需求规格说明,是典型的非形式化方法。使用数据流图或实体 — 关系图等图形符号建立模型,是典型的半形式化方法。 用于开发计算机系统的形式化方法,是描述系统性质的基于数学的技术 。. Anthony Hall 在其关于形式化方法的介绍性讨论[H all90 ]中说到:
E N D
第9章 形式化方法 • 基本概念 • 数学预备知识 • 应用数学符号描述形式化规格说明 • 形式规格说明语言 • Z规格说明语言 • 有穷状态机 • Petri网
基本概念 • 根据形式化的程度,可以把软件工程方法划分成非形式化、半形式化和形式化三类。使用自然语言描述需求规格说明,是典型的非形式化方法。使用数据流图或实体—关系图等图形符号建立模型,是典型的半形式化方法。 • 用于开发计算机系统的形式化方法,是描述系统性质的基于数学的技术。
Anthony Hall在其关于形式化方法的介绍性讨论[Hall90]中说到: 形式化方法是有争议的。支持者声称形式化方法可以引发软件开发的革命。而批评者认为:这是极端困难的。同时,对大多数人来说,他们对形式化方法是如此的不熟悉,以至难于判断这些争论。
《The Encyclopedia of Software Engineering》[MAR94]中对形式化方法的定义如下: 如果一个方法有良好的数学基础,特别地,是以形式化说明语言描述的,那么它是形式化的。这种数学基础提供了精确定义诸如一致性和完整性概念的表示方法,以及更进一步地定义规格说明、实现和正确性。
形式化规格说明的期望特性——一致性、完整性及无歧义性——是所有规格说明方法的目标。形式化方法的使用增加了这些理想实现的可能性。形式化规格说明的期望特性——一致性、完整性及无歧义性——是所有规格说明方法的目标。形式化方法的使用增加了这些理想实现的可能性。 • 规格说明语言的形式化语法使得需求或设计以唯一的方式被解释,从而排除了读者解释自然语言(例如英语)或图形表示时经常产生的歧义性; • 集合论和逻辑符号的描述便利使得可以清晰地陈述事实(需求)。 • 要达到一致,在规格说明中某地方陈述的事实就不能与其他地方有矛盾。一致性是通过数学证明将初始事实形式化地映射(使用推理规则)到规格说明中后面的陈述来保证的。
非形式化方法的缺点 使用自然语言描述的系统规格说明,可能存在矛盾、二义性、含糊性、不完整性以及抽象层次混杂等问题。
软件开发中的数学 • 数学最有用的性质之一是,它能够简洁、准确地描述物理现象、对象或动作的结果,因此是理想的建模工具。 • 在软件开发过程中使用数学的另一个优点是,可以在软件工程活动之间平滑地过渡。不仅功能规格说明,而且系统设计也可以用数学表达,当然,程序代码也是一种数学符号(虽然是一种相当繁琐、冗长的数学符号)。 • 数学作为软件开发工具的最后一个优点是,它提供了高层确认的手段。可以使用数学方法证明,设计符合规格说明,程序代码正确地反映了设计结果。
形式化方法中的主要概念 • 本节的目的是给出软件系统的数学规格说明中涉及的主要概念,而不是给读者堆砌太多的数学细节。为此,我们使用一些简单例子: 例1:符号表。 使用一个程序来维护符号表,此符号表在许多不同类型的应用中频繁使用。它由一组没有重复的项构成。
图1 给出了一个典型的符号表例子。它表示操作系统用于保存系统用户名的表。 假设本例中的表包括的职员数量不大于MaxIds 。可以使用数据不变式为表设定限制条件。数据不变式是一个条件,它在包含一组数据的系统的执行过程中总保持为真。 符号表的数据不变式有两个构成成分: (1)表中包含的名字数不超过MaxIds; (2)在表中没有重复的名字。 图1 符号表
另一个重要的概念是状态。许多形式化语言(如OCL)使用状态概念;另一个重要的概念是状态。许多形式化语言(如OCL)使用状态概念; • 也就是说,一个系统可能处于多种状态之一,每一种状态都表示外部可观察到的行为模式。 • 在Z语言中,对术语状态有不同的定义。在Z(及相关的语言)中,一个系统的状态由系统的存储数据来表示(因此,Z给出了太多的状态来表示每种可能的数据配置)。 • 在符号表程序的例子中使用后面的定义,状态就是符号表。
最后一个概念是操作,这是在系统中发生的读写数据的动作。最后一个概念是操作,这是在系统中发生的读写数据的动作。 • 如果对符号表程序考虑从符号表加入或去除职员名,则它将关联两个操作: (1)将一个指定名增加到符号表的操作; (2)从符号表中去除一个现存名的操作。 如果程序提供检查是否某指定名包含在表中的机制,则将有一个返回某种指示值的操作,这个指示值表示名字是否在表中。
有三种类型的条件与操作相关联:不变式、前置条件和后置条件。有三种类型的条件与操作相关联:不变式、前置条件和后置条件。 • 不变式定义什么保持不变。例如,符号表有一个不变式表示元素的个数总是小于或等于MaxIds。 • 前置条件定义一个特定操作有效的环境。例如,增加一个名字到职员标识符符号表的前置条件是有效的,仅当表中不含有将被加入的名字,而且在表中只有少于MaxIds 的职员标识符。 • 操作的后置条件定义当操作完成后保证什么为真,这是通过其对数据的影响来定义的。在增加标识符到职员标识符符号表操作的例子中,后置条件将数学地描述表已经增加了新标识符。
例2:块处理器。 在操作系统中一个更重要的部分是维护由用户创建的文件的子系统。块处理器是文件子系统中的一部分。文件存储中的文件由存储设备上的存储块构成,在计算机的操作中,文件被创建和删除,需要存储块的获取和释放。 为了处理这些,文件子系统维持一个未用块池,并保持对当前使用块的跟踪。当块从被删除文件释放时,它们通常被加入到等待进入未用块池的块队列中。
图2显示了一些部件:未用块池、被操作系统管理的文件使用的块、以及那些等待被加入到未用块池中的块。等待块被组织为队列,队列中每个元素包含来自于被删除文件的一组块。图2显示了一些部件:未用块池、被操作系统管理的文件使用的块、以及那些等待被加入到未用块池中的块。等待块被组织为队列,队列中每个元素包含来自于被删除文件的一组块。 图2 块处理器
对这个子系统来说,状态是自由块的集合、已用块的集合、以及返回块的队列。数据不变式用自然语言表达如下:对这个子系统来说,状态是自由块的集合、已用块的集合、以及返回块的队列。数据不变式用自然语言表达如下: • 块未同时被标记为未用和已用。 • 所有在队列中的块集合将是当前已用块集合的子集。 • 队列元素未包含相同的块号。 • 已用块和未用块的集合将是组成文件的块的总集。 • 在未用块集合中没有重复的块号。 • 在已用块集合中没有重复的块号。 图2 块处理器
与数据不变式相关联的某些操作是:(1) 将一个块集合加到队列的末尾; (2) 从队列前面去除一个已用块集合并将其放到未用块集合中; (3) 检查块队列是否为空。 • 第一个操作的前置条件是:将被加入的块必须在已用块集合中;后置条件是:这个块集合现在处于队列的末尾。 • 第二个操作的前置条件是:队列中必须至少有一项;后置条件是:块必须被加到未用块集合中。 • 最后一个操作——检查返回块的队列是否为空——没有前置条件,这意味着不管状态具有什么值,操作总是有定义的。后置条件是:如果队列为空,返回true,否则,返回false。
应用形式化方法的准则 选择适用于当前项目的符号系统。 • 应该形式化,但不要过分形式化。通常没有必要对系统的每个方面都使用形式化方法。 • 应该进行成本/效益分析。 • 需要有形式化方法的顾问。 • 不要放弃传统的开发方法。把形式化方法和结构化方法或面向对象方法集成起来是可能的,而且由于取长补短往往能获得很好的效果。
应该建立详尽的文档。建议使用自然语言注释来配合形式化的规格说明,以帮助读者理解系统。应该建立详尽的文档。建议使用自然语言注释来配合形式化的规格说明,以帮助读者理解系统。 • 不应该放弃质量标准。在系统开发过程中必须一如既往地实施其他SQA活动。 • 不应该盲目依赖形式化方法,这种方法并不能保证系统绝对正确。 • 应该测试、测试再测试。由于形式化方法不能保证系统绝对正确,因此,软件测试的重要性并没有降低。 • 应该重用。即使使用了形式化方法,软件重用仍然是降低软件成本和提高软件质量的唯一合理的方法。
数学预备知识 • 为了有效地应用形式化方法,软件工程师必须具有与集合和序列相关的数学符号知识,以及谓词演算中的逻辑符号方面的知识。
集合与构造性规格说明 • 集合是对象或元素的聚集,被用于形式化方法的基础。集合中包含的元素是唯一的(即,不允许重复)。具有少量元素的集合用花括号括起来,元素间用逗号分开。例如,集合 {C++,Smalltalk,Ada,COBOL,Java} 包含五种程序设计语言的名字。
集合中元素出现的顺序是不重要的,集合中元素的数量称为集合的基数(cardinality),操作符#给出集合的基数,例如,表达式集合中元素出现的顺序是不重要的,集合中元素的数量称为集合的基数(cardinality),操作符#给出集合的基数,例如,表达式 #{A, B, C, D}= 4 说明基数操作符被用于已知集合,其结果指出集合中项的数量。
有两种定义集合的方式: • 通过枚举出集合的元素来定义(如上面的集合定义); • 创建一个构造性集合规格说明。集合成员的一般形式用布尔表达式来指定。因为构造性集合规格说明可以为大集合提供简洁的定义,所以它优于枚举方式。它也显式地定义了用于构造集合的规则。
考虑下面构造性规格说明的例子: {n:N|n<3·n} 这个规格说明中有三个部分:特征n:N,谓词n<3,以及项n。 • 特征描述在形成集合时考虑的值的范围; • 谓词(布尔表达式)定义集合如何被构造; • 项给出了集合中项的一般形式。 在上面例子中,N 表示自然数,这样自然数将被考虑;谓词指出只有小于3的自然数被包含在集合中;项规定集合中每个元素的形式为n。 这样,上面的规格说明定义的集合为: {0,1,2}
当集合元素的形式是明显的时候,项可以省略。例如,上面集合可表示为:当集合元素的形式是明显的时候,项可以省略。例如,上面集合可表示为: {n:N|n < 3} • 上述的集合均只含单项元素。集合元素可以是对,三元组等等,例如,集合规格说明: {x,y:N|x+y=10·(x,y2)} 描述了形为(x,y2)的自然数对的集合,这里x和y 之和是10,下面是此集合: {(1,81),(2,64),(3,49),...}
集合运算符 • 集合中的成员关系:, • 集合间关系: , ,∪ ,∩ • 空集,对应数学中的0。空集具有这样的性质:它是所有其它集合的子集。涉及空集的两个有用的等式是:对任何集合A, ∪A=A 和∩A= 其中,∪被称为并运算符,有时称作“cup”;∩被称为交运算符,有时称作“cap”。
集合差运算符\,顾名思义,结果为从第一个操作数中去掉第二个操作数中的元素而得到的集合。这样,表达式集合差运算符\,顾名思义,结果为从第一个操作数中去掉第二个操作数中的元素而得到的集合。这样,表达式 {New,Old,TaxFile,Sysparam}\{Old,Sysparam} 的结果为集合{New,TaxFile}
叉积(cross product)×,有时也称为笛卡尔积。它以两个集合为操作数,其结果是对的集合,这里每个对由来自第一个操作数的元素和来自第二个操作数的元素构成。下面是包含叉积表达式的例子: {1,2}×{4,5,6} 该表达式的结果为 {(1,4),(1,5),(1,6),(2,4),(2,5),(2,6)}
幂集(powerset),一个集合的幂集是一个其元素是该集合的子集的集合。本章中用来表示幂集运算符的符号是P。它是一个一元运算符,当应用于某集合时,得到其操作数的子集的集合。幂集(powerset),一个集合的幂集是一个其元素是该集合的子集的集合。本章中用来表示幂集运算符的符号是P。它是一个一元运算符,当应用于某集合时,得到其操作数的子集的集合。 例如: P{1,2,3}= {,{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}} 其中所有元素均是集合{1,2,3}的子集。
逻辑运算符 • 形式化方法的另一个重要成分是逻辑:关于真、假表达式的代数。和常见的程序设计语言关联的逻辑运算符是用键盘上已有的符号表示的,和这些符号等价的数学运算符为: ∧与(and) ∨或(or) 非(not) 蕴含(implies)
全称量化是对集合中元素的一种陈述方法,该陈述对集合中每个元素都成立。全称量化使用符号",它的使用的一个例子如下:全称量化是对集合中元素的一种陈述方法,该陈述对集合中每个元素都成立。全称量化使用符号",它的使用的一个例子如下: " i, j: N · i > j i 2 > j 2 该表达式陈述的是:对在自然数集合中的每一个值对,如果i 大于j,则i 的平方大于j 的平方。
序列 • 序列是一种数学结构,用于对元素是有序的这一事实进行建模。一个序列s 是对的集合,其元素的取值范围从1 到最大数。例如, {(1,Jones),(2,Wilson),(3,Shapiro),(4,Estavez)} 是一个序列。形成对的第一个元素的项总称为序列的定义域,第二个元素的聚集称为序列的值域。本书中序列用尖括号指明。例如,上面的序列通常写作: <Jones,Wilson,Shapiro,Estavez> • 和集合不同,序列中的元素允许重复,且序列的顺序是重要的。因此, 〈Jones,Wilson,Shapiro〉≠〈Jones,Shapiro,Wilson〉 • 空序列表示为〈〉。
在形式化规格说明中使用一组序列运算符。连接(Catenation)⌒是一个二元运算符,它通过将第二个操作数加到第一个操作数的尾部而形成新的序列。在形式化规格说明中使用一组序列运算符。连接(Catenation)⌒是一个二元运算符,它通过将第二个操作数加到第一个操作数的尾部而形成新的序列。 例如, 〈2,3,34,1〉⌒〈12,33,34,200〉 的结果为序列〈2,3,34,1,12,33,34,200〉
其他的序列运算符有head, tail, front 和last。运算符head 抽取出序列的第一个元素;tail 返回长度为n 的序列中后面的n-1 个元素所形成的序列; last 抽取出序列的最后一个元素;front 返回长度为n 的序列中前面的n-1 个元素形成的序列。例如, head<2,3,34,1,99,101>=2 tail<2,3,34,1, 99, 101>=<3, 34,1,99, 101> last<2,3,34,1,99,101>=101 front<2,3,34,1,99,101>=<2,3,34,1,99>
因为序列是对的集合,集合运算符均可用于序列。当一个序列被用在状态中时,它应当通过关键字seq 指明。 例如, FileList:seq FILES NoUsers:N 描述了一个具有两个成分的状态:一个文件序列和一个自然数。
应用数学符号描述形式化规格说明 • 为了说明数学表示法在软件构件的形式化规格说明中的使用,我们前面提出的块处理器的例子。回顾一下,计算机操作系统中的一个重要构件维护用户创建的文件。块处理器维护一个未用块池,并同时保持对当前被使用块的跟踪。当块从被删除文件释放时,它们通常被加入到等待进入未用块池的块队列中。这一点如图2 所示。 图2 块处理器
?如何使用前面已经介绍的集合和逻辑运算符来表示状态和数据不变式??如何使用前面已经介绍的集合和逻辑运算符来表示状态和数据不变式? 假定名为BLOCKS的集合包含任意块号,集合AllBlocks 是位于l 和MaxBlocks 间的块的集合。 状态将由两个集合和一个序列来模拟,两个集合分别是used 和free。这两个集合均包含块,used 集合包含当前被文件使用的块,free 包含对新文件可用的块。 序列将包含准备从已删除文件中释放的块的集合。状态可以被描述为: used,free:P BLOCKS BlockQueue:seq P BLOCKS
这和程序变量的声明非常相似,它说明used 和free 是块的集合,BlockQueue 将是一个序列,序列中的元素是块的集合。数据不变式可以描述为: used ∩ free = ∧ used ∪ free = AllBlocks ∧ " i : dom BlockQusue·BlockQueus i used ∧ " i, j : dom BlockQueue·ijBlockQueue i∩BlockQueue j =
我们将定义的第一个操作是从块队列头去除一个元素,前置条件是队列中必须至少有一项:我们将定义的第一个操作是从块队列头去除一个元素,前置条件是队列中必须至少有一项: #BlockQueue>0 后置条件是队列头从队列中去除,并放入自由块集合中,调整队列以显示这一操作: used'=used\head BlockQueue ∧ free' = free ∪ head BlockQueue ∧ BlockQueue' = tail BlockQueue 在许多形式化方法中的一种习惯用法是以操作后的变量值为主,这样,上面给出的表达式的第一行说明新的已用块(used')将等于旧的已用块减去已被去除的块;第二行说明新的自由块(free')将等于旧的自由块加上块队列的头;第三行说明新的块队列将等于旧的块队列的尾,即除了第一个元素外的所有元素的队列。
第二个操作是将一个块集合Ablocks加入到块队列中,前置条件是Ablocks 为当前已用块的集合: Ablocks used 后置条件是块集合被加入到块队列的尾部,同时已用块和自由块的集合均保持不变: BlockQueue' = BlockQueue <Ablocks>∧ used'=used ∧ free'=free 毫无疑问,块队列的数学规格说明比自然语言叙述或图形模型要严格得多,这种严格需要更多的工作,但从一致性和完整性的提高方面得到的好处可在很多类型的应用中得到证明。
形式规格说明语言 • 形式规格说明语言通常由三个主要的成分构成: (1)语法,定义用于表示规格说明的特定表示方法; (2)语义,帮助定义用于描述系统的“对象的全域(universe of objects)”; (3)一组关系,定义确定哪个对象真正满足规格说明的规则。
形式规格说明语言的语法域通常基于从标准集合论表示法和谓词演算导出的语法。例如,变量如x,y,z 描述一组和问题(有时称为论域)相关的对象,并与集合运算符联合使用。虽然语法通常是符号的,但如果图符(如方框、箭头和圆等图形符号)没有歧义性,也可以使用。
规格说明语言的语义域指出语言如何表示系统需求。 例如,程序设计语言有一组形式语义使得软件开发者可以描述将输入转换成输出的算法。 然而,由于程序设计语言只能表示计算功能,所以它并不是好的规格说明语言。
规格说明语言必须有更广的语义域,即,规格说明语言的语义域必须能够表达这样的概念:“对于在无限集A 中的所有x,在无限集B 中存在某个y,使得性质P 对x 和y 成立”[WIN90]。 • 其他规格说明语言可应用于描述系统行为的语义。例如,可以设计一种语法和语义用来描述状态和状态转换、事件和它们对状态转换的影响、同步及定时。
目前已有许多形式规格说明语言在使用。OCL、Z、LARCH、及VDM是具有前面所讲述特性的、具有代表性的形式化规格说明语言。目前已有许多形式规格说明语言在使用。OCL、Z、LARCH、及VDM是具有前面所讲述特性的、具有代表性的形式化规格说明语言。
Z规格说明语言 • Z(正确读音为“zed”)是在过去二十年里发展起来的规格说明语言,已在形式化方法领域中广泛使用。 • 使用Z语言需要具备集合论、函数、数理逻辑等方面的知识。
Z语法及语义 • Z规格说明由一组格(schema,盒子式的结构)组成,用于说明变量及这些变量之间的关系。一个schema 实质上类似于程序设计语言构件的形式化规格说明。 • 一个schema描述系统存取及修改的存储数据。在Z语言中被称为“状态”。Schema能够标识系统内用于改变状态及关系的操作。
schema的一般结构如下: 其中,声明表示组成系统状态的变量,不变式对状态演变的方式进行约束。
集合(Sets): S∶P X S 被声明为X 的集合。 x S x 是S 中的成员。 x S x 不是S 中的成员。 S T S 是T 的子集:S 的每个元素均在T 中。 S T S 和T 的并:包含在S 或T 或二者中的每个元素。 S T S 和T 的交:包含同时在S 和T 中的元素。 S \T S 和T 的差:包含在S 中的而不在T 中的每个元素。 空集:不包含任何成员。 {x} 单元素集:只包含x。 N自然数集合: 0,1, 2,…。 S∶F XS 被声明为X 的有限集。 max(S) 非空的数字集合S 中的最大者。
函数(Functions): f∶X Y f 被声明为从X 到Y 的部分内射。 dom f f 的定义域:定义f(x)的x 的值集。Z表示法小结 ran f f 的值域:当x 在f 的定义域上变化时,f(x)的值集。 f {x y} 与f 相同的函数,除了x 被映射到y。 {X}f 一个和f 相似的函数,除了x 被从定义域中去除。 逻辑(Logic): P∧Q: P and Q:P 与Q 都为真时,其值为真。 P Q P 蕴含Q:或者Q 为真或者P 为假时,其值为真。 θS'=θS 在操作中,schema S 中没有成分改变。