Dafny拒绝一个简单的后置条件

时间:2017-07-26 07:44:20

标签: dafny

下面是第一次证明各种简单定理的尝试,在这种情况下是关于奇偶校验的。达夫尼/诉。 1.9.9.40414/验证将2加到偶数会产生偶数,但不接受任何一个注释掉的条件。

function IsEven(a : int) : bool
requires a >= 0
{
    if a == 0 then      true 
    else if a == 1 then false 
    else                IsEven(a - 2)
}

method Check1(a : int)
requires a >= 0
ensures IsEven(a) ==> IsEven(a + 2)
//ensures IsEven(a) ==> IsEven(a + a)
//ensures IsEven(a) ==> IsEven(a * a)
{
}

由于我刚刚开始研究这个奇妙的工具,我的方法或实现可能是不正确的。任何建议将不胜感激。

1 个答案:

答案 0 :(得分:1)

这里几乎没有什么不同的东西。我将依次讨论三个后置条件中的每一个。

第一和第二后置条件

由于IsEven是一个递归定义的谓词,一般而言,关于它的事实将需要通过归纳证明。你的第一个帖子条件很简单,不需要归纳,这就是它通过的原因。

你的第二个后置条件确实要求归纳证明。 Dafny具有自动执行归纳的启发式方法,但这些启发式方法仅在某些情况下被调用。特别是,Dafny只会尝试对“幽灵方法”(也称为“lemmas”)进行归纳。

如果您在ghost method前面添加关键字Check1(或将method更改为lemma,这相当于),您会看到第二个后置条件goes through。这是因为Dafny的归纳启发式被调用并设法完成证明。

第三个后置条件

第三个后置条件更复杂,因为它涉及非线性算法。 (换句话说,它涉及将两个变量相乘的非平凡推理。)Dafny的底层求解器难以推理这类事物,因此感应的启发式证明不会通过。

证明a * a即使a是偶数

证明它的一种方法是here。我已将IsEven(a) ==> IsEven(a * a)分解为自己的引理,称为EvenSquare。我也把它改为要求IsEven(a)作为前提条件,而不是在后置条件中加以暗示。 (类似的证据也反过来暗示,但是使用像这样的引理而不是含义的先决条件是惯用的Dafny。)

EvenSquare的证明是a的(手动)归纳。基本案例是自动处理的。在归纳的情况下(if语句的主体),我调用归纳假设(即,我对EvenSquare进行递归方法调用以确定(a - 2) * (a - 2)是偶数)。然后我断言a * a可以写成(a - 2) * (a - 2)和一些偏移的总和。断言自动发送。如果我可以证明这种平等的右手是均匀的,那么将会进行证明。

要做到这一点,我已经知道(a - 2) * (a - 2)是偶数,所以我首先调用另一个引理来证明偏移是偶数,因为它是其他两倍。最后,我引用最后一个引理来表明两个偶数之和是偶数。

这样就完成了证明,假设有两个引理。

两个引理的证据

仍然表明两次都是偶数,两个偶数之和是偶数。虽然不是完全无足轻重,但也不像EvenSquare那么复杂。

引理EvenDouble证明了两次都是偶数。 (这实际上是你的第二个后置条件的更强版本。你的第二个后置条件是将任何偶数数加倍。事实上,任何(非负的,在你的均匀性定义下)数量加倍一切都是均匀的。)EvenDouble的证据通过({1}}上的(手动)归纳进行。基本案例是自动处理的。归纳案例只需要明确地引用归纳假设。

引理a几乎是由Dafny的归纳启发式自动证明的,除了它跳过一个错误或其他问题导致求解器中的循环。经过一些调试后,我确定注释EvenPlus(或{:induction x},就此而言)使证明不循环。这些注释告诉Dafny的启发式试图导入哪些变量。默认情况下,在这种情况下,Dafny尝试引入 {:induction y}x,这由于某种原因导致求解器循环。但是引入任何一个变量都是有效的。我正在进一步研究这个问题,但目前的解决方案是有效的。