Dafny-检查数组值是否唯一,但嵌套的所有嵌套值都不由循环维护

时间:2019-10-02 00:53:27

标签: dafny

我正在检查某个键是否仅在数组中显示一次(其中b是返回值),但是以下不变量表示它不是由循环维护的:

invariant b <==> exists j | 0 <= j < i :: a[j] == key && forall k | 0 <= k < i && j != k :: a[k] != key

循环继续如下

  var i := 0;
  b := false;
  var keyCount := 0;
  while i < a.Length
  invariant 0 <= i <= a.Length
  invariant b <==> exists j | 0 <= j < i :: a[j] == key && forall k | 0 <= k < i && j != k :: a[k] != key
  {
    if (a[i] == key)
    { keyCount := keyCount + 1; }
    if (keyCount == 1)
    { b := true; }
    else
    { b := false; }
    i := i + 1;
  }

在我看来,逻辑很合理-我缺少什么吗?

1 个答案:

答案 0 :(得分:1)

在我的设置中,Dafny在尝试验证给定的循环不变式时超时。但是,我认为您可以通过将循环不变式替换为更强的不变式来完成您想要的事情:

invariant multiset(a[..i])[key] == keyCount
invariant b <==> (keyCount == 1)

第一个陈述为在包含a的第i个元素的多重集中,键的数量等于计算出的keyCount。第二个与bkeyCount相关。完整的解决方案如下:

method only_once<a(==)>(a: array<a>, key: a)
{
  var i := 0;
  var b := false;
  var keyCount := 0;
  while i < a.Length
  invariant 0 <= i <= a.Length
  invariant multiset(a[..i])[key] == keyCount
  invariant b <==> (keyCount == 1)
  {
    ghost var preCount := keyCount;
    if (a[i] == key)
    { keyCount := keyCount + 1; }
    if (keyCount == 1)
    { b := true; }
    else
    { b := false; }
    i := i + 1;
  }
  assert a[..a.Length] == a[..];
  assert b <==> multiset(a[..])[key] == 1;
}

我相信最后的主张就是你想要的。我不确定Dafny为什么需要倒数第二个断言a[..a.Length] == a[..],但是删除它会导致最后一个断言的验证失败。