首先,你是对的,如果没有其他错误报告,那么你可以断定验证成功。
该警告与 Z3(以及 Dafny)如何通过基于启发式模式的实例化处理量词有关。消息是说 Dafny 已决定选择a[i]
作为此量词的触发器(模式),即使它有一个所谓的“匹配循环”与a[i+1]
. Dafny 决定这样做是因为它觉得它没有其他选择作为触发器。
请注意,全称量词上的模式仅在稍后使用量化事实时才相关,而不是在证明它时。通过在由模式确定的具体值上实例化它来使用普遍量化的事实。(双重地,存在量词上的模式仅在证明它们时才相关;通过尝试使用与模式匹配的值作为见证来证明存在量词。)
当使用与模式匹配的值实例化量词时,通用量词上的模式会导致匹配循环,这会导致构造另一个不同的值。对于您的示例,该模式意味着“任何时候您在上下文中浮动a[i]
形式的表达式,尝试通过插入for 来实例化量词。假设值在上下文中浮动。然后量词将被实例化为产生基本条款a[blah]
blah
a[i]
a[0]
i == 0
0 <= i < a.Length - 1 ==> a[0] <= a[1]
这个新子句被添加到上下文中,并包含值a[1]
,它也与模式匹配。所以求解器可能会再次实例化量词,这将导致值a[2]
被添加到上下文中。这可能会永远持续下去并降低求解器的性能。
使用像 Dafny 这样的工具的一部分艺术是设计公式以避免匹配循环。此公式的一种解决方法是将其重写为
forall i, j :: 0 <= i <= j < a.Length - 1 ==> a[i] <= a[j]
由于<=
是传递的,这在逻辑上等价于前面的公式。但是当模式是时它没有匹配循环{a[i], a[j]}
(有两个量化变量,因此需要扩展模式以包含它们),因为用特定值实例化它不会创建与模式匹配的新值。
此公式的另一个解决方法是
forall i, j :: 0 <= i <= j < a.Length - 1 && j == i+1 ==> a[i] <= a[j]
这个公式在逻辑上也等同于第一个公式,因为它被限制j
为 的同义词i+1
。虽然这似乎是一种奇怪的编写方式,但它也消除了循环。
事实上,现代版本的 Dafny 会透明地将您的原始公式重写为最后一个公式,以消除循环并避免警告。