我从BVD得到以下结果,我不明白。
让我感到困惑的是,第二个不变量似乎在生成反例时被忽略了。如果两个不变量是I0和I1且守卫是G,那么验证条件肯定是 I0&& I1&& !G ==> qy> X 并且反例应该满足对此的否定。我误解了什么?
下面是为了方便任何想要的人而编写的代码。
function TwoToThe( i : int ) : int
decreases i
requires i >= 0
{
if i==0 then 1 else 2*TwoToThe( i-1 )
}
method interestingBVD(x : int, y : int)
requires y > 0
requires x >= 0
{
var q := 1 ;
var qy := y ; // Tracks q*y
ghost var i := 0 ;
// Double q until q*y exceeds x
while( qy < x ) // Off by one error.
invariant qy == q*y
invariant q == TwoToThe(i)
decreases 2*x-qy ;
{
q, qy, i := 2*q, 2*qy, i + 1 ;
}
// In the BVD we get actual numbers!!
assert q*y == qy > x && q == TwoToThe(i) ;
}
答案 0 :(得分:1)
验证调试器指出qy
可能等于x
,尤其是它们都可能是2988
。实际上,您评论中的!G
是x <= qy
,而不是qy > x
。
在此示例中,还有一个值得注意的问题:
根据第二个不变式,验证者确实知道q == TwoToThe(i)
。这是预料之中的,可以像完成操作一样使用assert
进行测试。换句话说,验证者知道q
等于将TwoToThe
应用于i
的结果。验证调试器显示q
和i
具有值2988
和5330
。这似乎很奇怪,因为我们知道TwoToThe(5330)
远大于2988
。那么,这是怎么回事?
要弄清TwoToThe(5330)
的值,必须将TwoToThe
的定义展开5330次。验证程序不会尝试多次定义,因此,2988
似乎仍然显示TwoToThe(5330)
的合理值。当调试失败的验证时,这可能是有用的信息。
总而言之,验证调试器可以洞悉验证者的世界,即洞悉验证者在“思考”什么。在这里,我们可以看到它“认为” TwoToThe(5330)
返回2988
。然后,我们进而得知,TwoToThe
的定义不是其名称所暗示的含义,或者验证者没有完全扩展确定该值所需的成千上万的{{1}}递归调用。>
Rustan