对于Dafny程序,BVD的结果是奇怪的(?)

时间:2016-10-04 15:29:57

标签: dafny

当我验证以下程序片段中有一个错误的错误时, a Dafny method reproduced below

我从BVD得到以下结果,我不明白。

BVD result

让我感到困惑的是,第二个不变量似乎在生成反例时被忽略了。如果两个不变量是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) ; 
}

1 个答案:

答案 0 :(得分:1)

验证调试器指出qy可能等于x,尤其是它们都可能是2988。实际上,您评论中的!Gx <= qy,而不是qy > x

在此示例中,还有一个值得注意的问题:

根据第二个不变式,验证者确实知道q == TwoToThe(i)。这是预料之中的,可以像完成操作一样使用assert进行测试。换句话说,验证者知道q等于将TwoToThe应用于i的结果。验证调试器显示qi具有值29885330。这似乎很奇怪,因为我们知道TwoToThe(5330)远大于2988。那么,这是怎么回事?

要弄清TwoToThe(5330)的值,必须将TwoToThe的定义展开5330次。验证程序不会尝试多次定义,因此,2988似乎仍然显示TwoToThe(5330)的合理值。当调试失败的验证时,这可能是有用的信息。

总而言之,验证调试器可以洞悉验证者的世界,即洞悉验证者在“思考”什么。在这里,我们可以看到它“认为” TwoToThe(5330)返回2988。然后,我们进而得知,TwoToThe的定义不是其名称所暗示的含义,或者验证者没有完全扩展确定该值所需的成千上万的{{​​1}}递归调用。

Rustan