From 3e8c9098eee26ad53017522d3ecd1949353bc0f9 Mon Sep 17 00:00:00 2001
From: Nicolas Voirol <voirol.nicolas@gmail.com>
Date: Thu, 26 Mar 2015 15:39:53 +0100
Subject: [PATCH] Fixed issue in termination checker and added test-cases

---
 .../solvers/templates/LambdaManager.scala     |  2 +-
 .../scala/leon/termination/ChainBuilder.scala | 10 ++--
 .../leon/termination/ChainComparator.scala    |  2 +-
 .../leon/termination/ChainProcessor.scala     |  3 +-
 .../leon/termination/LoopProcessor.scala      |  3 +-
 .../higher-order/invalid/Continuations1.scala |  6 +--
 .../higher-order/invalid/Lists1.scala         |  7 ---
 .../higher-order/invalid/Lists2.scala         | 51 +++++++++++++++++++
 .../higher-order/invalid/Transformation.scala | 49 ++++++++++++++++++
 9 files changed, 112 insertions(+), 21 deletions(-)
 create mode 100644 testcases/verification/higher-order/invalid/Lists2.scala
 create mode 100644 testcases/verification/higher-order/invalid/Transformation.scala

diff --git a/src/main/scala/leon/solvers/templates/LambdaManager.scala b/src/main/scala/leon/solvers/templates/LambdaManager.scala
index 6c69b458d..202ecc735 100644
--- a/src/main/scala/leon/solvers/templates/LambdaManager.scala
+++ b/src/main/scala/leon/solvers/templates/LambdaManager.scala
@@ -88,7 +88,7 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) {
         clauses ++= newClauses
         newCalls.foreach(p => callBlockers += p._1 -> (callBlockers(p._1) ++ p._2))
         newApps.foreach(p => appBlockers += p._1 -> (appBlockers(p._1) ++ p._2))
-      } else {
+      } else if (!freeLambdas(tpe).contains(caller)) {
         val key = b -> app
 
         // make sure that even if byType(tpe) is empty, app is recorded in blockers
diff --git a/src/main/scala/leon/termination/ChainBuilder.scala b/src/main/scala/leon/termination/ChainBuilder.scala
index 742aca7aa..a93386655 100644
--- a/src/main/scala/leon/termination/ChainBuilder.scala
+++ b/src/main/scala/leon/termination/ChainBuilder.scala
@@ -48,7 +48,7 @@ final case class Chain(relations: List[Relation]) {
 
   lazy val finalParams : Seq[ValDef] = inlining.last._1
 
-  def loop(initialSubst: Map[Identifier, Identifier] = Map(), finalSubst: Map[Identifier, Identifier] = Map()) : Seq[Expr] = {
+  def loop(initialArgs: Seq[Identifier] = Seq.empty, finalArgs: Seq[Identifier] = Seq.empty): Seq[Expr] = {
     def rec(relations: List[Relation], funDef: TypedFunDef, subst: Map[Identifier, Identifier]): Seq[Expr] = {
       val translate : Expr => Expr = {
         val map : Map[Expr, Expr] = subst.map(p => p._1.toVariable -> p._2.toVariable)
@@ -61,18 +61,18 @@ final case class Chain(relations: List[Relation]) {
       lazy val newArgs = args.map(translate)
 
       path.map(translate) ++ (relations.tail match {
-        case Nil => if (finalSubst.isEmpty) Seq.empty else {
-          (tfd.params.map(vd => finalSubst(vd.id).toVariable) zip newArgs).map(p => Equals(p._1, p._2))
-        }
+        case Nil =>
+          (finalArgs zip newArgs).map { case (finalArg, newArg) => Equals(finalArg.toVariable, newArg) }
         case xs =>
           val params = tfd.params.map(_.id)
           val freshParams = tfd.params.map(arg => FreshIdentifier(arg.id.name, arg.getType, true))
           val bindings = (freshParams.map(_.toVariable) zip newArgs).map(p => Equals(p._1, p._2))
           bindings ++ rec(xs, tfd, (params zip freshParams).toMap)
       })
+
     }
 
-    rec(relations, funDef.typed(funDef.tparams.map(_.tp)), initialSubst)
+    rec(relations, funDef.typedWithDef, (funDef.params.map(_.id) zip initialArgs).toMap)
   }
 
   /*
diff --git a/src/main/scala/leon/termination/ChainComparator.scala b/src/main/scala/leon/termination/ChainComparator.scala
index bcaa86c4e..e3f6ed623 100644
--- a/src/main/scala/leon/termination/ChainComparator.scala
+++ b/src/main/scala/leon/termination/ChainComparator.scala
@@ -203,7 +203,7 @@ trait ChainComparator { self : StructuralSize with TerminationChecker =>
         }
 
         val lowers = if (endpoint == LowerBoundEndpoint || endpoint == AnyEndpoint) {
-          Some(And(e2s map { case (path, e2) => implies(andJoin(path), LessThan(e, recons(e2))) }))
+          Some(andJoin(e2s map { case (path, e2) => implies(andJoin(path), LessThan(e, recons(e2))) }))
         } else {
           None
         }
diff --git a/src/main/scala/leon/termination/ChainProcessor.scala b/src/main/scala/leon/termination/ChainProcessor.scala
index 3f1c0b437..f7f02d0e1 100644
--- a/src/main/scala/leon/termination/ChainProcessor.scala
+++ b/src/main/scala/leon/termination/ChainProcessor.scala
@@ -37,8 +37,7 @@ class ChainProcessor(val checker: TerminationChecker with ChainBuilder with Chai
         val e1 = tupleWrap(fd.params.map(_.toVariable))
         val e2s = fdChains.toSeq.map { chain =>
           val freshParams = chain.finalParams.map(arg => FreshIdentifier(arg.id.name, arg.id.getType, true))
-          val finalBindings = (chain.finalParams.map(_.id) zip freshParams).toMap
-          (chain.loop(finalSubst = finalBindings), tupleWrap(freshParams.map(_.toVariable)))
+          (chain.loop(finalArgs = freshParams), tupleWrap(freshParams.map(_.toVariable)))
         }
 
         (e1, e2s, fdChains)
diff --git a/src/main/scala/leon/termination/LoopProcessor.scala b/src/main/scala/leon/termination/LoopProcessor.scala
index 3fedb900d..52f4a69c2 100644
--- a/src/main/scala/leon/termination/LoopProcessor.scala
+++ b/src/main/scala/leon/termination/LoopProcessor.scala
@@ -29,8 +29,7 @@ class LoopProcessor(val checker: TerminationChecker with ChainBuilder with Stren
       for (chain <- cs if !nonTerminating.isDefinedAt(chain.funDef) &&
           (chain.funDef.params zip chain.finalParams).forall(p => p._1.getType == p._2.getType)) {
         val freshParams = chain.funDef.params.map(arg => FreshIdentifier(arg.id.name, arg.getType, true))
-        val finalBindings = (chain.funDef.params.map(_.id) zip freshParams).toMap
-        val path = chain.loop(finalSubst = finalBindings)
+        val path = chain.loop(finalArgs = freshParams)
 
         val srcTuple = tupleWrap(chain.funDef.params.map(_.toVariable))
         val resTuple = tupleWrap(freshParams.map(_.toVariable))
diff --git a/testcases/verification/higher-order/invalid/Continuations1.scala b/testcases/verification/higher-order/invalid/Continuations1.scala
index 9511a8157..82f4bdea4 100644
--- a/testcases/verification/higher-order/invalid/Continuations1.scala
+++ b/testcases/verification/higher-order/invalid/Continuations1.scala
@@ -20,8 +20,8 @@ object Continuations1 {
     pythagoras_cps(a, b)(_ == a*a + b*b)
   }.holds
 
-  def lemma2(a: BigInt, b: BigInt): Boolean = {
-    require(a > 0 && b > 0)
-    pythagoras_cps(a, b)(_ == a*a)
+  def lemma2(a: BigInt, b: BigInt, c: BigInt): Boolean = {
+    require(a > 0 && b > 0 && c > 0)
+    pythagoras_cps(a, b)(_ == c*c)
   }.holds
 }
diff --git a/testcases/verification/higher-order/invalid/Lists1.scala b/testcases/verification/higher-order/invalid/Lists1.scala
index b84787c4e..e7582fad6 100644
--- a/testcases/verification/higher-order/invalid/Lists1.scala
+++ b/testcases/verification/higher-order/invalid/Lists1.scala
@@ -19,13 +19,6 @@ object Lists1 {
 
   def positive_lemma(list: List[Int]): Boolean = {
     positive(list) == forall(list, gt(0))
-  }
-
-  def failling_1(list: List[Int]): Boolean = {
-    list match {
-      case Nil() => positive_lemma(list)
-      case Cons(head, tail) => positive_lemma(list) && failling_1(tail)
-    }
   }.holds
 }
 
diff --git a/testcases/verification/higher-order/invalid/Lists2.scala b/testcases/verification/higher-order/invalid/Lists2.scala
new file mode 100644
index 000000000..777223617
--- /dev/null
+++ b/testcases/verification/higher-order/invalid/Lists2.scala
@@ -0,0 +1,51 @@
+import leon._
+import leon.lang._
+import leon.annotation._
+import leon.collection._
+
+
+object Lists2 {
+
+  /**
+   * SORTING
+   **/
+
+  def isSorted[A](l: List[A])(implicit ord: (A, A) => Boolean): Boolean = l match {
+    case Cons(h1, Cons(h2, _)) if !ord(h1, h2) => false
+    case Cons(h, t) => isSorted(t)
+    case Nil() => true
+  }
+
+  def sort[A](l: List[A])(implicit ord: (A, A) => Boolean): List[A] = {
+    val (res, sres) = bubble(l)
+    res
+    /*
+    if (sres) {
+      sort(res)
+    } else {
+      res
+    }
+    */
+  } ensuring {
+    isSorted(_)
+  }
+
+  def bubble[A](l: List[A])(implicit ord: (A, A) => Boolean): (List[A], Boolean) = {
+    l match {
+      case Cons(h1, t1 @ Cons(h2, t2)) if !ord(h1, h2) => (Cons(h2, Cons(h1, t2)), true)
+      case Cons(h1, t1) =>
+        val (tres, sres) = bubble(t1)
+        (Cons(h1, tres), sres)
+      case Nil() =>
+        (Nil(), false)
+    }
+  } ensuring { _ match {
+    /*res =>
+    res match {*/
+      case (lr, sr) => if (!sr) isSorted(lr) else true
+    //}
+    }
+  }
+
+}
+
diff --git a/testcases/verification/higher-order/invalid/Transformation.scala b/testcases/verification/higher-order/invalid/Transformation.scala
new file mode 100644
index 000000000..83c265aee
--- /dev/null
+++ b/testcases/verification/higher-order/invalid/Transformation.scala
@@ -0,0 +1,49 @@
+import leon._
+import leon.lang._
+
+object Transformation {
+  
+  abstract class Expr
+  case class If(cond: Expr, t: Expr, e: Expr) extends Expr
+  case class Add(e1: Expr, e2: Expr) extends Expr
+  case class Equals(e1: Expr, e2: Expr) extends Expr
+  case class Literal(i: BigInt) extends Expr
+
+  def transform(f: Expr => Option[Expr])(expr: Expr): Expr = {
+    val rec = (x: Expr) => transform(f)(x)
+    val newExpr = expr match {
+      case If(cond, t, e) => If(rec(cond), rec(t), rec(e))
+      case Add(e1, e2) => Add(rec(e1), rec(e2))
+      case Equals(e1, e2) => Equals(rec(e1), rec(e2))
+      case Literal(i) => Literal(i)
+    }
+
+    f(newExpr) match {
+      case Some(e) => e
+      case None() => newExpr
+    }
+  }
+
+  def exists(f: Expr => Boolean)(expr: Expr): Boolean = {
+    val rec = (x: Expr) => exists(f)(x)
+    f(expr) || (expr match {
+      case If(cond, t, e) => rec(cond) || rec(t) || rec(e)
+      case Add(e1, e2) => rec(e1) || rec(e2)
+      case Equals(e1, e2) => rec(e1) || rec(e2)
+      case Literal(i) => false
+    })
+  }
+
+  def test(expr: Expr) = {
+    val t = transform(e => e match {
+      case Equals(Add(Literal(i), Literal(j)), e2) => Some(Equals(Literal(i + j), e2))
+      case Equals(e1, Add(Literal(i), Literal(j))) => Some(Equals(e1, Literal(i + j)))
+      case _ => None[Expr]()
+    })(expr)
+
+    !exists(e => e match {
+      case Equals(_, Add(Literal(i), Literal(j))) => true
+      case _ => false
+    })(t)
+  }.holds
+}
-- 
GitLab