我如何帮助Dafny证明以下两个断言是相同的:
# A tibble: 46 x 10
game_pk atBatIndex launchSpeed launchAngle totalDistance trajectory hardness location coordX coordY
<chr> <int> <dbl> <dbl> <dbl> <chr> <chr> <chr> <dbl> <dbl>
1 565711 4 76.6 2.74 188. ground_ball medium 9 178. 145.
2 565711 5 101. 15.4 328. line_drive hard 8 145. 62.2
3 565711 6 103. 29.4 382. line_drive medium 9 237. 79.4
4 565711 8 109. 15.6 319. line_drive hard 9 181. 102.
5 565711 9 75.8 47.8 239. fly_ball medium 7 99.8 103.
6 565711 10 91.6 44.1 311. fly_ball medium 8 140. 69.3
7 565711 12 79.1 23.4 246. line_drive medium 7 52.3 126.
8 565711 13 67.3 -21.3 124. ground_ball medium 6 108. 156.
9 565711 14 89.9 -21.6 7.41 ground_ball medium 6 108. 152.
10 565711 15 110. 27.7 420. fly_ball medium 9 250. 69.0
# … with 36 more rows
而且,Dafny似乎能够证明以下内容相同。为什么会这样?
method foo(xs : seq<int>)
requires forall x :: x in xs ==> 0 <= x < 5;
{
assert forall x :: x in xs ==> 0 <= x < 5;
assert forall i :: 0 <= i < |xs| ==> 0 <= xs[i] < 5;
}
答案 0 :(得分:1)
这与量词触发器有关。您可以在Dafny FAQ中了解有关触发器的更多信息。
在这种情况下,最终断言在您的第一个示例中失败的原因是forall
子句中的requires
量词,并且第一个断言在x in xs
上触发。 1 这意味着将不会在值v
上使用此量化事实 ,除非v in xs
在验证者的“范围内”。为了证明第二个断言,验证者需要使用值为xs[i]
的较早的量化事实,但是xs[i] in xs
不在“范围内”。这听起来可能很奇怪,因为xs[i] in xs
始终为真,但是事实证明,在没有您的帮助下,验证者无法弄清楚这一点。
因此,要证明第二个断言,您需要以某种方式获得事实xs[i] in xs
的范围。一种方法是将断言更改为
assert forall i :: 0 <= i < |xs| ==> xs[i] in xs && 0 <= xs[i] < 5;
(在结论中添加xs[i] in xs
)。实际上,一旦证明了该新断言,Dafny便可以然后证明您的第二个断言,因为此新断言是在xs[i]
上触发的,它也在第二个断言的“范围内”
最后,您的第二个示例进行验证的原因是因为引入谓词test
更改了可用的触发器。现在,forall
子句中的requires
在x in xs
和 test(x)
上都被触发。由于foo
已经出现,因此新触发器与test(xs[i])
主体中的断言新版本中的匹配。这导致第一个forall
被正确实例化,这意味着断言通过。在按摩触发器以使它们执行您想要的操作时,引入这样的无用的命名谓词是一个常见的技巧。
forall
上,或通过在命令行上运行带有选项/printTooltips
,可以查看正在使用哪些触发器。在第一个示例中的第一个断言,您应该看到类似Selected triggers: {x in xs}
的内容。