在进行基本线性搜索时,遇到了Valid()谓词错误。它似乎仅在我取消构造函数和数据方法上的附加ensure语句时才起作用。也就是说,当我对内容非常明确时。
如果找不到该项目,我也会遇到搜索后置条件的问题。
有关如何解决这些问题的任何建议吗?
class Search{
ghost var Contents: set<int>;
var a : array<int>;
predicate Valid()
reads this, a;
{
a != null &&
a.Length > 0 &&
Contents == set x | 0 <= x < a.Length :: a[x]
}
constructor ()
ensures a != null;
ensures a.Length == 4;
//ensures a[0] == 0;
ensures Valid();
{
a := new int[4](_ => 0);
Contents := {0};
new;
}
method data()
modifies this, a;
requires Valid();
requires a != null;
requires a.Length == 4;
ensures a != null;
ensures a.Length == 4;
// ensures a[0] == 0;
// ensures a[1] == 1;
// ensures a[2] == 2;
// ensures a[3] == 3;
ensures Valid();
{
a[0] := 0;
a[1] := 1;
a[2] := 2;
a[3] := 3;
Contents := {0, 1, 2, 3};
}
method search(e: int) returns (r: bool)
modifies this, a;
requires Valid();
ensures Valid();
ensures r == (e in Contents)
ensures r == exists i: int :: 0 <= i < a.Length && a[i] == e
{
var length := a.Length - 1;
while (length >= 0)
decreases length;
{
var removed := a[length];
if (e == removed)
{
return true;
}
length := length - 1;
}
return false;
}
}
method Main()
{
var s := new Search();
s.data();
}
答案 0 :(得分:0)
这里有几个正交问题。
首先,您注意到Dafny不愿意推断描述Valid
的{{1}}部分。在推理Dafny中的集合时,这是一个常见问题。从本质上讲,Dafny将“注意到”某些东西是集合Contents
的成员的唯一方法是它是否已经在某个地方放置了表达式set x | 0 <= x < a.Length :: a[x]
。包含额外后置条件的解决方案之所以有效,是因为它提到了a[x]
形式的大量表达式。另一种解决方案是将这些事实包括为断言而不是后置条件:
a[x]
其次,Dafny无法证明您的// in data()
assert a[0] == 0;
assert a[1] == 1;
assert a[2] == 2;
assert a[3] == 3;
程序满足其后置条件。您需要一个循环不变量来跟踪搜索的进度。有关如何设计循环不变量的更多信息,请参阅guide。
第三,Dafny报告了search
关于修改子句的问题。您可以通过向Main
添加后置条件fresh(a)
来解决此问题。这里的问题是constructor
方法声称要修改data
,但Dafny无法判断调用者是否可以看到a
。