在使用VS的Dafny插件时,我收到了以下警告消息。任何人都可以解释它的含义吗?
Selected triggers: {a[i]} (may loop with "a[i + 1]"). Suppressing loops would leave this expression without triggers.
有问题的一行是
assert forall i : int :: 0<=i<a.Length-1 ==> a[i] <= a[i+1] ;
此外,由于这只是一条警告信息,我能否断定验证是否成功?
答案 0 :(得分:1)
首先,你是对的,如果没有报告其他错误,那么你可以断定验证是否成功。
警告与Z3(以及Dafny)如何通过基于启发式模式的实例化处理量词有关。消息是Dafny决定选择a[i]
作为此量词的触发器(模式),即使它具有与a[i+1]
的所谓“匹配循环”。 Dafny决定这样做,因为它觉得它没有其他选择的触发器。
请注意,通用量词上的模式仅在以后使用量化事实时才相关,而不是在证明时。通过将其实例化为由模式确定的具体值来使用普遍量化的事实。 (双重地,存在量词的模式只有在证明它们时才是相关的;通过尝试使用与模式匹配的值作为证人来证明存在量词。)
通用量词上的模式在使用与模式匹配的值实例化量词时导致匹配循环导致构造另一个不同的值。对于您的示例,模式a[i]
表示“只要您在上下文中浮动表单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将透明地将原始公式重写为最后一个,以消除循环并避免警告。