我在达夫尼遇到一个奇怪的问题。我尝试在此处尽可能提取它:https://rise4fun.com/Dafny/F7sK
问题是,在修改 truthAssignment 之后,即使 stack.valid 不知道, stack.valid 也会失败> truthAssignment 。
assert stack.valid();
truthAssignment[variable] := 1;
assert stack.valid(); // assertion violation
答案 0 :(得分:2)
Dafny无法验证断言assert stack.valid();
的原因是valid()
正文中的最后一个合词:
(forall c :: c in contents ==>
exists i,j :: 0 <= i < stack.Length
&& 0 <= j < |stack[i]|
&& stack[i][j] == c)
它的形式为forall ... exists ...
,对于验证者来说很难证明这种条件是不变的。一旦确定这是valid()
验证者无法证明的部分(例如,您可以通过手动内联valid()
的定义来代替断言来做到),然后解决方案是为验证者提供一些帮助。
当验证者(或人类)试图证明forall c :: P(c)
形式的某物时,则组成任意c
,然后尝试证明“ {{ 1}}”。 (逻辑学家将此规则称为“通用介绍”。)很简单。然后,为了证明格式为P(c)
,验证者将寻找“ exists i,j :: Q(i,j)
”的见证人。 (这被称为“现有介绍”。)这里,验证者不是特别有创造力,经常需要帮助。有时,您必须自己弄清楚一些Q(i,j)
和i
,然后断言j
。在其他时候,只需提及所需的Q(i,j)
的某些组成部分,然后验证程序将找出其余的部分。确切地讲,这可能是一个反复试验的过程。
James做出上述补救措施的原因是,它在更新Q(i,j)
之后提到了stack.stack[..]
。这以使验证者看到光线的方式使验证者挠痒痒。只需编写琐碎证明的断言即可:
truthAssignment[variable] := 1;
在这种情况下,更新后也可以使用。
Rustan
答案 1 :(得分:1)
以下内容可为我验证:
assert stack.valid();
ghost var old_stack := stack.stack[..];
truthAssignment[variable] := 1;
assert stack.stack[..] == old_stack;
assert stack.valid();
我真的不明白为什么会这样,但是它属于“序列的相等性对达夫尼而言很难”的一般类别。