diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
index b3e8df10c058e4ef4e1d70067fc44af26e7c121f..0a53b4c908ee4a5b3b7d58654fcb9351e15f7cb8 100644
--- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
@@ -413,7 +413,8 @@ trait AbstractZ3Solver extends solvers.IncrementalSolverBuilder {
           val rl = rec(l)
           val rr = rec(r)
           // z3.mkIff used to trigger a bug
-          z3.mkAnd(z3.mkImplies(rl, rr), z3.mkImplies(rr, rl))
+          // z3.mkAnd(z3.mkImplies(rl, rr), z3.mkImplies(rr, rl))
+          z3.mkIff(rl, rr)
         }
         case Not(Iff(l, r)) => z3.mkXor(rec(l), rec(r))
         case Not(Equals(l, r)) => z3.mkDistinct(rec(l), rec(r))
diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
index 63da5306845402b6ff2ba05a5529a863c1da1bf2..3258128f8774807ac1bc7d4980a1350c85e08f0b 100644
--- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
@@ -14,6 +14,8 @@ import purescala.TypeTrees._
 
 import evaluators._
 
+import termination._
+
 import scala.collection.mutable.{Map => MutableMap}
 import scala.collection.mutable.{Set => MutableSet}
 
@@ -37,13 +39,12 @@ class FairZ3Solver(context : LeonContext)
   )
 
   // What wouldn't we do to avoid defining vars?
-  val (feelingLucky, checkModels, useCodeGen, evalGroundApps, unrollUnsatCores, pruneUnsatCores) = locally {
+  val (feelingLucky, checkModels, useCodeGen, evalGroundApps, unrollUnsatCores) = locally {
     var lucky            = false
     var check            = false
     var codegen          = false
     var evalground       = false
     var unrollUnsatCores = false
-    var pruneUnsatCores  = true
 
     for(opt <- context.options) opt match {
       case LeonFlagOption("checkmodels")        => check            = true
@@ -54,12 +55,15 @@ class FairZ3Solver(context : LeonContext)
       case _ =>
     }
 
-    (lucky, check, codegen, evalground, unrollUnsatCores, pruneUnsatCores)
+    (lucky, check, codegen, evalground, unrollUnsatCores)
   }
 
   private var evaluator : Evaluator = null
   protected[z3] def getEvaluator : Evaluator = evaluator
 
+  private var terminator : TerminationChecker = null
+  protected[z3] def getTerminator : TerminationChecker = terminator
+
   override def setProgram(prog : Program) {
     super.setProgram(prog)
 
@@ -70,6 +74,8 @@ class FairZ3Solver(context : LeonContext)
     } else {
       new DefaultEvaluator(context, prog)
     }
+
+    terminator = new SimpleTerminationChecker(context, prog)
   }
 
   // This is fixed.
@@ -211,10 +217,10 @@ class FairZ3Solver(context : LeonContext)
   }
 
   class UnrollingBank {
-    // Keep which function invocation is guarded by which guard with polarity,
-    // also specify the generation of the blocker
+    // Keep which function invocation is guarded by which guard,
+    // also specify the generation of the blocker.
 
-    private var blockersInfoStack : List[MutableMap[(Z3AST,Boolean), (Int, Int, Z3AST, Set[Z3FunctionInvocation])]] = List(MutableMap())
+    private var blockersInfoStack : List[MutableMap[Z3AST,(Int,Int,Z3AST,Set[Z3FunctionInvocation])]] = List(MutableMap())
 
     def blockersInfo = blockersInfoStack.head
 
@@ -232,15 +238,15 @@ class FairZ3Solver(context : LeonContext)
       blockersInfo.groupBy(_._2._1).toSeq.sortBy(_._1).foreach { case (gen, entries) =>
         reporter.info("--- "+gen)
 
-        for (((bast, bpol), (gen, origGen, ast, fis)) <- entries) {
-          reporter.info(".     "+(if(!bpol) "¬" else "")+bast +" ~> "+fis.map(_.funDef.id))
+        for (((bast), (gen, origGen, ast, fis)) <- entries) {
+          reporter.info(".     "+bast +" ~> "+fis.map(_.funDef.id))
         }
       }
     }
 
     def canUnroll = !blockersInfo.isEmpty
 
-    def getZ3BlockersToUnlock: Seq[(Z3AST, Boolean)] = {
+    def getZ3BlockersToUnlock: Seq[Z3AST] = {
       if (!blockersInfo.isEmpty) {
         val minGeneration = blockersInfo.values.map(_._1).min
 
@@ -250,22 +256,22 @@ class FairZ3Solver(context : LeonContext)
       }
     }
 
-    private def registerBlocker(gen: Int, id: Z3AST, pol: Boolean, fis: Set[Z3FunctionInvocation]) {
-      val pair = (id, pol)
-
-      val z3ast          = if (pol) z3.mkNot(id) else id
-
-      blockersInfo.get(pair) match {
+    private def registerBlocker(gen: Int, id: Z3AST, fis: Set[Z3FunctionInvocation]) {
+      val z3ast = z3.mkNot(id)
+      blockersInfo.get(id) match {
         case Some((exGen, origGen, _, exFis)) =>
-          assert(exGen == gen, "Mixing the same pair "+pair+" with various generations "+ exGen+" and "+gen)
+          assert(exGen == gen, "Mixing the same id "+id+" with various generations "+ exGen+" and "+gen)
 
-          blockersInfo(pair) = ((gen, origGen, z3ast, fis++exFis))
+          blockersInfo(id) = ((gen, origGen, z3ast, fis++exFis))
         case None =>
-          blockersInfo(pair) = ((gen, gen, z3ast, fis))
+          blockersInfo(id) = ((gen, gen, z3ast, fis))
       }
     }
 
     def scanForNewTemplates(expr: Expr): Seq[Z3AST] = {
+      // OK, now this is subtle. This `getTemplate` will return
+      // a template for a "fake" function. Now, this template will
+      // define an activating boolean...
       val template = getTemplate(expr)
 
       val z3args = for (vd <- template.funDef.args) yield {
@@ -280,15 +286,18 @@ class FairZ3Solver(context : LeonContext)
         }
       }
 
-      val (newClauses, newBlocks) = template.instantiate(template.z3ActivatingBool, true, z3args)
+      // ...now this template defines clauses that are all guarded
+      // by that activating boolean. If that activating boolean is 
+      // undefined (or false) these clauses have no effect...
+      val (newClauses, newBlocks) =
+        template.instantiate(template.z3ActivatingBool, z3args)
 
-      val extraClauses = for(((i, p), fis) <- newBlocks) yield {
-        registerBlocker(nextGeneration(0), i, p, fis)
-        //unlock(i, p)
-        Nil
+      for((i, fis) <- newBlocks) {
+        registerBlocker(nextGeneration(0), i, fis)
       }
-
-      newClauses ++ extraClauses.flatten
+      
+      // ...so we must force it to true!
+      template.z3ActivatingBool +: newClauses
     }
 
     def nextGeneration(gen: Int) = gen + 3
@@ -300,35 +309,31 @@ class FairZ3Solver(context : LeonContext)
       }
     }
 
-    def prune(ast: Z3AST, pol: Boolean) = {
-      val b = (ast, pol)
-      blockersInfo -= b
-    }
-
-    def promoteBlocker(bast: Z3AST, pol: Boolean) = {
-      val b = (bast, pol)
+    def promoteBlocker(b: Z3AST) = {
       if (blockersInfo contains b) {
         val (gen, origGen, ast, finvs) = blockersInfo(b)
         blockersInfo(b) = (1, origGen, ast, finvs)
       }
     }
 
-    def unlock(id: Z3AST, pol: Boolean) : Seq[Z3AST] = {
-      val pair = (id, pol)
-      assert(blockersInfo contains pair)
+    def unlock(id: Z3AST) : Seq[Z3AST] = {
+      assert(blockersInfo contains id)
 
-      val (gen, origGen, _, fis) = blockersInfo(pair)
-      blockersInfo -= pair
+      val (gen, origGen, _, fis) = blockersInfo(id)
+      blockersInfo -= id
 
       var newClauses : Seq[Z3AST] = Seq.empty
 
       for(fi <- fis) {
         val template              = getTemplate(fi.funDef)
-        val (newExprs, newBlocks) = template.instantiate(id, pol, fi.args)
+        val (newExprs, newBlocks) = template.instantiate(id, fi.args)
 
-        for(((i, p), fis) <- newBlocks) {
-          // We use origGen here
-          registerBlocker(nextGeneration(origGen), i, p, fis)
+        // println("In unlock :")
+        // println("CLAUSES")
+        // newExprs.foreach(println) 
+
+        for((i, fis) <- newBlocks) {
+          registerBlocker(nextGeneration(gen), i, fis)
         }
 
         newClauses ++= newExprs
@@ -440,7 +445,6 @@ class FairZ3Solver(context : LeonContext)
         }).toSet
       }
 
-
       while(!foundDefinitiveAnswer && !forceStop) {
 
         //val blockingSetAsZ3 : Seq[Z3AST] = blockingSet.toSeq.map(toZ3Formula(_).get)
@@ -524,24 +528,13 @@ class FairZ3Solver(context : LeonContext)
 
               for (c <- solver.getUnsatCore) {
                 val (z3ast, pol) = coreElemToBlocker(c)
+                assert(pol == true)
 
-                unrollingBank.promoteBlocker(z3ast, pol)
+                unrollingBank.promoteBlocker(z3ast)
               }
 
             }
 
-            if (pruneUnsatCores) {
-              z3Core.toSeq match {
-                case Seq(c) => 
-                  // If there is only one element in the Seq, we can prune
-                  val (z3ast, pol) = coreElemToBlocker(c)
-
-                  unrollingBank.prune(z3ast, !pol)
-                  solver.assertCnstr(if (pol) z3ast else z3.mkNot(z3ast))
-                case _ =>
-              }
-            }
-
             reporter.info("UNSAT BECAUSE: "+solver.getUnsatCore.mkString("\n  AND  \n"))
             //reporter.info("UNSAT BECAUSE: "+core.mkString("  AND  "))
 
@@ -593,16 +586,10 @@ class FairZ3Solver(context : LeonContext)
 
               reporter.info(" - more unrollings")
 
-              unrollingBank.dumpBlockers
-
-              for((id, polarity) <- toReleaseAsPairs) {
+              for(id <- toReleaseAsPairs) {
                 unlockingTime.start
-                val newClauses = unrollingBank.unlock(id, polarity)
+                val newClauses = unrollingBank.unlock(id)
                 unlockingTime.stop
-                reporter.info(" - - Unrolling behind "+(if(!polarity) "¬" else "")+id)
-                //for (cl <- newClauses) {
-                //  reporter.info(" - - - "+cl)
-                //}
 
                 unrollingTime.start
                 for(ncl <- newClauses) {
diff --git a/src/main/scala/leon/solvers/z3/FunctionTemplate.scala b/src/main/scala/leon/solvers/z3/FunctionTemplate.scala
index da4de64711a03fc1a8c068263b673ba81232c37a..f4e3724c45d6d26d6d41475ca18694cf0d1fb209 100644
--- a/src/main/scala/leon/solvers/z3/FunctionTemplate.scala
+++ b/src/main/scala/leon/solvers/z3/FunctionTemplate.scala
@@ -22,14 +22,24 @@ class FunctionTemplate private(
   activatingBool : Identifier,
   condVars : Set[Identifier],
   exprVars : Set[Identifier],
-  guardedExprs : Map[(Identifier,Boolean),Seq[Expr]],
+  guardedExprs : Map[Identifier,Seq[Expr]],
   isRealFunDef : Boolean) {
 
+  private val isTerminatingForAllInputs : Boolean = (
+       isRealFunDef
+    && !funDef.hasPrecondition
+    && solver.getTerminator.terminates(funDef).isGuaranteed
+  )
+
+  // if(isRealFunDef) {
+  //   println("Just created template for %s... Safe? %s".format(funDef.id.name, isTerminatingForAllInputs.toString))
+  // }
+
   private val z3 = solver.z3
 
   private val asClauses : Seq[Expr] = {
-    (for(((b,p),es) <- guardedExprs; e <- es) yield {
-      Implies(if(!p) Not(Variable(b)) else Variable(b), e)
+    (for((b,es) <- guardedExprs; e <- es) yield {
+      Implies(Variable(b), e)
     }).toSeq
   }
 
@@ -50,27 +60,29 @@ class FunctionTemplate private(
 
   val asZ3Clauses: Seq[Z3AST] = asClauses.map(solver.toZ3Formula(_, idToZ3Ids).get)
 
-  private val blockers : Map[(Identifier,Boolean),Set[FunctionInvocation]] = {
+  private val blockers : Map[Identifier,Set[FunctionInvocation]] = {
     val idCall = FunctionInvocation(funDef, funDef.args.map(_.toVariable))
 
-    Map((for((p, es) <- guardedExprs) yield {
+    Map((for((b, es) <- guardedExprs) yield {
       val calls = es.foldLeft(Set.empty[FunctionInvocation])((s,e) => s ++ functionCallsOf(e)) - idCall
       if(calls.isEmpty) {
         None
       } else {
-        Some((p, calls))
+        Some((b, calls))
       }
     }).flatten.toSeq : _*)
   }
 
-  val z3Blockers: Map[(Z3AST, Boolean), Set[Z3FunctionInvocation]] = blockers.map {
-    case ((b, p), funs) => ((idToZ3Ids(b), p) -> funs.map(fi => Z3FunctionInvocation(fi.funDef, fi.args.map(solver.toZ3Formula(_, idToZ3Ids).get))))
+  val z3Blockers: Map[Z3AST,Set[Z3FunctionInvocation]] = blockers.map {
+    case (b, funs) =>
+      (idToZ3Ids(b) -> funs.map(fi => Z3FunctionInvocation(fi.funDef, fi.args.map(solver.toZ3Formula(_, idToZ3Ids).get))))
   }
 
-  def instantiate(aVar : Z3AST, aPol : Boolean, args : Seq[Z3AST]) : (Seq[Z3AST], Map[(Z3AST, Boolean), Set[Z3FunctionInvocation]]) = {
+  def instantiate(aVar : Z3AST, args : Seq[Z3AST]) : (Seq[Z3AST], Map[Z3AST,Set[Z3FunctionInvocation]]) = {
     assert(args.size == funDef.args.size)
 
-    // The "isRealFunDef" part is to prevent evaluation of "fake" function templates, as generated from FairZ3Solver.
+    // The "isRealFunDef" part is to prevent evaluation of "fake"
+    // function templates, as generated from FairZ3Solver.
     if(solver.evalGroundApps && isRealFunDef) {
       val ga = args.view.map(solver.asGround)
       if(ga.forall(_.isDefined)) {
@@ -89,7 +101,7 @@ class FunctionTemplate private(
     }
 
     val idSubstMap : Map[Z3AST, Z3AST] =
-      Map(z3ActivatingBool -> (if (aPol) aVar else z3.mkNot(aVar))) ++
+      Map(z3ActivatingBool -> aVar) ++
       (zippedExprVars ++ zippedCondVars).map{ case (id, c) => c -> solver.idToFreshZ3Id(id) } ++
       (z3FunDefArgs zip args)
 
@@ -97,11 +109,11 @@ class FunctionTemplate private(
     val (fromArray, toArray) = (from.toArray, to.toArray)
 
     val newClauses  = asZ3Clauses.map(z3.substitute(_, fromArray, toArray))
-    val newBlockers = z3Blockers.map { case ((b, p), funs) =>
+    val newBlockers = z3Blockers.map { case (b, funs) =>
       val bp = if (b == z3ActivatingBool) {
-        (aVar, p == aPol)
+        aVar
       } else {
-        (idSubstMap(b), p)
+        idSubstMap(b)
       }
 
       val newFuns = funs.map(fi => fi.copy(args = fi.args.map(z3.substitute(_, fromArray, toArray))))
@@ -127,18 +139,17 @@ object FunctionTemplate {
     val condVars : MutableSet[Identifier] = MutableSet.empty
     val exprVars : MutableSet[Identifier] = MutableSet.empty
 
-    // represents clauses of the form:
-    //    (~)id => expr && ... && expr
-    val guardedExprs : MutableMap[(Identifier,Boolean),Seq[Expr]] = MutableMap.empty
+    // Represents clauses of the form:
+    //    id => expr && ... && expr
+    val guardedExprs : MutableMap[Identifier,Seq[Expr]] = MutableMap.empty
 
-    def storeGuarded(guardVar : Identifier, guardPol : Boolean, expr : Expr) : Unit = {
+    def storeGuarded(guardVar : Identifier, expr : Expr) : Unit = {
       assert(expr.getType == BooleanType)
-      val p : (Identifier,Boolean) = (guardVar,guardPol)
-      if(guardedExprs.isDefinedAt(p)) {
-        val prev : Seq[Expr] = guardedExprs(p)
-        guardedExprs(p) = expr +: prev
+      if(guardedExprs.isDefinedAt(guardVar)) {
+        val prev : Seq[Expr] = guardedExprs(guardVar)
+        guardedExprs(guardVar) = expr +: prev
       } else {
-        guardedExprs(p) = Seq(expr)
+        guardedExprs(guardVar) = Seq(expr)
       }
     }
 
@@ -165,21 +176,21 @@ object FunctionTemplate {
       res
     }
 
-    def rec(pathVar : Identifier, pathPol : Boolean, expr : Expr) : Expr = {
+    def rec(pathVar : Identifier, expr : Expr) : Expr = {
       expr match {
         case l @ Let(i, e, b) =>
           val newExpr : Identifier = FreshIdentifier("lt", true).setType(i.getType)
           exprVars += newExpr
-          val re = rec(pathVar, pathPol, e)
-          storeGuarded(pathVar, pathPol, Equals(Variable(newExpr), re))
-          val rb = rec(pathVar, pathPol, replace(Map(Variable(i) -> Variable(newExpr)), b))
+          val re = rec(pathVar, e)
+          storeGuarded(pathVar, Equals(Variable(newExpr), re))
+          val rb = rec(pathVar, replace(Map(Variable(i) -> Variable(newExpr)), b))
           rb
 
         case m : MatchExpr => sys.error("MatchExpr's should have been eliminated.")
 
         case i @ Implies(lhs, rhs) =>
           if (containsFunctionCalls(i)) {
-            rec(pathVar, pathPol, IfExpr(lhs, rhs, BooleanLiteral(true)))
+            rec(pathVar, IfExpr(lhs, rhs, BooleanLiteral(true)))
           } else {
             i
           }
@@ -190,7 +201,7 @@ object FunctionTemplate {
 
             val ifExpr = partitions.map(And(_)).reduceRight{ (a: Expr, b: Expr) => IfExpr(a, b, BooleanLiteral(false)) }
 
-            rec(pathVar, pathPol, ifExpr)
+            rec(pathVar, ifExpr)
           } else {
             a
           }
@@ -201,7 +212,7 @@ object FunctionTemplate {
 
             val ifExpr = partitions.map(Or(_)).reduceRight{ (a: Expr, b: Expr) => IfExpr(a, BooleanLiteral(true), b) }
 
-            rec(pathVar, pathPol, ifExpr)
+            rec(pathVar, ifExpr)
           } else {
             o
           }
@@ -210,27 +221,35 @@ object FunctionTemplate {
           if(!containsFunctionCalls(cond) && !containsFunctionCalls(then) && !containsFunctionCalls(elze)) {
             i
           } else {
-            val newBool : Identifier = FreshIdentifier("b", true).setType(BooleanType)
+            val newBool1 : Identifier = FreshIdentifier("b", true).setType(BooleanType)
+            val newBool2 : Identifier = FreshIdentifier("b", true).setType(BooleanType)
             val newExpr : Identifier = FreshIdentifier("e", true).setType(i.getType)
-            condVars += newBool
+
+            condVars += newBool1
+            condVars += newBool2
+
             exprVars += newExpr
-            
-            val crec = rec(pathVar, pathPol, cond)
-            val trec = rec(newBool, true, then)
-            val erec = rec(newBool, false, elze)
-
-            storeGuarded(pathVar, pathPol, Iff(Variable(newBool), crec))
-            storeGuarded(newBool, true,  Equals(Variable(newExpr), trec))
-            storeGuarded(newBool, false, Equals(Variable(newExpr), erec))
+
+            val crec = rec(pathVar, cond)
+            val trec = rec(newBool1, then)
+            val erec = rec(newBool2, elze)
+
+            storeGuarded(pathVar, Or(Variable(newBool1), Variable(newBool2)))
+            storeGuarded(pathVar, Or(Not(Variable(newBool1)), Not(Variable(newBool2))))
+            // TODO can we improve this? i.e. make it more symmetrical?
+            // Probably it's symmetrical enough to Z3.
+            storeGuarded(pathVar, Iff(Variable(newBool1), crec)) 
+            storeGuarded(newBool1, Equals(Variable(newExpr), trec))
+            storeGuarded(newBool2, Equals(Variable(newExpr), erec))
             Variable(newExpr)
           }
         }
 
         case c @ Choose(_, _) => Variable(FreshIdentifier("choose", true).setType(c.getType))
 
-        case n @ NAryOperator(as, r) => r(as.map(a => rec(pathVar, pathPol, a))).setType(n.getType)
-        case b @ BinaryOperator(a1, a2, r) => r(rec(pathVar, pathPol, a1), rec(pathVar, pathPol, a2)).setType(b.getType)
-        case u @ UnaryOperator(a, r) => r(rec(pathVar, pathPol, a)).setType(u.getType)
+        case n @ NAryOperator(as, r) => r(as.map(a => rec(pathVar, a))).setType(n.getType)
+        case b @ BinaryOperator(a1, a2, r) => r(rec(pathVar, a1), rec(pathVar, a2)).setType(b.getType)
+        case u @ UnaryOperator(a, r) => r(rec(pathVar, a)).setType(u.getType)
         case t : Terminal => t
       }
     }
@@ -259,12 +278,11 @@ object FunctionTemplate {
     val activatingBool : Identifier = FreshIdentifier("start", true).setType(BooleanType)
 
     if (isRealFunDef) {
-      val finalPred : Option[Expr] = invocationEqualsBody.map(expr => rec(activatingBool, true, expr))
-      finalPred.foreach(p => storeGuarded(activatingBool, true, p))
+      val finalPred : Option[Expr] = invocationEqualsBody.map(expr => rec(activatingBool, expr))
+      finalPred.foreach(p => storeGuarded(activatingBool, p))
     } else {
-       storeGuarded(activatingBool, false, BooleanLiteral(false))
-       val newFormula = rec(activatingBool, true, newBody.get)
-       storeGuarded(activatingBool, true, newFormula)
+       val newFormula = rec(activatingBool, newBody.get)
+       storeGuarded(activatingBool, newFormula)
     }
 
     // Now the postcondition.
@@ -279,8 +297,8 @@ object FunctionTemplate {
           post
         }
 
-      val finalPred2 : Expr = rec(activatingBool, true, postHolds)
-      storeGuarded(activatingBool, true, finalPred2)
+      val finalPred2 : Expr = rec(activatingBool,  postHolds)
+      storeGuarded(activatingBool, finalPred2)
     }
 
     new FunctionTemplate(solver, funDef, activatingBool, Set(condVars.toSeq : _*), Set(exprVars.toSeq : _*), Map(guardedExprs.toSeq : _*),
diff --git a/src/main/scala/leon/termination/SimpleTerminationChecker.scala b/src/main/scala/leon/termination/SimpleTerminationChecker.scala
index 840c16f2518de7df54b3f627d5ed7146dc4cf158..43d18726fbffd9af99d4b6643db3f36fdb1004e5 100644
--- a/src/main/scala/leon/termination/SimpleTerminationChecker.scala
+++ b/src/main/scala/leon/termination/SimpleTerminationChecker.scala
@@ -44,7 +44,9 @@ class SimpleTerminationChecker(context : LeonContext, program : Program) extends
     if(!funDef.hasImplementation)
       return NoGuarantee
 
-    val sccIndex   = funDefToSCCIndex(funDef)
+    val sccIndex   = funDefToSCCIndex.getOrElse(funDef, {
+      return NoGuarantee
+    })
     val sccCallees = sccGraph(sccIndex)
 
     // We check all functions that are in a "lower" scc. These must