Dafny,Dutch Flag,循环不变量可能不会被循环维护

时间:2018-05-23 10:07:58

标签: z3 verification dafny

在下面的程序中我创建了类似荷兰国旗问题的东西,并遵循同样的逻辑,也提供了here 程序以0s,1s和2s的数组排序,中间的开头0s和结尾的2s都是1。 [1,1,1,0,0,2,2,2]。 但是在循环不变量中,我收到错误This loop invariant might not be maintained by the loop.

最初,ij位于索引0,k位于最后一个索引处。逻辑是,如果j看到2则向上移动,与k交换,如果看到0,j向上移动,则会减少;如果看到1与i交换,i和{ {1}}增加。

代码也在rise4fun

j

这里有 method sort(input: array?<int>) modifies input requires input !=null; requires input.Length>0; requires forall x::0<=x<input.Length ==> input[x]==0||input[x]==1||input[x]==2; ensures sorted(input); { var k: int := input.Length; var i, j: int := 0 , 0; while(j != k ) invariant 0<=i<=j<=k<=input.Length; /* the following invariants might not be maintained by the loop.*/ invariant forall x:: 0<=x<i ==> input[x]==1; invariant forall x:: i<=x<j ==> input[x]==0; invariant forall x:: k<=x<input.Length ==> input[x]==2; invariant forall x:: j<=x<k ==> input[x]==0||input[x]==1||input[x]==2; decreases if j <= k then k - j else j - k { if(input[j] == 2){ swap(input, j, k-1); k := k - 1; } else if(input[j] == 0){ j := j + 1; } else { swap(input, i, j); i:= i + 1; j := j + 1; } } } 方法和swap谓词

sorted

1 个答案:

答案 0 :(得分:2)

问题是swap没有后置条件。默认后置条件为true,因此swap的规范表明它以任意方式更改数组。

当验证者在方法swap的主体中看到对sort的调用时,它只关注swap的规范 - 而不是它的正文。因此,在调用swap之后,数组中可以包含任何值,至少就验证者所知。因此,无法证明任何与数组内容相关的不变量都无法证明。

swap的以下规范应该有效:

method swap(input: array?<int>, n:int, m:int)
    modifies input;
    requires input!=null;
    requires input.Length>0;
    requires 0<=n<input.Length && 0<=m<input.Length
    ensures n < m ==> input[..] == old( input[0..n] + [input[m]] + input[n+1..m] + [input[n]] + input[m+1..] ) ;
    ensures n==m ==> input[..] == old(input[..])
    ensures n > m ==> input[..] == old( input[0..m] + [input[n]] + input[m+1..n] + [input[m]] + input[n+1..] ) ;

这应该是

method swap(input: array?<int>, n:int, m:int)
    modifies input;
    requires input!=null;
    requires input.Length>0;
    requires 0<=n<input.Length && 0<=m<input.Length
    ensures input[n] == old( input[m] ) ;
    ensures input[m] == old( input[n] ) ;
    ensures forall i | 0 <= i < input.Length && i != n && i != m :: input[i] == old(input[i])