How to simplify and extend verified algorithm? - quicksort

I implemented and verified a quicksort function based on the implementation here on page 22.
It verifies (hurray!) but I'm not too happy with the proof, quicksortSorted, that the quicksort function is sorted for a couple reasons that lead to the following questions.
For whatever reason it seems like the proof will not verify because of the two recursive calls needed by the lemma. I got around this by setting the quicksort function to opaque and using another helping lemma quicksortDef when I needed to assert something about its definition. I feel like making the function opaque shouldn't be required. Is there another way to call the recursive subcases that doesn't explode? (better inductive setup?)
Following from above I saw the {:fuel} attribute exists, can it be used to improve this situation?
Although I was able to verify the lemma that quicksort ensures the result is sorted. It would be nice if that fact was part of the ensure conditions of the quicksort function, but my attempts to add it there always seemed to trigger endless recursion. Is there a better way to define quicksort or to prove it which allows this?
When I tried to set filter and quicksort to be function methods I got an error about filters parameter being a ghost variable. Why is a generic predicate function parameter a ghost variable?
Finally the quicksortSorted lemma feels a bit over-complicated, any suggestion on how to simplify it?
Whole implementation on github:
function {:opaque} quicksort(xs: seq<int>): seq<int>
// ensures sortedRec(quicksort(xs))
ensures multiset(xs) == multiset(quicksort(xs))
ensures xs == [] ==> quicksort(xs) == []
ensures xs == [] ==> quicksort(xs) == []
decreases multiset(xs)
{
if xs == [] then [] else
assert xs == [xs[0]] + xs[1..];
filterPreservesMultiset(xs);
// var ln := y => y < xs[0];
// var gn := y => y >= xs[0];
var ln := lessThanFirst(xs);
var gn := greaterOrEqualFirst(xs);
filterMultiSetSlice(xs, xs[1..], ln);
filterMultiSetSlice(xs, xs[1..], gn);
quicksort(filter(xs[1..], ln)) + [xs[0]] + quicksort(filter(xs[1..], gn))
}
lemma quicksortDef(xs: seq<int>)
requires |xs| > 0
ensures quicksort(xs) == quicksort(filter(xs[1..], lessThanFirst(xs))) + [xs[0]] + quicksort(filter(xs[1..], greaterOrEqualFirst(xs)))
{
reveal quicksort();
}
lemma quicksortSorted(xs: seq<int>)
ensures sortedRec(quicksort(xs))
decreases multiset(xs)
{
if xs == [] {
assert quicksort(xs) == [];
assert sortedRec(quicksort(xs));
}else{
assert xs == [xs[0]] + xs[1..];
var ln := lessThanFirst(xs);
var gn := greaterOrEqualFirst(xs);
if xs[1..] == [] {
assert xs == [xs[0]];
assert sortedRec([xs[0]]);
}else{
// filterPreservesMultiset(xs[1..]);
filterMultiSetSlice(xs, xs[1..], ln);
filterMultiSetSlice(xs, xs[1..], gn);
var lessThan := filter(xs[1..], ln);
var greaterThan := filter(xs[1..], gn);
var sortedLt := quicksort(lessThan);
var sortedGt := quicksort(greaterThan);
// assert multiset(lessThan) == multiset(sortedLt);
assert multiset(greaterThan) == multiset(sortedGt);
assert forall y :: y in multiset(sortedGt) ==> y in multiset(greaterThan) && y in sortedGt && y in greaterThan;
assert listPartition(lessThan, [xs[0]]);
quicksortPreservesRelations(lessThan, [xs[0]]);
assert listPartition(sortedLt, [xs[0]]);
assert forall x :: x in sortedLt ==> forall y :: y in [xs[0]] ==> x < y ==> x < xs[0];
forall x | x in sortedLt + [xs[0]]
ensures forall y :: y in sortedGt ==> x <= y
{
forall y | y in sortedGt
ensures x <= y
{
assert y in greaterThan;
assert y >= xs[0];
if x in sortedLt {
assert forall z :: z in [xs[0]] ==> x < z ==> x < xs[0];
}else if x in [xs[0]] {
assert x == xs[0];
assert y >= xs[0];
}
}
}
quicksortSorted(lessThan);
quicksortSorted(greaterThan);
assert listPartition(sortedLt + [xs[0]], sortedGt);
// assert sortedRec(sortedLt);
// assert sortedRec(sortedGt);
sortedConcat(sortedLt, [xs[0]]);
assert sortedRec(sortedLt+[xs[0]]);
sortedConcat(sortedLt + [xs[0]], sortedGt);
assert sortedRec((sortedLt + [xs[0]]) + sortedGt);
quicksortDef(xs);
assert quicksort(xs) == sortedLt + [xs[0]] + sortedGt;
assert sortedRec(quicksort(xs));
}
}
}
predicate listPartition(xs: seq<int>, ys: seq<int>)
{
forall x :: x in xs ==> forall y :: y in ys ==> x <= y
}
predicate sortedRec(list: seq<int>) {
if list == [] then true else (forall y :: y in list[1..] ==> list[0] <= y) && sortedRec(list[1..])
}
lemma sortedConcat(xs: seq<int>, ys: seq<int>)
requires sortedRec(xs)
requires sortedRec(ys)
requires listPartition(xs,ys)
ensures sortedRec(xs + ys)
{
if xs == [] || ys == [] {
if xs == [] {
assert xs + ys == ys;
assert sortedRec(xs + ys);
} else if ys == [] {
assert xs + ys == xs;
assert sortedRec(xs+ys);
}
}else{
assert sortedRec([xs[0]]);
assert sortedRec([ys[0]]);
var sum := xs + ys;
assert xs == [xs[0]] + xs[1..];
assert ys == [ys[0]] + ys[1..];
assert xs[0] in xs;
assert forall y :: y in ys ==> xs[0] <= y;
assert forall xz :: xz in xs[1..] ==> xz in xs && forall y :: y in ys ==> xz <= y;
sortedConcat(xs[1..], ys);
assert xs+ys == [xs[0]] + (xs[1..]+ys);
assert sortedRec(xs + ys );
}
}

Related

How to write a specification of a method that char array convert to an integer in dafny?

method atoi(a:array<char>) returns(r:int)
requires a.Length>0
requires forall k :: 0<= k <a.Length ==> (a[k] as int) - ('0' as int) <= 9
ensures ??
{
var j:int := 0;
while j < a.Length
invariant ??
{
r := r*10 + (a[j] as int) - ('0' as int);
j := j + 1;
}
}
How to write "ensures" for the atoi method and "invariant" for the while loops in dafny?
I express the idea "each bit of the return value corresponds to each bit of the character array" as following:
// Ten to the NTH power
// e.g.: ten_pos_pow(2) == 10*10 == 100
function ten_pos_pow(p:int):int
requires p>=0
ensures ten_pos_pow(p) >= 1
{
if p==0 then 1 else
10*ten_pos_pow(p-1)
}
// Count from right to left, the ith digit of integer v (i starts from zero)
// e.g.: num_in_int(123,0) == 3 num_in_int(123,1) == 2 num_in_int(123,2) == 1
function num_in_int(v:int,i:int) : int
requires i>=0
{
(v % ten_pos_pow(i+1))/ten_pos_pow(i)
}
method atoi(a:array<char>) returns(r:int)
requires a.Length>0
requires forall k :: 0<= k <a.Length ==> (a[k] as int) - ('0' as int) <= 9
ensures forall k :: 0<= k < a.Length ==> ((a[k] as int) - ('0' as int)) == num_in_int(r,a.Length-k-1)
{
var i:int := 0;
r := 0;
while i < a.Length
invariant 0<= i <= a.Length
invariant forall k :: 0<= k < i ==> ((a[k] as int) - ('0' as int)) == num_in_int(r,i-k-1) // loop invariant violation
{
r := r*10 + (a[i] as int) - ('0' as int);
i := i + 1;
}
}
But the loops invariant violation. How to write a correct and provable specification?

Trigger Dafny with multisets

This lemma verifies, but it raises the warning Not triggers found:
lemma multisetPreservesGreater (a:seq<int>, b:seq<int>, c:int, f:int, x:int)
requires |a|==|b| && 0 <= c <= f + 1 <= |b|
requires (forall j :: c <= j <= f ==> a[j] >= x)
requires multiset(a[c..f+1]) == multiset(b[c..f+1])
ensures (forall j :: c <= j <= f ==> b[j] >= x)
{
assert (forall j :: j in multiset(a[c..f+1]) ==> j in multiset(b[c..f+1]));
}
I do not know how to instantiate this trigger (cannot instantiate it as a function, or can I?). Any help?
Edit: Maybe I can instantiate a method f such that takes an array and inserts it in a multiset, and therefore I can trigger f(a), but that does not mention i. I will try.
Here's one way to transform the program so that there are no trigger warnings.
function SeqRangeToMultiSet(a: seq<int>, c: int, f: int): multiset<int>
requires 0 <= c <= f + 1 <= |a|
{
multiset(a[c..f+1])
}
lemma multisetPreservesGreater (a:seq<int>, b:seq<int>, c:int, f:int, x:int)
requires |a|==|b| && 0 <= c <= f + 1 <= |b|
requires (forall j :: c <= j <= f ==> a[j] >= x)
requires multiset(a[c..f+1]) == multiset(b[c..f+1])
ensures (forall j :: c <= j <= f ==> b[j] >= x)
{
assert forall j :: j in SeqRangeToMultiSet(a, c, f) ==> j in SeqRangeToMultiSet(b, c, f);
forall j | c <= j <= f
ensures b[j] >= x
{
assert b[j] in SeqRangeToMultiSet(b, c, f);
}
}
The point is that we introduce the function SeqRangeToMultiSet to stand for a subexpression that is not a valid trigger (because it contains arithmetic). Then SeqRangeToMultiSet itself can be the trigger.
The downside of this approach is that it decreases automation. You can see that we had to add a forall statement to prove the postcondition. The reason is that we need to mention the trigger, which does not appear in the post condition.

Type of union of disjunct functions?

Given two functions:
f :: EvenInteger -> {0}
g :: OddInteger -> {1}
consider the function
h = (x :: Integer) => {
if(x is even)return f(x);
return g(x);
}
What the smallest type T such that
h :: T
I was thinking that it is simply
h :: (typeof f) & (typeof g)
But then I would also think that a function call distributes over conjunction i.e., that
x :: EvenInteger
h(x) :: (typeof f(x)) & (typeof g(x))
which begs another question:
What is
(OddInteger -> {1})(EvenInteger)

Haskell to Scala

Im new to Scala but I know something about functional programing thanks to Haskell and I'm looking for some examples, can you tell me how this would be in Scala?
scalarProduct :: [Int] -> [Int] -> Int
scalarProduct [] _ = 0
scalarProduct _ [] = 0
scalarProduct (x:xs) (y:ys) = if length(xs) == length (ys) then x*y + scalarProduct xs ys else 0
lessThan :: [Float] -> Float -> Int
lessThan [] _ = 0
lessThan (x:xs) n = if x < n then 1 + lessThan xs n else lessThan xs n
removeLast :: [a] -> [a]
removeLast [] = []
removeLast (x:xs) = if length(xs) == 0 then [] else [x] ++ removeLast xs
funcion :: Int -> Float
funcion x | x >= 6 = fromIntegral(product[9..x*2])
| x > 0 = fromIntegral(x) ** (1/4)
| x <= 0 = fromIntegral(product[1..(-x)]) * 5.0**fromIntegral(x)
If you want literal transformations, I think the below is as close as you will get. Bear in mind you have to put this inside an object/class/trait for this to compile (or just past it into the REPL).
def scalarProduct(list1: List[Int], list2: List[Int]): Int = (list1,list2) match {
case (Nil,_) => 0
case (_,Nil) => 0
case (x :: xs, y :: ys) => if (xs.length == ys.length) x*y + scalarProduct(xs,ys) else 0
}
def lessThan(floats: List[Float], bound: Float): Int = floats match {
case Nil => 0
case x :: xs => if (x < bound) 1 + lessThan(xs,n) else lessThan(xs,n)
}
def removeLast[A](list: List[A]): List[A] = list match {
case Nil => Nil
case x :: xs => if (xs.length == 0) Nil else List(x) ++ removeLast(xs)
}
def funcion(x: Int): Double = {
if (x >= 6)
(9 to x*2).product
else if (x > 0)
Math.pow(x,0.25)
else
(1 to -x).product.toDouble * Math.pow(5.0,x)
}
This code is pretty un-Scala-like. For example, the Scala way of doing the first three would probably be with an implicit conversion class RichList[A]. Also, these can all be done much more simply using library functions - but I don't think that's what you are looking for (else you would've used the corresponding library functions for the Haskell code).

syntax explanation for pattern matching a list in scala

I was reading this blog post and i was not able to understand a part of the code.
object O {
def maximum(x: List[Int]): Int = x match {
case Nil => error("maximum undefined for empty list")
case x :: y :: ys => maximum((if(x > y) x else y) :: ys)
case x :: _ => x
}
}
Please explain the code maximum((if(x > y) x else y) :: ys)
How the if condition can be a part of the method maximum ?
I understand that if condition is not exactly a parameter.
In Scala, if is an expression, not a statement.
Try this in the REPL:
scala> val x=1; val y=0
x: Int = 1
y: Int = 0
scala> val test=if(x > y) x else y
test: Int = 1
if evaluates to 1 and 1 is assigned to test. In Java if could be expressed with the conditional operator (x > y) ? x : y
Now, you have a function called maximum that takes a List[Int] as a parameter.
maximum((if(x > y) x else y) :: ys) calls maximum (recursively) with a list obtained prepending one between x and y (depending on what the if evaluates to) to ys.