From 47fc02790d288cf71dd39d01c2f7249aa7067478 Mon Sep 17 00:00:00 2001
From: Marco Antognini <antognini.marco@gmail.com>
Date: Sun, 3 Jan 2016 18:29:37 +0100
Subject: [PATCH] Add IntegralColor testcase for GenC

---
 .../regression/genc/valid/IntegralColor.scala | 175 ++++++++++++++++++
 1 file changed, 175 insertions(+)
 create mode 100644 src/test/resources/regression/genc/valid/IntegralColor.scala

diff --git a/src/test/resources/regression/genc/valid/IntegralColor.scala b/src/test/resources/regression/genc/valid/IntegralColor.scala
new file mode 100644
index 000000000..0bed04399
--- /dev/null
+++ b/src/test/resources/regression/genc/valid/IntegralColor.scala
@@ -0,0 +1,175 @@
+import leon.lang._
+
+object IntegralColor {
+
+  def isValidComponent(x: Int) = x >= 0 && x <= 255
+
+  def getRed(rgb: Int): Int = {
+    (rgb & 0x00FF0000) >> 16
+  } ensuring isValidComponent _
+
+  def getGreen(rgb: Int): Int = {
+    (rgb & 0x0000FF00) >> 8
+  } ensuring isValidComponent _
+
+  def getBlue(rgb: Int): Int = {
+    rgb & 0x000000FF
+  } ensuring isValidComponent _
+
+  def getGray(rgb: Int): Int = {
+    (getRed(rgb) + getGreen(rgb) + getBlue(rgb)) / 3
+  } ensuring isValidComponent _
+
+  def testColorSinglePixel: Boolean = {
+    val color = 0x20C0FF
+
+    32 == getRed(color) && 192 == getGreen(color) &&
+    255 == getBlue(color) && 159 == getGray(color)
+  }.holds
+
+  case class Color(r: Int, g: Int, b: Int)
+
+  def getColor(rgb: Int) = Color(getRed(rgb), getGreen(rgb), getBlue(rgb))
+
+  /*
+   *case class Image(width: Int, height: Int, buffer: Array[Int]) {
+   *  // currently not enforced:
+   *  require(width <= 1000 && height <= 1000 && buffer.length == width * height)
+   *}
+   */
+
+  def matches(value: Array[Int], expected: Array[Int]): Boolean = {
+    require(value.length == expected.length)
+
+    var test = true
+    var idx = 0
+    (while (idx < value.length) {
+      test = test && value(idx) == expected(idx)
+      idx = idx + 1
+    }) invariant { idx >= 0 && idx <= value.length }
+
+    test
+  }
+
+  def testColorWholeImage: Boolean = {
+    val WIDTH  = 2
+    val HEIGHT = 2
+
+    /*
+     *val source   = Image(WIDTH, HEIGHT, Array(0x20c0ff, 0x123456, 0xffffff, 0x000000))
+     *val expected = Image(WIDTH, HEIGHT, Array(159, 52, 255, 0)) // gray convertion
+     *val gray     = Image(WIDTH, HEIGHT, Array.fill(4)(0))
+     */
+
+    val source   = Array(0x20c0ff, 0x123456, 0xffffff, 0x000000)
+    val expected = Array(159, 52, 255, 0) // gray convertion
+    val gray     = Array.fill(4)(0)
+
+    // NOTE: Cannot define toGray function as XLang doesn't allow mutating
+    // arguments and GenC doesn't allow returning arrays
+
+    var idx = 0
+    (while (idx < WIDTH * HEIGHT) {
+      gray(idx) = getGray(source(idx))
+      idx = idx + 1
+    }) invariant { idx >= 0 && idx <= WIDTH * HEIGHT && gray.length == WIDTH * HEIGHT }
+    // NB: the last invariant is very important -- without it the verification times out
+
+    matches(gray, expected)
+  }.holds
+
+  // Only for square kernels
+  case class Kernel(size: Int, buffer: Array[Int])
+
+  def isKernelValid(kernel: Kernel): Boolean =
+    kernel.size > 0 && kernel.size < 1000 && kernel.size % 2 == 1 &&
+    kernel.buffer.length == kernel.size * kernel.size
+
+  def applyFilter(gray: Array[Int], size: Int, idx: Int, kernel: Kernel): Int = {
+    require(size > 0 && size < 1000 &&
+            gray.length == size * size &&
+            idx >= 0 && idx < gray.length &&
+            isKernelValid(kernel))
+
+    def up(x: Int): Int = {
+      if (x < 0) 0 else x
+    } ensuring { _ >= 0 }
+
+    def down(x: Int): Int = {
+      if (x >= size) size - 1 else x
+    } ensuring { _ < size }
+
+    def fix(x: Int): Int = {
+      down(up(x))
+    } ensuring { res => res >= 0 && res < size }
+
+    def at(row: Int, col: Int): Int = {
+      val r = fix(row)
+      val c = fix(col)
+
+      gray(r * size + c)
+    }
+
+    val mid = kernel.size / 2
+
+    val i = idx / size
+    val j = idx % size
+
+    var res = 0
+    var p = -mid
+    (while (p <= mid) {
+      var q = -mid
+
+      (while (q <= mid) {
+        val krow = p + mid
+        val kcol = q + mid
+
+        assert(krow >= 0 && krow < kernel.size)
+        assert(kcol >= 0 && kcol < kernel.size)
+
+        val kidx = krow * kernel.size + kcol
+
+        res += at(i + p, j + q) * kernel.buffer(kidx)
+
+        q = q + 1
+      }) invariant { q >= -mid && q <= mid + 1 }
+
+      p = p + 1
+    }) invariant { p >= -mid && p <= mid + 1 }
+
+    res
+  }
+
+  def testFilterConvolutionSmooth: Boolean = {
+    val gray = Array(127, 255, 51, 0)
+    val expected = Array(124, 158, 76, 73)
+    val size = 2 // grey is size x size
+
+    // NOTE: Cannot define toGray function as XLang doesn't allow mutating
+    // arguments and GenC doesn't allow returning arrays
+
+    val kernel = Kernel(3, Array(1, 1, 1,
+                                 1, 2, 1,
+                                 1, 1, 1))
+
+    val smoothed = Array.fill(gray.length)(0)
+    assert(smoothed.length == expected.length)
+
+    var idx = 0;
+    (while (idx < smoothed.length) {
+      smoothed(idx) = applyFilter(gray, size, idx, kernel) / 10
+      idx = idx + 1
+    }) invariant { idx >= 0 && idx <= smoothed.length && smoothed.length == gray.length }
+
+    matches(smoothed, expected)
+  }.holds
+
+
+  def main: Int = {
+    if (testColorSinglePixel && testColorWholeImage && testFilterConvolutionSmooth) 0
+    else 1
+  } ensuring { _ == 0 }
+
+}
+
+
-- 
GitLab