From ae34a9ea75baed0b929b0a062e691af84b4a7fb7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9gis=20Blanc?= <regwblanc@gmail.com>
Date: Thu, 4 Apr 2013 14:53:11 +0200
Subject: [PATCH] Introduces purely functional array benchmarks

This commit use array with a purely functional styles to process them.
In particular, it uses recursive function instead of while loop.
Those benchmarks are easier to debug than the equivalent ones relying
on imperative features, because they do not go through any code
transformations.

Note that they still have the same limitation as the imperative ones
(cannot prove inductive properties), which shows that the imperative
transformation are not responsible for the limitation in proving
validity of program over arrays.
---
 testcases/BinarySearchFun.scala | 59 +++++++++++++++++++++++++++++++++
 testcases/BubbleFun.scala       | 28 ++++++++--------
 2 files changed, 74 insertions(+), 13 deletions(-)
 create mode 100644 testcases/BinarySearchFun.scala

diff --git a/testcases/BinarySearchFun.scala b/testcases/BinarySearchFun.scala
new file mode 100644
index 000000000..1398f9b9e
--- /dev/null
+++ b/testcases/BinarySearchFun.scala
@@ -0,0 +1,59 @@
+import leon.Utils._
+
+object BinarySearchFun {
+
+  def binarySearch(a: Array[Int], key: Int, low: Int, high: Int): Int = ({
+    require(a.length > 0 && sorted(a, low, high) &&
+        0 <= low && low <= high + 1 && high < a.length
+    )
+
+    if(low <= high) {
+      val i = (high + low) / 2
+      val v = a(i)
+
+      if(v == key) i
+      else if (v > key) binarySearch(a, key, low, i - 1)
+      else binarySearch(a, key, i + 1, high)
+    } else -1
+  }) ensuring(res =>
+      res >= -1 &&
+      res < a.length &&
+      (if (res >= 0)
+          a(res) == key else
+          (high < 0 || (!occurs(a, low, (high+low)/2, key) && !occurs(a, (high+low)/2, high, key)))
+      )
+    )
+
+
+  def occurs(a: Array[Int], from: Int, to: Int, key: Int): Boolean = {
+    require(a.length >= 0 && to <= a.length && from >= 0)
+    def rec(i: Int): Boolean = {
+      require(i >= 0)
+      if(i >= to)
+        false
+      else {
+       if(a(i) == key) true else rec(i+1)
+      }
+    }
+    if(from >= to)
+      false
+    else
+      rec(from)
+  }
+
+
+  def sorted(a: Array[Int], l: Int, u: Int) : Boolean = {
+    require(a.length >= 0 && l >= 0 && l <= u + 1 && u < a.length)
+    val t = sortedWhile(true, l, l, u, a)
+    t._1
+  }
+
+  def sortedWhile(isSorted: Boolean, k: Int, l: Int, u: Int, a: Array[Int]): (Boolean, Int) = {
+    require(a.length >= 0 && l >= 0 && l <= u+1 && u < a.length && k >= l && k <= u + 1)
+    if(k < u) {
+      sortedWhile(if(a(k) > a(k + 1)) false else isSorted, k + 1, l, u, a)
+    } else (isSorted, k)
+  }
+}
+
+// vim: set ts=4 sw=4 et:
diff --git a/testcases/BubbleFun.scala b/testcases/BubbleFun.scala
index 5962eea28..4847fc8ac 100644
--- a/testcases/BubbleFun.scala
+++ b/testcases/BubbleFun.scala
@@ -19,7 +19,7 @@ object BubbleFun {
         val t = sortNestedWhile(sortedArray, 0, i, size)
         sortWhile(t._2, t._1, i - 1, size)
       } else (j, sortedArray, i)
-    }) ensuring(res => isArray(res._2, size) && 
+    }) ensuring(res => isArray(res._2, size) &&
                        sorted(res._2, size, res._3, size - 1) &&
                        partitioned(res._2, size, 0, res._3, res._3+1, size-1) &&
                        res._3 >= 0 && res._3 <= 0 /*&& content(res._2, size) == content(sortedArray, size)*/
@@ -32,7 +32,7 @@ object BubbleFun {
               partitioned(sortedArray, size, 0, i, i+1, size-1) &&
               partitioned(sortedArray, size, 0, j-1, j, j))
       if(j < i) {
-        val newSortedArray = 
+        val newSortedArray =
           if(sortedArray(j) > sortedArray(j + 1))
             sortedArray.updated(j, sortedArray(j + 1)).updated(j+1, sortedArray(j))
           else
@@ -91,7 +91,7 @@ object BubbleFun {
     // ------------- partitioned ------------------
     def partitioned(a: Map[Int,Int], size: Int, l1: Int, u1: Int, l2: Int, u2: Int) : Boolean = {
       require(isArray(a, size) && size < 5 && l1 >= 0 && u1 < l2 && u2 < size)
-      if(l2 > u2 || l1 > u1) 
+      if(l2 > u2 || l1 > u1)
         true
       else {
         val t = partitionedWhile(l2, true, l1, l1, size, u2, l2, u1, a)
@@ -114,20 +114,20 @@ object BubbleFun {
           (if (a(i) > a(j))
             false
           else
-            isPartitionned), 
+            isPartitionned),
           j + 1, i, l1, u1, size, u2, a, l2)
       } else (isPartitionned, j)
     }
 
 
     //------------ isArray -------------------
-    def isArray(a: Map[Int,Int], size: Int): Boolean = 
+    def isArray(a: Map[Int,Int], size: Int): Boolean =
       if(size <= 0)
         false
       else
         isArrayRec(0, size, a)
 
-    def isArrayRec(i: Int, size: Int, a: Map[Int,Int]): Boolean = 
+    def isArrayRec(i: Int, size: Int, a: Map[Int,Int]): Boolean =
       if (i >= size)
         true
       else {
@@ -141,13 +141,15 @@ object BubbleFun {
     // ----------------- content ------------------
     def content(a: Map[Int, Int], size: Int): Set[Int] = {
       require(isArray(a, size) && size < 5)
-      var i = 0
-      var s = Set.empty[Int]
-      while(i < size) {
-        s = s ++ Set(a(i))
-        i = i + 1
-      }
-      s
+      contentRec(a, size, 0)
+    }
+
+    def contentRec(a: Map[Int, Int], size: Int, i: Int): Set[Int] = {
+      require(isArray(a, size) && i >= 0)
+      if(i < size)
+        Set(a(i)) ++ contentRec(a, size, i+1)
+      else
+        Set.empty[Int]
     }
 
 }
-- 
GitLab