diff --git a/src/main/scala/leon/purescala/Constructors.scala b/src/main/scala/leon/purescala/Constructors.scala
index a4f365a2508f72646488aef29641035ddba0e2d1..cd66e57d665ba5e310cc3b832772eae6af4e2c8c 100644
--- a/src/main/scala/leon/purescala/Constructors.scala
+++ b/src/main/scala/leon/purescala/Constructors.scala
@@ -281,7 +281,27 @@ object Constructors {
     if (a == b && isDeterministic(a)) {
       BooleanLiteral(true)
     } else  {
-      Equals(a, b)
+      (a, b) match {
+        case (a: Literal[_], b: Literal[_]) =>
+          if (a.value == b.value) {
+            BooleanLiteral(true)
+          } else {
+            BooleanLiteral(false)
+          }
+
+        case _ =>
+          Equals(a, b)
+      }
+    }
+  }
+
+  def assertion(c: Expr, err: Option[String], res: Expr) = {
+    if (c == BooleanLiteral(true)) {
+      res
+    } else if (c == BooleanLiteral(false)) {
+      Error(res.getType, err.getOrElse("Assertion failed"))
+    } else {
+      Assert(c, err, res)
     }
   }
 
diff --git a/src/main/scala/leon/purescala/Definitions.scala b/src/main/scala/leon/purescala/Definitions.scala
index 464c91445906d075800412b5f1eb7343ac36a004..d9fd1d1d6696991909ffd5cd9b1f2e95590db7a4 100644
--- a/src/main/scala/leon/purescala/Definitions.scala
+++ b/src/main/scala/leon/purescala/Definitions.scala
@@ -205,8 +205,8 @@ object Definitions {
   // If this class was a method. owner is the original owner of the method
   case class IsMethod(owner: ClassDef) extends FunctionFlag
   // If this function represents a loop that was there before XLangElimination
-  // Contains a copy of the original looping function
-  case class IsLoop(orig: FunDef) extends FunctionFlag
+  // Contains a link to the FunDef where the loop was defined
+  case class IsLoop(owner: FunDef) extends FunctionFlag
   // If extraction fails of the function's body fais, it is marked as abstract
   case object IsAbstract extends FunctionFlag
   // Currently, the only synthetic functions are those that calculate default values of parameters
diff --git a/src/main/scala/leon/purescala/FunctionClosure.scala b/src/main/scala/leon/purescala/FunctionClosure.scala
index 0c18b51e3b9e473556aaf5817b49ad0d8104ea40..07c6781a8389be1df4e16681cd518bb043cb608a 100644
--- a/src/main/scala/leon/purescala/FunctionClosure.scala
+++ b/src/main/scala/leon/purescala/FunctionClosure.scala
@@ -145,11 +145,11 @@ object FunctionClosure extends TransformationPhase {
     )
 
     newFd.fullBody = preMap {
-      case FunctionInvocation(tfd, args) if tfd.fd == inner =>
+      case fi@FunctionInvocation(tfd, args) if tfd.fd == inner =>
         Some(FunctionInvocation(
           newFd.typed(tfd.tps ++ tpFresh.map{ _.tp }),
           args ++ freshVals.drop(args.length).map(Variable)
-        ))
+        ).setPos(fi))
       case _ => None
     }(instBody)
 
diff --git a/src/main/scala/leon/repair/Repairman.scala b/src/main/scala/leon/repair/Repairman.scala
index 4959ae799c8f34b25dbdf1cac812ef8d954b4717..6523a1104127c174edf5c1e9d994be27b797d421 100644
--- a/src/main/scala/leon/repair/Repairman.scala
+++ b/src/main/scala/leon/repair/Repairman.scala
@@ -2,9 +2,11 @@
 
 package leon
 package repair
-  
+
+import purescala.Common._
 import purescala.Definitions._
 import purescala.Expressions._
+import purescala.Extractors._
 import purescala.ExprOps._
 import purescala.Types._
 import purescala.DefOps._
@@ -98,6 +100,60 @@ class Repairman(ctx0: LeonContext, initProgram: Program, fd: FunDef, verifTimeou
             bh.write()
           }
 
+          reporter.ifDebug { printer =>
+            import java.io.FileWriter
+            import java.text.SimpleDateFormat
+            import java.util.Date
+
+            val categoryName = fd.getPos.file.toString.split("/").dropRight(1).lastOption.getOrElse("?")
+            val benchName = categoryName+"."+fd.id.name
+
+            val defs = visibleFunDefsFromMain(program).collect {
+              case fd: FunDef => 1 + fd.params.size + formulaSize(fd.fullBody)
+            }
+
+            val pSize = defs.sum;
+            val fSize = formulaSize(fd.body.get)
+
+            def localizedExprs(n: graph.Node): List[Expr] = {
+              n match {
+                case on: graph.OrNode =>
+                  on.selected.map(localizedExprs).flatten
+                case an: graph.AndNode if an.ri.rule == Focus =>
+                  an.selected.map(localizedExprs).flatten
+                case an: graph.AndNode =>
+                  val TopLevelAnds(clauses) = an.p.ws
+
+                  val res = clauses.collect {
+                    case Guide(expr) => expr
+                  }
+
+                  res.toList
+              }
+            }
+
+            val locSize = localizedExprs(search.g.root).map(formulaSize).sum;
+
+            val (solSize, proof) = solutions.headOption match {
+              case Some((sol, trusted)) =>
+                val solExpr = sol.toSimplifiedExpr(ctx, program)
+                val totalSolSize = formulaSize(solExpr)
+                (locSize+totalSolSize-fSize, if (trusted) "$\\chmark$" else "")
+              case _ =>
+                (0, "X")
+            }
+
+            val date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())
+
+            val fw = new java.io.FileWriter("repair-report.txt", true)
+
+            try {
+              fw.write(f"$date:  $benchName%-30s & $pSize%4d & $fSize%4d & $locSize%4d & $solSize%4d & ${timeTests/1000.0}%2.1f &  ${timeSynth/1000.0}%2.1f & $proof%7s \\\\\n")
+            } finally {
+              fw.close
+            }
+          }(DebugSectionReport)
+
           if (synth.settings.generateDerivationTrees) {
             val dot = new DotGenerator(search.g)
             dot.writeFile("derivation"+ dotGenIds.nextGlobal + ".dot")
diff --git a/src/main/scala/leon/solvers/combinators/UnrollingSolver.scala b/src/main/scala/leon/solvers/combinators/UnrollingSolver.scala
index b9c0dfd94e449ac5a7d130e1279da8ebb7c19b92..1235d69c6d16a2726971cac386732fdcea501b95 100644
--- a/src/main/scala/leon/solvers/combinators/UnrollingSolver.scala
+++ b/src/main/scala/leon/solvers/combinators/UnrollingSolver.scala
@@ -16,6 +16,7 @@ import utils._
 import z3.FairZ3Component.{optFeelingLucky, optUseCodeGen, optAssumePre, optNoChecks, optUnfoldFactor}
 import templates._
 import evaluators._
+import Template._
 
 class UnrollingSolver(val context: LeonContext, val program: Program, underlying: Solver)
   extends Solver
@@ -116,7 +117,7 @@ class UnrollingSolver(val context: LeonContext, val program: Program, underlying
       val optEnabler = evaluator.eval(b, model).result
 
       if (optEnabler == Some(BooleanLiteral(true))) {
-        val optArgs = m.args.map(arg => evaluator.eval(Matcher.argValue(arg), model).result)
+        val optArgs = m.args.map(arg => evaluator.eval(arg.encoded, model).result)
         if (optArgs.forall(_.isDefined)) {
           Set(optArgs.map(_.get))
         } else {
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
index 4ab8fa908b666c09f2f6b65fa03fdd941c4c6e41..820d74662b44ca252418b58087deabbaabfc5025 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
@@ -543,10 +543,8 @@ trait SMTLIBTarget extends Interruptible {
        * ===== Everything else =====
        */
       case ap @ Application(caller, args) =>
-        FunctionApplication(
-          declareLambda(caller.getType.asInstanceOf[FunctionType]),
-          (caller +: args).map(toSMT)
-        )
+        val dyn = declareLambda(caller.getType.asInstanceOf[FunctionType])
+        FunctionApplication(dyn, (caller +: args).map(toSMT))
 
       case Not(u)          => Core.Not(toSMT(u))
       case UMinus(u)       => Ints.Neg(toSMT(u))
diff --git a/src/main/scala/leon/solvers/templates/LambdaManager.scala b/src/main/scala/leon/solvers/templates/LambdaManager.scala
index 75d163815a17fbf31c56b684d58e3d26efe7feaa..036654c25ab64839efa5af4cb0d49a6566ffcf20 100644
--- a/src/main/scala/leon/solvers/templates/LambdaManager.scala
+++ b/src/main/scala/leon/solvers/templates/LambdaManager.scala
@@ -12,9 +12,10 @@ import purescala.Types._
 
 import utils._
 import Instantiation._
+import Template._
 
-case class App[T](caller: T, tpe: FunctionType, args: Seq[T]) {
-  override def toString = "(" + caller + " : " + tpe + ")" + args.mkString("(", ",", ")")
+case class App[T](caller: T, tpe: FunctionType, args: Seq[Arg[T]]) {
+  override def toString = "(" + caller + " : " + tpe + ")" + args.map(_.encoded).mkString("(", ",", ")")
 }
 
 object LambdaTemplate {
@@ -72,6 +73,28 @@ object LambdaTemplate {
   }
 }
 
+trait KeyedTemplate[T, E <: Expr] {
+  val dependencies: Map[Identifier, T]
+  val structuralKey: E
+
+  lazy val key: (E, Seq[T]) = {
+    def rec(e: Expr): Seq[Identifier] = e match {
+      case Variable(id) =>
+        if (dependencies.isDefinedAt(id)) {
+          Seq(id)
+        } else {
+          Seq.empty
+        }
+
+      case Operator(es, _) => es.flatMap(rec)
+
+      case _ => Seq.empty
+    }
+
+    structuralKey -> rec(structuralKey).distinct.map(dependencies)
+  }
+}
+
 class LambdaTemplate[T] private (
   val ids: (Identifier, T),
   val encoder: TemplateEncoder[T],
@@ -87,34 +110,39 @@ class LambdaTemplate[T] private (
   val quantifications: Seq[QuantificationTemplate[T]],
   val matchers: Map[T, Set[Matcher[T]]],
   val lambdas: Seq[LambdaTemplate[T]],
-  private[templates] val dependencies: Map[Identifier, T],
-  private[templates] val structuralKey: Lambda,
-  stringRepr: () => String) extends Template[T] {
+  val dependencies: Map[Identifier, T],
+  val structuralKey: Lambda,
+  stringRepr: () => String) extends Template[T] with KeyedTemplate[T, Lambda] {
 
   val args = arguments.map(_._2)
   val tpe = ids._1.getType.asInstanceOf[FunctionType]
 
-  def substitute(substituter: T => T): LambdaTemplate[T] = {
+  def substitute(substituter: T => T, matcherSubst: Map[T, Matcher[T]]): LambdaTemplate[T] = {
     val newStart = substituter(start)
     val newClauses = clauses.map(substituter)
     val newBlockers = blockers.map { case (b, fis) =>
       val bp = if (b == start) newStart else b
-      bp -> fis.map(fi => fi.copy(args = fi.args.map(substituter)))
+      bp -> fis.map(fi => fi.copy(
+        args = fi.args.map(_.substitute(substituter, matcherSubst))
+      ))
     }
 
     val newApplications = applications.map { case (b, fas) =>
       val bp = if (b == start) newStart else b
-      bp -> fas.map(fa => fa.copy(caller = substituter(fa.caller), args = fa.args.map(substituter)))
+      bp -> fas.map(fa => fa.copy(
+        caller = substituter(fa.caller),
+        args = fa.args.map(_.substitute(substituter, matcherSubst))
+      ))
     }
 
-    val newQuantifications = quantifications.map(_.substitute(substituter))
+    val newQuantifications = quantifications.map(_.substitute(substituter, matcherSubst))
 
     val newMatchers = matchers.map { case (b, ms) =>
       val bp = if (b == start) newStart else b
-      bp -> ms.map(_.substitute(substituter))
+      bp -> ms.map(_.substitute(substituter, matcherSubst))
     }
 
-    val newLambdas = lambdas.map(_.substitute(substituter))
+    val newLambdas = lambdas.map(_.substitute(substituter, matcherSubst))
 
     val newDependencies = dependencies.map(p => p._1 -> substituter(p._2))
 
@@ -139,45 +167,20 @@ class LambdaTemplate[T] private (
     )
   }
 
-  private lazy val str : String = stringRepr()
-  override def toString : String = str
-
-  lazy val key: (Expr, Seq[T]) = {
-    def rec(e: Expr): Seq[Identifier] = e match {
-      case Variable(id) =>
-        if (dependencies.isDefinedAt(id)) {
-          Seq(id)
-        } else {
-          Seq.empty
-        }
-
-      case Operator(es, _) => es.flatMap(rec)
-
-      case _ => Seq.empty
-    }
-
-    structuralKey -> rec(structuralKey).distinct.map(dependencies)
-  }
-
-  override def equals(that: Any): Boolean = that match {
-    case t: LambdaTemplate[T] =>
-      val (lambda1, deps1) = key
-      val (lambda2, deps2) = t.key
-      (lambda1 == lambda2) && {
-        (deps1 zip deps2).forall { case (id1, id2) =>
-          (manager.byID.get(id1), manager.byID.get(id2)) match {
-            case (Some(t1), Some(t2)) => t1 == t2
-            case _ => id1 == id2
-          }
-        }
-      }
-
-    case _ => false
+  def withId(idT: T): LambdaTemplate[T] = {
+    val substituter = encoder.substitute(Map(ids._2 -> idT))
+    new LambdaTemplate[T](
+      ids._1 -> idT, encoder, manager, pathVar, arguments, condVars, exprVars, condTree,
+      clauses map substituter, // make sure the body-defining clause is inlined!
+      blockers, applications, quantifications, matchers, lambdas,
+      dependencies, structuralKey, stringRepr
+    )
   }
 
-  override def hashCode: Int = key.hashCode
+  private lazy val str : String = stringRepr()
+  override def toString : String = str
 
-  override def instantiate(substMap: Map[T, T]): Instantiation[T] = {
+  override def instantiate(substMap: Map[T, Arg[T]]): Instantiation[T] = {
     super.instantiate(substMap) ++ manager.instantiateAxiom(this, substMap)
   }
 }
@@ -186,7 +189,7 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) extends TemplateManager(enco
   private[templates] lazy val trueT = encoder.encodeExpr(Map.empty)(BooleanLiteral(true))
 
   protected[templates] val byID = new IncrementalMap[T, LambdaTemplate[T]]
-  protected val byType          = new IncrementalMap[FunctionType, Set[LambdaTemplate[T]]].withDefaultValue(Set.empty)
+  protected val byType          = new IncrementalMap[FunctionType, Map[(Expr, Seq[T]), LambdaTemplate[T]]].withDefaultValue(Map.empty)
   protected val applications    = new IncrementalMap[FunctionType, Set[(T, App[T])]].withDefaultValue(Set.empty)
   protected val freeLambdas     = new IncrementalMap[FunctionType, Set[T]].withDefaultValue(Set.empty)
 
@@ -203,27 +206,30 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) extends TemplateManager(enco
     }
   }
 
-  def instantiateLambda(template: LambdaTemplate[T]): Instantiation[T] = {
-    val idT = template.ids._2
-    var clauses      : Clauses[T]     = equalityClauses(template)
-    var appBlockers  : AppBlockers[T] = Map.empty.withDefaultValue(Set.empty)
+  def instantiateLambda(template: LambdaTemplate[T]): (T, Instantiation[T]) = {
+    byType(template.tpe).get(template.key) match {
+      case Some(template) =>
+        (template.ids._2, Instantiation.empty)
 
-    // make sure the new lambda isn't equal to any free lambda var
-    clauses ++= freeLambdas(template.tpe).map(pIdT => encoder.mkNot(encoder.mkEquals(pIdT, idT)))
+      case None =>
+        val idT = encoder.encodeId(template.ids._1)
+        val newTemplate = template.withId(idT)
 
-    byID += idT -> template
+        var clauses      : Clauses[T]     = equalityClauses(newTemplate)
+        var appBlockers  : AppBlockers[T] = Map.empty.withDefaultValue(Set.empty)
 
-    if (byType(template.tpe)(template)) {
-      (clauses, Map.empty, Map.empty)
-    } else {
-      byType += template.tpe -> (byType(template.tpe) + template)
+        // make sure the new lambda isn't equal to any free lambda var
+        clauses ++= freeLambdas(newTemplate.tpe).map(pIdT => encoder.mkNot(encoder.mkEquals(idT, pIdT)))
 
-      for (blockedApp @ (_, App(caller, tpe, args)) <- applications(template.tpe)) {
-        val equals = encoder.mkEquals(idT, caller)
-        appBlockers += (blockedApp -> (appBlockers(blockedApp) + TemplateAppInfo(template, equals, args)))
-      }
+        byID += idT -> newTemplate
+        byType += newTemplate.tpe -> (byType(newTemplate.tpe) + (newTemplate.key -> newTemplate))
+
+        for (blockedApp @ (_, App(caller, tpe, args)) <- applications(newTemplate.tpe)) {
+          val equals = encoder.mkEquals(idT, caller)
+          appBlockers += (blockedApp -> (appBlockers(blockedApp) + TemplateAppInfo(newTemplate, equals, args)))
+        }
 
-      (clauses, Map.empty, appBlockers)
+        (idT, (clauses, Map.empty, appBlockers))
     }
   }
 
@@ -244,7 +250,7 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) extends TemplateManager(enco
           // make sure that even if byType(tpe) is empty, app is recorded in blockers
           // so that UnrollingBank will generate the initial block!
           val init = instantiation withApps Map(key -> Set.empty)
-          val inst = byType(tpe).foldLeft(init) {
+          val inst = byType(tpe).values.foldLeft(init) {
             case (instantiation, template) =>
               val equals = encoder.mkEquals(template.ids._2, caller)
               instantiation withApp (key -> TemplateAppInfo(template, equals, args))
@@ -260,7 +266,7 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) extends TemplateManager(enco
 
   private def equalityClauses(template: LambdaTemplate[T]): Seq[T] = {
     val (s1, deps1) = template.key
-    byType(template.tpe).map { that =>
+    byType(template.tpe).values.map { that =>
       val (s2, deps2) = that.key
       val equals = encoder.mkEquals(template.ids._2, that.ids._2)
       if (s1 == s2) {
diff --git a/src/main/scala/leon/solvers/templates/QuantificationManager.scala b/src/main/scala/leon/solvers/templates/QuantificationManager.scala
index c7f715b5eefe573d88eeb94b45293ba7cde646bf..bc31267c09d8023390ac541b0cb99ecece6691ea 100644
--- a/src/main/scala/leon/solvers/templates/QuantificationManager.scala
+++ b/src/main/scala/leon/solvers/templates/QuantificationManager.scala
@@ -14,23 +14,17 @@ import purescala.Types._
 import purescala.Quantification.{QuantificationTypeMatcher => QTM}
 
 import Instantiation._
+import Template._
 
 import scala.collection.mutable.{Map => MutableMap, Set => MutableSet, Stack => MutableStack, Queue}
 
-object Matcher {
-  def argValue[T](arg: Either[T, Matcher[T]]): T = arg match {
-    case Left(value) => value
-    case Right(matcher) => matcher.encoded
-  }
-}
-
-case class Matcher[T](caller: T, tpe: TypeTree, args: Seq[Either[T, Matcher[T]]], encoded: T) {
+case class Matcher[T](caller: T, tpe: TypeTree, args: Seq[Arg[T]], encoded: T) {
   override def toString = caller + args.map {
     case Right(m) => m.toString
     case Left(v) => v.toString
   }.mkString("(",",",")")
 
-  def substitute(substituter: T => T, matcherSubst: Map[T, Matcher[T]] = Map.empty): Matcher[T] = copy(
+  def substitute(substituter: T => T, matcherSubst: Map[T, Matcher[T]]): Matcher[T] = copy(
     caller = substituter(caller),
     args = args.map {
       case Left(v) => matcherSubst.get(v) match {
@@ -58,11 +52,13 @@ class QuantificationTemplate[T](
   val blockers: Map[T, Set[TemplateCallInfo[T]]],
   val applications: Map[T, Set[App[T]]],
   val matchers: Map[T, Set[Matcher[T]]],
-  val lambdas: Seq[LambdaTemplate[T]]) {
+  val lambdas: Seq[LambdaTemplate[T]],
+  val dependencies: Map[Identifier, T],
+  val structuralKey: Forall) extends KeyedTemplate[T, Forall] {
 
   lazy val start = pathVar._2
 
-  def substitute(substituter: T => T): QuantificationTemplate[T] = {
+  def substitute(substituter: T => T, matcherSubst: Map[T, Matcher[T]]): QuantificationTemplate[T] = {
     new QuantificationTemplate[T](
       quantificationManager,
       pathVar._1 -> substituter(start),
@@ -76,15 +72,22 @@ class QuantificationTemplate[T](
       condTree,
       clauses.map(substituter),
       blockers.map { case (b, fis) =>
-        substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(substituter)))
+        substituter(b) -> fis.map(fi => fi.copy(
+          args = fi.args.map(_.substitute(substituter, matcherSubst))
+        ))
       },
       applications.map { case (b, apps) =>
-        substituter(b) -> apps.map(app => app.copy(caller = substituter(app.caller), args = app.args.map(substituter)))
+        substituter(b) -> apps.map(app => app.copy(
+          caller = substituter(app.caller),
+          args = app.args.map(_.substitute(substituter, matcherSubst))
+        ))
       },
       matchers.map { case (b, ms) =>
-        substituter(b) -> ms.map(_.substitute(substituter))
+        substituter(b) -> ms.map(_.substitute(substituter, matcherSubst))
       },
-      lambdas.map(_.substitute(substituter))
+      lambdas.map(_.substitute(substituter, matcherSubst)),
+      dependencies.map { case (id, value) => id -> substituter(value) },
+      structuralKey
     )
   }
 }
@@ -104,7 +107,9 @@ object QuantificationTemplate {
     condTree: Map[Identifier, Set[Identifier]],
     guardedExprs: Map[Identifier, Seq[Expr]],
     lambdas: Seq[LambdaTemplate[T]],
-    subst: Map[Identifier, T]
+    baseSubstMap: Map[Identifier, T],
+    dependencies: Map[Identifier, T],
+    proposition: Forall
   ): QuantificationTemplate[T] = {
 
     val q2s: (Identifier, T) = q2 -> encoder.encodeId(q2)
@@ -113,11 +118,15 @@ object QuantificationTemplate {
 
     val (clauses, blockers, applications, matchers, _) =
       Template.encode(encoder, pathVar, quantifiers, condVars, exprVars, guardedExprs, lambdas,
-        substMap = subst + q2s + insts + guards + qs)
+        substMap = baseSubstMap + q2s + insts + guards + qs)
+
+    val (structuralQuant, structSubst) = normalizeStructure(proposition)
+    val keyDeps = dependencies.map { case (id, idT) => structSubst(id) -> idT }
+    val key = structuralQuant.asInstanceOf[Forall]
 
     new QuantificationTemplate[T](quantificationManager,
-      pathVar, qs, q2s, insts, guards._2, quantifiers,
-      condVars, exprVars, condTree, clauses, blockers, applications, matchers, lambdas)
+      pathVar, qs, q2s, insts, guards._2, quantifiers, condVars, exprVars, condTree,
+      clauses, blockers, applications, matchers, lambdas, keyDeps, key)
   }
 }
 
@@ -130,9 +139,10 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
 
   private val known           = new IncrementalSet[T]
   private val lambdaAxioms    = new IncrementalSet[(LambdaTemplate[T], Seq[(Identifier, T)])]
+  private val templates       = new IncrementalMap[(Expr, Seq[T]), T]
 
   override protected def incrementals: List[IncrementalState] =
-    List(quantifications, instCtx, handled, ignored, known, lambdaAxioms) ++ super.incrementals
+    List(quantifications, instCtx, handled, ignored, known, lambdaAxioms, templates) ++ super.incrementals
 
   private sealed abstract class MatcherKey(val tpe: TypeTree)
   private case class CallerKey(caller: T, tt: TypeTree) extends MatcherKey(tt)
@@ -386,7 +396,7 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
        *      matchers in the argument and quorum positions
        */
           allMappings.filter { s =>
-            def expand(ms: Traversable[(Either[T,Matcher[T]], Either[T,Matcher[T]])]): Set[(Matcher[T], Matcher[T])] = ms.flatMap {
+            def expand(ms: Traversable[(Arg[T], Arg[T])]): Set[(Matcher[T], Matcher[T])] = ms.flatMap {
               case (Right(qm), Right(m)) => Set(qm -> m) ++ expand(qm.args zip m.args)
               case _ => Set.empty[(Matcher[T], Matcher[T])]
             }.toSet
@@ -398,11 +408,11 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
         }
     }
 
-    private def extractSubst(mapping: Set[(Set[T], Matcher[T], Matcher[T])]): (Set[T], Map[T,Either[T, Matcher[T]]], Boolean) = {
+    private def extractSubst(mapping: Set[(Set[T], Matcher[T], Matcher[T])]): (Set[T], Map[T,Arg[T]], Boolean) = {
       var constraints: Set[T] = Set.empty
       var eqConstraints: Set[(T, T)] = Set.empty
       var matcherEqs: List[(T, T)] = Nil
-      var subst: Map[T, Either[T, Matcher[T]]] = Map.empty
+      var subst: Map[T, Arg[T]] = Map.empty
 
       for {
         (bs, qm @ Matcher(qcaller, _, qargs, _), m @ Matcher(caller, _, args, _)) <- mapping
@@ -411,16 +421,16 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
         (qarg, arg) <- (qargs zip args)
       } qarg match {
         case Left(quant) if subst.isDefinedAt(quant) =>
-          eqConstraints += (quant -> Matcher.argValue(arg))
+          eqConstraints += (quant -> arg.encoded)
         case Left(quant) if quantified(quant) =>
           subst += quant -> arg
         case Right(qam) =>
-          val argVal = Matcher.argValue(arg)
+          val argVal = arg.encoded
           eqConstraints += (qam.encoded -> argVal)
           matcherEqs :+= qam.encoded -> argVal
       }
 
-      val substituter = encoder.substitute(subst.mapValues(Matcher.argValue))
+      val substituter = encoder.substitute(subst.mapValues(_.encoded))
       val substConstraints = constraints.filter(_ != trueT).map(substituter)
       val substEqs = eqConstraints.map(p => substituter(p._1) -> p._2)
         .filter(p => p._1 != p._2).map(p => encoder.mkEquals(p._1, p._2))
@@ -437,25 +447,25 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
         val (enablers, subst, isStrict) = extractSubst(mapping)
         val (enabler, optEnabler) = freshBlocker(enablers)
 
-        if (optEnabler.isDefined) {
-          instantiation = instantiation withClause encoder.mkEquals(enabler, optEnabler.get)
-        }
-
-        val baseSubstMap = exprVars.map { case (id, idT) => idT -> encoder.encodeId(id) } ++
-                           freshConds(pathVar._1 -> enabler, condVars, condTree)
-        val lambdaSubstMap = lambdas map (lambda => lambda.ids._2 -> encoder.encodeId(lambda.ids._1))
-        val substMap = subst.mapValues(Matcher.argValue) ++ baseSubstMap ++ lambdaSubstMap ++ instanceSubst(enablers)
+        val baseSubst = subst ++ instanceSubst(enablers).mapValues(Left(_))
+        val (substMap, inst) = Template.substitution(encoder, QuantificationManager.this,
+          condVars, exprVars, condTree, Seq.empty, lambdas, baseSubst, pathVar._1, enabler)
 
         if (!skip(substMap)) {
+          if (optEnabler.isDefined) {
+            instantiation = instantiation withClause encoder.mkEquals(enabler, optEnabler.get)
+          }
+
+          instantiation ++= inst
           instantiation ++= Template.instantiate(encoder, QuantificationManager.this,
             clauses, blockers, applications, Seq.empty, Map.empty[T, Set[Matcher[T]]], lambdas, substMap)
 
-          val msubst = subst.collect { case (c, Right(m)) => c -> m }
-          val substituter = encoder.substitute(substMap)
+          val msubst = substMap.collect { case (c, Right(m)) => c -> m }
+          val substituter = encoder.substitute(substMap.mapValues(_.encoded))
 
           for ((b,ms) <- allMatchers; m <- ms) {
             val sb = enablers ++ (if (b == start) Set.empty else Set(substituter(b)))
-            val sm = m.substitute(substituter, matcherSubst = msubst)
+            val sm = m.substitute(substituter, msubst)
 
             if (matchers(m)) {
               handled += sb -> sm
@@ -473,7 +483,7 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
 
     protected def instanceSubst(enablers: Set[T]): Map[T, T]
 
-    protected def skip(subst: Map[T, T]): Boolean = false
+    protected def skip(subst: Map[T, Arg[T]]): Boolean = false
   }
 
   private class Quantification (
@@ -545,10 +555,11 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
       Map(guardVar -> guardT, blocker -> newBlocker)
     }
 
-    override protected def skip(subst: Map[T, T]): Boolean = {
-      val substituter = encoder.substitute(subst)
+    override protected def skip(subst: Map[T, Arg[T]]): Boolean = {
+      val substituter = encoder.substitute(subst.mapValues(_.encoded))
+      val msubst = subst.collect { case (c, Right(m)) => c -> m }
       allMatchers.forall { case (b, ms) =>
-        ms.forall(m => matchers(m) || instCtx(Set(substituter(b)) -> m.substitute(substituter)))
+        ms.forall(m => matchers(m) || instCtx(Set(substituter(b)) -> m.substitute(substituter, msubst)))
       }
     }
   }
@@ -577,9 +588,9 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
       (m: Matcher[T]) => m.args.collect { case Left(a) if quantified(a) => a }.toSet)
   }
 
-  def instantiateAxiom(template: LambdaTemplate[T], substMap: Map[T, T]): Instantiation[T] = {
-    val quantifiers = template.arguments map {
-      case (id, idT) => id -> substMap(idT)
+  def instantiateAxiom(template: LambdaTemplate[T], substMap: Map[T, Arg[T]]): Instantiation[T] = {
+    val quantifiers = template.arguments flatMap {
+      case (id, idT) => substMap(idT).left.toOption.map(id -> _)
     } filter (p => isQuantifier(p._2))
 
     if (quantifiers.isEmpty || lambdaAxioms(template -> quantifiers)) {
@@ -591,19 +602,24 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
       val guard = FreshIdentifier("guard", BooleanType, true)
       val guardT = encoder.encodeId(guard)
 
-      val substituter = encoder.substitute(substMap + (template.start -> blockerT))
-      val allMatchers = template.matchers map { case (b, ms) => substituter(b) -> ms.map(_.substitute(substituter)) }
+      val substituter = encoder.substitute(substMap.mapValues(_.encoded) + (template.start -> blockerT))
+      val msubst = substMap.collect { case (c, Right(m)) => c -> m }
+
+      val allMatchers = template.matchers map { case (b, ms) =>
+        substituter(b) -> ms.map(_.substitute(substituter, msubst))
+      }
+
       val qMatchers = allMatchers.flatMap(_._2).toSet
 
-      val encArgs = template.args map substituter
+      val encArgs = template.args map (arg => Left(arg).substitute(substituter, msubst))
       val app = Application(Variable(template.ids._1), template.arguments.map(_._1.toVariable))
-      val appT = encoder.encodeExpr((template.arguments.map(_._1) zip encArgs).toMap + template.ids)(app)
-      val selfMatcher = Matcher(template.ids._2, template.tpe, encArgs.map(Left(_)), appT)
+      val appT = encoder.encodeExpr((template.arguments.map(_._1) zip encArgs.map(_.encoded)).toMap + template.ids)(app)
+      val selfMatcher = Matcher(template.ids._2, template.tpe, encArgs, appT)
 
       val enablingClause = encoder.mkImplies(guardT, blockerT)
 
       instantiateAxiom(
-        template.pathVar._1 -> substMap(template.start),
+        template.pathVar._1 -> substituter(template.start),
         blockerT,
         guardT,
         quantifiers,
@@ -614,12 +630,17 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
         template.condTree,
         (template.clauses map substituter) :+ enablingClause,
         template.blockers map { case (b, fis) =>
-          substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(substituter)))
+          substituter(b) -> fis.map(fi => fi.copy(
+            args = fi.args.map(_.substitute(substituter, msubst))
+          ))
         },
         template.applications map { case (b, apps) =>
-          substituter(b) -> apps.map(app => app.copy(caller = substituter(app.caller), args = app.args.map(substituter)))
+          substituter(b) -> apps.map(app => app.copy(
+            caller = substituter(app.caller),
+            args = app.args.map(_.substitute(substituter, msubst))
+          ))
         },
-        template.lambdas map (_.substitute(substituter))
+        template.lambdas map (_.substitute(substituter, msubst))
       )
     }
   }
@@ -664,73 +685,70 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
 
     for {
       m <- matchers
-      sm = m.substitute(substituter)
+      sm = m.substitute(substituter, Map.empty)
       if !instCtx.corresponding(sm).exists(_._2.args == sm.args)
     } instantiation ++= instCtx.instantiate(Set.empty, sm)(quantifications.toSeq : _*)
 
     instantiation
   }
 
-  def instantiateQuantification(template: QuantificationTemplate[T], substMap: Map[T, T]): Instantiation[T] = {
-    val quantified = template.quantifiers.map(_._2).toSet
-    val matchQuorums = extractQuorums(quantified, template.matchers.flatMap(_._2).toSet, template.lambdas)
-
-    var instantiation = Instantiation.empty[T]
+  def instantiateQuantification(template: QuantificationTemplate[T]): (T, Instantiation[T]) = {
+    templates.get(template.key) match {
+      case Some(idT) =>
+        (idT, Instantiation.empty)
 
-    val qs = for (matchers <- matchQuorums) yield {
-      val newQ = encoder.encodeId(template.qs._1)
-      val subst = substMap + (template.qs._2 -> newQ)
-
-      val substituter = encoder.substitute(subst)
-      val quantification = new Quantification(
-        template.pathVar._1 -> substituter(template.start),
-        template.qs._1 -> newQ,
-        template.q2s, template.insts, template.guardVar,
-        quantified,
-        matchers map (_.substitute(substituter)),
-        template.matchers map { case (b, ms) => substituter(b) -> ms.map(_.substitute(substituter)) },
-        template.condVars,
-        template.exprVars,
-        template.condTree,
-        template.clauses map substituter,
-        template.blockers map { case (b, fis) =>
-          substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(substituter)))
-        },
-        template.applications map { case (b, fas) =>
-          substituter(b) -> fas.map(fa => fa.copy(caller = substituter(fa.caller), args = fa.args.map(substituter)))
-        },
-        template.lambdas map (_.substitute(substituter))
-      )
+      case None =>
+        val qT = encoder.encodeId(template.qs._1)
+        val quantified = template.quantifiers.map(_._2).toSet
+        val matchQuorums = extractQuorums(quantified, template.matchers.flatMap(_._2).toSet, template.lambdas)
 
-      quantifications += quantification
+        var instantiation = Instantiation.empty[T]
 
-      val newCtx = new InstantiationContext()
-      for ((b,m) <- instCtx.instantiated) {
-        instantiation ++= newCtx.instantiate(b, m)(quantification)
-      }
-      instCtx.merge(newCtx)
+        val qs = for (matchers <- matchQuorums) yield {
+          val newQ = encoder.encodeId(template.qs._1)
+          val substituter = encoder.substitute(Map(template.qs._2 -> newQ))
+
+          val quantification = new Quantification(
+            template.pathVar,
+            template.qs._1 -> newQ,
+            template.q2s, template.insts, template.guardVar,
+            quantified, matchers, template.matchers,
+            template.condVars, template.exprVars, template.condTree,
+            template.clauses map substituter, // one clause depends on 'q' (and therefore 'newQ')
+            template.blockers, template.applications, template.lambdas
+          )
+
+          quantifications += quantification
+
+          val newCtx = new InstantiationContext()
+          for ((b,m) <- instCtx.instantiated) {
+            instantiation ++= newCtx.instantiate(b, m)(quantification)
+          }
+          instCtx.merge(newCtx)
 
-      quantification.qs._2
-    }
+          quantification.qs._2
+        }
 
-    instantiation = instantiation withClause {
-      val newQs =
-        if (qs.isEmpty) trueT
-        else if (qs.size == 1) qs.head
-        else encoder.mkAnd(qs : _*)
-      encoder.mkImplies(substMap(template.start), encoder.mkEquals(substMap(template.qs._2), newQs))
-    }
+        instantiation = instantiation withClause {
+          val newQs =
+            if (qs.isEmpty) trueT
+            else if (qs.size == 1) qs.head
+            else encoder.mkAnd(qs : _*)
+          encoder.mkImplies(template.start, encoder.mkEquals(qT, newQs))
+        }
 
-    val quantifierSubst = uniformSubst(template.quantifiers)
-    val substituter = encoder.substitute(substMap ++ quantifierSubst)
+        val quantifierSubst = uniformSubst(template.quantifiers)
+        val substituter = encoder.substitute(quantifierSubst)
 
-    for {
-      (_, ms) <- template.matchers; m <- ms
-      sm = m.substitute(substituter)
-      if !instCtx.corresponding(sm).exists(_._2.args == sm.args)
-    } instantiation ++= instCtx.instantiate(Set.empty, sm)(quantifications.toSeq : _*)
+        for {
+          (_, ms) <- template.matchers; m <- ms
+          sm = m.substitute(substituter, Map.empty)
+          if !instCtx.corresponding(sm).exists(_._2.args == sm.args)
+        } instantiation ++= instCtx.instantiate(Set.empty, sm)(quantifications.toSeq : _*)
 
-    instantiation
+        templates += template.key -> qT
+        (qT, instantiation)
+    }
   }
 
   def instantiateMatcher(blocker: T, matcher: Matcher[T]): Instantiation[T] = {
@@ -779,7 +797,7 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
       var prev = emptyT
       for ((b, m) <- insts.toSeq) {
         val next = encoder.encodeId(setNext)
-        val argsMap = (elems zip m.args).map { case (idT, arg) => idT -> Matcher.argValue(arg) }
+        val argsMap = (elems zip m.args).map { case (idT, arg) => idT -> arg.encoded }
         val substMap = Map(guardT -> b, setPrevT -> prev, setNextT -> next) ++ argsMap
         prev = next
         clauses += encoder.substitute(substMap)(setT)
@@ -787,7 +805,7 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
 
       val setMap = Map(setPrevT -> prev)
       for ((b, m) <- ctx.toSeq) {
-        val substMap = setMap ++ (elems zip m.args).map(p => p._1 -> Matcher.argValue(p._2))
+        val substMap = setMap ++ (elems zip m.args).map(p => p._1 -> p._2.encoded)
         clauses += encoder.substitute(substMap)(encoder.mkImplies(b, containsT))
       }
     }
diff --git a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala
index 4434eafd5ae0569640b1c4f7cc60c3946ef56d7b..aa0e5dad6506be945919cb22361cce649f40c077 100644
--- a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala
+++ b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala
@@ -65,7 +65,9 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T],
 
     val invocationEqualsBody : Option[Expr] = lambdaBody match {
       case Some(body) if isRealFunDef =>
-        val b : Expr = And(Equals(invocation, body), liftedEquals(invocation, body, lambdaArguments))
+        val b : Expr = And(
+          liftedEquals(invocation, body, lambdaArguments),
+          Equals(invocation, body))
 
         Some(if(prec.isDefined) {
           Implies(prec.get, b)
@@ -121,7 +123,7 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T],
   }
 
   private def lambdaArgs(expr: Expr): Seq[Identifier] = expr match {
-    case Lambda(args, body) => args.map(_.id) ++ lambdaArgs(body)
+    case Lambda(args, body) => args.map(_.id.freshen) ++ lambdaArgs(body)
     case IsTyped(_, _: FunctionType) => sys.error("Only applicable on lambda chains")
     case _ => Seq.empty
   }
@@ -133,7 +135,7 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T],
         val arguments = currArgs.map(_.toVariable)
         val apply = if (inline) application _ else Application
         val (appliedInv, appliedBody) = (apply(i, arguments), apply(b, arguments))
-        Equals(appliedInv, appliedBody) +: rec(appliedInv, appliedBody, nextArgs, false)
+        rec(appliedInv, appliedBody, nextArgs, false) :+ Equals(appliedInv, appliedBody)
       case _ =>
         assert(args.isEmpty, "liftedEquals should consume all provided arguments")
         Seq.empty
@@ -453,8 +455,10 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T],
               Equals(Variable(q), And(Variable(q2), Variable(inst)))
             ) ++ qGuarded.getOrElse(pathVar, Seq.empty)))
 
+            val dependencies: Map[Identifier, T] = vars.filterNot(quantifiers).map(id => id -> localSubst(id)).toMap
             val template = QuantificationTemplate[T](encoder, manager, pathVar -> encodedCond(pathVar),
-              qs, q2, inst, guard, idQuantifiers zip trQuantifiers, qConds, qExprs, qTree, allGuarded, qTemplates, localSubst)
+              qs, q2, inst, guard, idQuantifiers zip trQuantifiers, qConds, qExprs, qTree, allGuarded, qTemplates, localSubst,
+              dependencies, Forall(quantifiers.toSeq.sortBy(_.uniqueName).map(ValDef(_)), flatConj))
             registerQuantification(template)
             Variable(q)
           }
diff --git a/src/main/scala/leon/solvers/templates/TemplateInfo.scala b/src/main/scala/leon/solvers/templates/TemplateInfo.scala
index 033f15dd6f251026a260ed6344212239e1714a37..27df9b25d13412c106f2bf30d6c75b1266b19d93 100644
--- a/src/main/scala/leon/solvers/templates/TemplateInfo.scala
+++ b/src/main/scala/leon/solvers/templates/TemplateInfo.scala
@@ -5,15 +5,22 @@ package solvers
 package templates
 
 import purescala.Definitions.TypedFunDef
+import Template.Arg
 
-case class TemplateCallInfo[T](tfd: TypedFunDef, args: Seq[T]) {
+case class TemplateCallInfo[T](tfd: TypedFunDef, args: Seq[Arg[T]]) {
   override def toString = {
-    tfd.signature+args.mkString("(", ", ", ")")
+    tfd.signature + args.map {
+      case Right(m) => m.toString
+      case Left(v) => v.toString
+    }.mkString("(", ", ", ")")
   }
 }
 
-case class TemplateAppInfo[T](template: LambdaTemplate[T], equals: T, args: Seq[T]) {
+case class TemplateAppInfo[T](template: LambdaTemplate[T], equals: T, args: Seq[Arg[T]]) {
   override def toString = {
-    template.ids._2 + "|" + equals + args.mkString("(", ",", ")")
+    template.ids._2 + "|" + equals + args.map {
+      case Right(m) => m.toString
+      case Left(v) => v.toString
+    }.mkString("(", ",", ")")
   }
 }
diff --git a/src/main/scala/leon/solvers/templates/TemplateManager.scala b/src/main/scala/leon/solvers/templates/TemplateManager.scala
index bb6629ec16988a79eb686259aea4fa32c6111dbb..2b75f08f0480cf272515bb8d8393e01e29d4dbf1 100644
--- a/src/main/scala/leon/solvers/templates/TemplateManager.scala
+++ b/src/main/scala/leon/solvers/templates/TemplateManager.scala
@@ -57,6 +57,7 @@ object Instantiation {
 }
 
 import Instantiation.{empty => _, _}
+import Template.Arg
 
 trait Template[T] { self =>
   val encoder : TemplateEncoder[T]
@@ -76,27 +77,14 @@ trait Template[T] { self =>
 
   lazy val start = pathVar._2
 
-  private var substCache : Map[Seq[T],Map[T,T]] = Map.empty
-
-  def instantiate(aVar: T, args: Seq[T]): Instantiation[T] = {
-
-    val baseSubstMap : Map[T,T] = substCache.get(args) match {
-      case Some(subst) => subst
-      case None =>
-        val subst = exprVars.map { case (id, idT) => idT -> encoder.encodeId(id) } ++
-                    manager.freshConds(pathVar._1 -> aVar, condVars, condTree) ++
-                    (this.args zip args)
-        substCache += args -> subst
-        subst
-    }
-
-    val lambdaSubstMap = lambdas.map(lambda => lambda.ids._2 -> encoder.encodeId(lambda.ids._1))
-    val quantificationSubstMap = quantifications.map(q => q.qs._2 -> encoder.encodeId(q.qs._1))
-    val substMap : Map[T,T] = baseSubstMap ++ lambdaSubstMap ++ quantificationSubstMap + (start -> aVar)
-    instantiate(substMap)
+  def instantiate(aVar: T, args: Seq[Arg[T]]): Instantiation[T] = {
+    val (substMap, instantiation) = Template.substitution(encoder, manager,
+      condVars, exprVars, condTree, quantifications, lambdas,
+      (this.args zip args).toMap + (start -> Left(aVar)), pathVar._1, aVar)
+    instantiation ++ instantiate(substMap)
   }
 
-  protected def instantiate(substMap: Map[T, T]): Instantiation[T] = {
+  protected def instantiate(substMap: Map[T, Arg[T]]): Instantiation[T] = {
     Template.instantiate(encoder, manager,
       clauses, blockers, applications, quantifications, matchers, lambdas, substMap)
   }
@@ -106,6 +94,23 @@ trait Template[T] { self =>
 
 object Template {
 
+  type Arg[T] = Either[T, Matcher[T]]
+
+  implicit class ArgWrapper[T](arg: Arg[T]) {
+    def encoded: T = arg match {
+      case Left(value) => value
+      case Right(matcher) => matcher.encoded
+    }
+
+    def substitute(substituter: T => T, matcherSubst: Map[T, Matcher[T]]): Arg[T] = arg match {
+      case Left(v) => matcherSubst.get(v) match {
+        case Some(m) => Right(m)
+        case None => Left(substituter(v))
+      }
+      case Right(m) => Right(m.substitute(substituter, matcherSubst))
+    }
+  }
+
   private def invocationMatcher[T](encodeExpr: Expr => T)(tfd: TypedFunDef, args: Seq[Expr]): Matcher[T] = {
     assert(tfd.returnType.isInstanceOf[FunctionType], "invocationMatcher() is only defined on function-typed defs")
 
@@ -144,9 +149,9 @@ object Template {
       encodeExpr(Implies(Variable(b), e))
     }).toSeq
 
-    val optIdCall = optCall.map(tfd => TemplateCallInfo[T](tfd, arguments.map(_._2)))
+    val optIdCall = optCall.map(tfd => TemplateCallInfo[T](tfd, arguments.map(p => Left(p._2))))
     val optIdApp = optApp.map { case (idT, tpe) =>
-      App(idT, bestRealType(tpe).asInstanceOf[FunctionType], arguments.map(_._2))
+      App(idT, bestRealType(tpe).asInstanceOf[FunctionType], arguments.map(p => Left(p._2)))
     }
 
     lazy val invocMatcher = optCall.filter(_.returnType.isInstanceOf[FunctionType])
@@ -163,12 +168,7 @@ object Template {
         var matchInfos : Set[Matcher[T]]          = Set.empty
 
         for (e <- es) {
-          funInfos ++= firstOrderCallsOf(e).map(p => TemplateCallInfo(p._1, p._2.map(encodeExpr)))
-          appInfos ++= firstOrderAppsOf(e).map { case (c, args) =>
-            App(encodeExpr(c), bestRealType(c.getType).asInstanceOf[FunctionType], args.map(encodeExpr))
-          }
-
-          matchInfos ++= fold[Map[Expr, Matcher[T]]] { (expr, res) =>
+          val exprToMatcher = fold[Map[Expr, Matcher[T]]] { (expr, res) =>
             val result = res.flatten.toMap
 
             result ++ (expr match {
@@ -183,7 +183,19 @@ object Template {
                 Some(expr -> Matcher(encodeExpr(c), bestRealType(c.getType), encodedArgs, encodeExpr(expr)))
               case _ => None
             })
-          }(e).values
+          }(e)
+
+          def encodeArg(arg: Expr): Arg[T] = exprToMatcher.get(arg) match {
+            case Some(matcher) => Right(matcher)
+            case None => Left(encodeExpr(arg))
+          }
+
+          funInfos ++= firstOrderCallsOf(e).map(p => TemplateCallInfo(p._1, p._2.map(encodeArg)))
+          appInfos ++= firstOrderAppsOf(e).map { case (c, args) =>
+            App(encodeExpr(c), bestRealType(c.getType).asInstanceOf[FunctionType], args.map(encodeArg))
+          }
+
+          matchInfos ++= exprToMatcher.values
         }
 
         val calls = funInfos -- optIdCall
@@ -194,7 +206,7 @@ object Template {
 
         val matchs = matchInfos.filter { case m @ Matcher(mc, mtpe, margs, _) =>
           !optIdApp.exists { case App(ac, atpe, aargs) =>
-            mc == ac && mtpe == atpe && margs.map(Matcher.argValue) == aargs
+            mc == ac && mtpe == atpe && margs == aargs
           }
         } ++ (if (funInfos.exists(info => Some(info) == optIdCall)) invocMatcher else None)
 
@@ -212,8 +224,9 @@ object Template {
       " * Activating boolean : " + pathVar._1 + "\n" +
       " * Control booleans   : " + condVars.keys.mkString(", ") + "\n" +
       " * Expression vars    : " + exprVars.keys.mkString(", ") + "\n" +
-      " * Clauses            : " +
-        (for ((b,es) <- guardedExprs; e <- es) yield (b + " ==> " + e)).mkString("\n   ") + "\n" +
+      " * Clauses            : " + (if (guardedExprs.isEmpty) "\n" else {
+        "\n   " + (for ((b,es) <- guardedExprs; e <- es) yield (b + " ==> " + e)).mkString("\n   ") + "\n"
+      }) +
       " * Invocation-blocks  :" + (if (blockers.isEmpty) "\n" else {
         "\n   " + blockers.map(p => p._1 + " ==> " + p._2).mkString("\n   ") + "\n"
       }) +
@@ -231,6 +244,60 @@ object Template {
     (clauses, encodedBlockers, encodedApps, encodedMatchers, stringRepr)
   }
 
+  def substitution[T](
+    encoder: TemplateEncoder[T],
+    manager: QuantificationManager[T],
+    condVars: Map[Identifier, T],
+    exprVars: Map[Identifier, T],
+    condTree: Map[Identifier, Set[Identifier]],
+    quantifications: Seq[QuantificationTemplate[T]],
+    lambdas: Seq[LambdaTemplate[T]],
+    baseSubst: Map[T, Arg[T]],
+    pathVar: Identifier,
+    aVar: T
+  ): (Map[T, Arg[T]], Instantiation[T]) = {
+    val freshSubst = exprVars.map { case (id, idT) => idT -> encoder.encodeId(id) } ++
+                     manager.freshConds(pathVar -> aVar, condVars, condTree)
+    val matcherSubst = baseSubst.collect { case (c, Right(m)) => c -> m }
+    var subst = freshSubst.mapValues(Left(_)) ++ baseSubst
+
+    // /!\ CAREFUL /!\
+    // We have to be wary while computing the lambda subst map since lambdas can
+    // depend on each other. However, these dependencies cannot be cyclic so it
+    // suffices to make sure the traversal order is correct.
+    var instantiation : Instantiation[T] = Instantiation.empty
+    var seen          : Set[LambdaTemplate[T]] = Set.empty
+
+    val lambdaKeys = lambdas.map(lambda => lambda.ids._1 -> lambda).toMap
+    def extractSubst(lambda: LambdaTemplate[T]): Unit = {
+      for {
+        dep <- lambda.dependencies.flatMap(p => lambdaKeys.get(p._1))
+        if !seen(dep)
+      } extractSubst(dep)
+
+      if (!seen(lambda)) {
+        val substMap = subst.mapValues(_.encoded)
+        val substLambda = lambda.substitute(encoder.substitute(substMap), matcherSubst)
+        val (idT, inst) = manager.instantiateLambda(substLambda)
+        instantiation ++= inst
+        subst += lambda.ids._2 -> Left(idT)
+        seen += lambda
+      }
+    }
+
+    for (l <- lambdas) extractSubst(l)
+
+    for (q <- quantifications) {
+      val substMap = subst.mapValues(_.encoded)
+      val substQuant = q.substitute(encoder.substitute(substMap), matcherSubst)
+      val (qT, inst) = manager.instantiateQuantification(substQuant)
+      instantiation ++= inst
+      subst += q.qs._2 -> Left(qT)
+    }
+
+    (subst, instantiation)
+  }
+
   def instantiate[T](
     encoder: TemplateEncoder[T],
     manager: QuantificationManager[T],
@@ -240,33 +307,27 @@ object Template {
     quantifications: Seq[QuantificationTemplate[T]],
     matchers: Map[T, Set[Matcher[T]]],
     lambdas: Seq[LambdaTemplate[T]],
-    substMap: Map[T, T]
+    substMap: Map[T, Arg[T]]
   ): Instantiation[T] = {
 
-    val substituter : T => T = encoder.substitute(substMap)
+    val substituter : T => T = encoder.substitute(substMap.mapValues(_.encoded))
+    val msubst = substMap.collect { case (c, Right(m)) => c -> m }
 
     val newClauses = clauses.map(substituter)
     val newBlockers = blockers.map { case (b,fis) =>
-      substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(substituter)))
+      substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(_.substitute(substituter, msubst))))
     }
 
     var instantiation: Instantiation[T] = (newClauses, newBlockers, Map.empty)
 
-    for (lambda <- lambdas) {
-      instantiation ++= manager.instantiateLambda(lambda.substitute(substituter))
-    }
-
     for ((b,apps) <- applications; bp = substituter(b); app <- apps) {
-      val newApp = app.copy(caller = substituter(app.caller), args = app.args.map(substituter))
+      val newApp = app.copy(caller = substituter(app.caller), args = app.args.map(_.substitute(substituter, msubst)))
       instantiation ++= manager.instantiateApp(bp, newApp)
     }
 
     for ((b, matchs) <- matchers; bp = substituter(b); m <- matchs) {
-      instantiation ++= manager.instantiateMatcher(bp, m.substitute(substituter))
-    }
-
-    for (q <- quantifications) {
-      instantiation ++= manager.instantiateQuantification(q, substMap)
+      val newMatcher = m.substitute(substituter, msubst)
+      instantiation ++= manager.instantiateMatcher(bp, newMatcher)
     }
 
     instantiation
@@ -343,8 +404,8 @@ class FunctionTemplate[T] private(
   private lazy val str : String = stringRepr()
   override def toString : String = str
 
-  override def instantiate(aVar: T, args: Seq[T]): (Seq[T], Map[T, Set[TemplateCallInfo[T]]], Map[(T, App[T]), Set[TemplateAppInfo[T]]]) = {
-    if (!isRealFunDef) manager.registerFree(tfd.params.map(_.id) zip args)
+  override def instantiate(aVar: T, args: Seq[Arg[T]]): Instantiation[T] = {
+    if (!isRealFunDef) manager.registerFree(tfd.params.map(_.id) zip args.map(_.left.get))
     super.instantiate(aVar, args)
   }
 }
diff --git a/src/main/scala/leon/solvers/templates/UnrollingBank.scala b/src/main/scala/leon/solvers/templates/UnrollingBank.scala
index d1c4432a3c69f1882c9b4a1787a12dc8cf64f520..4543262d74204dd9f77d3eeea8882bf543956a90 100644
--- a/src/main/scala/leon/solvers/templates/UnrollingBank.scala
+++ b/src/main/scala/leon/solvers/templates/UnrollingBank.scala
@@ -171,7 +171,7 @@ class UnrollingBank[T <% Printable](ctx: LeonContext, templateGenerator: Templat
     // define an activating boolean...
     val template = templateGenerator.mkTemplate(expr)
 
-    val trArgs = template.tfd.params.map(vd => bindings(Variable(vd.id)))
+    val trArgs = template.tfd.params.map(vd => Left(bindings(Variable(vd.id))))
 
     for (vd <- template.tfd.params if vd.getType.isInstanceOf[FunctionType]) {
       functionVars += vd.getType -> (functionVars.getOrElse(vd.getType, Set()) + bindings(vd.toVariable))
@@ -240,16 +240,22 @@ class UnrollingBank[T <% Printable](ctx: LeonContext, templateGenerator: Templat
     callInfos --= ids
 
     val apps = ids.flatMap(id => blockerToApps.get(id))
-    val thisAppInfos = apps.map(app => app -> appInfos(app))
+    val thisAppInfos = apps.map(app => app -> {
+      val (gen, _, _, _, infos) = appInfos(app)
+      (gen, infos)
+    })
+
     blockerToApps --= ids
     appInfos --= apps
 
-    for ((app, (_, _, _, _, infos)) <- thisAppInfos if infos.nonEmpty) {
+    for ((app, (_, infos)) <- thisAppInfos if infos.nonEmpty) {
       val extension = extendAppBlock(app, infos)
       reporter.debug(" -> extending lambda blocker: " + extension)
       newClauses :+= extension
     }
 
+    var fastAppInfos : Map[(T, App[T]), (Int, Set[TemplateAppInfo[T]])] = Map.empty
+
     for ((id, (gen, _, _, infos)) <- newCallInfos; info @ TemplateCallInfo(tfd, args) <- infos) {
       var newCls = Seq[T]()
 
@@ -268,13 +274,23 @@ class UnrollingBank[T <% Printable](ctx: LeonContext, templateGenerator: Templat
           //reporter.debug(template)
 
           val (newExprs, callBlocks, appBlocks) = template.instantiate(defBlocker, args)
-          val blockExprs = freshAppBlocks(appBlocks.keys)
+
+          // we handle obvious appBlocks in an immediate manner in order to increase
+          // performance for folds that just pass a lambda around to recursive calls
+          val (fastApps, nextApps) = appBlocks.partition(p => p._2.toSeq match {
+            case Seq(TemplateAppInfo(_, equals, _)) if equals == manager.trueT => true
+            case _ => false
+          })
+
+          fastAppInfos ++= fastApps.mapValues(gen -> _)
+
+          val blockExprs = freshAppBlocks(nextApps.keys)
 
           for((b, newInfos) <- callBlocks) {
             registerCallBlocker(nextGeneration(gen), b, newInfos)
           }
 
-          for ((app, newInfos) <- appBlocks) {
+          for ((app, newInfos) <- nextApps) {
             registerAppBlocker(nextGeneration(gen), app, newInfos)
           }
 
@@ -296,7 +312,7 @@ class UnrollingBank[T <% Printable](ctx: LeonContext, templateGenerator: Templat
       newClauses ++= newCls
     }
 
-    for ((app @ (b, _), (gen, _, _, _, infos)) <- thisAppInfos; info @ TemplateAppInfo(template, equals, args) <- infos) {
+    for ((app @ (b, _), (gen, infos)) <- thisAppInfos ++ fastAppInfos; info @ TemplateAppInfo(template, equals, args) <- infos) {
       var newCls = Seq.empty[T]
 
       val lambdaBlocker = lambdaBlockers.get(info) match {
diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
index 6a96848c5fb283ec1a6ae22817afff95f9300122..3d39ae7e7e99e45b344859d46496c31baa17ad8c 100644
--- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
@@ -17,6 +17,7 @@ import purescala.ExprOps._
 import purescala.Types._
 
 import solvers.templates._
+import Template._
 
 import evaluators._
 
@@ -66,7 +67,7 @@ class FairZ3Solver(val context: LeonContext, val program: Program)
 
       if (optEnabler == Some(true)) {
         val optArgs = (m.args zip fromTypes).map {
-          p => softFromZ3Formula(model, model.eval(Matcher.argValue(p._1), true).get, p._2)
+          p => softFromZ3Formula(model, model.eval(p._1.encoded, true).get, p._2)
         }
 
         if (optArgs.forall(_.isDefined)) {
@@ -243,7 +244,7 @@ class FairZ3Solver(val context: LeonContext, val program: Program)
             solver.assertCnstr(clause)
           }
 
-          reporter.debug(" - Verifying model transitivity")
+          reporter.debug(" - Enforcing model transitivity")
           val timer = context.timers.solvers.z3.check.start()
           solver.push() // FIXME: remove when z3 bug is fixed
           val res = solver.checkAssumptions((assumptionsAsZ3 ++ unrollingBank.satisfactionAssumptions) :_*)
diff --git a/src/main/scala/leon/synthesis/ConversionPhase.scala b/src/main/scala/leon/synthesis/ConversionPhase.scala
index d172c27204e8fac1219ad4041221ad874f4b9ba2..13f1788fffec11ca03139210d52815699d386324 100644
--- a/src/main/scala/leon/synthesis/ConversionPhase.scala
+++ b/src/main/scala/leon/synthesis/ConversionPhase.scala
@@ -189,6 +189,8 @@ object ConversionPhase extends UnitPhase[Program] {
 
     // extract spec from chooses at the top-level
     fullBody match {
+      case Require(_, Choose(spec)) =>
+        withPostcondition(fullBody, Some(spec))
       case Choose(spec) =>
         withPostcondition(fullBody, Some(spec))
       case _ =>
diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala
index 5565aa4e54c970d08f8ba29bcb32c95f0c05e7bf..cd27e272d53e9669f4c2d1f2c8e07356819b4827 100644
--- a/src/main/scala/leon/synthesis/Rules.scala
+++ b/src/main/scala/leon/synthesis/Rules.scala
@@ -42,10 +42,12 @@ object Rules {
     Unification.OccursCheck, // probably useless
     Disunification.Decomp,
     ADTDual,
-    //OnePoint,
+    OnePoint,
     Ground,
     CaseSplit,
+    IndependentSplit,
     IfSplit,
+    InputSplit,
     UnusedInput,
     EquivalentInputs,
     UnconstrainedOutput,
diff --git a/src/main/scala/leon/synthesis/SynthesisPhase.scala b/src/main/scala/leon/synthesis/SynthesisPhase.scala
index 72cfffec3f8ef3fd8a526d778fda1f26a9ec1a41..b9ba6df1f688e01edf631e995ba2f8623bcfc5fe 100644
--- a/src/main/scala/leon/synthesis/SynthesisPhase.scala
+++ b/src/main/scala/leon/synthesis/SynthesisPhase.scala
@@ -6,6 +6,7 @@ package synthesis
 import purescala.ExprOps._
 
 import purescala.ScalaPrinter
+import leon.utils._
 import purescala.Definitions.{Program, FunDef}
 import leon.utils.ASCIIHelpers
 
@@ -20,12 +21,11 @@ object SynthesisPhase extends TransformationPhase {
   val optDerivTrees  = LeonFlagOptionDef( "derivtrees", "Generate derivation trees", false)
 
   // CEGIS options
-  val optCEGISShrink     = LeonFlagOptionDef( "cegis:shrink",     "Shrink non-det programs when tests pruning works well",  true)
   val optCEGISOptTimeout = LeonFlagOptionDef( "cegis:opttimeout", "Consider a time-out of CE-search as untrusted solution", true)
   val optCEGISVanuatoo   = LeonFlagOptionDef( "cegis:vanuatoo",   "Generate inputs using new korat-style generator",       false)
 
   override val definedOptions : Set[LeonOptionDef[Any]] =
-    Set(optManual, optCostModel, optDerivTrees, optCEGISShrink, optCEGISOptTimeout, optCEGISVanuatoo)
+    Set(optManual, optCostModel, optDerivTrees, optCEGISOptTimeout, optCEGISVanuatoo)
 
   def processOptions(ctx: LeonContext): SynthesisSettings = {
     val ms = ctx.findOption(optManual)
@@ -57,7 +57,6 @@ object SynthesisPhase extends TransformationPhase {
       manualSearch = ms,
       functions = ctx.findOption(SharedOptions.optFunctions) map { _.toSet },
       cegisUseOptTimeout = ctx.findOption(optCEGISOptTimeout),
-      cegisUseShrink = ctx.findOption(optCEGISShrink),
       cegisUseVanuatoo = ctx.findOption(optCEGISVanuatoo)
     )
   }
@@ -74,21 +73,25 @@ object SynthesisPhase extends TransformationPhase {
 
       val synthesizer = new Synthesizer(ctx, program, ci, options)
 
-      val (search, solutions) = synthesizer.validate(synthesizer.synthesize(), allowPartial = true)
+      val to = new TimeoutFor(ctx.interruptManager)
 
-      try {
-        if (options.generateDerivationTrees) {
-          val dot = new DotGenerator(search.g)
-          dot.writeFile("derivation"+dotGenIds.nextGlobal+".dot")
-        }
+      to.interruptAfter(options.timeoutMs) {
+        val (search, solutions) = synthesizer.validate(synthesizer.synthesize(), allowPartial = true)
+
+        try {
+          if (options.generateDerivationTrees) {
+            val dot = new DotGenerator(search.g)
+            dot.writeFile("derivation"+dotGenIds.nextGlobal+".dot")
+          }
 
-        val (sol, _) = solutions.head
+          val (sol, _) = solutions.head
 
-        val expr = sol.toSimplifiedExpr(ctx, program)
-        fd.body = fd.body.map(b => replace(Map(ci.source -> expr), b))
-        functions += fd
-      } finally {
-        synthesizer.shutdown()
+          val expr = sol.toSimplifiedExpr(ctx, program)
+          fd.body = fd.body.map(b => replace(Map(ci.source -> expr), b))
+          functions += fd
+        } finally {
+          synthesizer.shutdown()
+        }
       }
     }
 
diff --git a/src/main/scala/leon/synthesis/SynthesisSettings.scala b/src/main/scala/leon/synthesis/SynthesisSettings.scala
index 9d227bdb611f2ca44eb70a95ce52bc506712e160..5202818e18765ebf4086ef41d1685967a14940d0 100644
--- a/src/main/scala/leon/synthesis/SynthesisSettings.scala
+++ b/src/main/scala/leon/synthesis/SynthesisSettings.scala
@@ -17,7 +17,6 @@ case class SynthesisSettings(
   
   // Cegis related options
   cegisUseOptTimeout: Option[Boolean] = None,
-  cegisUseShrink: Option[Boolean]     = None,
   cegisUseVanuatoo: Option[Boolean]   = None
 
 )
diff --git a/src/main/scala/leon/synthesis/Synthesizer.scala b/src/main/scala/leon/synthesis/Synthesizer.scala
index 35fdfb845ae0a5de611ab3a01a3111005aff7a05..bafed6ec2bab51539bfc0547563bbad2aeea873e 100644
--- a/src/main/scala/leon/synthesis/Synthesizer.scala
+++ b/src/main/scala/leon/synthesis/Synthesizer.scala
@@ -8,6 +8,7 @@ import purescala.ExprOps._
 import purescala.DefOps._
 import purescala.ScalaPrinter
 import solvers._
+import leon.utils._
 
 import scala.concurrent.duration._
 
@@ -34,9 +35,10 @@ class Synthesizer(val context : LeonContext,
     }
   }
 
-  def synthesize(): (Search, Stream[Solution]) = {
+  private var lastTime: Long = 0
 
-    reporter.ifDebug { printer => 
+  def synthesize(): (Search, Stream[Solution]) = {
+    reporter.ifDebug { printer =>
       printer(problem.eb.asString("Tests available for synthesis")(context))
     }
 
@@ -47,8 +49,12 @@ class Synthesizer(val context : LeonContext,
     val sols = s.search(sctx)
 
     val diff = t.stop()
+
+    lastTime = diff
+
     reporter.info("Finished in "+diff+"ms")
 
+
     (s, sols)
   }
 
@@ -62,6 +68,43 @@ class Synthesizer(val context : LeonContext,
         validateSolution(s, sol, 5.seconds)
     }
 
+    // Print out report for synthesis, if necessary
+    reporter.ifDebug { printer =>
+      import java.io.FileWriter
+      import java.text.SimpleDateFormat
+      import java.util.Date
+
+      val categoryName = ci.fd.getPos.file.toString.split("/").dropRight(1).lastOption.getOrElse("?")
+      val benchName = categoryName+"."+ci.fd.id.name
+      var time = lastTime/1000.0;
+
+      val defs = visibleDefsFrom(ci.fd)(program).collect {
+        case cd: ClassDef => 1 + cd.fields.size
+        case fd: FunDef => 1 + fd.params.size + formulaSize(fd.fullBody)
+      }
+
+      val psize = defs.sum;
+
+
+      val (size, calls, proof) = result.headOption match {
+        case Some((sol, trusted)) =>
+          val expr = sol.toSimplifiedExpr(context, program)
+          (formulaSize(expr), functionCallsOf(expr).size, if (trusted) "$\\surd$" else "")
+        case _ =>
+          (0, 0, "X")
+      }
+
+      val date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())
+
+      val fw = new java.io.FileWriter("synthesis-report.txt", true)
+
+      try {
+        fw.write(f"$date:  $benchName%-50s & $psize%4d & $size%4d & $calls%4d & $proof%7s & $time%2.1f \\\\\n")
+      } finally {
+        fw.close
+      }
+    }(DebugSectionReport)
+
     (s, if (result.isEmpty && allowPartial) {
       List((new PartialSolution(s.g, true).getSolution, false)).toStream
     } else {
diff --git a/src/main/scala/leon/synthesis/rules/CEGISLike.scala b/src/main/scala/leon/synthesis/rules/CEGISLike.scala
index 5d06aa76a3c1186e806edf605431643e6b2a9359..4f03c9bed6ca7c7ce5338d04283483ab9f348890 100644
--- a/src/main/scala/leon/synthesis/rules/CEGISLike.scala
+++ b/src/main/scala/leon/synthesis/rules/CEGISLike.scala
@@ -45,14 +45,10 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
     // CEGIS Flags to activate or deactivate features
     val useOptTimeout    = sctx.settings.cegisUseOptTimeout.getOrElse(true)
     val useVanuatoo      = sctx.settings.cegisUseVanuatoo.getOrElse(false)
-    val useShrink        = sctx.settings.cegisUseShrink.getOrElse(false)
 
     // Limits the number of programs CEGIS will specifically validate individually
     val validateUpTo     = 3
 
-    // Shrink the program when the ratio of passing cases is less than the threshold
-    val shrinkThreshold  = 1.0/2
-
     val interruptManager = sctx.context.interruptManager
 
     val params = getParams(sctx, p)
@@ -67,9 +63,7 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
 
       val grammar = SizeBoundedGrammar(params.grammar)
 
-      def rootLabel(tpe: TypeTree) = SizedLabel(params.rootLabel(tpe), termSize)
-
-      def xLabels = p.xs.map(x => rootLabel(x.getType))
+      def rootLabel = SizedLabel(params.rootLabel(tupleTypeWrap(p.xs.map(_.getType))), termSize)
 
       var nAltsCache = Map[SizedLabel[T], Int]()
 
@@ -84,7 +78,7 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
       }
 
       def allProgramsCount(): Int = {
-        xLabels.map(countAlternatives).product
+        countAlternatives(rootLabel)
       }
 
       /**
@@ -108,7 +102,7 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
 
 
       // C identifiers corresponding to p.xs
-      private var rootCs: Seq[Identifier]    = Seq()
+      private var rootC: Identifier    = _
 
       private var bs: Set[Identifier]        = Set()
 
@@ -179,9 +173,9 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
 
         val cGen = new CGenerator()
 
-        rootCs = for (l <- xLabels) yield {
-          val c = cGen.getNext(l)
-          defineCTreeFor(l, c)
+        rootC = {
+          val c = cGen.getNext(rootLabel)
+          defineCTreeFor(rootLabel, c)
           c
         }
 
@@ -244,7 +238,7 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
           }
         }
 
-        allProgramsFor(rootCs)
+        allProgramsFor(Seq(rootC))
       }
 
       private def debugCTree(cTree: Map[Identifier, Seq[(Identifier, Seq[Expr] => Expr, Seq[Identifier])]],
@@ -299,11 +293,11 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
           cToFd(c).fullBody = body
         }
 
-        // Top-level expression for rootCs
-        val expr = tupleWrap(rootCs.map { c =>
-          val fd = cToFd(c)
+        // Top-level expression for rootC
+        val expr = {
+          val fd = cToFd(rootC)
           FunctionInvocation(fd.typed, fd.params.map(_.toVariable))
-        })
+        }
 
         (expr, cToFd.values.toSeq)
       }
@@ -441,7 +435,7 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
           }
         }
 
-        tupleWrap(rootCs.map(c => getCValue(c)))
+        getCValue(rootC)
       }
 
       /**
@@ -521,7 +515,7 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
         val bvs = if (isMinimal) {
           bs
         } else {
-          rootCs.flatMap(filterBTree).toSet
+          filterBTree(rootC)
         }
 
         excludedPrograms += bvs
@@ -829,14 +823,13 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) {
 
                     if (nPassing <= validateUpTo) {
                       // All programs failed verification, we filter everything out and unfold
-                      //ndProgram.shrinkTo(Set(), unfolding == maxUnfoldings)
                       doFilter     = false
                       skipCESearch = true
                     }
                 }
               }
 
-              if (doFilter && !(nPassing < nInitial * shrinkThreshold && useShrink)) {
+              if (doFilter) {
                 sctx.reporter.debug("Excluding "+wrongPrograms.size+" programs")
                 wrongPrograms.foreach {
                   ndProgram.excludeProgram(_, true)
diff --git a/src/main/scala/leon/synthesis/rules/DetupleInput.scala b/src/main/scala/leon/synthesis/rules/DetupleInput.scala
index ed68fbfac84543b1922b44cb91273043756b3cb1..2ae2b1d5d0292a6ed725055e61b1b4af4100a63c 100644
--- a/src/main/scala/leon/synthesis/rules/DetupleInput.scala
+++ b/src/main/scala/leon/synthesis/rules/DetupleInput.scala
@@ -30,20 +30,28 @@ case object DetupleInput extends NormalizingRule("Detuple In") {
      * into a list of fresh typed identifiers, the tuple of these new identifiers,
      * and the mapping of those identifiers to their respective expressions.
      */
-    def decompose(id: Identifier): (List[Identifier], Expr, Map[Identifier, Expr]) = id.getType match {
+    def decompose(id: Identifier): (List[Identifier], Expr, Map[Identifier, Expr], Expr => Seq[Expr]) = id.getType match {
       case cct @ CaseClassType(ccd, _) if !ccd.isAbstract =>
         val newIds = cct.fields.map{ vd => FreshIdentifier(vd.id.name, vd.getType, true) }
 
         val map = (ccd.fields zip newIds).map{ case (vd, nid) => nid -> caseClassSelector(cct, Variable(id), vd.id) }.toMap
 
-        (newIds.toList, CaseClass(cct, newIds.map(Variable)), map)
+        val tMap: (Expr => Seq[Expr]) = {
+          case CaseClass(ccd, fields) => fields
+        }
+
+        (newIds.toList, CaseClass(cct, newIds.map(Variable)), map, tMap)
 
       case TupleType(ts) =>
         val newIds = ts.zipWithIndex.map{ case (t, i) => FreshIdentifier(id.name+"_"+(i+1), t, true) }
 
         val map = newIds.zipWithIndex.map{ case (nid, i) => nid -> TupleSelect(Variable(id), i+1) }.toMap
 
-        (newIds.toList, tupleWrap(newIds.map(Variable)), map)
+        val tMap: (Expr => Seq[Expr]) = {
+          case Tuple(fields) => fields
+        }
+
+        (newIds.toList, tupleWrap(newIds.map(Variable)), map, tMap)
 
       case _ => sys.error("woot")
     }
@@ -55,9 +63,11 @@ case object DetupleInput extends NormalizingRule("Detuple In") {
 
       var reverseMap = Map[Identifier, Expr]()
 
+      var ebMapInfo = Map[Identifier, Expr => Seq[Expr]]()
+
       val subAs = p.as.map { a =>
         if (isDecomposable(a)) {
-          val (newIds, expr, map) = decompose(a)
+          val (newIds, expr, map, tMap) = decompose(a)
 
           subProblem = subst(a -> expr, subProblem)
           subPc      = subst(a -> expr, subPc)
@@ -65,12 +75,25 @@ case object DetupleInput extends NormalizingRule("Detuple In") {
 
           reverseMap ++= map
 
+          ebMapInfo += a -> tMap
+
           newIds
         } else {
           List(a)
         }
       }
 
+      var eb = p.qeb.mapIns { info =>
+        List(info.flatMap { case (id, v) =>
+          ebMapInfo.get(id) match {
+            case Some(m) =>
+              m(v)
+            case None =>
+              List(v)
+          }
+        })
+      }
+
       val newAs = subAs.flatten
 
       // Recompose CaseClasses and Tuples.
@@ -101,7 +124,7 @@ case object DetupleInput extends NormalizingRule("Detuple In") {
         case other => other
       }
       
-      val sub = Problem(newAs, subWs, subPc, subProblem, p.xs)
+      val sub = Problem(newAs, subWs, subPc, subProblem, p.xs, eb)
 
       val s = {substAll(reverseMap, _:Expr)} andThen { simplePostTransform(recompose) }
      
diff --git a/src/main/scala/leon/synthesis/rules/IndependentSplit.scala b/src/main/scala/leon/synthesis/rules/IndependentSplit.scala
new file mode 100644
index 0000000000000000000000000000000000000000..72be06b9cff76a63ced4506ef086a58622326bef
--- /dev/null
+++ b/src/main/scala/leon/synthesis/rules/IndependentSplit.scala
@@ -0,0 +1,80 @@
+/* Copyright 2009-2015 EPFL, Lausanne */
+
+package leon
+package synthesis
+package rules
+
+import leon.utils._
+import purescala.Expressions._
+import purescala.ExprOps._
+import purescala.Extractors._
+import purescala.Constructors._
+import purescala.Common._
+import purescala.Types.CaseClassType
+
+case object IndependentSplit extends NormalizingRule("IndependentSplit") {
+  def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = {
+    val TopLevelAnds(clauses) = and(p.pc, p.phi)
+
+    var independentClasses = Set[Set[Identifier]]()
+
+    // We group connect variables together
+    for(c <- clauses) {
+      val vs = variablesOf(c)
+
+      var newClasses = Set[Set[Identifier]]()
+
+      var thisClass = vs
+
+      for (cl <- independentClasses) {
+        if ((cl & vs).nonEmpty) {
+          thisClass ++= cl
+        } else {
+          newClasses += cl
+        }
+      }
+
+      independentClasses = newClasses + thisClass
+    }
+
+    val outClasses = independentClasses.map(cl => cl & p.xs.toSet).filter(_.nonEmpty)
+
+    if (outClasses.size > 1) {
+
+      val TopLevelAnds(phiClauses) = p.phi
+
+      val subs = (for (cl <- outClasses.toList) yield {
+        val xs = p.xs.filter(cl)
+
+        if (xs.nonEmpty) {
+          val phi = andJoin(phiClauses.filter(c => (variablesOf(c) & cl).nonEmpty))
+
+          val xsToRemove = p.xs.filterNot(cl).toSet
+
+          val eb = p.qeb.removeOuts(xsToRemove)
+
+          Some(p.copy(phi = phi, xs = xs, eb = eb))
+        } else {
+          None
+        }
+      }).flatten
+
+      val onSuccess: List[Solution] => Option[Solution] = { sols =>
+
+        val infos = subs.map(_.xs).zip(sols.map(_.term))
+
+        val term = infos.foldLeft(tupleWrap(p.xs.map(_.toVariable))) {
+          case (expr, (xs, term)) =>
+            letTuple(xs, term, expr)
+        }
+
+        Some(Solution(andJoin(sols.map(_.pre)), sols.map(_.defs).flatten.toSet, term, sols.forall(_.isTrusted)))
+      }
+
+
+      List(decomp(subs, onSuccess, "Independent Clusters"))
+    } else {
+      Nil
+    }
+  }
+}
diff --git a/src/main/scala/leon/synthesis/rules/InputSplit.scala b/src/main/scala/leon/synthesis/rules/InputSplit.scala
new file mode 100644
index 0000000000000000000000000000000000000000..4b9ffef53793528b628b41485c0a9156e171f188
--- /dev/null
+++ b/src/main/scala/leon/synthesis/rules/InputSplit.scala
@@ -0,0 +1,49 @@
+/* Copyright 2009-2015 EPFL, Lausanne */
+
+package leon
+package synthesis
+package rules
+
+import leon.purescala.Common.Identifier
+import purescala.Expressions._
+import purescala.Extractors._
+import purescala.ExprOps._
+import purescala.Constructors._
+import purescala.Types._
+
+import solvers._
+
+import scala.concurrent.duration._
+
+case object InputSplit extends Rule("In. Split") {
+  def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = {
+    p.as.filter(_.getType == BooleanType).flatMap { a =>
+        def getProblem(v: Boolean): Problem = {
+          def replaceA(e: Expr) = replaceFromIDs(Map(a -> BooleanLiteral(v)), e)
+
+          p.copy(
+            as  = p.as.filterNot(_ == a),
+            ws  = replaceA(p.ws),
+            pc  = replaceA(p.pc),
+            phi = replaceA(p.phi),
+            eb  = p.qeb.removeIns(Set(a))
+          )
+        }
+
+        val sub1 = getProblem(true)
+        val sub2 = getProblem(false)
+
+        val onSuccess: List[Solution] => Option[Solution] = {
+          case List(s1, s2) =>
+            Some(Solution(or(and(Equals(Variable(a), BooleanLiteral(true)), s1.pre), 
+                             and(Equals(Variable(a), BooleanLiteral(false)), s2.pre)),
+                          s1.defs ++ s2.defs, 
+                          IfExpr(Variable(a), s1.term, s2.term), s1.isTrusted && s2.isTrusted))
+          case _ =>
+            None
+        }
+
+      Some(decomp(List(sub1, sub2), onSuccess, s"Split on '$a'"))
+    }
+  }
+}
diff --git a/src/main/scala/leon/utils/DebugSections.scala b/src/main/scala/leon/utils/DebugSections.scala
index c18881e47f23fd9c5503320888158cc38f68b10d..a0b790243a6dc309953d07ba02d504e463185880 100644
--- a/src/main/scala/leon/utils/DebugSections.scala
+++ b/src/main/scala/leon/utils/DebugSections.scala
@@ -23,6 +23,7 @@ case object DebugSectionLeon         extends DebugSection("leon",         1 << 1
 case object DebugSectionXLang        extends DebugSection("xlang",        1 << 12)
 case object DebugSectionTypes        extends DebugSection("types",        1 << 13)
 case object DebugSectionIsabelle     extends DebugSection("isabelle",     1 << 14)
+case object DebugSectionReport       extends DebugSection("report",       1 << 15)
 
 object DebugSections {
   val all = Set[DebugSection](
@@ -40,6 +41,7 @@ object DebugSections {
     DebugSectionLeon,
     DebugSectionXLang,
     DebugSectionTypes,
-    DebugSectionIsabelle
+    DebugSectionIsabelle,
+    DebugSectionReport
   )
 }
diff --git a/src/main/scala/leon/verification/InjectAsserts.scala b/src/main/scala/leon/verification/InjectAsserts.scala
index 418da12eb62e1fb1ead33bc0317da9ceb9662e28..a2ba463a6519a4c10e224c583263b805b4f660d7 100644
--- a/src/main/scala/leon/verification/InjectAsserts.scala
+++ b/src/main/scala/leon/verification/InjectAsserts.scala
@@ -42,34 +42,34 @@ object InjectAsserts extends SimpleLeonPhase[Program, Program] {
                      ).setPos(e))
 
         case e @ Division(_, d)  =>
-          Some(Assert(Not(Equals(d, InfiniteIntegerLiteral(0))),
+          Some(assertion(not(equality(d, InfiniteIntegerLiteral(0))),
                       Some("Division by zero"),
                       e
                      ).setPos(e))
         case e @ Remainder(_, d)  =>
-          Some(Assert(Not(Equals(d, InfiniteIntegerLiteral(0))),
+          Some(assertion(not(equality(d, InfiniteIntegerLiteral(0))),
                       Some("Remainder by zero"),
                       e
                      ).setPos(e))
         case e @ Modulo(_, d)  =>
-          Some(Assert(Not(Equals(d, InfiniteIntegerLiteral(0))),
+          Some(assertion(not(equality(d, InfiniteIntegerLiteral(0))),
                       Some("Modulo by zero"),
                       e
                      ).setPos(e))
 
         case e @ BVDivision(_, d)  =>
-          Some(Assert(Not(Equals(d, IntLiteral(0))),
+          Some(assertion(not(equality(d, IntLiteral(0))),
                       Some("Division by zero"),
                       e
                      ).setPos(e))
         case e @ BVRemainder(_, d)  =>
-          Some(Assert(Not(Equals(d, IntLiteral(0))),
+          Some(assertion(not(equality(d, IntLiteral(0))),
                       Some("Remainder by zero"),
                       e
                      ).setPos(e))
 
         case e @ RealDivision(_, d)  =>
-          Some(Assert(Not(Equals(d, FractionalLiteral(0, 1))),
+          Some(assertion(not(equality(d, FractionalLiteral(0, 1))),
                       Some("Division by zero"),
                       e
                      ).setPos(e))
diff --git a/src/main/scala/leon/xlang/ImperativeCodeElimination.scala b/src/main/scala/leon/xlang/ImperativeCodeElimination.scala
index 600640c7b35229f3d1c02dbcd54765d7e665b0d0..b6c5f9036003725c2493f35cbdfa2a3a9960ec3d 100644
--- a/src/main/scala/leon/xlang/ImperativeCodeElimination.scala
+++ b/src/main/scala/leon/xlang/ImperativeCodeElimination.scala
@@ -131,68 +131,22 @@ object ImperativeCodeElimination extends UnitPhase[Program] {
         (resId.toVariable, scope, scrutFun ++ modifiedVars.zip(freshIds).toMap)
  
       case wh@While(cond, body) =>
-        //TODO: rewrite by re-using the nested function transformation code
-        val (condRes, condScope, condFun) = toFunction(cond)
-        val (_, bodyScope, bodyFun) = toFunction(body)
-        val condBodyFun = condFun ++ bodyFun
-
-        val modifiedVars: Seq[Identifier] = condBodyFun.keys.toSet.intersect(varsInScope).toSeq
-
-        if(modifiedVars.isEmpty)
-          (UnitLiteral(), (b: Expr) => b, Map())
-        else {
-          val whileFunVars = modifiedVars.map(id => FreshIdentifier(id.name, id.getType))
-          val modifiedVars2WhileFunVars = modifiedVars.zip(whileFunVars).toMap
-          val whileFunValDefs = whileFunVars.map(ValDef(_))
-          val whileFunReturnType = tupleTypeWrap(whileFunVars.map(_.getType))
-          val whileFunDef = new FunDef(parent.id.freshen, Nil, whileFunValDefs, whileFunReturnType).setPos(wh)
-          whileFunDef.addFlag(IsLoop(parent))
-          
-          val whileFunCond = condScope(condRes)
-          val whileFunRecursiveCall = replaceNames(condFun,
-            bodyScope(FunctionInvocation(whileFunDef.typed, modifiedVars.map(id => condBodyFun(id).toVariable)).setPos(wh)))
-          val whileFunBaseCase =
-            tupleWrap(modifiedVars.map(id => condFun.getOrElse(id, modifiedVars2WhileFunVars(id)).toVariable))
-          val whileFunBody = replaceNames(modifiedVars2WhileFunVars, 
-            condScope(IfExpr(whileFunCond, whileFunRecursiveCall, whileFunBaseCase)))
-          whileFunDef.body = Some(whileFunBody)
-
-          val resVar = Variable(FreshIdentifier("res", whileFunReturnType))
-          val whileFunVars2ResultVars: Map[Expr, Expr] = 
-            whileFunVars.zipWithIndex.map{ case (v, i) => 
-              (v.toVariable, tupleSelect(resVar, i+1, whileFunVars.size))
-            }.toMap
-          val modifiedVars2ResultVars: Map[Expr, Expr]  = modifiedVars.map(id => 
-            (id.toVariable, whileFunVars2ResultVars(modifiedVars2WhileFunVars(id).toVariable))).toMap
-
-          //the mapping of the trivial post condition variables depends on whether the condition has had some side effect
-          val trivialPostcondition: Option[Expr] = Some(Not(replace(
-            modifiedVars.map(id => (condFun.getOrElse(id, id).toVariable, modifiedVars2ResultVars(id.toVariable))).toMap,
-            whileFunCond)))
-          val invariantPrecondition: Option[Expr] = wh.invariant.map(expr => replaceNames(modifiedVars2WhileFunVars, expr))
-          val invariantPostcondition: Option[Expr] = wh.invariant.map(expr => replace(modifiedVars2ResultVars, expr))
-          whileFunDef.precondition = invariantPrecondition
-          whileFunDef.postcondition = trivialPostcondition.map( expr => 
-            Lambda(
-              Seq(ValDef(resVar.id)), 
-              and(expr, invariantPostcondition.getOrElse(BooleanLiteral(true))).setPos(wh)
-            ).setPos(wh)
-          )
-
-          val finalVars = modifiedVars.map(_.freshen)
-          val finalScope = (body: Expr) => {
-            val tupleId = FreshIdentifier("t", whileFunReturnType)
-            LetDef(Seq(whileFunDef), Let(
-              tupleId,
-              FunctionInvocation(whileFunDef.typed, modifiedVars.map(_.toVariable)).setPos(wh),
-              finalVars.zipWithIndex.foldLeft(body) { (b, id) =>
-                Let(id._1, tupleSelect(tupleId.toVariable, id._2 + 1, finalVars.size), b)
-              }
-            ))
-          }
+        val whileFunDef = new FunDef(parent.id.freshen, Nil, Nil, UnitType).setPos(wh)
+        whileFunDef.addFlag(IsLoop(parent))
+        whileFunDef.body = Some(
+          IfExpr(cond, 
+                 Block(Seq(body), FunctionInvocation(whileFunDef.typed, Seq()).setPos(wh)),
+                 UnitLiteral()))
+        whileFunDef.precondition = wh.invariant
+        whileFunDef.postcondition = Some(
+          Lambda(
+            Seq(ValDef(FreshIdentifier("bodyRes", UnitType))),
+            and(Not(getFunctionalResult(cond)), wh.invariant.getOrElse(BooleanLiteral(true))).setPos(wh)
+          ).setPos(wh)
+        )
 
-          (UnitLiteral(), finalScope, modifiedVars.zip(finalVars).toMap)
-        }
+        val newExpr = LetDef(List(whileFunDef), FunctionInvocation(whileFunDef.typed, Seq()).setPos(wh)).setPos(wh)
+        toFunction(newExpr)
 
       case Block(Seq(), expr) =>
         toFunction(expr)
@@ -281,6 +235,7 @@ object ImperativeCodeElimination extends UnitPhase[Program] {
             val modifiedVars: List[Identifier] =
               collect[Identifier]({
                 case Assignment(v, _) => Set(v)
+                case FunctionInvocation(tfd, _) => state.funDefsMapping.get(tfd.fd).map(p => p._2.toSet).getOrElse(Set())
                 case _ => Set()
               })(bd).intersect(state.varsInScope).toList
             (fd, modifiedVars)
@@ -318,7 +273,11 @@ object ImperativeCodeElimination extends UnitPhase[Program] {
               yield TupleType(fd.returnType :: modifiedVars.map(_.getType))
 
             val newFds = for(((fd, newParams), newReturnType) <- newParams.zip(newReturnType))
-              yield (fd, new FunDef(fd.id.freshen, fd.tparams, newParams, newReturnType).setPos(fd))
+              yield {
+                val newFd = new FunDef(fd.id.freshen, fd.tparams, newParams, newReturnType).setPos(fd)
+                newFd.addFlags(fd.flags)
+                (fd, newFd)
+              }
               
             val mappingToAdd: Seq[(FunDef, (FunDef, List[Identifier]))] =
               for(((fd, newFd), (_, freshVarDecls)) <- newFds.zip(freshVarDecls)) yield (fd -> ((newFd, freshVarDecls.toList)))
@@ -328,7 +287,9 @@ object ImperativeCodeElimination extends UnitPhase[Program] {
               wrappedBodyOpt.map(wrappedBody => 
                 toFunction(wrappedBody)(
                   State(state.parent, Set(), 
-                        state.funDefsMapping ++ mappingToAdd)
+                        state.funDefsMapping.map{
+  case (fd, (nfd, mvs)) =>
+  (fd, (nfd, mvs.map(v => rewritingMap.getOrElse(v, v))))} ++ mappingToAdd)
                 )
               )
             }
@@ -399,4 +360,13 @@ object ImperativeCodeElimination extends UnitPhase[Program] {
 
   def replaceNames(fun: Map[Identifier, Identifier], expr: Expr) = replaceFromIDs(fun mapValues Variable, expr)
 
+  
+  /* Extract functional result value. Useful to remove side effect from conditions when moving it to post-condition */
+  private def getFunctionalResult(expr: Expr): Expr = {
+    preMap({
+      case Block(_, res) => Some(res)
+      case _ => None
+    })(expr)
+  }
+
 }
diff --git a/src/test/resources/regression/verification/purescala/invalid/PropositionalLogic.scala b/src/test/resources/regression/verification/purescala/invalid/PropositionalLogic.scala
index a8927f360e817d10761723c8a4b7e9085bf0738d..aa00e12d446e1b11984f741500279a5647cfe426 100644
--- a/src/test/resources/regression/verification/purescala/invalid/PropositionalLogic.scala
+++ b/src/test/resources/regression/verification/purescala/invalid/PropositionalLogic.scala
@@ -10,14 +10,11 @@ object PropositionalLogic {
   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
+  case class Literal(id: BigInt) 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
+    case _ => f
   }) ensuring(isSimplified(_))
 
   def isSimplified(f: Formula): Boolean = f match {
@@ -28,18 +25,6 @@ object PropositionalLogic {
     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)
@@ -49,39 +34,14 @@ object PropositionalLogic {
     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 = {
+ 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/src/test/resources/regression/verification/purescala/valid/Formulas.scala b/src/test/resources/regression/verification/purescala/valid/Formulas.scala
new file mode 100644
index 0000000000000000000000000000000000000000..0fafe4158a2fcbd1b6654d21dbfa072ec42d614f
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/Formulas.scala
@@ -0,0 +1,50 @@
+import leon.lang._
+import leon._
+
+object Formulas {
+  abstract class Expr
+  case class And(lhs: Expr, rhs: Expr) extends Expr
+  case class Or(lhs: Expr, rhs: Expr) extends Expr
+  case class Implies(lhs: Expr, rhs: Expr) extends Expr
+  case class Not(e : Expr) extends Expr
+  case class BoolLiteral(i: BigInt) extends Expr
+
+  def exists(e: Expr, f: Expr => Boolean): Boolean = {
+    f(e) || (e match {
+      case And(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Or(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Implies(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Not(e) => exists(e, f)
+      case _ => false
+    })
+  }
+
+  def existsImplies(e: Expr): Boolean = {
+    e.isInstanceOf[Implies] || (e match {
+      case And(lhs, rhs) => existsImplies(lhs) || existsImplies(rhs)
+      case Or(lhs, rhs) => existsImplies(lhs) || existsImplies(rhs)
+      case Implies(lhs, rhs) => existsImplies(lhs) || existsImplies(rhs)
+      case Not(e) => existsImplies(e)
+      case _ => false
+    })
+  }
+
+  abstract class Value
+  case class BoolValue(b: Boolean) extends Value
+  case class IntValue(i: BigInt) extends Value
+  case object Error extends Value
+
+  def desugar(e: Expr): Expr = {
+    e match {
+      case And(lhs, rhs) => And(desugar(lhs), desugar(rhs))
+      case Or(lhs, rhs) => Or(desugar(lhs), desugar(rhs))
+      case Implies(lhs, rhs) =>
+        Or(Not(desugar(lhs)), desugar(rhs))
+      case Not(e) => Not(desugar(e))
+      case e => e
+    }
+  } ensuring { out =>
+    !existsImplies(out) &&
+    !exists(out, f => f.isInstanceOf[Implies])
+  }
+}
diff --git a/src/test/resources/regression/verification/xlang/valid/WhileAsFun1.scala b/src/test/resources/regression/verification/xlang/valid/WhileAsFun1.scala
new file mode 100644
index 0000000000000000000000000000000000000000..b81ea38598aed9b208da96bc88cd9385260b2e5b
--- /dev/null
+++ b/src/test/resources/regression/verification/xlang/valid/WhileAsFun1.scala
@@ -0,0 +1,25 @@
+/* Copyright 2009-2015 EPFL, Lausanne */
+import leon.lang._
+
+object WhileAsFun1 {
+
+
+  def counterN(n: Int): Int = {
+    require(n > 0)
+
+    var i = 0
+    def rec(): Unit = {
+      require(i >= 0 && i <= n)
+      if(i < n) {
+        i += 1
+        rec()
+      } else {
+        ()
+      }
+    } ensuring(_ => i >= 0 && i <= n && i >= n)
+    rec()
+
+    i
+  } ensuring(_ == n)
+
+}
diff --git a/src/test/resources/regression/verification/xlang/valid/WhileAsFun2.scala b/src/test/resources/regression/verification/xlang/valid/WhileAsFun2.scala
new file mode 100644
index 0000000000000000000000000000000000000000..968aadfdbf044fd057d3628a6adffd4e917fdf67
--- /dev/null
+++ b/src/test/resources/regression/verification/xlang/valid/WhileAsFun2.scala
@@ -0,0 +1,33 @@
+/* Copyright 2009-2015 EPFL, Lausanne */
+import leon.lang._
+
+object WhileAsFun2 {
+
+
+  def counterN(n: Int): Int = {
+    require(n > 0)
+
+    var counter = 0
+
+    def inc(): Unit = {
+      counter += 1
+    }
+
+    var i = 0
+    def rec(): Unit = {
+      require(i >= 0 && counter == i && i <= n)
+      if(i < n) {
+        inc()
+        i += 1
+        rec()
+      } else {
+        ()
+      }
+    } ensuring(_ => i >= 0 && counter == i && i <= n && i >= n)
+    rec()
+
+
+    counter
+  } ensuring(_ == n)
+
+}
diff --git a/testcases/repair/Compiler/Compiler4.scala b/testcases/repair/Compiler/Compiler4.scala
index f49670ddc31632343fea32f1b8d39ca288f214d4..6323496df930172e84b71bf5c55006eb33767c6a 100644
--- a/testcases/repair/Compiler/Compiler4.scala
+++ b/testcases/repair/Compiler/Compiler4.scala
@@ -150,7 +150,7 @@ object Desugar {
     case Trees.LessThan(lhs, rhs) => LessThan(desugar(lhs), desugar(rhs))
     case Trees.And  (lhs, rhs) => Ite(desugar(lhs), desugar(rhs), Literal(0)) 
     case Trees.Or   (lhs, rhs) => Ite(desugar(lhs), Literal(1), desugar(rhs))
-    case Trees.Not(e) => Ite(desugar(e), Literal(1), Literal(1)) // FIMXE should be 0
+    case Trees.Not(e) => Ite(desugar(e), Literal(1), Literal(1)) // FIXME should be 0
     case Trees.Eq(lhs, rhs) =>
       Eq(desugar(lhs), desugar(rhs))
     case Trees.Ite(cond, thn, els) => Ite(desugar(cond), desugar(thn), desugar(els))
diff --git a/testcases/repair/Compiler/Compiler6.scala b/testcases/repair/Compiler/Compiler6.scala
index 44bf523ec7aff63376ba24312594045296536dcf..dc633b1ae3d4d929e262ea44d6466a41ee4babf0 100644
--- a/testcases/repair/Compiler/Compiler6.scala
+++ b/testcases/repair/Compiler/Compiler6.scala
@@ -207,6 +207,8 @@ object Simplifier {
       case e => e
     }
   } ensuring {
-    res => eval(res) == eval(e)
+    res => eval(res) == eval(e) && ((e, res) passes {
+      case Plus(IntLiteral(BigInt(0)), IntLiteral(a)) => IntLiteral(a)
+    })
   }
 }
diff --git a/testcases/repair/Heap/Heap3.scala b/testcases/repair/Heap/Heap3.scala
index 3305b5d15a0731bd3aeaa1269c2404807f49a266..8e3013399534679c58221bd4d5547a14a76d9b57 100644
--- a/testcases/repair/Heap/Heap3.scala
+++ b/testcases/repair/Heap/Heap3.scala
@@ -51,7 +51,7 @@ object Heaps {
     case Node(v, l, r) => heapSize(l) + 1 + heapSize(r)
   }} ensuring(_ >= 0)
 
-  private def merge(h1: Heap, h2: Heap) : Heap = {
+  def merge(h1: Heap, h2: Heap) : Heap = {
     require(
       hasLeftistProperty(h1) && hasLeftistProperty(h2) && 
       hasHeapProperty(h1) && hasHeapProperty(h2)
diff --git a/testcases/repair/List/List13.scala b/testcases/repair/List/List13.scala
index 914f0caacd49b42448ec428df24af6ea155c53d2..1093efc3dc951ee8307c2257d8dcec2d154c9ecd 100644
--- a/testcases/repair/List/List13.scala
+++ b/testcases/repair/List/List13.scala
@@ -78,14 +78,22 @@ sealed abstract class List[T] {
       }
   }
 
-  def drop(i: BigInt): List[T] = (this, i) match {
-    case (Nil(), _) => Nil()
-    case (Cons(h, t), i) =>
-      if (i == 0) {
-        Cons(h, t)
-      } else {
-        t.drop(i) // FIXME Should be -1
-      }
+  def drop(i: BigInt): List[T] = {
+    require(i >= 0)
+    (this, i) match {
+      case (Nil(), _) => Nil[T]()
+      case (Cons(h, t), i) =>
+        if (i == 0) {
+          Cons[T](h, t)
+        } else {
+          t.drop(i) // FIXME Should be -1
+        }
+    }
+  } ensuring { (res: List[T]) =>
+    ((this, i), res) passes {
+      case (Cons(a, Cons(b, Nil())), BigInt(1)) => Cons(b, Nil())
+      case (Cons(a, Cons(b, Nil())), BigInt(2)) => Nil()
+    }
   }
 
   def slice(from: BigInt, to: BigInt): List[T] = {
diff --git a/testcases/repair/List/List4.scala b/testcases/repair/List/List4.scala
index b6cb5e276741be29d86da86b7c43cbe7e1639c62..1ee180b3331e9cc51df34207b8ab5b6fec9b710b 100644
--- a/testcases/repair/List/List4.scala
+++ b/testcases/repair/List/List4.scala
@@ -78,16 +78,18 @@ sealed abstract class List[T] {
       }
   }
 
-  def drop(i: BigInt): List[T] = { (this, i) match {
-    case (Nil(), _) => Nil[T]()
-    case (Cons(h, t), i) =>
-      // FIXME
-      //if (i == 0) {
-      //  Cons(h, t)
-      //} else {
-        t.drop(i-1)
-      //}
-  }} ensuring { ((this, i), _) passes { 
+  def drop(i: BigInt): List[T] = {
+    (this, i) match {
+      case (Nil(), _) => Nil[T]()
+      case (Cons(h, t), i) =>
+        // FIXME
+        if (i != 0) {
+          Cons(h, t)
+        } else {
+          t.drop(i-1)
+        }
+    }
+  } ensuring { ((this, i), _) passes { 
     case (Cons(_, Nil()), BigInt(42)) => Nil()
     case (l@Cons(_, _), BigInt(0)) => l
     case (Cons(a, Cons(b, Nil())), BigInt(1)) => Cons(b, Nil())
diff --git a/testcases/repair/List/List5.scala b/testcases/repair/List/List5.scala
index 743cced6533536eac8c03bbc3f2381378b8190b8..f13f91da3d55d7cdcf0eb0d3ef41027e1a8e94d8 100644
--- a/testcases/repair/List/List5.scala
+++ b/testcases/repair/List/List5.scala
@@ -97,11 +97,11 @@ sealed abstract class List[T] {
     case Nil() => Nil[T]()
     case Cons(h, t) =>
       val r = t.replace(from, to)
-      //if (h == from) { FIXME
-      //  Cons(to, r)
-      //} else {
+      if (h != from) { // FIXME
+        Cons(to, r)
+      } else {
         Cons(h, r)
-      //}
+      }
   }} ensuring { res => 
     (((this.content -- Set(from)) ++ (if (this.content contains from) Set(to) else Set[T]())) == res.content) &&
     res.size == this.size
diff --git a/testcases/repair/List/List7.scala b/testcases/repair/List/List7.scala
index 7eef0585e9cb467f75da05fdb7957db4f9838afa..41972f4cefffa0bd63245856b2d31b0cfe241c10 100644
--- a/testcases/repair/List/List7.scala
+++ b/testcases/repair/List/List7.scala
@@ -191,7 +191,7 @@ sealed abstract class List[T] {
       }
   }} ensuring { res =>
     if (this.content contains e) {
-      res.isDefined && this.size > res.get && this.apply(res.get) == e
+      res.isDefined && this.size > res.get && this.apply(res.get) == e && res.get >= 0
     } else {
       res.isEmpty
     }
diff --git a/testcases/repair/List/List8.scala b/testcases/repair/List/List8.scala
index faf7571e9582f652e3ba494b11eb34c5923d4dac..02f5294c26e7f3b4f29e307db07186927bfff82c 100644
--- a/testcases/repair/List/List8.scala
+++ b/testcases/repair/List/List8.scala
@@ -191,7 +191,7 @@ sealed abstract class List[T] {
       }
   }} ensuring { res =>
     if (this.content contains e) {
-      res.isDefined && this.size > res.get && this.apply(res.get) == e
+      res.isDefined && this.size > res.get && this.apply(res.get) == e && res.get >= 0
     } else {
       res.isEmpty
     }
diff --git a/testcases/repair/List/List9.scala b/testcases/repair/List/List9.scala
index 12a8152b1701fe993f36c33392eebda724ec4aad..104e2ecabdfa0ac8bef8cc179ff68acc1a7c6ccc 100644
--- a/testcases/repair/List/List9.scala
+++ b/testcases/repair/List/List9.scala
@@ -191,7 +191,7 @@ sealed abstract class List[T] {
       }
   }} ensuring { res =>
     if (this.content contains e) {
-      res.isDefined && this.size > res.get && this.apply(res.get) == e
+      res.isDefined && this.size > res.get && this.apply(res.get) == e && res.get >= 0
     } else {
       res.isEmpty
     }
diff --git a/testcases/repair/MergeSort/MergeSort1.scala b/testcases/repair/MergeSort/MergeSort1.scala
index 88b0319086023675c766cf8f6c74ccd420d2a182..340dfbc46077306b64752e73cebeb725ef40a781 100644
--- a/testcases/repair/MergeSort/MergeSort1.scala
+++ b/testcases/repair/MergeSort/MergeSort1.scala
@@ -5,7 +5,7 @@ object MergeSort {
   def split(l : List[BigInt]) : (List[BigInt],List[BigInt]) = { l match {
     case Cons(a, Cons(b, t)) => 
       val (rec1, rec2) = split(t)
-      (rec1, rec2) // FIXME: Forgot a,b
+      (rec1, Cons(b, rec2)) // FIXME: Forgot a
     case other => (other, Nil[BigInt]())
   }} ensuring { res =>
     val (l1, l2) = res
diff --git a/testcases/repair/runTests.sh b/testcases/repair/runTests.sh
index 55ca5cdf9f74828855e9ce85eb8aa18bf8ba3169..896054f51dc75131d690b14dfa00dd8a3a747c46 100755
--- a/testcases/repair/runTests.sh
+++ b/testcases/repair/runTests.sh
@@ -15,53 +15,56 @@ echo "################################" >> $summaryLog
 echo "#           Category,                 File,             function, p.S, fuS, foS,   Tms,   Fms,   Rms, verif?" >> $summaryLog
 
 #All benchmarks:
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler1.scala   | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler2.scala   | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler3.scala   | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler4.scala   | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler5.scala   | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=simplify testcases/repair/Compiler/Compiler6.scala   | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=simplify testcases/repair/Compiler/Compiler7.scala   | tee -a $fullLog
 
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap3.scala        | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap4.scala        | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap5.scala        | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap6.scala        | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap7.scala        | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=insert   testcases/repair/Heap/Heap8.scala        | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=makeN    testcases/repair/Heap/Heap9.scala        | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap10.scala       | tee -a $fullLog
+echo "=====================================================================" >> repair-report.txt
 
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic1.scala | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic2.scala | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic3.scala | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic4.scala | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic5.scala | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler1.scala   | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler2.scala   | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler3.scala   | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler4.scala   | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=desugar  testcases/repair/Compiler/Compiler5.scala   | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=simplify testcases/repair/Compiler/Compiler6.scala   | tee -a $fullLog
 
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=pad     testcases/repair/List/List1.scala           | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=++      testcases/repair/List/List2.scala           | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=:+      testcases/repair/List/List3.scala           | tee -a $fullLog
-./leon --repair --timeout=30                       --functions=drop    testcases/repair/List/List4.scala           | tee -a $fullLog
-./leon --repair --timeout=30                       --functions=replace testcases/repair/List/List5.scala           | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=count   testcases/repair/List/List6.scala           | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=find    testcases/repair/List/List7.scala           | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=find    testcases/repair/List/List8.scala           | tee -a $fullLog
-./leon --repair --timeout=30                       --functions=find    testcases/repair/List/List9.scala           | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=size    testcases/repair/List/List10.scala          | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=sum     testcases/repair/List/List11.scala          | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=-       testcases/repair/List/List12.scala          | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=drop    testcases/repair/List/List13.scala          | tee -a $fullLog
 
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=power    testcases/repair/Numerical/Numerical1.scala | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=moddiv   testcases/repair/Numerical/Numerical3.scala | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap3.scala        | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap4.scala        | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap5.scala        | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap6.scala        | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap7.scala        | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/Heap/Heap10.scala       | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=insert   testcases/repair/Heap/Heap8.scala        | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=makeN    testcases/repair/Heap/Heap9.scala        | tee -a $fullLog
 
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=split    testcases/repair/MergeSort/MergeSort1.scala | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/MergeSort/MergeSort2.scala | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/MergeSort/MergeSort3.scala | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/MergeSort/MergeSort4.scala | tee -a $fullLog
-./leon --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/MergeSort/MergeSort5.scala | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic1.scala | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic2.scala | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic3.scala | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic4.scala | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=nnf      testcases/repair/PropLogic/PropLogic5.scala | tee -a $fullLog
+
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=pad     testcases/repair/List/List1.scala           | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=++      testcases/repair/List/List2.scala           | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=:+      testcases/repair/List/List3.scala           | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30                       --functions=replace testcases/repair/List/List5.scala           | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=count   testcases/repair/List/List6.scala           | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=find    testcases/repair/List/List7.scala           | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=find    testcases/repair/List/List8.scala           | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30                       --functions=find    testcases/repair/List/List9.scala           | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=size    testcases/repair/List/List10.scala          | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=sum     testcases/repair/List/List11.scala          | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=-       testcases/repair/List/List12.scala          | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30                       --functions=drop    testcases/repair/List/List4.scala           | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=drop    testcases/repair/List/List13.scala          | tee -a $fullLog
+
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=power    testcases/repair/Numerical/Numerical1.scala | tee -a $fullLog
+#./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=moddiv   testcases/repair/Numerical/Numerical3.scala | tee -a $fullLog
+
+./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=split    testcases/repair/MergeSort/MergeSort1.scala | tee -a $fullLog
+./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/MergeSort/MergeSort2.scala | tee -a $fullLog
+./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/MergeSort/MergeSort3.scala | tee -a $fullLog
+./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/MergeSort/MergeSort4.scala | tee -a $fullLog
+./leon --debug=report --repair --timeout=30 --solvers=fairz3,enum --functions=merge    testcases/repair/MergeSort/MergeSort5.scala | tee -a $fullLog
 
 # Average results
-cat $log >> $summaryLog
-awk '{ total1 += $7; total2 += $8; total3 += $9; count++ } END { printf "#%74s Avg: %5d, %5d, %5d\n\n", "", total1/count, total2/count, total3/count }' $log >> $summaryLog
+#cat $log >> $summaryLog
+#awk '{ total1 += $7; total2 += $8; total3 += $9; count++ } END { printf "#%74s Avg: %5d, %5d, %5d\n\n", "", total1/count, total2/count, total3/count }' $log >> $summaryLog
 
diff --git a/testcases/synthesis/etienne-thesis/AddressBook/Make.scala b/testcases/synthesis/etienne-thesis/AddressBook/Make.scala
new file mode 100644
index 0000000000000000000000000000000000000000..1fd12466c2c6f932f776c893a66e1a290d2212ca
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/AddressBook/Make.scala
@@ -0,0 +1,53 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object AddressBookMake {
+
+  case class Address[A](info: A, priv: Boolean)
+
+  sealed abstract class AddressList[A] {
+    def size: BigInt = {
+      this match {
+        case Nil() => BigInt(0)
+        case Cons(head, tail) => BigInt(1) + tail.size
+      }
+    } ensuring { res => res >= 0 }
+
+    def content: Set[Address[A]] = this match {
+      case Nil() => Set[Address[A]]()
+      case Cons(addr, l1) => Set(addr) ++ l1.content
+    }
+  }
+
+  case class Cons[A](a: Address[A], tail: AddressList[A]) extends AddressList[A]
+  case class Nil[A]() extends AddressList[A]
+
+  def allPersonal[A](l: AddressList[A]): Boolean = l match {
+    case Nil() => true
+    case Cons(a, l1) =>
+      if (a.priv) allPersonal(l1)
+      else false
+  }
+
+  def allBusiness[A](l: AddressList[A]): Boolean = l match {
+    case Nil() => true
+    case Cons(a, l1) =>
+      if (a.priv) false
+      else allBusiness(l1)
+  }
+
+  case class AddressBook[A](business: AddressList[A], personal: AddressList[A]) {
+    def size: BigInt = business.size + personal.size
+
+    def content: Set[Address[A]] = business.content ++ personal.content
+
+    def invariant = {
+      allPersonal(personal) && allBusiness(business)
+    }
+  }
+
+  def makeAddressBook[A](as: AddressList[A]): AddressBook[A] = {
+    choose( (res: AddressBook[A]) => res.content == as.content && res.invariant )
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/AddressBook/Merge.scala b/testcases/synthesis/etienne-thesis/AddressBook/Merge.scala
new file mode 100644
index 0000000000000000000000000000000000000000..92a5b5bfef213e35c4f2a76bbbc9f295e406d1f4
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/AddressBook/Merge.scala
@@ -0,0 +1,69 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object AddressBookMake {
+
+  case class Address[A](info: A, priv: Boolean)
+
+  sealed abstract class AddressList[A] {
+    def size: BigInt = {
+      this match {
+        case Nil() => BigInt(0)
+        case Cons(head, tail) => BigInt(1) + tail.size
+      }
+    } ensuring { res => res >= 0 }
+
+    def content: Set[Address[A]] = this match {
+      case Nil() => Set[Address[A]]()
+      case Cons(addr, l1) => Set(addr) ++ l1.content
+    }
+
+    def ++(that: AddressList[A]): AddressList[A] = {
+      this match {
+        case Cons(h, t) => Cons(h, t ++ that)
+        case Nil() => that
+      }
+    } ensuring {
+      res => res.content == this.content ++ that.content
+    }
+  }
+
+  case class Cons[A](a: Address[A], tail: AddressList[A]) extends AddressList[A]
+  case class Nil[A]() extends AddressList[A]
+
+  def allPersonal[A](l: AddressList[A]): Boolean = l match {
+    case Nil() => true
+    case Cons(a, l1) =>
+      if (a.priv) allPersonal(l1)
+      else false
+  }
+
+  def allBusiness[A](l: AddressList[A]): Boolean = l match {
+    case Nil() => true
+    case Cons(a, l1) =>
+      if (a.priv) false
+      else allBusiness(l1)
+  }
+
+  case class AddressBook[A](business: AddressList[A], personal: AddressList[A]) {
+    def size: BigInt = business.size + personal.size
+
+    def content: Set[Address[A]] = business.content ++ personal.content
+
+    @inline
+    def invariant = {
+      allPersonal(personal) && allBusiness(business)
+    }
+  }
+
+  def merge[A](a1: AddressBook[A], a2: AddressBook[A]): AddressBook[A] = {
+    require(a1.invariant && a2.invariant)
+
+    choose( (res: AddressBook[A]) =>
+      res.personal.content == (a1.personal.content ++ a2.personal.content) &&
+      res.business.content == (a1.business.content ++ a2.business.content) &&
+      res.invariant
+    )
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/BatchedQueue/Dequeue.scala b/testcases/synthesis/etienne-thesis/BatchedQueue/Dequeue.scala
new file mode 100644
index 0000000000000000000000000000000000000000..c44fc062847b9af2264a9b3bba05186a313ab36b
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/BatchedQueue/Dequeue.scala
@@ -0,0 +1,80 @@
+import leon.lang._
+import leon.lang.synthesis._
+
+object BatchedQueue {
+  sealed abstract class List[T] {
+    def content: Set[T] = {
+      this match {
+        case Cons(h, t) => Set(h) ++ t.content
+        case Nil() => Set()
+      }
+    }
+
+    def size: BigInt = {
+      this match {
+        case Cons(h, t) => BigInt(1) + t.size
+        case Nil() => BigInt(0)
+      }
+    } ensuring { _ >= 0 }
+
+    def reverse: List[T] = {
+      this match {
+        case Cons(h, t) => t.reverse.append(Cons(h, Nil[T]()))
+        case Nil() => Nil[T]()
+      }
+    } ensuring { res =>
+      this.content == res.content
+    }
+
+    def append(r: List[T]): List[T] = {
+      this match {
+        case Cons(h, t) => Cons(h, t.append(r))
+        case Nil() => r
+      }
+    }
+
+    def isEmpty: Boolean = {
+      this == Nil[T]()
+    }
+
+    def tail: List[T] = {
+      require(this != Nil[T]())
+      this match {
+        case Cons(h, t) => t
+      }
+    }
+
+    def head: T = {
+      require(this != Nil[T]())
+      this match {
+        case Cons(h, t) => h
+      }
+    }
+  }
+
+  case class Cons[T](h: T, t: List[T]) extends List[T]
+  case class Nil[T]() extends List[T]
+
+  case class Queue[T](f: List[T], r: List[T]) {
+    def content: Set[T] = f.content ++ r.content
+    def size: BigInt = f.size + r.size
+
+    def isEmpty: Boolean = f.isEmpty && r.isEmpty
+
+    def invariant: Boolean = {
+      (f.isEmpty) ==> (r.isEmpty)
+    }
+
+    def toList: List[T] = f.append(r.reverse)
+
+    def dequeue: Queue[T] = {
+      require(invariant && !isEmpty)
+
+      choose { (res: Queue[T]) =>
+        res.size == size-1 && res.toList == this.toList.tail && res.invariant
+      }
+    }
+  }
+
+  val test = Queue[BigInt](Cons(42, Nil()), Nil()).dequeue
+}
diff --git a/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala b/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala
new file mode 100644
index 0000000000000000000000000000000000000000..fe01946d158153d2dd9ae2a3be2234ee4cd18aa9
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala
@@ -0,0 +1,88 @@
+import leon.lang._
+import leon.lang.synthesis._
+
+object BatchedQueue {
+  sealed abstract class List[T] {
+    def content: Set[T] = {
+      this match {
+        case Cons(h, t) => Set(h) ++ t.content
+        case Nil() => Set()
+      }
+    }
+
+    def size: BigInt = {
+      this match {
+        case Cons(h, t) => BigInt(1) + t.size
+        case Nil() => BigInt(0)
+      }
+    } ensuring { _ >= 0 }
+
+    def reverse: List[T] = {
+      this match {
+        case Cons(h, t) => t.reverse.append(Cons(h, Nil[T]()))
+        case Nil() => Nil[T]()
+      }
+    } ensuring { res =>
+      this.content == res.content
+    }
+
+    def append(r: List[T]): List[T] = {
+      this match {
+        case Cons(h, t) => Cons(h, t.append(r))
+        case Nil() => r
+      }
+    }
+
+    def tail: List[T] = {
+      require(this != Nil[T]())
+      this match {
+        case Cons(h, t) => t
+      }
+    }
+
+    def head: T = {
+      require(this != Nil[T]())
+      this match {
+        case Cons(h, t) => h
+      }
+    }
+
+    def last: T = {
+      require(this != Nil[T]())
+      this match {
+        case Cons(h, Nil()) => h
+        case Cons(h, t) => t.last
+      }
+    }
+  }
+
+  case class Cons[T](h: T, t: List[T]) extends List[T]
+  case class Nil[T]() extends List[T]
+
+  case class Queue[T](f: List[T], r: List[T]) {
+    def content: Set[T] = f.content ++ r.content
+    def size: BigInt = f.size + r.size
+
+    def invariant: Boolean = {
+      (f == Nil[T]()) ==> (r == Nil[T]())
+    }
+
+    def toList: List[T] = f.append(r.reverse)
+
+    def enqueue(v: T): Queue[T] = {
+      require(invariant)
+
+      f match {
+        case Cons(h, t) =>
+          Queue(f, Cons(v, r))
+        case Nil() =>
+          Queue(Cons(v, f), Nil())
+      }
+
+    } ensuring { (res: Queue[T]) =>
+        res.invariant &&
+        res.toList.last == v &&
+        res.content == this.content ++ Set(v)
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/Compiler/Desugar.scala b/testcases/synthesis/etienne-thesis/Compiler/Desugar.scala
new file mode 100644
index 0000000000000000000000000000000000000000..2684c71b2b8bbc9e5fe6cc307899ca7b92d366b4
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/Compiler/Desugar.scala
@@ -0,0 +1,118 @@
+import leon.lang._
+import leon.lang.synthesis._
+import leon._
+
+object Compiler {
+  abstract class Expr
+  case class Plus(lhs: Expr, rhs: Expr) extends Expr
+  case class Minus(lhs: Expr, rhs: Expr) extends Expr
+  case class UMinus(e: Expr) extends Expr
+  case class LessThan(lhs: Expr, rhs: Expr) extends Expr
+  case class And(lhs: Expr, rhs: Expr) extends Expr
+  case class Implies(lhs: Expr, rhs: Expr) extends Expr
+  case class Or(lhs: Expr, rhs: Expr) extends Expr
+  case class Not(e : Expr) extends Expr
+  case class Eq(lhs: Expr, rhs: Expr) extends Expr
+  case class Ite(cond: Expr, thn: Expr, els: Expr) extends Expr
+  case class BoolLiteral(b : Boolean) extends Expr
+  case class IntLiteral(i: BigInt) extends Expr
+
+  abstract class Value
+  case class BoolValue(b: Boolean) extends Value
+  case class IntValue(i: BigInt) extends Value
+  case object Error extends Value
+
+  def eval(e: Expr): Value = e match {
+    case Plus(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => IntValue(il+ir)
+        case _ => Error
+      }
+
+    case Minus(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => IntValue(il-ir)
+        case _ => Error
+      }
+
+    case UMinus(l) =>
+      eval(l) match {
+        case IntValue(b) => IntValue(-b)
+        case _ => Error
+      }
+
+    case LessThan(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => BoolValue(il < ir)
+        case _ => Error
+      }
+
+    case And(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(false) => b
+        case b: BoolValue =>
+          eval(r)
+        case _ =>
+          Error
+      }
+
+    case Or(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(true) =>
+          b
+        case b: BoolValue =>
+          eval(r)
+        case _ =>
+          Error
+      }
+
+    case Implies(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(true) =>
+          eval(r)
+        case b @ BoolValue(false) =>
+          BoolValue(true)
+        case _ => Error
+      }
+
+    case Not(l) =>
+      eval(l) match {
+        case BoolValue(b) => BoolValue(!b)
+        case _ => Error
+      }
+
+    case Eq(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir))   => BoolValue(il == ir)
+        case (BoolValue(il), BoolValue(ir)) => BoolValue(il == ir)
+        case _ => Error
+      }
+
+    case Ite(c, t, e) =>
+      eval(c) match {
+        case BoolValue(true) => eval(t)
+        case BoolValue(false) => eval(t)
+        case _ => Error
+      }
+
+    case IntLiteral(l)  => IntValue(l)
+    case BoolLiteral(b) => BoolValue(b)
+  }
+
+  def rewriteMinus(in: Minus): Expr = {
+    choose{ (out: Expr) =>
+      eval(in) == eval(out) && !(out.isInstanceOf[Minus])
+    }
+  }
+
+  def rewriteImplies(in: Implies): Expr = {
+    choose{ (out: Expr) =>
+      eval(in) == eval(out) && !(out.isInstanceOf[Implies])
+    }
+  }
+
+
+  def plop(x: Expr) = {
+    eval(x) == Error//eval(Not(IntLiteral(BigInt(2))))
+  }.holds
+}
diff --git a/testcases/synthesis/etienne-thesis/Compiler/DesugarImplies.scala b/testcases/synthesis/etienne-thesis/Compiler/DesugarImplies.scala
new file mode 100644
index 0000000000000000000000000000000000000000..de5c544ff368043ca7847376af8cd9ae6b513f4d
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/Compiler/DesugarImplies.scala
@@ -0,0 +1,144 @@
+import leon.lang._
+import leon.lang.synthesis._
+import leon._
+
+object Compiler {
+  abstract class Expr
+  case class Plus(lhs: Expr, rhs: Expr) extends Expr
+  case class Minus(lhs: Expr, rhs: Expr) extends Expr
+  case class UMinus(e: Expr) extends Expr
+  case class LessThan(lhs: Expr, rhs: Expr) extends Expr
+  case class And(lhs: Expr, rhs: Expr) extends Expr
+  case class Implies(lhs: Expr, rhs: Expr) extends Expr
+  case class Or(lhs: Expr, rhs: Expr) extends Expr
+  case class Not(e : Expr) extends Expr
+  case class Eq(lhs: Expr, rhs: Expr) extends Expr
+  case class Ite(cond: Expr, thn: Expr, els: Expr) extends Expr
+  case class BoolLiteral(b : Boolean) extends Expr
+  case class IntLiteral(i: BigInt) extends Expr
+
+  def exists(e: Expr, f: Expr => Boolean): Boolean = {
+    f(e) || (e match {
+      case Plus(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Minus(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case LessThan(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case And(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Or(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Implies(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Eq(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Ite(c, t, e) => exists(c, f) || exists(t, f) || exists(e, f)
+      case Not(e) => exists(e, f)
+      case UMinus(e) => exists(e, f)
+      case _ => false
+    })
+  }
+
+  abstract class Value
+  case class BoolValue(b: Boolean) extends Value
+  case class IntValue(i: BigInt) extends Value
+  case object Error extends Value
+
+  def eval(e: Expr): Value = e match {
+    case Plus(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => IntValue(il+ir)
+        case _ => Error
+      }
+
+    case Minus(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => IntValue(il-ir)
+        case _ => Error
+      }
+
+    case UMinus(l) =>
+      eval(l) match {
+        case IntValue(b) => IntValue(-b)
+        case _ => Error
+      }
+
+    case LessThan(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => BoolValue(il < ir)
+        case _ => Error
+      }
+
+    case And(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(false) => b
+        case b: BoolValue =>
+          eval(r)
+        case _ =>
+          Error
+      }
+
+    case Or(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(true) =>
+          b
+        case b: BoolValue =>
+          eval(r)
+        case _ =>
+          Error
+      }
+
+    case Implies(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(true) =>
+          eval(r)
+        case b @ BoolValue(false) =>
+          BoolValue(true)
+        case _ => Error
+      }
+
+    case Not(l) =>
+      eval(l) match {
+        case BoolValue(b) => BoolValue(!b)
+        case _ => Error
+      }
+
+    case Eq(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir))   => BoolValue(il == ir)
+        case (BoolValue(il), BoolValue(ir)) => BoolValue(il == ir)
+        case _ => Error
+      }
+
+    case Ite(c, t, e) =>
+      eval(c) match {
+        case BoolValue(true) => eval(t)
+        case BoolValue(false) => eval(t)
+        case _ => Error
+      }
+
+    case IntLiteral(l)  => IntValue(l)
+    case BoolLiteral(b) => BoolValue(b)
+  }
+
+
+  //def desugar(e: Expr): Expr = {
+  //  choose{ (out: Expr) =>
+  //    eval(e) == eval(out) && !exists(out, f => f.isInstanceOf[Implies])
+  //  }
+  //}
+
+  def desugar(e: Expr): Expr = {
+    e match {
+      case Plus(lhs, rhs) => Plus(desugar(lhs), desugar(rhs))
+      case Minus(lhs, rhs) => Minus(desugar(lhs), desugar(rhs))
+      case LessThan(lhs, rhs) => LessThan(desugar(lhs), desugar(rhs))
+      case And(lhs, rhs) => And(desugar(lhs), desugar(rhs))
+      case Or(lhs, rhs) => Or(desugar(lhs), desugar(rhs))
+      case Implies(lhs, rhs) => //Implies(desugar(lhs), desugar(rhs))
+        Or(Not(desugar(lhs)), desugar(rhs))
+      case Eq(lhs, rhs) => Eq(desugar(lhs), desugar(rhs))
+      case Ite(c, t, e) => Ite(desugar(c), desugar(t), desugar(e))
+      case Not(e) => Not(desugar(e))
+      case UMinus(e) => UMinus(desugar(e))
+      case e => e
+    }
+  } ensuring { out =>
+    //eval(e) == eval(out) && 
+    !exists(out, f => f.isInstanceOf[Implies])
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/Compiler/RewriteImplies.scala b/testcases/synthesis/etienne-thesis/Compiler/RewriteImplies.scala
new file mode 100644
index 0000000000000000000000000000000000000000..4b50b9cbe34043f65d1a8feeaadac929822e6c70
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/Compiler/RewriteImplies.scala
@@ -0,0 +1,124 @@
+import leon.lang._
+import leon.lang.synthesis._
+import leon._
+
+object Compiler {
+  abstract class Expr
+  case class Plus(lhs: Expr, rhs: Expr) extends Expr
+  case class Minus(lhs: Expr, rhs: Expr) extends Expr
+  case class UMinus(e: Expr) extends Expr
+  case class LessThan(lhs: Expr, rhs: Expr) extends Expr
+  case class And(lhs: Expr, rhs: Expr) extends Expr
+  case class Implies(lhs: Expr, rhs: Expr) extends Expr
+  case class Or(lhs: Expr, rhs: Expr) extends Expr
+  case class Not(e : Expr) extends Expr
+  case class Eq(lhs: Expr, rhs: Expr) extends Expr
+  case class Ite(cond: Expr, thn: Expr, els: Expr) extends Expr
+  case class BoolLiteral(b : Boolean) extends Expr
+  case class IntLiteral(i: BigInt) extends Expr
+
+  def exists(e: Expr, f: Expr => Boolean): Boolean = {
+    f(e) || (e match {
+      case Plus(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Minus(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case LessThan(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case And(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Or(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Implies(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Eq(lhs, rhs) => exists(lhs, f) || exists(rhs, f)
+      case Ite(c, t, e) => exists(c, f) || exists(t, f) || exists(e, f)
+      case Not(e) => exists(e, f)
+      case UMinus(e) => exists(e, f)
+      case _ => false
+    })
+  }
+
+  abstract class Value
+  case class BoolValue(b: Boolean) extends Value
+  case class IntValue(i: BigInt) extends Value
+  case object Error extends Value
+
+  def eval(e: Expr): Value = e match {
+    case Plus(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => IntValue(il+ir)
+        case _ => Error
+      }
+
+    case Minus(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => IntValue(il-ir)
+        case _ => Error
+      }
+
+    case UMinus(l) =>
+      eval(l) match {
+        case IntValue(b) => IntValue(-b)
+        case _ => Error
+      }
+
+    case LessThan(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => BoolValue(il < ir)
+        case _ => Error
+      }
+
+    case And(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(false) => b
+        case b: BoolValue =>
+          eval(r)
+        case _ =>
+          Error
+      }
+
+    case Or(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(true) =>
+          b
+        case b: BoolValue =>
+          eval(r)
+        case _ =>
+          Error
+      }
+
+    case Implies(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(true) =>
+          eval(r)
+        case b @ BoolValue(false) =>
+          BoolValue(true)
+        case _ => Error
+      }
+
+    case Not(l) =>
+      eval(l) match {
+        case BoolValue(b) => BoolValue(!b)
+        case _ => Error
+      }
+
+    case Eq(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir))   => BoolValue(il == ir)
+        case (BoolValue(il), BoolValue(ir)) => BoolValue(il == ir)
+        case _ => Error
+      }
+
+    case Ite(c, t, e) =>
+      eval(c) match {
+        case BoolValue(true) => eval(t)
+        case BoolValue(false) => eval(t)
+        case _ => Error
+      }
+
+    case IntLiteral(l)  => IntValue(l)
+    case BoolLiteral(b) => BoolValue(b)
+  }
+
+
+  def desugar(in: Expr): Expr = {
+    choose{ (out: Expr) =>
+      eval(in) == eval(out) && !(out.isInstanceOf[Implies])
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/Compiler/RewriteMinus.scala b/testcases/synthesis/etienne-thesis/Compiler/RewriteMinus.scala
new file mode 100644
index 0000000000000000000000000000000000000000..de2fa4360de5fa899110b43c171e592be5282803
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/Compiler/RewriteMinus.scala
@@ -0,0 +1,107 @@
+import leon.lang._
+import leon.lang.synthesis._
+import leon._
+
+object Compiler {
+  abstract class Expr
+  case class Plus(lhs: Expr, rhs: Expr) extends Expr
+  case class Minus(lhs: Expr, rhs: Expr) extends Expr
+  case class UMinus(e: Expr) extends Expr
+  case class LessThan(lhs: Expr, rhs: Expr) extends Expr
+  case class And(lhs: Expr, rhs: Expr) extends Expr
+  case class Implies(lhs: Expr, rhs: Expr) extends Expr
+  case class Or(lhs: Expr, rhs: Expr) extends Expr
+  case class Not(e : Expr) extends Expr
+  case class Eq(lhs: Expr, rhs: Expr) extends Expr
+  case class Ite(cond: Expr, thn: Expr, els: Expr) extends Expr
+  case class BoolLiteral(b : Boolean) extends Expr
+  case class IntLiteral(i: BigInt) extends Expr
+
+  abstract class Value
+  case class BoolValue(b: Boolean) extends Value
+  case class IntValue(i: BigInt) extends Value
+  case object Error extends Value
+
+  def eval(e: Expr): Value = e match {
+    case Plus(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => IntValue(il+ir)
+        case _ => Error
+      }
+
+    case Minus(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => IntValue(il-ir)
+        case _ => Error
+      }
+
+    case UMinus(l) =>
+      eval(l) match {
+        case IntValue(b) => IntValue(-b)
+        case _ => Error
+      }
+
+    case LessThan(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir)) => BoolValue(il < ir)
+        case _ => Error
+      }
+
+    case And(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(false) => b
+        case b: BoolValue =>
+          eval(r)
+        case _ =>
+          Error
+      }
+
+    case Or(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(true) =>
+          b
+        case b: BoolValue =>
+          eval(r)
+        case _ =>
+          Error
+      }
+
+    case Implies(l, r) =>
+      eval(l) match {
+        case b @ BoolValue(true) =>
+          eval(r)
+        case b @ BoolValue(false) =>
+          BoolValue(true)
+        case _ => Error
+      }
+
+    case Not(l) =>
+      eval(l) match {
+        case BoolValue(b) => BoolValue(!b)
+        case _ => Error
+      }
+
+    case Eq(l, r) =>
+      (eval(l), eval(r)) match {
+        case (IntValue(il), IntValue(ir))   => BoolValue(il == ir)
+        case (BoolValue(il), BoolValue(ir)) => BoolValue(il == ir)
+        case _ => Error
+      }
+
+    case Ite(c, t, e) =>
+      eval(c) match {
+        case BoolValue(true) => eval(t)
+        case BoolValue(false) => eval(t)
+        case _ => Error
+      }
+
+    case IntLiteral(l)  => IntValue(l)
+    case BoolLiteral(b) => BoolValue(b)
+  }
+
+  def rewriteMinus(in: Minus): Expr = {
+    choose{ (out: Expr) =>
+      eval(in) == eval(out) && !(out.isInstanceOf[Minus])
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/List/Delete.scala b/testcases/synthesis/etienne-thesis/List/Delete.scala
index 46f0710878d25a30e679f034ff07f985078950d1..30716c5919256f052d0a0e741a147d30c5bc82fa 100644
--- a/testcases/synthesis/etienne-thesis/List/Delete.scala
+++ b/testcases/synthesis/etienne-thesis/List/Delete.scala
@@ -7,7 +7,7 @@ object Delete {
   case class Cons(head: BigInt, tail: List) extends List
   case object Nil extends List
 
-  def size(l: List) : BigInt = (l match {
+  def size(l: List): BigInt = (l match {
     case Nil => BigInt(0)
     case Cons(_, t) => BigInt(1) + size(t)
   }) ensuring(res => res >= 0)
@@ -17,25 +17,10 @@ object Delete {
     case Cons(i, t) => Set(i) ++ content(t)
   }
 
-  def insert(in1: List, v: BigInt): List = {
-    Cons(v, in1)
-  } ensuring { content(_) == content(in1) ++ Set(v) }
-
-  //def delete(in1: List, v: BigInt): List = {
-  //  in1 match {
-  //    case Cons(h,t) =>
-  //      if (h == v) {
-  //        delete(t, v)
-  //      } else {
-  //        Cons(h, delete(t, v))
-  //      }
-  //    case Nil =>
-  //      Nil
-  //  }
-  //} ensuring { content(_) == content(in1) -- Set(v) }
-
-  def delete(in1: List, v: BigInt) = choose {
+  def delete(in: List, v: BigInt) = {
+    ???[List]
+  } ensuring {
     (out : List) =>
-      content(out) == content(in1) -- Set(v)
+      content(out) == content(in) -- Set(v)
   }
 }
diff --git a/testcases/synthesis/etienne-thesis/SortedList/Delete.scala b/testcases/synthesis/etienne-thesis/SortedList/Delete.scala
new file mode 100644
index 0000000000000000000000000000000000000000..788f232d35449cff75ac27442ce7e9cb50f42391
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/SortedList/Delete.scala
@@ -0,0 +1,34 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object SortedListDelete {
+  sealed abstract class List
+  case class Cons(head: BigInt, tail: List) extends List
+  case object Nil extends List
+
+  def size(l: List): BigInt = (l match {
+    case Nil => BigInt(0)
+    case Cons(_, t) => BigInt(1) + size(t)
+  }) ensuring(res => res >= 0)
+
+  def content(l: List): Set[BigInt] = l match {
+    case Nil => Set.empty[BigInt]
+    case Cons(i, t) => Set(i) ++ content(t)
+  }
+
+  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 delete(in: List, v: BigInt) = {
+    require(isSorted(in))
+
+    choose( (res : List) =>
+        (content(res) == content(in) -- Set(v)) && isSorted(res)
+    )
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/SortedList/Diff.scala b/testcases/synthesis/etienne-thesis/SortedList/Diff.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d391b85ba60e2b405530ddb45b40d94071263725
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/SortedList/Diff.scala
@@ -0,0 +1,53 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object SortedListDiff {
+  sealed abstract class List
+  case class Cons(head: BigInt, tail: List) extends List
+  case object Nil extends List
+
+  def size(l: List): BigInt = (l match {
+    case Nil => BigInt(0)
+    case Cons(_, t) => BigInt(1) + size(t)
+  }) ensuring(res => res >= 0)
+
+  def content(l: List): Set[BigInt] = l match {
+    case Nil => Set.empty[BigInt]
+    case Cons(i, t) => Set(i) ++ content(t)
+  }
+
+  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 delete(in1: List, v: BigInt): List = {
+    require(isSorted(in1))
+    in1 match {
+      case Cons(h,t) =>
+        if (h < v) {
+          Cons(h, delete(t, v))
+        } else if (h == v) {
+          delete(t, v)
+        } else {
+          in1
+        }
+      case Nil =>
+        Nil
+    }
+  } ensuring { res => content(res) == content(in1) -- Set(v) && isSorted(res) }
+
+
+  def diff(in1: List, in2: List) = {
+    require(isSorted(in1) && isSorted(in2))
+
+    choose {
+      (out : List) =>
+        (content(out) == content(in1) -- content(in2)) && isSorted(out)
+    }
+  }
+
+}
diff --git a/testcases/synthesis/etienne-thesis/SortedList/Insert.scala b/testcases/synthesis/etienne-thesis/SortedList/Insert.scala
new file mode 100644
index 0000000000000000000000000000000000000000..0bf80d1e99cef290e602b0da905d6966713c77b7
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/SortedList/Insert.scala
@@ -0,0 +1,34 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object SortedListInsert {
+  sealed abstract class List
+  case class Cons(head: BigInt, tail: List) extends List
+  case object Nil extends List
+
+  def size(l: List): BigInt = (l match {
+    case Nil => BigInt(0)
+    case Cons(_, t) => BigInt(1) + size(t)
+  }) ensuring(res => res >= 0)
+
+  def content(l: List): Set[BigInt] = l match {
+    case Nil => Set.empty[BigInt]
+    case Cons(i, t) => Set(i) ++ content(t)
+  }
+
+  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 insert(in1: List, v: BigInt): List = {
+    require(isSorted(in1))
+
+    choose { (out : List) =>
+      (content(out) == content(in1) ++ Set(v)) && isSorted(out)
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/SortedList/InsertAlways.scala b/testcases/synthesis/etienne-thesis/SortedList/InsertAlways.scala
new file mode 100644
index 0000000000000000000000000000000000000000..73e0b240d776780fab6ac8091a8f0c925c56e695
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/SortedList/InsertAlways.scala
@@ -0,0 +1,34 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object SortedListInsertAlways {
+  sealed abstract class List
+  case class Cons(head: BigInt, tail: List) extends List
+  case object Nil extends List
+
+  def size(l: List): BigInt = (l match {
+    case Nil => BigInt(0)
+    case Cons(_, t) => BigInt(1) + size(t)
+  }) ensuring(res => res >= 0)
+
+  def content(l: List): Set[BigInt] = l match {
+    case Nil => Set.empty[BigInt]
+    case Cons(i, t) => Set(i) ++ content(t)
+  }
+
+  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 insertAlways(in1: List, v: BigInt) = {
+    require(isSorted(in1))
+
+    choose{ (out : List) =>
+      (content(out) == content(in1) ++ Set(v)) && isSorted(out) && size(out) == size(in1) + 1
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/SortedList/InsertionSort.scala b/testcases/synthesis/etienne-thesis/SortedList/InsertionSort.scala
new file mode 100644
index 0000000000000000000000000000000000000000..0752ad33fe2249de829d7180e6facaab8fb6e160
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/SortedList/InsertionSort.scala
@@ -0,0 +1,49 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object SortedListInsertionSort {
+  sealed abstract class List
+  case class Cons(head: BigInt, tail: List) extends List
+  case object Nil extends List
+
+  def size(l: List): BigInt = (l match {
+    case Nil => BigInt(0)
+    case Cons(_, t) => BigInt(1) + size(t)
+  }) ensuring(res => res >= 0)
+
+  def content(l: List): Set[BigInt] = l match {
+    case Nil => Set.empty[BigInt]
+    case Cons(i, t) => Set(i) ++ content(t)
+  }
+
+  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 insert(in1: List, v: BigInt): List = {
+    require(isSorted(in1))
+    in1 match {
+      case Cons(h, t) =>
+        if (v < h) {
+          Cons(v, in1)
+        } else if (v == h) {
+          in1
+        } else {
+          Cons(h, insert(t, v))
+        }
+      case Nil =>
+        Cons(v, Nil)
+    }
+
+  } ensuring { res => (content(res) == content(in1) ++ Set(v)) && isSorted(res) }
+
+  def insertionSort(in1: List): List = {
+    choose { (out: List) =>
+      content(out) == content(in1) && isSorted(out)
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/SortedList/Union.scala b/testcases/synthesis/etienne-thesis/SortedList/Union.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d3f11adcccc07e44d1b82c1c6aed7144cb30523c
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/SortedList/Union.scala
@@ -0,0 +1,51 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object SortedListUnion {
+  sealed abstract class List
+  case class Cons(head: BigInt, tail: List) extends List
+  case object Nil extends List
+
+  def size(l: List): BigInt = (l match {
+    case Nil => BigInt(0)
+    case Cons(_, t) => BigInt(1) + size(t)
+  }) ensuring(res => res >= 0)
+
+  def content(l: List): Set[BigInt] = l match {
+    case Nil => Set.empty[BigInt]
+    case Cons(i, t) => Set(i) ++ content(t)
+  }
+
+  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 insert(in1: List, v: BigInt): List = {
+    require(isSorted(in1))
+    in1 match {
+      case Cons(h, t) =>
+        if (v < h) {
+          Cons(v, in1)
+        } else if (v == h) {
+          in1
+        } else {
+          Cons(h, insert(t, v))
+        }
+      case Nil =>
+        Cons(v, Nil)
+    }
+
+  } ensuring { res => (content(res) == content(in1) ++ Set(v)) && isSorted(res) }
+
+  def union(in1: List, in2: List) = {
+    require(isSorted(in1) && isSorted(in2))
+    choose {
+      (out : List) =>
+       (content(out) == content(in1) ++ content(in2)) && isSorted(out)
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/StrictSortedList/Delete.scala b/testcases/synthesis/etienne-thesis/StrictSortedList/Delete.scala
new file mode 100644
index 0000000000000000000000000000000000000000..23999d96c3577b80b00b252e0c07509f4b4b2176
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/StrictSortedList/Delete.scala
@@ -0,0 +1,34 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object StrictSortedListDelete {
+  sealed abstract class List
+  case class Cons(head: BigInt, tail: List) extends List
+  case object Nil extends List
+
+  def size(l: List): BigInt = (l match {
+    case Nil => BigInt(0)
+    case Cons(_, t) => BigInt(1) + size(t)
+  }) ensuring(res => res >= 0)
+
+  def content(l: List): Set[BigInt] = l match {
+    case Nil => Set.empty[BigInt]
+    case Cons(i, t) => Set(i) ++ content(t)
+  }
+
+  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 delete(in: List, v: BigInt) = {
+    require(isSorted(in))
+
+    choose( (res : List) =>
+        (content(res) == content(in) -- Set(v)) && isSorted(res)
+    )
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/StrictSortedList/Insert.scala b/testcases/synthesis/etienne-thesis/StrictSortedList/Insert.scala
new file mode 100644
index 0000000000000000000000000000000000000000..65f3c01f9d7b7d8d45136196a6289088df46fa22
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/StrictSortedList/Insert.scala
@@ -0,0 +1,34 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object StrictSortedListInsert {
+  sealed abstract class List
+  case class Cons(head: BigInt, tail: List) extends List
+  case object Nil extends List
+
+  def size(l: List): BigInt = (l match {
+    case Nil => BigInt(0)
+    case Cons(_, t) => BigInt(1) + size(t)
+  }) ensuring(res => res >= 0)
+
+  def content(l: List): Set[BigInt] = l match {
+    case Nil => Set.empty[BigInt]
+    case Cons(i, t) => Set(i) ++ content(t)
+  }
+
+  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 insert(in1: List, v: BigInt): List = {
+    require(isSorted(in1))
+
+    choose { (out : List) =>
+      (content(out) == content(in1) ++ Set(v)) && isSorted(out)
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/StrictSortedList/Union.scala b/testcases/synthesis/etienne-thesis/StrictSortedList/Union.scala
new file mode 100644
index 0000000000000000000000000000000000000000..c10ed419d3c2cc4fefc9690efb37bc723799ef1c
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/StrictSortedList/Union.scala
@@ -0,0 +1,51 @@
+import leon.annotation._
+import leon.lang._
+import leon.lang.synthesis._
+
+object StrictSortedListUnion {
+  sealed abstract class List
+  case class Cons(head: BigInt, tail: List) extends List
+  case object Nil extends List
+
+  def size(l: List): BigInt = (l match {
+    case Nil => BigInt(0)
+    case Cons(_, t) => BigInt(1) + size(t)
+  }) ensuring(res => res >= 0)
+
+  def content(l: List): Set[BigInt] = l match {
+    case Nil => Set.empty[BigInt]
+    case Cons(i, t) => Set(i) ++ content(t)
+  }
+
+  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 insert(in1: List, v: BigInt): List = {
+    require(isSorted(in1))
+    in1 match {
+      case Cons(h, t) =>
+        if (v < h) {
+          Cons(v, in1)
+        } else if (v == h) {
+          in1
+        } else {
+          Cons(h, insert(t, v))
+        }
+      case Nil =>
+        Cons(v, Nil)
+    }
+
+  } ensuring { res => (content(res) == content(in1) ++ Set(v)) && isSorted(res) }
+
+  def union(in1: List, in2: List) = {
+    require(isSorted(in1) && isSorted(in2))
+    choose {
+      (out : List) =>
+       (content(out) == content(in1) ++ content(in2)) && isSorted(out)
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/UnaryNumerals/Add.scala b/testcases/synthesis/etienne-thesis/UnaryNumerals/Add.scala
new file mode 100644
index 0000000000000000000000000000000000000000..a34d1834fbb5cc2418ca830c5576e64d74169b4f
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/UnaryNumerals/Add.scala
@@ -0,0 +1,21 @@
+import leon.lang._
+import leon.lang.synthesis._
+
+object UnaryNumeralsAdd {
+  sealed abstract class Num
+  case object Z extends Num
+  case class  S(pred: Num) extends Num
+
+  def value(n: Num): BigInt = {
+    n match {
+      case Z => BigInt(0)
+      case S(p) => BigInt(1) + value(p)
+    }
+  } ensuring (_ >= 0)
+
+  def add(x: Num, y: Num): Num = {
+    choose { (r : Num) =>
+      value(r) == value(x) + value(y)
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/UnaryNumerals/Distinct.scala b/testcases/synthesis/etienne-thesis/UnaryNumerals/Distinct.scala
new file mode 100644
index 0000000000000000000000000000000000000000..4287378d1f95225e4ff1ffae57b2d0579d72c3a5
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/UnaryNumerals/Distinct.scala
@@ -0,0 +1,30 @@
+import leon.lang._
+import leon.lang.synthesis._
+
+object UnaryNumeralsDistinct {
+  sealed abstract class Num
+  case object Z extends Num
+  case class  S(pred: Num) extends Num
+
+  def value(n: Num): BigInt = {
+    n match {
+      case Z => BigInt(0)
+      case S(p) => BigInt(1) + value(p)
+    }
+  } ensuring (_ >= 0)
+
+  def add(x: Num, y: Num): Num = {
+    x match {
+      case S(p) => S(add(p, y))
+      case Z => y
+    }
+  } ensuring { (r : Num) =>
+    value(r) == value(x) + value(y)
+  }
+
+  def distinct(x: Num, y: Num): Num = {
+    choose { (r : Num) =>
+      r != x && r != y
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/UnaryNumerals/Mult.scala b/testcases/synthesis/etienne-thesis/UnaryNumerals/Mult.scala
new file mode 100644
index 0000000000000000000000000000000000000000..bfa39365e8a8b35555ddc2265f40c775251b8d17
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/UnaryNumerals/Mult.scala
@@ -0,0 +1,30 @@
+import leon.lang._
+import leon.lang.synthesis._
+
+object UnaryNumeralsMult {
+  sealed abstract class Num
+  case object Z extends Num
+  case class  S(pred: Num) extends Num
+
+  def value(n: Num): BigInt = {
+    n match {
+      case Z => BigInt(0)
+      case S(p) => BigInt(1) + value(p)
+    }
+  } ensuring (_ >= 0)
+
+  def add(x: Num, y: Num): Num = {
+    x match {
+      case S(p) => S(add(p, y))
+      case Z => y
+    }
+  } ensuring { (r : Num) =>
+    value(r) == value(x) + value(y)
+  }
+
+  def mult(x: Num, y: Num): Num = {
+    choose { (r : Num) =>
+      value(r) == value(x) * value(y)
+    }
+  }
+}
diff --git a/testcases/synthesis/etienne-thesis/run.sh b/testcases/synthesis/etienne-thesis/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ee64d86702076bf5ff909c3437f321498a2afe68
--- /dev/null
+++ b/testcases/synthesis/etienne-thesis/run.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+function run {
+    cmd="./leon --debug=report --timeout=30 --synthesis $1"
+    echo "Running " $cmd
+    echo "------------------------------------------------------------------------------------------------------------------"
+    $cmd;
+}
+
+echo "==================================================================================================================" >> synthesis-report.txt
+# These are all the benchmarks included in my thesis
+# List
+run testcases/synthesis/etienne-thesis/List/Insert.scala
+run testcases/synthesis/etienne-thesis/List/Delete.scala
+run testcases/synthesis/etienne-thesis/List/Union.scala
+run testcases/synthesis/etienne-thesis/List/Diff.scala
+run testcases/synthesis/etienne-thesis/List/Split.scala
+
+# SortedList
+run testcases/synthesis/etienne-thesis/SortedList/Insert.scala
+run testcases/synthesis/etienne-thesis/SortedList/InsertAlways.scala
+run testcases/synthesis/etienne-thesis/SortedList/Delete.scala
+run testcases/synthesis/etienne-thesis/SortedList/Union.scala
+run testcases/synthesis/etienne-thesis/SortedList/Diff.scala
+run testcases/synthesis/etienne-thesis/SortedList/InsertionSort.scala
+
+# StrictSortedList
+run testcases/synthesis/etienne-thesis/StrictSortedList/Insert.scala
+run testcases/synthesis/etienne-thesis/StrictSortedList/Delete.scala
+run testcases/synthesis/etienne-thesis/StrictSortedList/Union.scala
+
+# UnaryNumerals
+run testcases/synthesis/etienne-thesis/UnaryNumerals/Add.scala
+run testcases/synthesis/etienne-thesis/UnaryNumerals/Distinct.scala
+run testcases/synthesis/etienne-thesis/UnaryNumerals/Mult.scala
+
+# BatchedQueue
+#run testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala
+run testcases/synthesis/etienne-thesis/BatchedQueue/Dequeue.scala
+
+# AddressBook
+#run testcases/synthesis/etienne-thesis/AddressBook/Make.scala
+run testcases/synthesis/etienne-thesis/AddressBook/Merge.scala
diff --git a/testcases/verification/xlang/BankTransfer.scala b/testcases/verification/xlang/BankTransfer.scala
new file mode 100644
index 0000000000000000000000000000000000000000..c533b4e08a6297446aad36d7a31fd04e148ccc37
--- /dev/null
+++ b/testcases/verification/xlang/BankTransfer.scala
@@ -0,0 +1,73 @@
+import leon.lang._
+
+object BankTransfer {
+
+  def okTransaction(): Unit = {
+    var balance: BigInt = 0
+
+    def balanceInvariant: Boolean = balance >= 0
+
+    def deposit(x: BigInt): Unit = {
+      require(balanceInvariant && x >= 0)
+      balance += x
+    } ensuring(_ => balance == old(balance) + x && balanceInvariant)
+
+    def withdrawal(x: BigInt): Unit = {
+      require(balanceInvariant && x >= 0 && x <= balance)
+      balance -= x
+    } ensuring(_ => balance == old(balance) - x && balanceInvariant)
+
+    deposit(35)
+    withdrawal(30)
+  }
+
+  def invalidTransaction(): Unit = {
+    var balance: BigInt = 0
+
+    def balanceInvariant: Boolean = balance >= 0
+
+    def deposit(x: BigInt): Unit = {
+      require(balanceInvariant && x >= 0)
+      balance += x
+    } ensuring(_ => balance == old(balance) + x && balanceInvariant)
+
+    def withdrawal(x: BigInt): Unit = {
+      require(balanceInvariant && x >= 0 && x <= balance)
+      balance -= x
+    } ensuring(_ => balance == old(balance) - x && balanceInvariant)
+
+    deposit(35)
+    withdrawal(40)
+  }
+
+
+  def internalTransfer(): Unit = {
+    var checking: BigInt = 0
+    var saving: BigInt = 0
+
+    def balance = checking + saving
+
+    def balanceInvariant: Boolean = balance >= 0
+
+    def deposit(x: BigInt): Unit = {
+      require(balanceInvariant && x >= 0)
+      checking += x
+    } ensuring(_ => checking == old(checking) + x && balanceInvariant)
+
+    def withdrawal(x: BigInt): Unit = {
+      require(balanceInvariant && x >= 0 && x <= checking)
+      checking -= x
+    } ensuring(_ => checking == old(checking) - x && balanceInvariant)
+
+    def checkingToSaving(x: BigInt): Unit = {
+      require(balanceInvariant && x >= 0 && checking >= x)
+      checking -= x
+      saving += x
+    } ensuring(_ => checking + saving == old(checking) + old(saving) && balanceInvariant)
+
+    deposit(50)
+    withdrawal(30)
+    checkingToSaving(10)
+  }
+
+}