我有以下代码用于排序我想在Stainless(以前称为Leon)中验证的数组:
import stainless.lang._
import stainless.collection._
object QuickSort {
def isSorted(list: List[BigInt]): Boolean = list match {
case Cons(x, xs @ Cons(y, _)) => x <= y && isSorted(xs)
case _ => true
}
def quickSort(list: List[BigInt]): List[BigInt] = (list match {
case Nil() => Nil[BigInt]()
case Cons(x, xs) => par(x, Nil(), Nil(), xs)
}) ensuring { res => isSorted(res) }
def par(x: BigInt, l: List[BigInt], r: List[BigInt], ls: List[BigInt]): List[BigInt] = {
require(l.forall(_ <= x) && r.forall(_ >= x))
ls match {
case Nil() => quickSort(l) ++ Cons(x, quickSort(r))
case Cons(x2, xs2) => if (x2 <= x) par(x, Cons(x2, l), r, xs2) else par(x, l, Cons(x2, r), xs2)
}
} ensuring {res => isSorted(res)}
}
我有很多指示要从这里开始(因为它没有成功验证)但是在我看来,验证应该成功提供提示,我想知道为什么它没有。我解释一下自己:
显然,为了验证par函数,我需要证明这两个案例分别暗示了isSorted后置条件。现在,由于第二种情况包含递归调用,因此很明显它暗示了后置条件。对于par的第一种情况,我们已经对左右子阵列进行了排序,前提条件告诉我所有元素都是根据枢轴进行排序的。
在我看来,最后一点应该意味着连接列表也是排序的。那为什么不验证呢?怎么能指示不锈钢验证它?我是否需要在长度和尺寸上添加提示以便完成不锈钢的任务?
修改
def concatIsSorted(l1 : List[BigInt],l2 : List[BigInt],pivot : BigInt) : Boolean = {
require(isSorted(l1) && isSorted(l2) && l1.forall(_ <= pivot) && l2.forall(_ >= pivot))
isSorted(l1 ++ Cons(pivot,l2)) because{
l1 match{
case Nil() => isSorted(Cons(pivot,l2))
case Cons(h,Nil()) => h <= pivot && isSorted(Cons(pivot,l2))
case Cons(h,t) => h <= t.head && concatIsSorted(t,l2,pivot)
}
}
}.holds
答案 0 :(得分:2)
由于looks like这是一个家庭作业问题,我将尝试引导您走向解决方案,而不是放弃它。
首先请注意,该程序会验证您是否使用Nil()
替换par
中的case Nil() => Nil()
个案。这表明验证者无法证明quickSort(l) ++ Cons(x, quickSort(r))
的结果已排序(但它设法为Nil()
执行此操作!)。
如果--debug=verification
不足以理解为什么验证者无法证明您认为应该这样做,那么继续进行的方法是引入额外的功能,您可以精确地表达您的期望。例如,如果您定义:
def plusplus(l: List[BigInt], r: List[BigInt]): List[BigInt] = l ++ r
并用你期望验证者证明的东西注释它,即
l
和r
已排序且l < r
(适用于<
的定义)l ++ r
的结果已排序您将看到验证者无法证明此属性,这意味着您需要使用附加辅助函数(前后条件)进一步指导验证。
请注意,此示例取自Dependent Types for Program Termination Verification,阅读本文可能会对您有所帮助。