我想实现一个方法,它接受一个输入字符数组,并以相反的顺序输出另一个由输入数组组成的数组。但我得到错误"索引我们的范围"并且"发布条件可能不成立" 我不知道发生了什么
这是我的代码:
predicate reversed (arr : array<char>, outarr: array<char>)
requires arr != null && outarr != null
//requires 0<=k<=arr.Length-1
reads arr, outarr
{
forall k :: 0<=k<=arr.Length-1 ==> outarr[k] == arr[(arr.Length-1-k)]
}
method yarra(arr : array<char>) returns (outarr : array<char>)
requires arr != null && arr.Length > 0
ensures outarr != null && reversed(arr,outarr)
{
var i:= 0;
var j:= arr.Length-1;
outarr := new char[arr.Length];
outarr[0] := arr[j];
i := i+1;
j := j-1;
while i<arr.Length && 0<=j<arr.Length
invariant 0<=i<=arr.Length
decreases arr.Length-i, j
{
outarr[i] := arr[j];
i:=i+1;
j:=j-1;
}
//return outarr;
}
method Main()
{
var s := ['a','b','a','b','a','b','a','b','a','b','a','b'];
var a,b,c,d := new char[5], new char[5], new char[5], new char[5];
a[0], a[1], a[2], a[3], a[4] := 'y', 'a', 'r', 'r', 'a';
d[0], d[1], d[2], d[3], d[4] := 'y', 'a', 'r', 'r', 'a';
b := yarra(a);
c := yarra(b);
assert c[..] == a[..];
//assert c.Length > -2;
//assert d[0] == a[0];
//print c; print a;
}
这是可能无法保留的后置条件。 13 26
stdin.dfy(6,43):错误:索引超出范围
stdin.dfy(21,2):错误BP5003:后退条件可能不适用于此返回路径
stdin.dfy(13,26):相关位置:这是可能无法保留的后置条件
stdin.dfy(6,2):相关位置
stdin.dfy(6,47):相关位置
答案 0 :(得分:0)
Here是您验证的程序版本。
有一些问题需要解决。
首先,您对reversed
的定义形成不良,因为Dafny无法看到访问outarr[k]
在界限内。我通过向arr.Length == outarr.Length
添加前置条件reversed
来解决此问题。
接下来,需要在调用reversed
的任何地方考虑新的前提条件。唯一这样的地方位于yarra
的后置条件中,我通过添加额外的后置条件arr.Length == outarr.Length
来修复。
然后,Dafny抱怨reversed
的后置条件可能不会在yarra
中保留。这需要加强循环不变量。这是一个典型的例子,我们试图通过逐个建立每个索引来证明一个数组的所有索引。在这种情况下,正确的循环不变量是“我已经在每个小于当前索引的索引处建立了它”。我们在这个循环中建立的东西是outarr[k] == arr[arr.Length-1-k]
,所以正确的不变量是:
forall k | 0 <= k < i :: outarr[k] == arr[arr.Length-1-k]
最后,要实现这一点,我们需要不变的j == arr.Length - 1 - i
。 (事实上,这个不变量意味着我们可以完全摆脱j
,但我并不打算这样做。)