我正在检查某个键是否仅在数组中显示一次(其中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;
}
在我看来,逻辑很合理-我缺少什么吗?
答案 0 :(得分:1)
在我的设置中,Dafny在尝试验证给定的循环不变式时超时。但是,我认为您可以通过将循环不变式替换为更强的不变式来完成您想要的事情:
invariant multiset(a[..i])[key] == keyCount
invariant b <==> (keyCount == 1)
第一个陈述为在包含a的第i个元素的多重集中,键的数量等于计算出的keyCount
。第二个与b
和keyCount
相关。完整的解决方案如下:
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[..]
,但是删除它会导致最后一个断言的验证失败。