Dafny量词在面对测试数据时没有得到实例化

时间:2016-05-10 04:12:35

标签: dafny

我正在尝试在dafny中创建一个谓词,用于确定字符数组是否包含任何重复项。它应该最终测试以下内容:对于数组中的任何两个元素,如果theor值相等,它们的索引也必须相等。请忽略少于2个元素的情况

predicate noDuplicates (a:array<char>)
requires a!= null
reads a
{
forall j,k:: (0<=j<a.Length && 0<=k<a.Length) ==> ((a[j]==a[k]) ==> (j==k))
}

然而,当我运行以下测试时,它无法断言。为什么会这样?

var b: array<char> := new char[5];
b[0], b[1], b[2], b[3], b[4] := 't', 'e', 's', 't', 's';
assert noDuplicates(b) == false; 

1 个答案:

答案 0 :(得分:0)

我认为问题在于解析器图中没有任何内容可供dafny用实例化量词。您可以通过添加额外的断言来验证它,以便Dafny能够使用这些值来实例化量词。

例如:

method Main() {
    var b: array<char> := new char[5];
    b[0], b[1], b[2], b[3], b[4] := 't', 'e', 's', 't', 's';
    assert b[0] == 't';
    assert b[3] == 't';
    assert noDuplicates(b) == false;
}

或者这个

method Main() {
    var b: array<char> := new char[5];
    b[0], b[1], b[2], b[3], b[4] := 't', 'e', 's', 't', 's';
    assert b[0] == b[3];
    assert noDuplicates(b) == false;
}

为什么会这样?

通常当Dafny需要证明涉及量词的东西时,它必须选择值来实例化量化器(由于减少到SAT)。它通常会尝试的一件事是一个新鲜的任意常数,但这不会让你在这里走得很远。您需要它来选择值0和3(例如)。然而,有很多整数,所以随机选择这些值的机会很低 - 这么低,实际上它甚至不会尝试。它的作用是查看它已经知道的任何事实,并挑选出与量化公式中的原子形状相匹配的任何事实。在这种情况下,它正在查找a[i]==a[j]之类的内容 - 所以通过引入涉及b[0]b[3]的断言,提示Dafny最终尝试值0和{{1 } {} {}}和3。直接版本i非常直接,而间接版本j会间接导致Dafny在其egraph中放置b[0]==b[3]b[0]==t && b[3]==t之间的边缘并推断事实{{1然后会提示它尝试b[0]b[3]来实例化量化器。

我很想知道任何其他解决方案。

修改

我想到了另一个解决方案using the fuel annotation,但我不知道它是否真的是更好的解决方案:

b[0]==b[3]