Dafny递归按顺序命中每个元素,无法验证

时间:2018-02-16 11:25:41

标签: dafny

以下函数seqToSet接受一系列元素并返回一个包含给定序列中所有(且仅)元素的集合。它通过使用相同的序列和空集调用递归辅助函数addSeqToSet来完成此操作。辅助函数将序列中的每个元素添加到给定的集合中并返回结果。它通过序列的头/尾结构的递归来实现。它在序列为空时完成,否则用序列的尾部递归调用自身,并使用包含序列头部的单例集的联合。

Dafny无法自行验证后置条件,声明结果集包含原始序列中的所有元素。

帮助它了解情况的正确策略是什么?

function method seqToSet(q: seq<int>): set<int>
{
    addSeqToSet(q, {})
}

function method addSeqToSet(q: seq<int>, t: set<int>): (r: set<int>)
    ensures forall i :: i in q ==> i in r
{
    if | q | == 0 then t
    else addSeqToSet (q[1..], t + { q[0] })
}

1 个答案:

答案 0 :(得分:1)

当Dafny尝试验证递归函数的后置条件时,它的归纳原因是:假设后置条件保留在任何递归调用上,并显示它也适用于当前调用。

想象一下Dafny如何推理addSeqToSet

在第一个分支中,| q | == 0暗示q为空,因此后置条件保持平凡,因为没有元素i in q

在第二个分支中,Dafny假定递归调用的后置条件:

forall i :: i in q[1..] ==> i in r

然后尝试证明当前调用的后置条件:

forall i :: i in q ==> i in r

请注意,由于addSeqToSet直接返回递归调用的答案,因此r在上述两个公式中都是相同的。

如果你想一下,你可以看到外部调用的后置条件不会跟随递归调用的后置条件,因为递归调用没有说明q[0]

你需要以某种方式加强后置条件,以便你知道q[0] in r

其中一个强化措施就是增加关于t

的额外帖子
ensures forall i :: i in t ==> i in r
然后,Dafny验证了两个后置条件。