在exercise_1a
中可以做些什么来使断言cnt > 0
有效?
method exercise_1a(n: int)
requires n > 0
{
var idx := 0;
var cnt := 0;
while idx < n
decreases n - idx
{
idx := idx + 1;
cnt := cnt + 1;
}
assert idx > 0; // valid
assert cnt > 0; // *** invalid ***
}
令人惊讶的是,该版本也使断言idx > 0
无效:
method exercise_1b(n: int)
requires n > 0
{
var idx := 0;
var cnt := 0;
while idx < n && cnt < n
decreases n - idx
decreases n - cnt
{
idx := idx + 1;
cnt := cnt + 1;
}
assert idx > 0; // *** invalid ***
assert cnt > 0; // *** invalid ***
}
答案 0 :(得分:1)
在您的第一段代码中,当while
循环退出时,Dafny只知道!(idx < n)
。因此,它可以推断出idx > 0
。但是,Dafny目前对cnt
变量一无所知,因此您的第二个断言失败。
在第二段代码中,当while
循环退出时,Dafny知道的只是!(idx < n && cnt < n)
(同样,while
循环上条件的否定)。这等效于idx > n || cnt > n
。 Dafny可以从那里推断出idx > 0 || cnt > 0
,但无法独自证明idx > 0
或cnt > 0
。
要解决此问题,您需要在Dafny可以检查然后使用的变量cnt
和idx
之间添加一些关系。
while idx < n && cnt < n
decreases n - idx
decreases n - cnt
invariant idx == cnt
{
idx := idx + 1;
cnt := cnt + 1;
}
多余的invariant
行告诉Dafny检查idx == cnt
将在循环的每次迭代中保持不变,然后可以在末尾使用该事实。但是,除非您告知事实,否则达夫妮不知道要考虑事实idx == cnt
。
(作为旁注,您会看到Dafny 能够自行确定n > 0
在while
循环的末尾成立,即使您没有像在invariant
中那样明确指定它,这是因为n
并没有在while循环的主体中进行修改,所以Dafny会自动发现n > 0
从一开始。)