diff --git a/testcases/BinaryTreeImp.scala b/testcases/BinaryTreeImp.scala new file mode 100644 index 0000000000000000000000000000000000000000..3005d199122e373e29cdc3ce19f932be29eb4c3d --- /dev/null +++ b/testcases/BinaryTreeImp.scala @@ -0,0 +1,101 @@ +import scala.collection.immutable.Set +import leon.Annotations._ +import leon.Utils._ + +object BinaryTree { + + sealed abstract class Tree + case class Leaf() extends Tree + case class Node(left: Tree, value: Int, right: Tree) extends Tree + + sealed abstract class OptionInt + case class Some(v : Int) extends OptionInt + case class None() extends OptionInt + + def content(t: Tree) : Set[Int] = t match { + case Leaf() => Set.empty + case Node(l, v, r) => content(l) ++ Set(v) ++ content(r) + } + + def size(t: Tree) : Int = (t match { + case Leaf() => 0 + case Node(l, v, r) => size(l) + 1 + size(r) + }) ensuring(_ >= 0) + + def binaryTreeProp(t: Tree): Boolean = t match { + case Leaf() => true + case Node(left, value, right) => { + val b1 = left match { + case Leaf() => true + case Node(a,b,c) => value >= treeMax(Node(a,b,c)) + } + val b2 = right match { + case Leaf() => true + case Node(a,b,c) => value <= treeMin(Node(a,b,c)) + } + binaryTreeProp(left) && binaryTreeProp(right) && b1 && b2 + } + } + + def treeMin(tree: Node): Int = { + require(binaryTreeProp(tree)) + tree match { + case Node(left, value, _) => left match { + case Leaf() => value + case Node(l, v, r) => treeMin(Node(l, v, r)) + } + } + } ensuring(content(tree).contains(_)) + + //def treeMin(tree: Node): Int = { + // require(binaryTreeProp(tree)) + // val Node(left, value, _) = tree + // var res = value + // var tmpLeft = left + // (while(!tmpLeft.isInstanceOf[Leaf]) { + // val Node(left, value, _) = tmpLeft + // res = value + // tmpLeft = left + // }) invariant(content(tmpLeft).contains(res)) + // res + //} ensuring(content(tree).contains(_)) + + def treeMax(tree: Node): Int = { + require(binaryTreeProp(tree)) + tree match { + case Node(_, v, right) => right match { + case Leaf() => v + case Node(l, v, r) => treeMax(Node(l, v, r)) + } + } + } ensuring(content(tree).contains(_)) + + + def search(t: Tree, x: Int): Boolean = { + require(binaryTreeProp(t)) + t match { + case Leaf() => false + case Node(left, value, right) => + if(value == x) true + else if(value < x) search(right, x) + else search(left, x) + } + } ensuring(res => res == content(t).contains(x)) + + def searchImp(t: Tree, x: Int): Boolean = { + require(binaryTreeProp(t)) + var res = false + var t2: Tree = t + (while(!t2.isInstanceOf[Leaf]) { + val Node(left, value, right) = t2 + if(value == x) + res = true + else if(value < x) + t2 = right + else + t2 = left + }) + res + } ensuring(res => res == content(t).contains(x)) + +} diff --git a/testcases/InsertionSortImp.scala b/testcases/InsertionSortImp.scala new file mode 100644 index 0000000000000000000000000000000000000000..266905b26329d3cb3c4bd09d45a9356f805c6005 --- /dev/null +++ b/testcases/InsertionSortImp.scala @@ -0,0 +1,107 @@ +import scala.collection.immutable.Set +import leon.Annotations._ +import leon.Utils._ + +object InsertionSort { + sealed abstract class List + case class Cons(head:Int,tail:List) extends List + case class Nil() extends List + + sealed abstract class OptInt + case class Some(value: Int) extends OptInt + case class None() extends OptInt + + def size(l : List) : Int = (l match { + case Nil() => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def contents(l: List): Set[Int] = l match { + case Nil() => Set.empty + case Cons(x,xs) => contents(xs) ++ Set(x) + } + + def min(l : List) : OptInt = l match { + case Nil() => None() + case Cons(x, xs) => min(xs) match { + case None() => Some(x) + case Some(x2) => if(x < x2) Some(x) else Some(x2) + } + } + + def isSorted(l: List): Boolean = l match { + case Nil() => true + case Cons(x, Nil()) => true + case Cons(x, Cons(y, ys)) => x <= y && isSorted(Cons(y, ys)) + } + def isReversedSorted(l: List): Boolean = l match { + case Nil() => true + case Cons(x, Nil()) => true + case Cons(x, Cons(y, ys)) => x >= y && isReversedSorted(Cons(y, ys)) + } + + def reverse(l: List): List = { + var r: List = Nil() + var l2: List = l + + (while(!l2.isInstanceOf[Nil]) { + val Cons(head, tail) = l2 + l2 = tail + r = Cons(head, r) + }) invariant(contents(r) ++ contents(l2) == contents(l) && size(r) + size(l2) == size(l) && + (if(isSorted(l)) isReversedSorted(r) else true)) + + r + } ensuring(res => contents(res) == contents(l) && size(res) == size(l) && + (if(isSorted(l)) isReversedSorted(res) else true)) + + def reverseSortedSpec(l: List): List = { + require(isSorted(l)) + reverse(l) + } ensuring(res => isReversedSorted(res)) + + /* Inserting element 'e' into a sorted list 'l' produces a sorted list with + * the expected content and size */ + def sortedIns(e: Int, l: List): List = { + require(isSorted(l)) + l match { + case Nil() => Cons(e,Nil()) + case Cons(x,xs) => if (x <= e) Cons(x,sortedIns(e, xs)) else Cons(e, l) + } + } ensuring(res => contents(res) == contents(l) ++ Set(e) + && isSorted(res) + && size(res) == size(l) + 1 + ) + + /* Inserting element 'e' into a sorted list 'l' produces a sorted list with + * the expected content and size */ + def buggySortedIns(e: Int, l: List): List = { + // require(isSorted(l)) + l match { + case Nil() => Cons(e,Nil()) + case Cons(x,xs) => if (x <= e) Cons(x,buggySortedIns(e, xs)) else Cons(e, l) + } + } ensuring(res => contents(res) == contents(l) ++ Set(e) + && isSorted(res) + && size(res) == size(l) + 1 + ) + + /* Insertion sort yields a sorted list of same size and content as the input + * list */ + def sort(l: List): List = (l match { + case Nil() => Nil() + case Cons(x,xs) => sortedIns(x, sort(xs)) + }) ensuring(res => contents(res) == contents(l) + && isSorted(res) + && size(res) == size(l) + ) + + def main(args: Array[String]): Unit = { + val ls: List = Cons(5, Cons(2, Cons(4, Cons(5, Cons(1, Cons(8,Nil())))))) + + println(ls) + println(sort(ls)) + } +} + +// vim: set ts=4 sw=4 et: diff --git a/testcases/QuickSortImp.scala b/testcases/QuickSortImp.scala new file mode 100644 index 0000000000000000000000000000000000000000..dd8e34b32c8262ee804e072872796050ed03d28a --- /dev/null +++ b/testcases/QuickSortImp.scala @@ -0,0 +1,79 @@ +import leon.Utils._ + +object QuickSortImp { + + + def quicksort(array: Array[Int]): Array[Int] = { + require(array.length > 0) + + def quicksort0(array: Array[Int], left: Int, right: Int): Array[Int] = { + require(array.length > 0 && left >= 0 && right < array.length) + + def partition(array: Array[Int], left: Int, right: Int, pivotIndex: Int): (Array[Int], Int) = { + require(array.length > 0 && left >= 0 && left < right && right < array.length && + pivotIndex >= left && pivotIndex <= right) + val pivotValue = array(pivotIndex) + val sa: Array[Int] = array.clone + val tmp = array(pivotIndex) + sa(pivotIndex) = sa(right) + sa(right) = tmp + var storeIndex = left + var i = left + (while(i < right) { + if(sa(i) < pivotValue) { + val tmp = sa(i) + sa(i) = sa(storeIndex) + sa(storeIndex) = tmp + storeIndex = storeIndex + 1 + } + i += 1 + }) invariant( + sa.length >= 0 && right < sa.length && sa.length == array.length && + storeIndex >= left && + i >= left && + storeIndex <= i && + storeIndex <= right && + i <= right + ) + + val tmp2 = array(storeIndex) + //sa(storeIndex) = sa(right) + sa(pivotIndex) = sa(right) + sa(right) = tmp2 + + (sa, storeIndex) + } ensuring(res => res._2 >= left && res._2 <= right && + res._1.length == array.length && res._1.length >= 0) + + + // If the list has 2 or more items + if(left < right) { + val pivotIndex = left + + val (as1, pivotNewIndex) = partition(array, left, right, pivotIndex) + + // Recursively sort elements smaller than the pivot + val as2 = quicksort0(as1, left, pivotNewIndex - 1) + + // Recursively sort elements at least as big as the pivot + quicksort0(as2, pivotNewIndex + 1, right) + } else array + } ensuring(res => res.length == array.length && res.length >= 0) + + quicksort0(array, 0, array.length-1) + } ensuring(res => sorted(res, 0, res.length-1)) + + def sorted(a: Array[Int], l: Int, u: Int): Boolean = { + require(a.length >= 0 && l >= 0 && u < a.length && l <= u) + var k = l + var isSorted = true + (while(k < u) { + if(a(k) > a(k+1)) + isSorted = false + k = k + 1 + }) invariant(k <= u && k >= l) + isSorted + } + + +} diff --git a/testcases/scala-workshop/AmortizedQueue.scala b/testcases/scala-workshop/AmortizedQueue.scala new file mode 100644 index 0000000000000000000000000000000000000000..dd5a75f89735805a74612665e487aa8fa99ec397 --- /dev/null +++ b/testcases/scala-workshop/AmortizedQueue.scala @@ -0,0 +1,124 @@ +import scala.collection.immutable.Set +import leon.Utils._ +import leon.Annotations._ + +object AmortizedQueue { + sealed abstract class List + case class Cons(head : Int, tail : List) extends List + case class Nil() extends List + + sealed abstract class AbsQueue + case class Queue(front : List, rear : List) extends AbsQueue + + def size(list : List) : Int = (list match { + case Nil() => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def content(l: List) : Set[Int] = l match { + case Nil() => Set.empty[Int] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def asList(queue : AbsQueue) : List = queue match { + case Queue(front, rear) => concat(front, reverse(rear)) + } + + def concat(l1 : List, l2 : List) : List = (l1 match { + case Nil() => l2 + case Cons(x,xs) => Cons(x, concat(xs, l2)) + }) ensuring (res => size(res) == size(l1) + size(l2) && content(res) == content(l1) ++ content(l2)) + + def isAmortized(queue : AbsQueue) : Boolean = queue match { + case Queue(front, rear) => size(front) >= size(rear) + } + + def isEmpty(queue : AbsQueue) : Boolean = queue match { + case Queue(Nil(), Nil()) => true + case _ => false + } + + def reverse(l : List) : List = (l match { + case Nil() => Nil() + case Cons(x, xs) => concat(reverse(xs), Cons(x, Nil())) + }) ensuring (content(_) == content(l)) + + def amortizedQueue(front : List, rear : List) : AbsQueue = { + if (size(rear) <= size(front)) + Queue(front, rear) + else + Queue(concat(front, reverse(rear)), Nil()) + } ensuring(isAmortized(_)) + + def enqueue(queue : AbsQueue, elem : Int) : AbsQueue = (queue match { + case Queue(front, rear) => amortizedQueue(front, Cons(elem, rear)) + }) ensuring(isAmortized(_)) + + def tail(queue : AbsQueue) : AbsQueue = { + require(isAmortized(queue) && !isEmpty(queue)) + queue match { + case Queue(Cons(f, fs), rear) => amortizedQueue(fs, rear) + } + } ensuring (isAmortized(_)) + + def front(queue : AbsQueue) : Int = { + require(isAmortized(queue) && !isEmpty(queue)) + queue match { + case Queue(Cons(f, _), _) => f + } + } + + // @induct + // def propEnqueue(rear : List, front : List, list : List, elem : Int) : Boolean = { + // require(isAmortized(Queue(front, rear))) + // val queue = Queue(front, rear) + // if (asList(queue) == list) { + // asList(enqueue(queue, elem)) == concat(list, Cons(elem, Nil())) + // } else + // true + // } holds + + @induct + def propFront(queue : AbsQueue, list : List, elem : Int) : Boolean = { + require(!isEmpty(queue) && isAmortized(queue)) + if (asList(queue) == list) { + list match { + case Cons(x, _) => front(queue) == x + } + } else + true + } holds + + @induct + def propTail(rear : List, front : List, list : List, elem : Int) : Boolean = { + require(!isEmpty(Queue(front, rear)) && isAmortized(Queue(front, rear))) + if (asList(Queue(front, rear)) == list) { + list match { + case Cons(_, xs) => asList(tail(Queue(front, rear))) == xs + } + } else + true + } // holds + + def enqueueAndFront(queue : AbsQueue, elem : Int) : Boolean = { + if (isEmpty(queue)) + front(enqueue(queue, elem)) == elem + else + true + } holds + + def enqueueDequeueThrice(queue : AbsQueue, e1 : Int, e2 : Int, e3 : Int) : Boolean = { + if (isEmpty(queue)) { + val q1 = enqueue(queue, e1) + val q2 = enqueue(q1, e2) + val q3 = enqueue(q2, e3) + val e1prime = front(q3) + val q4 = tail(q3) + val e2prime = front(q4) + val q5 = tail(q4) + val e3prime = front(q5) + e1 == e1prime && e2 == e2prime && e3 == e3prime + } else + true + } holds +} diff --git a/testcases/scala-workshop/AmortizedQueueImp.scala b/testcases/scala-workshop/AmortizedQueueImp.scala new file mode 100644 index 0000000000000000000000000000000000000000..71d199ea9d1152f708268f073e5cb57fde549100 --- /dev/null +++ b/testcases/scala-workshop/AmortizedQueueImp.scala @@ -0,0 +1,138 @@ +import scala.collection.immutable.Set +import leon.Utils._ +import leon.Annotations._ + +object AmortizedQueue { + sealed abstract class List + case class Cons(head : Int, tail : List) extends List + case class Nil() extends List + + sealed abstract class AbsQueue + case class Queue(front : List, rear : List) extends AbsQueue + + def size(list : List) : Int = (list match { + case Nil() => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def content(l: List) : Set[Int] = l match { + case Nil() => Set.empty[Int] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def asList(queue : AbsQueue) : List = queue match { + case Queue(front, rear) => concat(front, reverse(rear)) + } + + def concat(l1 : List, l2 : List) : List = { + var r: List = l2 + var tmp: List = reverse(l1) + + (while(!tmp.isInstanceOf[Nil]) { + val Cons(head, tail) = tmp + tmp = tail + r = Cons(head, r) + }) invariant(content(r) ++ content(tmp) == content(l1) ++ content(l2) && size(r) + size(tmp) == size(l1) + size(l2)) + + r + } ensuring(res => content(res) == content(l1) ++ content(l2) && size(res) == size(l1) + size(l2)) + + def isAmortized(queue : AbsQueue) : Boolean = queue match { + case Queue(front, rear) => size(front) >= size(rear) + } + + def isEmpty(queue : AbsQueue) : Boolean = queue match { + case Queue(Nil(), Nil()) => true + case _ => false + } + + def reverse(l: List): List = { + var r: List = Nil() + var l2: List = l + + (while(!l2.isInstanceOf[Nil]) { + val Cons(head, tail) = l2 + l2 = tail + r = Cons(head, r) + }) invariant(content(r) ++ content(l2) == content(l) && size(r) + size(l2) == size(l)) + + r + } ensuring(res => content(res) == content(l) && size(res) == size(l)) + + def amortizedQueue(front : List, rear : List) : AbsQueue = { + if (size(rear) <= size(front)) + Queue(front, rear) + else + Queue(concat(front, reverse(rear)), Nil()) + } ensuring(isAmortized(_)) + + def enqueue(queue : AbsQueue, elem : Int) : AbsQueue = (queue match { + case Queue(front, rear) => amortizedQueue(front, Cons(elem, rear)) + }) ensuring(isAmortized(_)) + + def tail(queue : AbsQueue) : AbsQueue = { + require(isAmortized(queue) && !isEmpty(queue)) + queue match { + case Queue(Cons(f, fs), rear) => amortizedQueue(fs, rear) + } + } ensuring (isAmortized(_)) + + def front(queue : AbsQueue) : Int = { + require(isAmortized(queue) && !isEmpty(queue)) + queue match { + case Queue(Cons(f, _), _) => f + } + } + + // @induct + // def propEnqueue(rear : List, front : List, list : List, elem : Int) : Boolean = { + // require(isAmortized(Queue(front, rear))) + // val queue = Queue(front, rear) + // if (asList(queue) == list) { + // asList(enqueue(queue, elem)) == concat(list, Cons(elem, Nil())) + // } else + // true + // } holds + + @induct + def propFront(queue : AbsQueue, list : List, elem : Int) : Boolean = { + require(!isEmpty(queue) && isAmortized(queue)) + if (asList(queue) == list) { + list match { + case Cons(x, _) => front(queue) == x + } + } else + true + } //holds + + @induct + def propTail(rear : List, front : List, list : List, elem : Int) : Boolean = { + require(!isEmpty(Queue(front, rear)) && isAmortized(Queue(front, rear))) + if (asList(Queue(front, rear)) == list) { + list match { + case Cons(_, xs) => asList(tail(Queue(front, rear))) == xs + } + } else + true + } // holds + + def enqueueAndFront(queue : AbsQueue, elem : Int) : Boolean = { + if (isEmpty(queue)) + front(enqueue(queue, elem)) == elem + else + true + } holds + + def enqueueDequeueTwice(queue : AbsQueue, e1 : Int, e2 : Int, e3 : Int) : Boolean = { + if (isEmpty(queue)) { + val q1 = enqueue(queue, e1) + val q2 = enqueue(q1, e2) + val e1prime = front(q2) + val q3 = tail(q2) + val e2prime = front(q3) + val q4 = tail(q3) + e1 == e1prime && e2 == e2prime + } else + true + } holds +} diff --git a/testcases/scala-workshop/Arithmetic.scala b/testcases/scala-workshop/Arithmetic.scala new file mode 100644 index 0000000000000000000000000000000000000000..2b90bda91805791950d4c9129196b0ebb30bb3e2 --- /dev/null +++ b/testcases/scala-workshop/Arithmetic.scala @@ -0,0 +1,84 @@ +import leon.Utils._ + +object Arithmetic { + + /* VSTTE 2008 - Dafny paper */ + def mult(x : Int, y : Int): Int = ({ + var r = 0 + if(y < 0) { + var n = y + (while(n != 0) { + r = r - x + n = n + 1 + }) invariant(r == x * (y - n) && 0 <= -n) + } else { + var n = y + (while(n != 0) { + r = r + x + n = n - 1 + }) invariant(r == x * (y - n) && 0 <= n) + } + r + }) ensuring(_ == x*y) + + /* VSTTE 2008 - Dafny paper */ + def add(x : Int, y : Int): Int = ({ + var r = x + if(y < 0) { + var n = y + (while(n != 0) { + r = r - 1 + n = n + 1 + }) invariant(r == x + y - n && 0 <= -n) + } else { + var n = y + (while(n != 0) { + r = r + 1 + n = n - 1 + }) invariant(r == x + y - n && 0 <= n) + } + r + }) ensuring(_ == x+y) + + /* VSTTE 2008 - Dafny paper */ + def addBuggy(x : Int, y : Int): Int = ({ + var r = x + if(y < 0) { + var n = y + (while(n != 0) { + r = r + 1 + n = n + 1 + }) invariant(r == x + y - n && 0 <= -n) + } else { + var n = y + (while(n != 0) { + r = r + 1 + n = n - 1 + }) invariant(r == x + y - n && 0 <= n) + } + r + }) ensuring(_ == x+y) + + def sum(n: Int): Int = { + require(n >= 0) + var r = 0 + var i = 0 + (while(i < n) { + i = i + 1 + r = r + i + }) invariant(r >= i && i >= 0 && r >= 0) + r + } ensuring(_ >= n) + + def divide(x: Int, y: Int): (Int, Int) = { + require(x >= 0 && y > 0) + var r = x + var q = 0 + (while(r >= y) { + r = r - y + q = q + 1 + }) invariant(x == y*q + r && r >= 0) + (q, r) + } ensuring(res => x == y*res._1 + res._2 && res._2 >= 0 && res._2 < y) + +} diff --git a/testcases/scala-workshop/AssociativeList.scala b/testcases/scala-workshop/AssociativeList.scala new file mode 100644 index 0000000000000000000000000000000000000000..f5a2fc0415a2cf6023f9ae1f3620e99f9fdc27cb --- /dev/null +++ b/testcases/scala-workshop/AssociativeList.scala @@ -0,0 +1,50 @@ +import scala.collection.immutable.Set +import leon.Utils._ +import leon.Annotations._ + +object AssociativeList { + sealed abstract class KeyValuePairAbs + case class KeyValuePair(key: Int, value: Int) extends KeyValuePairAbs + + sealed abstract class List + case class Cons(head: KeyValuePairAbs, tail: List) extends List + case class Nil() extends List + + sealed abstract class OptionInt + case class Some(i: Int) extends OptionInt + case class None() extends OptionInt + + def domain(l: List): Set[Int] = l match { + case Nil() => Set.empty[Int] + case Cons(KeyValuePair(k,_), xs) => Set(k) ++ domain(xs) + } + + def find(l: List, e: Int): OptionInt = l match { + case Nil() => None() + case Cons(KeyValuePair(k, v), xs) => if (k == e) Some(v) else find(xs, e) + } + + def noDuplicates(l: List): Boolean = l match { + case Nil() => true + case Cons(KeyValuePair(k, v), xs) => find(xs, k) == None() && noDuplicates(xs) + } + + def update(l1: List, l2: List): List = (l2 match { + case Nil() => l1 + case Cons(x, xs) => update(updateElem(l1, x), xs) + }) ensuring(domain(_) == domain(l1) ++ domain(l2)) + + def updateElem(l: List, e: KeyValuePairAbs): List = (l match { + case Nil() => Cons(e, Nil()) + case Cons(KeyValuePair(k, v), xs) => e match { + case KeyValuePair(ek, ev) => if (ek == k) Cons(KeyValuePair(ek, ev), xs) else Cons(KeyValuePair(k, v), updateElem(xs, e)) + } + }) ensuring(res => e match { + case KeyValuePair(k, v) => domain(res) == domain(l) ++ Set[Int](k) + }) + + @induct + def readOverWrite(l: List, k1: Int, k2: Int, e: Int) : Boolean = { + find(updateElem(l, KeyValuePair(k2,e)), k1) == (if (k1 == k2) Some(e) else find(l, k1)) + } holds +} diff --git a/testcases/scala-workshop/AssociativeListImp.scala b/testcases/scala-workshop/AssociativeListImp.scala new file mode 100644 index 0000000000000000000000000000000000000000..dabf9c994336fb3ddd74b18d5cc170aa7586d995 --- /dev/null +++ b/testcases/scala-workshop/AssociativeListImp.scala @@ -0,0 +1,98 @@ +import scala.collection.immutable.Set +import leon.Utils._ +import leon.Annotations._ + +object AssociativeListImp { + sealed abstract class KeyValuePairAbs + case class KeyValuePair(key: Int, value: Int) extends KeyValuePairAbs + + sealed abstract class List + case class Cons(head: KeyValuePairAbs, tail: List) extends List + case class Nil() extends List + + sealed abstract class OptionInt + case class Some(i: Int) extends OptionInt + case class None() extends OptionInt + + def domain(l: List): Set[Int] = l match { + case Nil() => Set.empty[Int] + case Cons(KeyValuePair(k,_), xs) => Set(k) ++ domain(xs) + } + + def findSpec(l: List, e: Int): OptionInt = l match { + case Nil() => None() + case Cons(KeyValuePair(k, v), xs) => if (k == e) Some(v) else find(xs, e) + } + + def findLast(l: List, e: Int): OptionInt = { + var res: OptionInt = None() + var l2 = l + while(!l2.isInstanceOf[Nil]) { + val Cons(KeyValuePair(k, v), tail) = l2 + l2 = tail + if(k == e) + res = Some(v) + } + res + } ensuring(res => findSpec(l, e) == res) + + def find(l: List, e: Int): OptionInt = { + var res: OptionInt = None() + var l2 = l + var seen: List = Nil() + (while(!l2.isInstanceOf[Nil]) { + val Cons(head@KeyValuePair(k, v), tail) = l2 + seen = Cons(head, seen) + l2 = tail + if(res == None() && k == e) + res = Some(v) + }) invariant((res match { + case Some(_) => domain(seen).contains(e) + case None() => !domain(seen).contains(e) + }) && domain(seen) ++ domain(l2) == domain(l)) + + res + } ensuring(res => res match { + case Some(_) => domain(l).contains(e) + case None() => !domain(l).contains(e) + }) + + def noDuplicates(l: List): Boolean = l match { + case Nil() => true + case Cons(KeyValuePair(k, v), xs) => find(xs, k) == None() && noDuplicates(xs) + } + + def updateElem(l: List, e: KeyValuePairAbs): List = { + var res: List = Nil() + var l2 = l + var found = false + val KeyValuePair(ek, ev) = e + (while(!l2.isInstanceOf[Nil]) { + val Cons(KeyValuePair(k, v), tail) = l2 + l2 = tail + if(k == ek) { + res = Cons(KeyValuePair(ek, ev), res) + found = true + } else { + res = Cons(KeyValuePair(k, v), res) + } + }) invariant( + (if(found) + domain(res) ++ domain(l2) == domain(l) ++ Set(ek) + else + domain(res) ++ domain(l2) == domain(l) + )) + if(!found) + Cons(KeyValuePair(ek, ev), res) + else + res + } ensuring(res => e match { + case KeyValuePair(k, v) => domain(res) == domain(l) ++ Set[Int](k) + }) + + @induct + def readOverWrite(l: List, k1: Int, k2: Int, e: Int) : Boolean = { + find(updateElem(l, KeyValuePair(k2,e)), k1) == (if (k1 == k2) Some(e) else find(l, k1)) + } //holds +} + diff --git a/testcases/scala-workshop/ListOperations.scala b/testcases/scala-workshop/ListOperations.scala new file mode 100644 index 0000000000000000000000000000000000000000..a4fc4f8dc44a90f59a772b52b1a05053316e94d2 --- /dev/null +++ b/testcases/scala-workshop/ListOperations.scala @@ -0,0 +1,107 @@ +import scala.collection.immutable.Set +import leon.Annotations._ +import leon.Utils._ + +object ListOperations { + sealed abstract class List + case class Cons(head: Int, tail: List) extends List + case class Nil() extends List + + sealed abstract class IntPairList + case class IPCons(head: IntPair, tail: IntPairList) extends IntPairList + case class IPNil() extends IntPairList + + sealed abstract class IntPair + case class IP(fst: Int, snd: Int) extends IntPair + + def size(l: List) : Int = (l match { + case Nil() => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def iplSize(l: IntPairList) : Int = (l match { + case IPNil() => 0 + case IPCons(_, xs) => 1 + iplSize(xs) + }) ensuring(_ >= 0) + + def zip(l1: List, l2: List) : IntPairList = { + // try to comment this and see how pattern-matching becomes + // non-exhaustive and post-condition fails + require(size(l1) == size(l2)) + + l1 match { + case Nil() => IPNil() + case Cons(x, xs) => l2 match { + case Cons(y, ys) => IPCons(IP(x, y), zip(xs, ys)) + } + } + } ensuring(iplSize(_) == size(l1)) + + def sizeTailRec(l: List) : Int = sizeTailRecAcc(l, 0) + def sizeTailRecAcc(l: List, acc: Int) : Int = { + require(acc >= 0) + l match { + case Nil() => acc + case Cons(_, xs) => sizeTailRecAcc(xs, acc+1) + } + } ensuring(res => res == size(l) + acc) + + def sizesAreEquiv(l: List) : Boolean = { + size(l) == sizeTailRec(l) + } holds + + def content(l: List) : Set[Int] = l match { + case Nil() => Set.empty[Int] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def sizeAndContent(l: List) : Boolean = { + size(l) == 0 || content(l) != Set.empty[Int] + } holds + + def drunk(l : List) : List = (l match { + case Nil() => Nil() + case Cons(x,l1) => Cons(x,Cons(x,drunk(l1))) + }) ensuring (size(_) == 2 * size(l)) + + def reverse(l: List) : List = reverse0(l, Nil()) ensuring(content(_) == content(l)) + def reverse0(l1: List, l2: List) : List = (l1 match { + case Nil() => l2 + case Cons(x, xs) => reverse0(xs, Cons(x, l2)) + }) ensuring(content(_) == content(l1) ++ content(l2)) + + def append(l1 : List, l2 : List) : List = (l1 match { + case Nil() => l2 + case Cons(x,xs) => Cons(x, append(xs, l2)) + }) ensuring(content(_) == content(l1) ++ content(l2)) + + @induct + def nilAppend(l : List) : Boolean = (append(l, Nil()) == l) holds + + @induct + def appendAssoc(xs : List, ys : List, zs : List) : Boolean = + (append(append(xs, ys), zs) == append(xs, append(ys, zs))) holds + + def revAuxBroken(l1 : List, e : Int, l2 : List) : Boolean = { + (append(reverse(l1), Cons(e,l2)) == reverse0(l1, l2)) + } holds + + @induct + def sizeAppend(l1 : List, l2 : List) : Boolean = + (size(append(l1, l2)) == size(l1) + size(l2)) holds + + @induct + def concat(l1: List, l2: List) : List = + concat0(l1, l2, Nil()) ensuring(content(_) == content(l1) ++ content(l2)) + + @induct + def concat0(l1: List, l2: List, l3: List) : List = (l1 match { + case Nil() => l2 match { + case Nil() => reverse(l3) + case Cons(y, ys) => { + concat0(Nil(), ys, Cons(y, l3)) + } + } + case Cons(x, xs) => concat0(xs, l2, Cons(x, l3)) + }) ensuring(content(_) == content(l1) ++ content(l2) ++ content(l3)) +} diff --git a/testcases/scala-workshop/ListOperationsImp.scala b/testcases/scala-workshop/ListOperationsImp.scala new file mode 100644 index 0000000000000000000000000000000000000000..f30c9d0be06e7a0436883f082d28f6ea687b8479 --- /dev/null +++ b/testcases/scala-workshop/ListOperationsImp.scala @@ -0,0 +1,146 @@ +import leon.Utils._ +import leon.Annotations._ + +object ListOperationsImp { + + sealed abstract class List + case class Cons(head: Int, tail: List) extends List + case class Nil() extends List + + sealed abstract class IPList + case class IPCons(head: (Int, Int), tail: IPList) extends IPList + case class IPNil() extends IPList + + def content(l: List) : Set[Int] = l match { + case Nil() => Set.empty[Int] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def iplContent(l: IPList) : Set[(Int, Int)] = l match { + case IPNil() => Set.empty[(Int, Int)] + case IPCons(x, xs) => Set(x) ++ iplContent(xs) + } + + def size(l: List) : Int = { + var r = 0 + var l2 = l + (while(!l2.isInstanceOf[Nil]) { + val Cons(_, tail) = l2 + l2 = tail + r = r+1 + }) invariant(r >= 0) + r + } ensuring(res => res >= 0) + + def sizeBuggy(l: List) : Int = { + var r = -1 + var l2 = l + (while(!l2.isInstanceOf[Nil]) { + val Cons(_, tail) = l2 + l2 = tail + r = r+1 + }) invariant(r >= 0) + r + } ensuring(res => res >= 0) + + //just to help for specification, makes sense since specification are not executed + def sizeFun(l: List) : Int = l match { + case Nil() => 0 + case Cons(_, t) => 1 + sizeFun(t) + } + def iplSizeFun(l: IPList) : Int = l match { + case IPNil() => 0 + case IPCons(_, t) => 1 + iplSizeFun(t) + } + + def iplSize(l: IPList) : Int = { + var r = 0 + var l2 = l + (while(!l2.isInstanceOf[IPNil]) { + val IPCons(_, tail) = l2 + l2 = tail + r = r+1 + }) invariant(r >= 0) + r + } ensuring(_ >= 0) + + def sizeStrongSpec(l: List): Int = { + var r = 0 + var l2 = l + (while(!l2.isInstanceOf[Nil]) { + val Cons(head, tail) = l2 + l2 = tail + r = r+1 + }) invariant(r == sizeFun(l) - sizeFun(l2)) + r + } ensuring(res => res == sizeFun(l)) + + def zip(l1: List, l2: List) : IPList = ({ + require(sizeFun(l1) == sizeFun(l2)) + var r: IPList = IPNil() + var ll1: List = l1 + var ll2 = l2 + + (while(!ll1.isInstanceOf[Nil]) { + val Cons(l1head, l1tail) = ll1 + val Cons(l2head, l2tail) = if(!ll2.isInstanceOf[Nil]) ll2 else Cons(0, Nil()) + r = IPCons((l1head, l2head), r) + ll1 = l1tail + ll2 = l2tail + }) invariant(iplSizeFun(r) + sizeFun(ll1) == sizeFun(l1)) + + iplReverse(r) + }) ensuring(res => iplSizeFun(res) == sizeFun(l1)) + + def drunk(l : List) : List = { + var r: List = Nil() + var l2 = l + (while(!l2.isInstanceOf[Nil]) { + val Cons(head, tail) = l2 + l2 = tail + r = Cons(head, Cons(head, r)) + }) invariant(sizeFun(r) == 2 * sizeFun(l) - 2 * sizeFun(l2)) + r + } ensuring (sizeFun(_) == 2 * sizeFun(l)) + + + def iplReverse(l: IPList): IPList = { + var r: IPList = IPNil() + var l2: IPList = l + + (while(!l2.isInstanceOf[IPNil]) { + val IPCons(head, tail) = l2 + l2 = tail + r = IPCons(head, r) + }) invariant(iplContent(r) ++ iplContent(l2) == iplContent(l) && iplSizeFun(r) + iplSizeFun(l2) == iplSizeFun(l)) + + r + } ensuring(res => iplContent(res) == iplContent(l) && iplSizeFun(res) == iplSizeFun(l)) + + def reverse(l: List): List = { + var r: List = Nil() + var l2: List = l + + (while(!l2.isInstanceOf[Nil]) { + val Cons(head, tail) = l2 + l2 = tail + r = Cons(head, r) + }) invariant(content(r) ++ content(l2) == content(l) && sizeFun(r) + sizeFun(l2) == sizeFun(l)) + + r + } ensuring(res => content(res) == content(l) && sizeFun(res) == sizeFun(l)) + + def append(l1 : List, l2 : List) : List = { + var r: List = l2 + var tmp: List = reverse(l1) + + (while(!tmp.isInstanceOf[Nil]) { + val Cons(head, tail) = tmp + tmp = tail + r = Cons(head, r) + }) invariant(content(r) ++ content(tmp) == content(l1) ++ content(l2)) + + r + } ensuring(content(_) == content(l1) ++ content(l2)) + +} diff --git a/testcases/scala-workshop/PropositionalLogic.scala b/testcases/scala-workshop/PropositionalLogic.scala new file mode 100644 index 0000000000000000000000000000000000000000..a35c3ef9be56871900d5e9474b385f0896edccd4 --- /dev/null +++ b/testcases/scala-workshop/PropositionalLogic.scala @@ -0,0 +1,86 @@ +import scala.collection.immutable.Set +import leon.Utils._ +import leon.Annotations._ + +object PropositionalLogic { + + sealed abstract class Formula + case class And(lhs: Formula, rhs: Formula) extends Formula + case class Or(lhs: Formula, rhs: Formula) extends Formula + case class Implies(lhs: Formula, rhs: Formula) extends Formula + case class Not(f: Formula) extends Formula + case class Literal(id: Int) extends Formula + + def simplify(f: Formula): Formula = (f match { + case And(lhs, rhs) => And(simplify(lhs), simplify(rhs)) + case Or(lhs, rhs) => Or(simplify(lhs), simplify(rhs)) + case Implies(lhs, rhs) => Or(Not(simplify(lhs)), simplify(rhs)) + case Not(f) => Not(simplify(f)) + case Literal(_) => f + }) ensuring(isSimplified(_)) + + def isSimplified(f: Formula): Boolean = f match { + case And(lhs, rhs) => isSimplified(lhs) && isSimplified(rhs) + case Or(lhs, rhs) => isSimplified(lhs) && isSimplified(rhs) + case Implies(_,_) => false + case Not(f) => isSimplified(f) + case Literal(_) => true + } + + def nnf(formula: Formula): Formula = (formula match { + case And(lhs, rhs) => And(nnf(lhs), nnf(rhs)) + case Or(lhs, rhs) => Or(nnf(lhs), nnf(rhs)) + case Implies(lhs, rhs) => Implies(nnf(lhs), nnf(rhs)) + case Not(And(lhs, rhs)) => Or(nnf(Not(lhs)), nnf(Not(rhs))) + case Not(Or(lhs, rhs)) => And(nnf(Not(lhs)), nnf(Not(rhs))) + case Not(Implies(lhs, rhs)) => And(nnf(lhs), nnf(Not(rhs))) + case Not(Not(f)) => nnf(f) + case Not(Literal(_)) => formula + case Literal(_) => formula + }) ensuring(isNNF(_)) + + def isNNF(f: Formula): Boolean = f match { + case And(lhs, rhs) => isNNF(lhs) && isNNF(rhs) + case Or(lhs, rhs) => isNNF(lhs) && isNNF(rhs) + case Implies(lhs, rhs) => isNNF(lhs) && isNNF(rhs) + case Not(Literal(_)) => true + case Not(_) => false + case Literal(_) => true + } + + def vars(f: Formula): Set[Int] = { + require(isNNF(f)) + f match { + case And(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Or(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Implies(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Not(Literal(i)) => Set[Int](i) + case Literal(i) => Set[Int](i) + } + } + + def fv(f : Formula) = { vars(nnf(f)) } + + // @induct + // def wrongCommutative(f: Formula) : Boolean = { + // nnf(simplify(f)) == simplify(nnf(f)) + // } holds + + @induct + def simplifyBreaksNNF(f: Formula) : Boolean = { + require(isNNF(f)) + isNNF(simplify(f)) + } holds + + @induct + def nnfIsStable(f: Formula) : Boolean = { + require(isNNF(f)) + nnf(f) == f + } holds + + @induct + def simplifyIsStable(f: Formula) : Boolean = { + require(isSimplified(f)) + simplify(f) == f + } holds +} diff --git a/testcases/scala-workshop/RedBlackTree.scala b/testcases/scala-workshop/RedBlackTree.scala new file mode 100644 index 0000000000000000000000000000000000000000..bc2de6ba96ee699736d4558932b752eea9ebba9f --- /dev/null +++ b/testcases/scala-workshop/RedBlackTree.scala @@ -0,0 +1,117 @@ +import scala.collection.immutable.Set +import leon.Annotations._ +import leon.Utils._ + +object RedBlackTree { + sealed abstract class Color + case class Red() extends Color + case class Black() extends Color + + sealed abstract class Tree + case class Empty() extends Tree + case class Node(color: Color, left: Tree, value: Int, right: Tree) extends Tree + + sealed abstract class OptionInt + case class Some(v : Int) extends OptionInt + case class None() extends OptionInt + + def content(t: Tree) : Set[Int] = t match { + case Empty() => Set.empty + case Node(_, l, v, r) => content(l) ++ Set(v) ++ content(r) + } + + def size(t: Tree) : Int = (t match { + case Empty() => 0 + case Node(_, l, v, r) => size(l) + 1 + size(r) + }) ensuring(_ >= 0) + + /* We consider leaves to be black by definition */ + def isBlack(t: Tree) : Boolean = t match { + case Empty() => true + case Node(Black(),_,_,_) => true + case _ => false + } + + def redNodesHaveBlackChildren(t: Tree) : Boolean = t match { + case Empty() => true + case Node(Black(), l, _, r) => redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r) + case Node(Red(), l, _, r) => isBlack(l) && isBlack(r) && redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r) + } + + def redDescHaveBlackChildren(t: Tree) : Boolean = t match { + case Empty() => true + case Node(_,l,_,r) => redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r) + } + + def blackBalanced(t : Tree) : Boolean = t match { + case Node(_,l,_,r) => blackBalanced(l) && blackBalanced(r) && blackHeight(l) == blackHeight(r) + case Empty() => true + } + + def blackHeight(t : Tree) : Int = t match { + case Empty() => 1 + case Node(Black(), l, _, _) => blackHeight(l) + 1 + case Node(Red(), l, _, _) => blackHeight(l) + } + + // <<insert element x into the tree t>> + def ins(x: Int, t: Tree): Tree = { + require(redNodesHaveBlackChildren(t) && blackBalanced(t)) + t match { + case Empty() => Node(Red(),Empty(),x,Empty()) + case Node(c,a,y,b) => + if (x < y) balance(c, ins(x, a), y, b) + else if (x == y) Node(c,a,y,b) + else balance(c,a,y,ins(x, b)) + } + } ensuring (res => content(res) == content(t) ++ Set(x) + && size(t) <= size(res) && size(res) <= size(t) + 1 + && redDescHaveBlackChildren(res) + && blackBalanced(res)) + + def makeBlack(n: Tree): Tree = { + require(redDescHaveBlackChildren(n) && blackBalanced(n)) + n match { + case Node(Red(),l,v,r) => Node(Black(),l,v,r) + case _ => n + } + } ensuring(res => redNodesHaveBlackChildren(res) && blackBalanced(res)) + + def add(x: Int, t: Tree): Tree = { + require(redNodesHaveBlackChildren(t) && blackBalanced(t)) + makeBlack(ins(x, t)) + } ensuring (res => content(res) == content(t) ++ Set(x) && redNodesHaveBlackChildren(res) && blackBalanced(res)) + + def buggyAdd(x: Int, t: Tree): Tree = { + require(redNodesHaveBlackChildren(t)) + ins(x, t) + } ensuring (res => content(res) == content(t) ++ Set(x) && redNodesHaveBlackChildren(res)) + + def balance(c: Color, a: Tree, x: Int, b: Tree): Tree = { + Node(c,a,x,b) match { + case Node(Black(),Node(Red(),Node(Red(),a,xV,b),yV,c),zV,d) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(Black(),Node(Red(),a,xV,Node(Red(),b,yV,c)),zV,d) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(Black(),a,xV,Node(Red(),Node(Red(),b,yV,c),zV,d)) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(Black(),a,xV,Node(Red(),b,yV,Node(Red(),c,zV,d))) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(c,a,xV,b) => Node(c,a,xV,b) + } + } ensuring (res => content(res) == content(Node(c,a,x,b)))// && redDescHaveBlackChildren(res)) + + def buggyBalance(c: Color, a: Tree, x: Int, b: Tree): Tree = { + Node(c,a,x,b) match { + case Node(Black(),Node(Red(),Node(Red(),a,xV,b),yV,c),zV,d) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(Black(),Node(Red(),a,xV,Node(Red(),b,yV,c)),zV,d) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(Black(),a,xV,Node(Red(),Node(Red(),b,yV,c),zV,d)) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(Black(),a,xV,Node(Red(),b,yV,Node(Red(),c,zV,d))) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + // case Node(c,a,xV,b) => Node(c,a,xV,b) + } + } ensuring (res => content(res) == content(Node(c,a,x,b)))// && redDescHaveBlackChildren(res)) +} diff --git a/testcases/scala-workshop/SearchLinkedList.scala b/testcases/scala-workshop/SearchLinkedList.scala new file mode 100644 index 0000000000000000000000000000000000000000..2c137fd4ad6b9d411f7e14b4ada6b834234c9e9e --- /dev/null +++ b/testcases/scala-workshop/SearchLinkedList.scala @@ -0,0 +1,48 @@ +import scala.collection.immutable.Set +import leon.Utils._ +import leon.Annotations._ + +object SearchLinkedList { + sealed abstract class List + case class Cons(head : Int, tail : List) extends List + case class Nil() extends List + + def size(list : List) : Int = (list match { + case Nil() => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def contains(list : List, elem : Int) : Boolean = (list match { + case Nil() => false + case Cons(x, xs) => x == elem || contains(xs, elem) + }) + + def firstZero(list : List) : Int = (list match { + case Nil() => 0 + case Cons(x, xs) => if (x == 0) 0 else firstZero(xs) + 1 + }) ensuring (res => + res >= 0 && (if (contains(list, 0)) { + firstZeroAtPos(list, res) + } else { + res == size(list) + })) + + def firstZeroAtPos(list : List, pos : Int) : Boolean = { + list match { + case Nil() => false + case Cons(x, xs) => if (pos == 0) x == 0 else x != 0 && firstZeroAtPos(xs, pos - 1) + } + } + + def goal(list : List, i : Int) : Boolean = { + if(firstZero(list) == i) { + if(contains(list, 0)) { + firstZeroAtPos(list, i) + } else { + i == size(list) + } + } else { + true + } + } holds +} diff --git a/testcases/scala-workshop/Sorting.scala b/testcases/scala-workshop/Sorting.scala new file mode 100644 index 0000000000000000000000000000000000000000..3c683e6e5f3873d2eaa4d4413ac9fe9f01a888ff --- /dev/null +++ b/testcases/scala-workshop/Sorting.scala @@ -0,0 +1,198 @@ +import leon.Annotations._ +import leon.Utils._ + +// Sorting lists is a fundamental problem in CS. +object Sorting { + // Data types + sealed abstract class List + case class Cons(head : Int, tail : List) extends List + case class Nil() extends List + + sealed abstract class LList + case class LCons(head : List, tail : LList) extends LList + case class LNil() extends LList + + // Abstraction functions + def content(list : List) : Set[Int] = list match { + case Nil() => Set.empty[Int] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def lContent(llist : LList) : Set[Int] = llist match { + case LNil() => Set.empty[Int] + case LCons(x, xs) => content(x) ++ lContent(xs) + } + + def size(list : List) : Int = (list match { + case Nil() => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def isSorted(list : List) : Boolean = list match { + case Nil() => true + case Cons(_, Nil()) => true + case Cons(x1, Cons(x2, _)) if(x1 > x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def lIsSorted(llist : LList) : Boolean = llist match { + case LNil() => true + case LCons(x, xs) => isSorted(x) && lIsSorted(xs) + } + + @induct + def sortedLemma(a: Int, x: Int, b: List) = { + !(isSorted(Cons(a,b)) && (content(b) contains x)) || (x >= a) + } holds + + def abs(i : Int) : Int = { + if(i < 0) -i else i + } ensuring(_ >= 0) + + /*************************** + * * + * I N S E R T I O N * + * * + ***************************/ + + def insertSpec(elem : Int, list : List, res : List) : Boolean = { +// isSorted(list) && // Part of precondition, really. + isSorted(res) && content(res) == content(list) ++ Set(elem) + } + + def insertImpl(elem : Int, list : List) : List = { + require(isSorted(list)) + list match { + case Nil() => Cons(elem, Nil()) + case c @ Cons(x, _) if(elem <= x) => Cons(elem, c) + case Cons(x, xs) => Cons(x, insertImpl(elem, xs)) + } + } ensuring(insertSpec(elem, list, _)) + + /********************************** + * * + * M E R G I N G (slow+fast) * + * * + **********************************/ + + def mergeSpec(list1 : List, list2 : List, res : List) : Boolean = { + // isSorted(list1) && isSorted(list2) && // Part of precondition, really. + isSorted(res) && content(res) == content(list1) ++ content(list2) + } + + def mergeImpl(list1 : List, list2 : List) : List = { + require(isSorted(list1) && isSorted(list2)) + + list1 match { + case Nil() => list2 + case Cons(x, xs) => insertImpl(x, mergeImpl(xs, list2)) + } + } ensuring(res => mergeSpec(list1, list2, res)) + + def mergeFastImpl(list1 : List, list2 : List) : List = { + require(isSorted(list1) && isSorted(list2)) + + (list1, list2) match { + case (_, Nil()) => list1 + case (Nil(), _) => list2 + case (Cons(x, xs), Cons(y, ys)) => + if(x <= y) { + Cons(x, mergeFastImpl(xs, list2)) + } else { + Cons(y, mergeFastImpl(list1, ys)) + } + } + } ensuring(res => mergeSpec(list1, list2, res)) + + /*************************** + * * + * S P L I T T I N G * + * * + ***************************/ + + def splitSpec(list : List, res : (List,List)) : Boolean = { + val s1 = size(res._1) + val s2 = size(res._2) + abs(s1 - s2) <= 1 && s1 + s2 == size(list) && + content(res._1) ++ content(res._2) == content(list) + } + + def splitImpl(list : List) : (List,List) = (list match { + case Nil() => (Nil(), Nil()) + case Cons(x, Nil()) => (Cons(x, Nil()), Nil()) + case Cons(x1, Cons(x2, xs)) => + val (s1,s2) = splitImpl(xs) + (Cons(x1, s1), Cons(x2, s2)) + }) ensuring(res => splitSpec(list, res)) + + /*********************** + * * + * S O R T I N G * + * * + ***********************/ + + def sortSpec(in : List, out : List) : Boolean = { + content(out) == content(in) && isSorted(out) + } + + def insertSorted(in: List, v: Int): List = { + require(isSorted(in)); + + in match { + case Cons(h, t) => + val r = insertSorted(t, v) + if (h < v) { + Cons(h, r) + } else if (h > v) { + Cons(v, Cons(h, t)) + } else { + Cons(h, t) + } + case _ => + Cons(v, Nil()) + } + } ensuring { res => isSorted(res) && content(res) == content(in) ++ Set(v) } + + def insertionSortImpl(in : List) : List = (in match { + case Nil() => Nil() + case Cons(x, xs) => insertImpl(x, insertionSortImpl(xs)) + }) ensuring(res => sortSpec(in, res)) + + // Not really quicksort, neither mergesort. + def weirdSortImpl(in : List) : List = (in match { + case Nil() => Nil() + case Cons(x, Nil()) => Cons(x, Nil()) + case _ => + val (s1,s2) = splitImpl(in) + mergeFastImpl(weirdSortImpl(s1), weirdSortImpl(s2)) + }) ensuring(res => sortSpec(in, res)) + + def toLList(list : List) : LList = (list match { + case Nil() => LNil() + case Cons(x, xs) => LCons(Cons(x, Nil()), toLList(xs)) + }) ensuring(res => lContent(res) == content(list) && lIsSorted(res)) + + def mergeMap(llist : LList) : LList = { + require(lIsSorted(llist)) + + llist match { + case LNil() => LNil() + case o @ LCons(x, LNil()) => o + case LCons(x, LCons(y, ys)) => LCons(mergeFastImpl(x, y), mergeMap(ys)) + } + } ensuring(res => lContent(res) == lContent(llist) && lIsSorted(res)) + + def mergeReduce(llist : LList) : List = { + require(lIsSorted(llist)) + + llist match { + case LNil() => Nil() + case LCons(x, LNil()) => x + case _ => mergeReduce(mergeMap(llist)) + } + } ensuring(res => content(res) == lContent(llist) && isSorted(res)) + + def mergeSortImpl(in : List) : List = { + mergeReduce(toLList(in)) + } ensuring(res => sortSpec(in, res)) +} diff --git a/testcases/scala-workshop/SumAndMax.scala b/testcases/scala-workshop/SumAndMax.scala new file mode 100644 index 0000000000000000000000000000000000000000..0aa4ce7060a391d34dd047338fcd1f638054843f --- /dev/null +++ b/testcases/scala-workshop/SumAndMax.scala @@ -0,0 +1,46 @@ +import leon.Utils._ +import leon.Annotations._ + +object SumAndMax { + sealed abstract class List + case class Cons(head : Int, tail : List) extends List + case class Nil() extends List + + def max(list : List) : Int = { + require(list != Nil()) + list match { + case Cons(x, Nil()) => x + case Cons(x, xs) => { + val m2 = max(xs) + if(m2 > x) m2 else x + } + } + } + + def sum(list : List) : Int = list match { + case Nil() => 0 + case Cons(x, xs) => x + sum(xs) + } + + def size(list : List) : Int = (list match { + case Nil() => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def allPos(list : List) : Boolean = list match { + case Nil() => true + case Cons(x, xs) => x >= 0 && allPos(xs) + } + + def prop0(list : List) : Boolean = { + require(list != Nil()) + !allPos(list) || max(list) >= 0 + } holds + + @induct + def property(list : List) : Boolean = { + // This precondition was given in the problem but isn't actually useful :D + // require(allPos(list)) + sum(list) <= size(list) * (if(list == Nil()) 0 else max(list)) + } holds +} diff --git a/testcases/scala-workshop/SumAndMaxImp.scala b/testcases/scala-workshop/SumAndMaxImp.scala new file mode 100644 index 0000000000000000000000000000000000000000..d6c9896a82aebb711d05a0fa9c3f8de156a51be9 --- /dev/null +++ b/testcases/scala-workshop/SumAndMaxImp.scala @@ -0,0 +1,36 @@ +import leon.Utils._ + +object SumAndMaxImp { + + def isPositive(a: Array[Int], size: Int): Boolean = { + require(a.length >= 0 && size <= a.length) + def rec(i: Int): Boolean = { + require(i >= 0) + if(i >= size) + true + else { + if(a(i) < 0) + false + else + rec(i+1) + } + } + rec(0) + } + + /* VSTTE 2010 challenge 1 */ + def maxSum(a: Array[Int]): (Int, Int) = { + require(a.length >= 0 && isPositive(a, a.length)) + var sum = 0 + var max = 0 + var i = 0 + (while(i < a.length) { + if(max < a(i)) + max = a(i) + sum = sum + a(i) + i = i + 1 + }) invariant (sum <= i * max && i >= 0 && i <= a.length) + (sum, max) + } ensuring(res => res._1 <= a.length * res._2) + +}