290 likes | 433 Views
三、净室软件开发. 赵建华 南京大学计算机系. 盒式结构开发. 设计过程或者算法,实现状态盒,使之展现出正确的外部行为。 是一个自顶向下的迭代过程。 从黑盒到状态盒之间的的转化存在一对多的关系: 数据状态信息 vs 控制状态信息 状态盒到明盒之间也存在着一对多的关系。. 明盒的结构. 明盒和相应的状态和之间具有相同的输入、响应集、外部行为和状态。 明盒的设计可以 复用已有的黑盒, 引入新的黑盒 定义临时数据 对于复杂的算法,状态盒需要完整的明盒分析,设计和正确性验证。. 明盒的控制结构( 1 ). 明盒的控制结构可以分成三类: 顺序 选择 循环.
E N D
三、净室软件开发 赵建华 南京大学计算机系
盒式结构开发 • 设计过程或者算法,实现状态盒,使之展现出正确的外部行为。 • 是一个自顶向下的迭代过程。 • 从黑盒到状态盒之间的的转化存在一对多的关系: • 数据状态信息vs控制状态信息 • 状态盒到明盒之间也存在着一对多的关系。
明盒的结构 • 明盒和相应的状态和之间具有相同的输入、响应集、外部行为和状态。 • 明盒的设计可以 • 复用已有的黑盒, • 引入新的黑盒 • 定义临时数据 • 对于复杂的算法,状态盒需要完整的明盒分析,设计和正确性验证。
明盒的控制结构(1) • 明盒的控制结构可以分成三类: • 顺序 • 选择 • 循环
明盒的控制结构(2) • 图中的方框表示功能点,菱形表示判定节点,圆圈表示控制流的汇合点 • 功能点可以将当前状态作为输入,并产生新的状态。 • 判定节点可以访问当前状态,但是不能改变状态。 • 圆圈点只是表示控制流的汇合,不做任何操作。 • 每一种控制结构都只有唯一的入口和唯一的出口。
明盒的抽象化和文档化 • 理解明盒时,应该考虑其从控制结构入口到控制结构出口对数据的影响。这个过程可以表示成为函数。 • 即新状态/输入和旧状态/输出之间的函数关系。
明盒的函数意义的例子 这些函数是对执行程序的抽象描述,它和程序的具体执行无关。也就是说,无论程序是如何运行的,它结束时必然满足这样的函数关系。
明盒设计的层次特性 g h k i
明盒函数的设计 • 明盒的设计从状态盒的规范不断地精化预期的函数。 • 采用自顶向下,逐步精化的原则。 • 每一步精化中,被精化的函数作为预期的函数,精化得到某种控制结构。
明盒的正确性问题 • 基于数学的方法证实一个过程与其规范相符。 • 过程的正确性证明通过其它形式来验证,通常称为函数理论正确性验证。 • 通常对于每一步精化,都需要回答一些问题来验证正确性。对于不同的控制结构,有不同的问题要回答。 • 顺序结构为1个,分支结构为2个,循环结构为3个。
控制结构的正确性问题(1) • 顺序结构
控制结构的正确性问题(2) • If-then-else结构
控制结构的正确性问题(3) • whiledo结构
控制结构的正确性问题(4) • dountil结构
关于循环的验证问题 • 循环的验证可以通过两种方式来验证 • 转换成为递归的if-then-else结构:将whiledo结构转换成为执行效果和原来一样的选择结构。 • 使用循环不变式:找出一种关系,使得它在循环的执行过程中总是成立。然后证明当循环结束时,这个关系蕴含了函数f。
循环的结构转换证明 • 首先将while p do g enddo转换为if p then g; while p do g endif,然后转换为if p then g;f endif • 然后检验这个if-then结构和f等价 g f g p p g p g p
循环的结构转换证明(2) • 例子
循环不变式方法 • 适用于更加具体的描述。证明更加严格。 • 是理解循环的重要手段。有时需要和类不变式以及全局不变式一起使用。 • 即使是一般编写程序,也需要考虑到不变式的问题。 • 对于while p do g enddo,假设有循环不变式I,我们需要证明 • p(x) and I(x)=>I(g(x)),且 • not p(x) and I(x)=>我们想要的性质
循环不变式方法 • 例如: • while x>1 do • x:=x-2; • enddo • 不变式如下: • x mod 2 = x0 mod 2 and x>=0 • 其中x0表示程序运行到while语句入口时的值。 • 显然,这个不变式总是成立的。 • 而当x<=1时,x要么是1,要么是0,因此满足前面的规约 • (initial x odd x:=1 | • initial x even x:=0)
另一个例子 • for(i=0;i<10;i++) • A[i] = A[i]+1; • 在循环体开始处的不变式是: • forall j(0<= j < i)A[j]=A0[j]+1 • 因此,这个程序片断的效果是 • 使得A中所有下标小于10的元素都增加1。 • 下面的例子呢?如果A是指针数组的情况 • for(i=0;i<10;i++) *(A[i]) = *(A[i])+1;
另一个循环不变式的例子 • Floyd最短路径算法 • for (k=0;k<n;k++) for (i=0;i<n;i++) for (j=0;j<n;j++) if (D[i][j]>D[i][k]+D[k][j]) D[i][j]=D[i][k]+D[k][j]; • 在第一层循环的开始处的不变式是: • D[i][j]表示从i开始到j,不经过大于等于k的节点的路径的最短长度。
正确性验证的较大的例子(1) • 根据职员序号搜索职员的下标,emp数组按照id的升序排列 [如果有可能, 将i设置为满足emp(i)=id且1<=i<=n的值,否则将i设置为0] procedure search(id,i:integer;emp(1..n):array of integer) bot, top,mid:integer i:=0; bot:=1; top:=n; [如果有可能,将i设置为满足emp(i)=id且 bot<=i<=top的值,否则i的值不变] while bot <=top and i == 0 [如果id==emp((bot+top)/2), 将i设置为(bot+top)/2, 否则如果id>emp(bot+top)/2,将bot设置为(bot+top)/2+1 否则如果id<emp((bot+top)/2), 将top设置为(bot+top)/2-1] do mid := (bot+top)/2; if emp(mid)=id then i:=mid else if emp(mid)<id then bot:=mid+1 else top:=mid-1 endif endif enddo
正确性验证的较大的例子(2) • 从总体的顺序结构(三个赋值语句和一个while结构),我们可知它实现了规约。 i:=0; bot:=1; top:=n; [如果有可能,将i设置为满足emp(i)=id且 bot<=i<=top的值, 否则i的值不变] • 对于while结构,我们证明: while bot <=top and i == 0 [如果id==emp((bot+top)/2), 将i设置为(bot+top)/2, 否则如果 id>emp((bot+top)/2),将bot设置为(bot+top)/2+1 否则如果 id<emp((bot+top)/2),将top设置为(bot+top)/2-1] 等价于: [如果有可能,将i设置为满足emp(i)=id且 bot<=i<=top的值,否则i的值不变] 1、首先,循环会终止(因为bot和top之间的差越来越小,最终会成为负数) 2、我们将这个循环展开成if的形式,并考虑条件为真的情况: [如果id==emp((bot+top)/2), 将i设置为(bot+top)/2, 否则如果 id>emp((bot+top)/2),将bot设置为(bot+top)/2+1 否则如果 id<emp((bot+top)/2),将top设置为(bot+top)/2-1] [如果有可能,将i设置为满足emp(i)=id且 bot<=i<=top的值,否则i的值不变] 可以验证这个情况和预期函数等价。
正确性验证的较大的例子(2) • 如果使用不变式方法: • 进入循环体时,所有第1到bot-1的元素都不等于id,且第top+1到n个的元素都不等于id。 • 离开循环体时,i== (bot+top)/2 && emp[i] ==id 或者 emp[(bot+top)/2 ] != id && i==0
安全报警器的例子 • 使用基于状态数据的高层开关结构 • 状态变量的实现方法如下: • Set激励激活设备,之后Light_Status为on • AlarmManager中AlarmStatus实现状态变量Alarm • CodeManager中,EngryStatus实现状态变量Code
主循环 #SB 9 while (Event != Stop) do get(Event); switch(Event): case (SET); #SB 10-17:处理SET信号的规则 case(TRIPSIGNAL); #SB 1-8:处理Trip的情况 AlarmManager(Query, SecurityStatus); if(SecurityStatus = CLEAR) then AlarmManager(Start); #SB 1,3,4,7:应该激励起ALARM的情况 codeManager(Alert, Event); #SB 4,7:将Code设置为Error的情况 else do nothing; #SB2,5,6,8:不处理的情况 endif default #SB 18-37:处理BadDigit的情况 CodeManager(Evaluate,Event); #code manager will return STOP if code entry is complete endswitch enddo
处理Trip的要求 • 表3.10:对于Trip的状态盒设计
处理Trip的程序 case(TRIPSIGNAL); #SB 1-8:处理Trip的情况 AlarmManager(Query, SecurityStatus); if(SecurityStatus = OFF) then AlarmManager(Start); #SB 1,3,4,7: codeManager(Alert, Event); #SB 4,7: else do nothing; #SB2,5,6,8:不处理的情况 endif • AlarmManager(Query, SecurityStatus)将SecurityStatus设置为AlarmStatus的值。 • codeManager(Alert, Event)在EntryStatus=1_OK或者2_OK的时候将EntryStatus设置为ERROR。 • 我们可以根据各个值的不同,来检查这些程序是否满足状态盒中的归约。