这里发生了一些不同的事情。我将依次讨论这三个后置条件。
第一个和第二个后置条件
因为IsEven
是一个递归定义的谓词,一般来说,关于它的事实需要归纳证明。您的第一个后置条件很简单,不需要归纳,这就是它通过的原因。
您的第二个后置条件确实需要证明归纳。Dafny 具有自动执行归纳的启发式方法,但这些启发式方法仅在某些上下文中调用。特别是,Dafny 只会尝试对“幽灵方法”(也称为“引理”)进行归纳。
如果您在 in 前面添加关键字(ghost
或更改为等效的 ),您将看到第二个后置条件通过。这是因为 Dafny 的归纳启发式被调用并设法完成了证明。method
Check1
method
lemma
第三个后置条件
第三个后置条件更复杂,因为它涉及非线性算术。(换句话说,它涉及将两个变量相乘的非平凡推理。)Dafny 的底层求解器难以推理这些事情,因此通过归纳的启发式证明没有通过。
a * a
即使a
是偶数的证明
证明它的一种方法是在这里。我已经考虑IsEven(a) ==> IsEven(a * a)
到它自己的引理,称为EvenSquare
. 我也将其更改为 requireIsEven(a)
作为前置条件,而不是在后置条件中添加含义。(类似的证明也适用于蕴涵,但是像这样在引理上使用先决条件而不是蕴涵是惯用的 Dafny。)
的证明EvenSquare
是通过(手动)归纳对a
。基本情况会自动处理。在归纳情况(if
语句的主体)中,我调用归纳假设(即,我进行递归方法调用EvenSquare
以建立(a - 2) * (a - 2)
偶数)。然后我断言a * a
可以写为总和(a - 2) * (a - 2)
和一些偏移量。断言是自动分派的。如果我能证明这个等式的右边是偶数,证明就会完成。
为此,我已经知道它(a - 2) * (a - 2)
是偶数,所以我首先调用另一个引理来表明偏移量是偶数,因为它是其他值的两倍。最后,我引用最后一个引理来证明两个偶数之和是偶数。
假设有两个引理,这就完成了证明。
两个引理的证明
它仍然证明任何事物的两倍是偶数,并且两个偶数的和是偶数。虽然并非完全微不足道,但也没有EvenSquare
.
引理EvenDouble
证明任何事物都是偶数的两倍。(这实际上是您的第二个后置条件的更强大的版本。您的第二个后置条件说将任何偶数加倍是偶数。事实上,将任何(非负,根据您的偶数定义)数加倍都是偶数。)证明EvenDouble
通过(手动)感应获得的收益a
。基本情况会自动处理。归纳案例只需要明确地调用归纳假设。
EvenPlus
Dafny 的归纳启发式几乎自动证明了这个引理,除了它遇到了一个错误或其他导致求解器循环的问题。经过一点调试,我确定注释{:induction x}
(或者{:induction y}
,就此而言)使证明不循环。这些注释告诉 Dafny 的启发式方法要尝试对哪些变量进行归纳。默认情况下,在这种情况下,Dafny 会尝试对和 x
进行感应y
,由于某种原因,这会导致求解器循环。但是单独对任一变量进行归纳都是有效的。我正在进一步调查这个问题,但目前的解决方案有效。