Dafny方法返回反转字符数组

时间:2017-05-21 07:09:48

标签: arrays dafny

我想实现一个方法,它接受一个输入字符数组,并以相反的顺序输出另一个由输入数组组成的数组。但我得到错误"索引我们的范围"并且"发布条件可能不成立" 我不知道发生了什么

这是我的代码:

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;
}
  1. 错误1索引超出范围6 43
  2. 错误2后退条件可能不适用于此返回路径。 21 2
  3. 这是可能无法保留的后置条件。 13 26

    stdin.dfy(6,43):错误:索引超出范围
    stdin.dfy(21,2):错误BP5003:后退条件可能不适用于此返回路径 stdin.dfy(13,26):相关位置:这是可能无法保留的后置条件 stdin.dfy(6,2):相关位置
    stdin.dfy(6,47):相关位置

1 个答案:

答案 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,但我并不打算这样做。)