diff --git a/src/main/scala/leon/Main.scala b/src/main/scala/leon/Main.scala
index 34fc1c98c52a9b8d4d165e5e9d5d3d21d0e20e57..23a0a7780463a1ba66809747df5cc9d690463b95 100644
--- a/src/main/scala/leon/Main.scala
+++ b/src/main/scala/leon/Main.scala
@@ -185,10 +185,9 @@ object Main {
         else if (terminationF) TerminationPhase
         else if (isabelleF) IsabellePhase
         else if (evalF) EvaluationPhase
-        else if (inferInvF) InstrumentationPhase andThen InferInvariantsPhase
+        else if (inferInvF) InferInvariantsPhase
         else if (instrumentF) InstrumentationPhase andThen FileOutputPhase
         else analysis
-
       }
 
       pipeBegin andThen
diff --git a/src/main/scala/leon/invariant/engine/InferInvariantsPhase.scala b/src/main/scala/leon/invariant/engine/InferInvariantsPhase.scala
index 30ca3fcdebedca181e58ea6929930d3b823aad9e..c724f05b37aa67f0df165af330e37f6b9bb5d9de 100644
--- a/src/main/scala/leon/invariant/engine/InferInvariantsPhase.scala
+++ b/src/main/scala/leon/invariant/engine/InferInvariantsPhase.scala
@@ -17,6 +17,7 @@ import transformations._
 import verification._
 import verification.VCKinds
 import leon.purescala.ScalaPrinter
+import leon.purescala.PrettyPrinter
 
 /**
  * @author ravi
@@ -44,7 +45,7 @@ object InferInvariantsPhase extends LeonPhase[Program, InferenceReport] {
         optDisableInfer)
 
   //TODO provide options for analyzing only selected functions
-  def run(ctx: LeonContext)(prog: Program): InferenceReport = {
+  def run(ctx: LeonContext)(program: Program): InferenceReport = {
 
     //control printing of statistics
     val dumpStats = true
@@ -67,70 +68,40 @@ object InferInvariantsPhase extends LeonPhase[Program, InferenceReport] {
     var autoInference = true
 
     for (opt <- ctx.options) (opt.optionDef.name, opt.value) match {
-      case ("wholeprogram", true) => {
-        //do not do a modular analysis
-        modularlyAnalyze = false
-      }
-
-      case ("fullunroll", true) => {
-        //do not do a modular analysis
-        targettedUnroll = false
-      }
-
-      case ("minbounds", true) => {
-        tightBounds = true
-      }
-
-      case ("withmult", true) => {
-        withmult = true
-      }
-
-      case ("usereals", true) => {
-        usereals = true
-      }
-
+      case ("wholeprogram", true) => 
+        modularlyAnalyze = false      
+      case ("fullunroll", true) =>         
+        targettedUnroll = false      
+      case ("minbounds", true) => 
+        tightBounds = true      
+      case ("withmult", true) => 
+        withmult = true      
+      case ("usereals", true) => 
+        usereals = true      
       case ("disableInfer", true) =>
         autoInference = false
-
-      case ("inferTemp", true) => {
-        inferTemp = true
-        var foundStrongest = false
-        //go over all post-conditions and pick the strongest relation
-        prog.definedFunctions.foreach((fd) => {
-          if (!foundStrongest && fd.hasPostcondition) {
-            val cond = fd.postcondition.get
-            simplePostTransform((e) => e match {
-              case Equals(_, _) => {
-                enumerationRelation = Equals.apply _
-                foundStrongest = true
-                e
-              }
-              case _ => e
-            })(cond)
-          }
-        })
-      }
-
-      case ("cegis", true) => {
-        useCegis = true
-      }
-
+      case ("inferTemp", true) => 
+        inferTemp = true              
+      case ("cegis", true) => 
+        useCegis = true      
       case ("timeout", timeOut: Int) =>
         timeout = timeOut
-
-      case ("stats-suffix", suffix: String) => {
-        statsSuff = suffix
-      }
-
+      case ("stats-suffix", suffix: String) => 
+        statsSuff = suffix      
       case _ =>
     }
+    
+    // (a) first run instrumentation phase
+    val instProg = InstrumentationPhase(ctx, program)
 
-    val funToTmpl = prog.definedFunctions.collect {
+    // (b) convert qmarks to tmpl functions 
+    val funToTmpl = instProg.definedFunctions.collect {
       case fd if fd.hasTemplate =>
         fd -> fd.getTemplate
     }.toMap
-    val qMarksRemovedProg = Util.assignTemplateAndCojoinPost(funToTmpl, prog, Map())
+    val qMarksRemovedProg = Util.assignTemplateAndCojoinPost(funToTmpl, instProg, Map())
 
+    // convert nonlinearity to recursive functions
     val newprog = if (usereals) {
       (new IntToRealProgram())(qMarksRemovedProg)
     } else qMarksRemovedProg
@@ -138,13 +109,33 @@ object InferInvariantsPhase extends LeonPhase[Program, InferenceReport] {
     val finalprog = nlelim(newprog)
 
     val toVerifyPost = validateAndCollectNotValidated(qMarksRemovedProg, ctx, timeout)
+
+    // collect strongest relation for enumeration if defined
+    var foundStrongest = false
+    //go over all post-conditions and pick the strongest relation
+    instProg.definedFunctions.foreach((fd) => {
+      if (!foundStrongest && fd.hasPostcondition) {
+        val cond = fd.postcondition.get
+        simplePostTransform((e) => e match {
+          case Equals(_, _) => {
+            enumerationRelation = Equals.apply _
+            foundStrongest = true
+            e
+          }
+          case _ => e
+        })(cond)
+      }
+    })
+    
     //populate the inference context and invoke inferenceEngine
-    val inferctx = new InferenceContext(finalprog, toVerifyPost, ctx,
+    val inferctx = new InferenceContext(program, finalprog, toVerifyPost, ctx,
       //multiplication operation
       (e1, e2) => FunctionInvocation(TypedFunDef(nlelim.multFun, nlelim.multFun.tparams.map(_.tp)), Seq(e1, e2)),
       enumerationRelation = LessEquals, modularlyAnalyze, targettedUnroll, autoInference,
       dumpStats, tightBounds, withmult, usereals, inferTemp, useCegis, timeout, maxCegisBound, statsSuff)
-    (new InferenceEngine(inferctx)).run()
+    val report = (new InferenceEngine(inferctx)).run()
+    println("Final Program: \n" +PrettyPrinter.apply(report.finalProgramWoInstrumentation))
+    report
   }
 
   def createLeonContext(ctx: LeonContext, opts: String*): LeonContext = {
diff --git a/src/main/scala/leon/invariant/engine/InferenceContext.scala b/src/main/scala/leon/invariant/engine/InferenceContext.scala
index 243cd54801a40ca9d4c2a60dfcb2d24ac3fdf802..bf3d83845b3fcb9b2ecbd3fe108186655dbc26b2 100644
--- a/src/main/scala/leon/invariant/engine/InferenceContext.scala
+++ b/src/main/scala/leon/invariant/engine/InferenceContext.scala
@@ -9,6 +9,7 @@ import purescala._
  * @author ravi
  */
 case class InferenceContext(
+  val uninstrumentedProgram : Program, 
   val program : Program,
   val toVerifyPostFor: Set[String],
   val leonContext : LeonContext,
diff --git a/src/main/scala/leon/invariant/engine/InferenceEngine.scala b/src/main/scala/leon/invariant/engine/InferenceEngine.scala
index 067eac087c5267cbc9c7c8eb7a62c90bfac3465f..03202f9dbb3a300a8eca4c2454b295e924dfd1b3 100644
--- a/src/main/scala/leon/invariant/engine/InferenceEngine.scala
+++ b/src/main/scala/leon/invariant/engine/InferenceEngine.scala
@@ -72,7 +72,7 @@ class InferenceEngine(ctx: InferenceContext) {
       reporter.info("- Dumping statistics")
       dumpStats(ctx.statsSuffix)
     }
-    new InferenceReport(program, results.map(pair => {
+    new InferenceReport(results.map(pair => {
       val (fd, ic) = pair
       (fd -> List[VC](ic))
     }))(ctx)
@@ -141,7 +141,7 @@ class InferenceEngine(ctx: InferenceContext) {
                 val inv = TemplateInstantiator.getAllInvariants(model.get,
                   Map(origFd -> origFd.getTemplate))
                 // record the inferred invariants
-                val ic = new InferenceCondition(Some(inv(origFd)), fd)
+                val ic = new InferenceCondition(Some(inv(origFd)), origFd)
                 ic.time = if (first) Some(funcTime) else Some(0.0)
                 // update analyzed set
                 analyzedSet += (origFd -> ic)
diff --git a/src/main/scala/leon/invariant/engine/InferenceReport.scala b/src/main/scala/leon/invariant/engine/InferenceReport.scala
index 21756faac1fb1deae5bd626070f517a935905291..15c1a1ffef4bbbc0d011431c3e915db8e3cf54e9 100644
--- a/src/main/scala/leon/invariant/engine/InferenceReport.scala
+++ b/src/main/scala/leon/invariant/engine/InferenceReport.scala
@@ -16,53 +16,52 @@ import invariant.structure._
 import leon.transformations.InstUtil
 import leon.purescala.PrettyPrinter
 
-
 class InferenceCondition(val invariant: Option[Expr], funDef: FunDef)
   extends VC(BooleanLiteral(true), funDef, null) {
 
-  var time : Option[Double] = None
+  var time: Option[Double] = None
 
   def status: String = invariant match {
     case None => "unknown"
     case Some(inv) => {
-      val prettyInv = simplifyArithmetic(InstUtil.replaceInstruVars(Util.multToTimes(inv),fd))
+      val prettyInv = simplifyArithmetic(InstUtil.replaceInstruVars(Util.multToTimes(inv), fd))
       PrettyPrinter(prettyInv)
     }
   }
 }
 
-class InferenceReport(p: Program, fvcs: Map[FunDef, List[VC]])(implicit ctx: InferenceContext)
-  extends VerificationReport(p : Program, Map()) {
+class InferenceReport(fvcs: Map[FunDef, List[VC]])(implicit ctx: InferenceContext)
+  extends VerificationReport(ctx.program, Map()) {
 
   import scala.math.Ordering.Implicits._
-  val conditions : Seq[InferenceCondition] =
+  val conditions: Seq[InferenceCondition] =
     fvcs.flatMap(_._2.map(_.asInstanceOf[InferenceCondition])).toSeq.sortBy(vc => vc.fd.id.name)
 
-  private def infoSep(size: Int)    : String = "╟" + ("┄" * size) + "╢\n"
-  private def infoFooter(size: Int) : String = "╚" + ("═" * size) + "╝"
-  private def infoHeader(size: Int) : String = ". ┌─────────┐\n" +
-                                          "╔═╡ Summary ╞" + ("═" * (size - 12)) + "╗\n" +
-                                          "║ └─────────┘" + (" " * (size - 12)) + "║"
+  private def infoSep(size: Int): String = "╟" + ("┄" * size) + "╢\n"
+  private def infoFooter(size: Int): String = "╚" + ("═" * size) + "╝"
+  private def infoHeader(size: Int): String = ". ┌─────────┐\n" +
+    "╔═╡ Summary ╞" + ("═" * (size - 12)) + "╗\n" +
+    "║ └─────────┘" + (" " * (size - 12)) + "║"
 
-  private def infoLine(str: String, size: Int) : String = {
-    "║ "+ str + (" " * (size - str.size - 2)) + " ║"
+  private def infoLine(str: String, size: Int): String = {
+    "║ " + str + (" " * (size - str.size - 2)) + " ║"
   }
 
-  private def fit(str : String, maxLength : Int) : String = {
-    if(str.length <= maxLength) {
+  private def fit(str: String, maxLength: Int): String = {
+    if (str.length <= maxLength) {
       str
     } else {
       str.substring(0, maxLength - 1) + "…"
     }
   }
 
-  private def funName(fd: FunDef)  = InstUtil.userFunctionName(fd)
+  private def funName(fd: FunDef) = InstUtil.userFunctionName(fd)
 
-  override def summaryString : String = if(conditions.size > 0) {
+  override def summaryString: String = if (conditions.size > 0) {
     val maxTempSize = (conditions.map(_.status.size).max + 3)
     val outputStrs = conditions.map(vc => {
       val timeStr = vc.time.map(t => "%-3.3f".format(t)).getOrElse("")
-      "%-15s %s %-4s".format(fit(funName(vc.fd), 15), vc.status + (" "*(maxTempSize-vc.status.size)), timeStr)
+      "%-15s %s %-4s".format(fit(funName(vc.fd), 15), vc.status + (" " * (maxTempSize - vc.status.size)), timeStr)
     })
     val summaryStr = {
       val totalTime = conditions.foldLeft(0.0)((a, ic) => a + ic.time.getOrElse(0.0))
@@ -73,12 +72,41 @@ class InferenceReport(p: Program, fvcs: Map[FunDef, List[VC]])(implicit ctx: Inf
     val entrySize = (outputStrs :+ summaryStr).map(_.size).max + 2
 
     infoHeader(entrySize) +
-    outputStrs.map(str => infoLine(str, entrySize)).mkString("\n", "\n", "\n") +
-    infoSep(entrySize) +
-    infoLine(summaryStr, entrySize) + "\n" +
-    infoFooter(entrySize)
+      outputStrs.map(str => infoLine(str, entrySize)).mkString("\n", "\n", "\n") +
+      infoSep(entrySize) +
+      infoLine(summaryStr, entrySize) + "\n" +
+      infoFooter(entrySize)
 
   } else {
     "No user provided templates were solved."
   }
+
+  def finalProgram: Program = {
+    val funToTmpl = conditions.collect {
+      case cd if cd.invariant.isDefined =>
+        cd.fd -> cd.invariant.get
+    }.toMap
+    Util.assignTemplateAndCojoinPost(funToTmpl, ctx.program)
+  }
+
+  def finalProgramWoInstrumentation: Program = {
+
+    val funToUninstFun = ctx.program.definedFunctions.foldLeft(Map[FunDef, FunDef]()) {
+      case (acc, fd) =>
+        val uninstFunName = InstUtil.userFunctionName(fd)
+        val uninstFdOpt =
+          if (uninstFunName.isEmpty) None
+          else Util.functionByName(uninstFunName, ctx.uninstrumentedProgram)
+        if (uninstFdOpt.isDefined) {          
+          acc + (fd -> uninstFdOpt.get)
+        }
+        else acc
+    }
+    val funToPost = conditions.collect {
+      case cd if cd.invariant.isDefined && funToUninstFun.contains(cd.fd) =>
+        funToUninstFun(cd.fd) -> cd.invariant.get
+    }.toMap
+    //println("Function to template: " + funToTmpl.map { case (k, v) => s"${k.id.name} --> $v" }.mkString("\n"))
+    Util.assignTemplateAndCojoinPost(Map(), ctx.uninstrumentedProgram, funToPost, uniqueIdDisplay = false)
+  }
 }
\ No newline at end of file
diff --git a/src/main/scala/leon/invariant/util/Util.scala b/src/main/scala/leon/invariant/util/Util.scala
index fdd70bf9a5bb21155d7269279d39be0e0559d5a1..cc9bf2b2c288c4975b832f36202c4343049ff04d 100644
--- a/src/main/scala/leon/invariant/util/Util.scala
+++ b/src/main/scala/leon/invariant/util/Util.scala
@@ -150,13 +150,14 @@ object Util {
     })(ine)
   }
 
-  def assignTemplateAndCojoinPost(funToTmpl: Map[FunDef, Expr], prog: Program, funToPost: Map[FunDef, Expr] = Map()): Program = {
+  def assignTemplateAndCojoinPost(funToTmpl: Map[FunDef, Expr], prog: Program, 
+      funToPost: Map[FunDef, Expr] = Map(), uniqueIdDisplay : Boolean = true): Program = {
 
     val funMap = Util.functionsWOFields(prog.definedFunctions).foldLeft(Map[FunDef, FunDef]()) {
       case (accMap, fd) if fd.isTheoryOperation =>
         accMap + (fd -> fd)
       case (accMap, fd) => {
-        val freshId = FreshIdentifier(fd.id.name, fd.returnType, true)
+        val freshId = FreshIdentifier(fd.id.name, fd.returnType, uniqueIdDisplay)
         val newfd = new FunDef(freshId, fd.tparams, fd.returnType, fd.params)
         accMap.updated(fd, newfd)
       }
diff --git a/src/main/scala/leon/transformations/InstrumentationUtil.scala b/src/main/scala/leon/transformations/InstrumentationUtil.scala
index fa35cc3f56cfe1dd37f2b013337373e619a5b086..01ab8f1716c9d5b47f93c6c008ffb022ea4ecba6 100644
--- a/src/main/scala/leon/transformations/InstrumentationUtil.scala
+++ b/src/main/scala/leon/transformations/InstrumentationUtil.scala
@@ -67,7 +67,11 @@ object InstUtil {
     mfd
   }
 
-  def userFunctionName(fd: FunDef) = fd.id.name.split("-")(0)
+  def userFunctionName(fd: FunDef) = {
+    val splits = fd.id.name.split("-")
+    if(!splits.isEmpty) splits(0)
+    else ""
+  }
 
   def getInstMap(fd: FunDef) = {
     val resvar = invariant.util.Util.getResId(fd).get.toVariable // note: every instrumented function has a postcondition