Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 方法前提条件在对数组中的方法值唯一性进行4次调用后失败_Arrays_Dafny - Fatal编程技术网

Arrays 方法前提条件在对数组中的方法值唯一性进行4次调用后失败

Arrays 方法前提条件在对数组中的方法值唯一性进行4次调用后失败,arrays,dafny,Arrays,Dafny,我正在尝试编写一个dafny程序,它有一个固定大小的数组。如果此数组尚未填充,并且正在添加的值在数组中不存在,则可以通过方法将其添加到。起初它似乎运行良好,但是,当我调用该方法超过4次时,我得到一个错误 SimpleTest.dfy(37,15): Error: A precondition for this call might not hold. SimpleTest.dfy(17,23): Related location: This is the precondition that mi

我正在尝试编写一个dafny程序,它有一个固定大小的数组。如果此数组尚未填充,并且正在添加的值在数组中不存在,则可以通过方法将其添加到。起初它似乎运行良好,但是,当我调用该方法超过4次时,我得到一个错误

SimpleTest.dfy(37,15): Error: A precondition for this call might not hold.
SimpleTest.dfy(17,23): Related location: This is the precondition that might not hold.
Execution trace:
    (0,0): anon0
这突出显示了行
需要x!在以下MCVE的arr[…]

为什么先决条件在方法被调用超过四次后开始失败?无论阵列的固定大小有多大,这种情况似乎都会发生

class {:autocontracts} Test
{
    var arr: array<nat>;
    var count: nat;

    constructor(maxArrSize: nat)
        requires maxArrSize > 1
        ensures count == 0
        ensures arr.Length == maxArrSize
        ensures forall i :: 0 <= i < arr.Length ==> arr[i] == 0
    {
        arr := new nat[maxArrSize](_ => 0);
        count := 0;
    }

    method AddIn(x: nat)
        requires x !in arr[..]
        requires x > 0
        requires 0 < arr.Length
        requires count < arr.Length
        ensures arr[..] == old(arr[.. count]) + [x] + old(arr[count + 1 ..])
        ensures count == old(count) + 1
        ensures arr == old(arr)
    {
        arr[count] := x;
        count := count + 1;
    }
}

method Main()
{
    var t := new Test(20);
    t.AddIn(345);
    t.AddIn(654);
    t.AddIn(542);
    t.AddIn(56);
    t.AddIn(76);
    t.AddIn(8786);
    print t.arr[..];
    print "\n";
    print t.count;
    print " / ";
    print t.arr.Length;
    print "\n";
}
class{:autocontracts}测试
{
var-arr:数组;
var计数:nat;
构造函数(maxArrSize:nat)
需要maxArrSize>1
确保计数=0
确保阵列长度==最大阵列大小
确保所有i::0 arr[i]==0
{
arr:=新nat[maxArrSize](=>0);
计数:=0;
}
方法AddIn(x:nat)
在arr[…]中需要x
需要x>0
要求0<阵列长度
要求计数<阵列长度
确保arr[…]==old(arr[…count])+[x]+old(arr[count+1..)
确保计数==旧(计数)+1
确保arr==旧(arr)
{
arr[count]:=x;
计数:=计数+1;
}
}
方法Main()
{
var t:=新试验(20);
t、 艾丁(345);
t、 艾丁(654);
t、 艾丁(542);
t、 艾丁(56);
t、 艾丁(76);
t、 艾丁(8786);
打印t.arr[…];
打印“\n”;
打印t.count;
打印“/”;
打印t.arr.Length;
打印“\n”;
}

为了证明该方法的先决条件,验证器必须经历许多情况,每个情况都使用堆、序列和构造函数后置条件中的量词的属性。这些情况似乎耗尽了验证器的一些限制,因此您得到了一个错误,即它无法证明某些东西

您可以通过编写一些断言来帮助验证者。这些断言还将确认您自己对程序正在构建的程序状态的理解。例如,如果添加这些
assert
语句,验证器将确认断言并能够证明整个程序

method Main()
{
  var t := new Test(20);
  assert t.arr[..] == seq(20, _ => 0);
  t.AddIn(345);
  assert t.arr[..] == [345] + seq(19, _ => 0);
  t.AddIn(654);
  assert t.arr[..] == [345, 654] + seq(18, _ => 0);
  t.AddIn(542);
  assert t.arr[..] == [345, 654, 542] + seq(17, _ => 0);
  t.AddIn(56);
  assert t.arr[..] == [345, 654, 542, 56] + seq(16, _ => 0);
  t.AddIn(76);
  assert t.arr[..] == [345, 654, 542, 56, 76] + seq(15, _ => 0);
  t.AddIn(8786);
  assert t.arr[..] == [345, 654, 542, 56, 76, 8786] + seq(14, _ => 0);
  print t.arr[..];
  print "\n";
  print t.count;
  print " / ";
  print t.arr.Length;
  print "\n";
}
您不需要所有这些断言,但我将它们留在这里,以便您可以看到一般形式

使用这些附加断言进行验证的原因是,每个断言都可以相当容易地从前面的断言中得到证明。因此,附加的断言会使验证者更快地找到证据(尤其是在验证者放弃之前找到证据)

顺便说一句,您对
Test
类的说明揭示了
Test
对象的内部表示。如果可以对调用者隐藏这些细节,通常会得到更多的信息隐藏、更好的规范以及更好的验证程序性能。要做到这一点,您需要添加一个对象不变量(按照习惯在Dafny中编码为
Valid()
谓词)。我有很多要解释的。但是我看到您已经在使用
{:autocontracts}
,所以您可能知道一些关于这方面的事情。因此,在不作进一步解释的情况下,下面是您的类的规范在更抽象的形式中的样子

class {:autocontracts} Test
{
  // The public view of the Test object is described by the following two fields:
  ghost var Contents: seq<nat>
  ghost var MaxSize: nat
  // The private implementation of the Test object is given in terms of the
  // following fields. These fields are never mentioned in pre/post specifications.
  var arr: array<nat>
  var count: nat

  predicate Valid() {
    count <= arr.Length == MaxSize &&
    Contents == arr[..count]
  }

  constructor(maxArrSize: nat)
    ensures Contents == [] && MaxSize == maxArrSize
  {
    arr := new nat[maxArrSize];
    Contents, MaxSize, count := [], maxArrSize, 0;
  }

  method AddIn(x: nat)
    requires x !in Contents
    requires |Contents| < MaxSize
    ensures Contents == old(Contents) + [x] && MaxSize == old(MaxSize)
  {
    arr[count], count := x, count + 1;
    Contents := Contents + [x];
  }
}

method Main()
{
  var t := new Test(20);
  t.AddIn(345);
  t.AddIn(654);
  t.AddIn(542);
  t.AddIn(56);
  t.AddIn(76);
  t.AddIn(8786);
  print t.arr[..], "\n";
  print t.count, " / ", t.arr.Length, "\n";
}
class{:autocontracts}测试
{
//测试对象的公共视图由以下两个字段描述:
重影变量内容:seq
ghost var MaxSize:nat
//测试对象的私有实现是根据
//以下字段。这些字段在前/后规范中从未提及。
var-arr:数组
变量计数:nat
谓词有效(){

谢谢你的回答。我知道
Valid
谓词,它实际上在我的主程序中使用,只是没有用于这一部分。虽然我不知道ghost-var,所以这真的很有用。