diff --git a/library/theories/String.scala b/library/theories/String.scala
index 85e4d90c7e1eca5a72a2d7c74aa0c63437d6c872..ca2b9027df5a9628ab3140416897ee6274904ff9 100644
--- a/library/theories/String.scala
+++ b/library/theories/String.scala
@@ -30,3 +30,47 @@ sealed abstract class String {
 
 case class StringCons(head: Char, tail: String) extends String
 case class StringNil() extends String
+
+@library
+object String {
+  def fromChar(i: Char): String = {
+    StringCons(i, StringNil())
+  }
+
+  @isabelle.noBody()
+  def fromBigInt(i: BigInt): String =
+    if(i < 0) StringCons('-', fromBigInt(-i))
+    else if(i == BigInt(0)) StringCons('0', StringNil())
+    else if(i == BigInt(1)) StringCons('1', StringNil())
+    else if(i == BigInt(2)) StringCons('2', StringNil())
+    else if(i == BigInt(3)) StringCons('3', StringNil())
+    else if(i == BigInt(4)) StringCons('4', StringNil())
+    else if(i == BigInt(5)) StringCons('5', StringNil())
+    else if(i == BigInt(6)) StringCons('6', StringNil())
+    else if(i == BigInt(7)) StringCons('7', StringNil())
+    else if(i == BigInt(8)) StringCons('8', StringNil())
+    else if(i == BigInt(9)) StringCons('9', StringNil())   
+    else fromBigInt(i / 10).concat(fromBigInt(i % 10))
+
+  @isabelle.noBody()
+  def fromInt(i: Int): String = i match {
+    case -2147483648 => StringCons('-', StringCons('2', fromInt(147483648)))
+    case i  if i < 0 => StringCons('-', fromInt(-i))
+    case 0 => StringCons('0', StringNil())
+    case 1 => StringCons('1', StringNil())
+    case 2 => StringCons('2', StringNil())
+    case 3 => StringCons('3', StringNil())
+    case 4 => StringCons('4', StringNil())
+    case 5 => StringCons('5', StringNil())
+    case 6 => StringCons('6', StringNil())
+    case 7 => StringCons('7', StringNil())
+    case 8 => StringCons('8', StringNil())
+    case 9 => StringCons('9', StringNil())
+    case i => fromInt(i / 10).concat(fromInt(i % 10))
+  }
+  
+  def fromBoolean(b: Boolean): String = {
+    if(b) StringCons('t', StringCons('r', StringCons('u', StringCons('e', StringNil()))))
+    else StringCons('f', StringCons('a', StringCons('l', StringCons('s', StringCons('e', StringNil())))))
+  }
+}
diff --git a/src/main/scala/leon/purescala/Constructors.scala b/src/main/scala/leon/purescala/Constructors.scala
index 67dcf315770120734684a459bad0b0d3be96120e..8597a0af22859ba0f730a0b534dd0b244a79a2c0 100644
--- a/src/main/scala/leon/purescala/Constructors.scala
+++ b/src/main/scala/leon/purescala/Constructors.scala
@@ -61,7 +61,7 @@ object Constructors {
     else bd
   }
 
-  /** $encodingof ``val (id1, id2, ...) = e; bd``, and returns `bd` if the identifiers are not bound in `bd`.
+  /** $encodingof ``val (...binders...) = value; body`` which is translated to  ``value match { case (...binders...) => body }``, and returns `body` if the identifiers are not bound in `body`.
     * @see [[purescala.Expressions.Let]]
     */
   def letTuple(binders: Seq[Identifier], value: Expr, body: Expr) = binders match {
@@ -72,7 +72,7 @@ object Constructors {
     case xs =>
       require(
         value.getType.isInstanceOf[TupleType],
-        s"The definition value in LetTuple must be of some tuple type; yet we got [${value.getType}]. In expr: \n$this"
+        s"The definition value in LetTuple must be of some tuple type; yet we got [${value.getType}]. In expr: \n$value"
       )
 
       Extractors.LetPattern(TuplePattern(None,binders map { b => WildcardPattern(Some(b)) }), value, body)
diff --git a/src/main/scala/leon/purescala/DefOps.scala b/src/main/scala/leon/purescala/DefOps.scala
index 6b7bf67e0ce10066f4719a34101fcb0d97cf17bc..db8905963760058b97611f0e2b966728cb8b2fd9 100644
--- a/src/main/scala/leon/purescala/DefOps.scala
+++ b/src/main/scala/leon/purescala/DefOps.scala
@@ -97,17 +97,17 @@ object DefOps {
   }
 
   private def stripPrefix(off: List[String], from: List[String]): List[String] = {
-    val commonPrefix = (off zip from).takeWhile(p => p._1 == p._2)
+      val commonPrefix = (off zip from).takeWhile(p => p._1 == p._2)
 
-    val res = off.drop(commonPrefix.size)
+      val res = off.drop(commonPrefix.size)
 
-    if (res.isEmpty) {
-      if (off.isEmpty) List()
-      else List(off.last)
-    } else {
-      res
+      if (res.isEmpty) {
+        if (off.isEmpty) List()
+        else List(off.last)
+      } else {
+        res
+      }
     }
-  }
   
   def simplifyPath(namesOf: List[String], from: Definition, useUniqueIds: Boolean)(implicit pgm: Program) = {
     val pathFrom = pathFromRoot(from).dropWhile(_.isInstanceOf[Program])
@@ -318,14 +318,23 @@ object DefOps {
     val transformer = new DefinitionTransformer(idMap, fdMap, cdMap) {
       override def transformExpr(expr: Expr)(implicit bindings: Map[Identifier, Identifier]): Option[Expr] = expr match {
         case fi @ FunctionInvocation(TypedFunDef(fd, tps), args) =>
-          fiMapF(fi, transform(fd))
+          val transformFd = transform(fd)
+          if(transformFd != fd)
+            fiMapF(fi, transformFd)
+          else
+            None
           //val nfi = fiMapF(fi, transform(fd)) getOrElse expr
           //Some(super.transform(nfi))
         case cc @ CaseClass(cct, args) =>
-          ciMapF(cc, transform(cct).asInstanceOf[CaseClassType])
+          val transformCct = transform(cct).asInstanceOf[CaseClassType]
+          if(transformCct != cct)
+            ciMapF(cc, transformCct)
+          else
+            None
           //val ncc = ciMapF(cc, transform(cct).asInstanceOf[CaseClassType]) getOrElse expr
           //Some(super.transform(ncc))
-        case _ => None
+        case _ =>
+          None
       }
 
       override def transformFunDef(fd: FunDef): Option[FunDef] = fdMapF(fd)
@@ -356,8 +365,9 @@ object DefOps {
                                  fiMapF: (FunctionInvocation, FunDef) => Option[Expr] = defaultFiMap)
                                  : (Program, Map[Identifier, Identifier], Map[FunDef, FunDef], Map[ClassDef, ClassDef]) = {
     replaceDefs(p)(fdMapF, cd => None, fiMapF)
-  }
+      }
 
+  /** Replaces all function calls by an expression depending on the previous function invocation and the new mapped function */
   def replaceFunCalls(e: Expr, fdMapF: FunDef => FunDef, fiMapF: (FunctionInvocation, FunDef) => Option[Expr] = defaultFiMap): Expr = {
     preMap {
       case me @ MatchExpr(scrut, cases) =>
@@ -606,9 +616,9 @@ object DefOps {
         case AsInstanceOf(e, ct) => Some(AsInstanceOf(e, tpMap(ct)))
         case MatchExpr(scrut, cases) => 
           Some(MatchExpr(scrut, cases.map{ 
-            case MatchCase(pattern, optGuard, rhs) =>
-              MatchCase(replaceClassDefUse(pattern), optGuard, rhs)
-          }))
+              case MatchCase(pattern, optGuard, rhs) =>
+                MatchCase(replaceClassDefUse(pattern), optGuard, rhs)
+            }))
         case fi @ FunctionInvocation(TypedFunDef(fd, tps), args) =>
           defaultFiMap(fi, fdMap(fd)).map(_.setPos(fi))
         case _ =>
@@ -662,7 +672,7 @@ object DefOps {
       p.definedFunctions.filter(f => f.id.name == after.id.name).map(fd => fd.id.name + " : " + fd) match {
         case Nil => 
         case e => println("Did you mean " + e)
-      }
+    }
       println(Thread.currentThread().getStackTrace.map(_.toString).take(10).mkString("\n"))
     }
 
diff --git a/src/main/scala/leon/solvers/theories/StringEncoder.scala b/src/main/scala/leon/solvers/theories/StringEncoder.scala
index 0519814409d09e717babfd17f37a3a541b88c607..02293fab327e7a79f1bb682c5fca65857a45bfd8 100644
--- a/src/main/scala/leon/solvers/theories/StringEncoder.scala
+++ b/src/main/scala/leon/solvers/theories/StringEncoder.scala
@@ -22,6 +22,12 @@ class StringEncoder(ctx: LeonContext, p: Program) extends TheoryEncoder {
   val Drop   = p.library.lookupUnique[FunDef]("leon.theories.String.drop").typed
   val Slice  = p.library.lookupUnique[FunDef]("leon.theories.String.slice").typed
   val Concat = p.library.lookupUnique[FunDef]("leon.theories.String.concat").typed
+  
+  val FromInt      = p.library.lookupUnique[FunDef]("leon.theories.String.fromInt").typed
+  val FromChar     = p.library.lookupUnique[FunDef]("leon.theories.String.fromChar").typed
+  val FromBoolean  = p.library.lookupUnique[FunDef]("leon.theories.String.fromBoolean").typed
+  val FromBigInt   = p.library.lookupUnique[FunDef]("leon.theories.String.fromBigInt").typed
+  
 
   private val stringBijection = new Bijection[String, Expr]()
   
@@ -48,6 +54,14 @@ class StringEncoder(ctx: LeonContext, p: Program) extends TheoryEncoder {
         Some(FunctionInvocation(Take, Seq(FunctionInvocation(Drop, Seq(transform(a), transform(start))), transform(length))).copiedFrom(e))
       case SubString(a, start, end)  => 
         Some(FunctionInvocation(Slice, Seq(transform(a), transform(start), transform(end))).copiedFrom(e))
+      case Int32ToString(a) => 
+        Some(FunctionInvocation(FromInt, Seq(transform(a))).copiedFrom(e))
+      case IntegerToString(a) =>
+        Some(FunctionInvocation(FromBigInt, Seq(transform(a))).copiedFrom(e))
+      case CharToString(a) =>
+        Some(FunctionInvocation(FromChar, Seq(transform(a))).copiedFrom(e))
+      case BooleanToString(a) =>
+        Some(FunctionInvocation(FromBoolean, Seq(transform(a))).copiedFrom(e))
       case _ => None
     }
 
@@ -85,6 +99,14 @@ class StringEncoder(ctx: LeonContext, p: Program) extends TheoryEncoder {
       case FunctionInvocation(Drop, Seq(a, count)) =>
         val ra = transform(a)
         Some(SubString(ra, transform(count), StringLength(ra)).copiedFrom(e))
+      case FunctionInvocation(FromInt, Seq(a)) =>
+        Some(Int32ToString(transform(a)).copiedFrom(e))
+      case FunctionInvocation(FromBigInt, Seq(a)) =>
+        Some(IntegerToString(transform(a)).copiedFrom(e))
+      case FunctionInvocation(FromChar, Seq(a)) =>
+        Some(CharToString(transform(a)).copiedFrom(e))
+      case FunctionInvocation(FromBoolean, Seq(a)) =>
+        Some(BooleanToString(transform(a)).copiedFrom(e))
       case _ => None
     }
 
diff --git a/src/main/scala/leon/synthesis/disambiguation/InputCoverage.scala b/src/main/scala/leon/synthesis/disambiguation/InputCoverage.scala
new file mode 100644
index 0000000000000000000000000000000000000000..775ed59d81c48fd97590ca6c848b76a1f3540d7e
--- /dev/null
+++ b/src/main/scala/leon/synthesis/disambiguation/InputCoverage.scala
@@ -0,0 +1,284 @@
+package leon
+package synthesis.disambiguation
+
+import synthesis.RuleClosed
+import synthesis.Solution
+import evaluators.DefaultEvaluator
+import purescala.Expressions._
+import purescala.ExprOps
+import purescala.Constructors._
+import purescala.Extractors._
+import purescala.Types.{TypeTree, TupleType, BooleanType}
+import purescala.Common.{Identifier, FreshIdentifier}
+import purescala.Definitions.{FunDef, Program, TypedFunDef, ValDef}
+import purescala.DefOps
+import grammars.ValueGrammar
+import bonsai.enumerators.MemoizedEnumerator
+import solvers.Model
+import solvers.ModelBuilder
+import scala.collection.mutable.ListBuffer
+import leon.LeonContext
+import leon.purescala.Definitions.TypedFunDef
+import leon.verification.VerificationContext
+import leon.verification.VerificationPhase
+import leon.solvers._
+import scala.concurrent.duration._
+import leon.verification.VCStatus
+import leon.verification.VCResult
+import leon.evaluators.AbstractEvaluator
+
+/**
+ * @author Mikael
+ * If possible, synthesizes a set of inputs for the function so that they cover all parts of the function.
+ * 
+ * @param fds The set of functions to cover
+ * @param fd The calling function
+ */
+class InputCoverage(fd: FunDef, fds: Set[FunDef])(implicit c: LeonContext, p: Program) {
+
+  /** If set, performs a cleaning up step to cover the whole function */
+  var minimizeExamples: Boolean = true
+  
+  /** If the sub-branches contain identifiers, it returns them unchanged.
+      Else it creates a new boolean indicating this branch. */
+  def wrapBranch(e: (Expr, Option[Seq[Identifier]])): (Expr, Some[Seq[Identifier]]) = e._2 match {
+    case None =>
+      val b = FreshIdentifier("l" + Math.abs(e._1.getPos.line) + "c" + Math.abs(e._1.getPos.col), BooleanType)
+      (tupleWrap(Seq(e._1, Variable(b))), Some(Seq(b)))
+    case Some(Seq()) =>
+      val b = FreshIdentifier("l" + Math.abs(e._1.getPos.line) + "c" + Math.abs(e._1.getPos.col), BooleanType)
+      
+      def putInLastBody(e: Expr): Expr = e match {
+        case Tuple(Seq(v, prev_b)) => Tuple(Seq(v, or(prev_b, b.toVariable))).copiedFrom(e)
+        case LetTuple(binders, value, body) => letTuple(binders, value, putInLastBody(body)).copiedFrom(e)
+        case MatchExpr(scrut, Seq(MatchCase(TuplePattern(optId, binders), None, rhs))) => 
+          MatchExpr(scrut, Seq(MatchCase(TuplePattern(optId, binders), None, putInLastBody(rhs)))).copiedFrom(e)
+        case _ => throw new Exception(s"Unexpected branching case: $e")
+        
+      }
+      (putInLastBody(e._1), Some(Seq(b)))
+    case e_2: Some[_] =>
+      // No need to introduce a new boolean since if one of the child booleans is true, then this IfExpr has been called.
+      (e._1, e_2)
+  }
+  
+  /** Returns true if there are some branching to monitor in the expression */
+  def hasConditionals(e: Expr) = {
+    ExprOps.exists{ case i:IfExpr => true case m: MatchExpr => true case f: FunctionInvocation if fds(f.tfd.fd) || f.tfd.fd == fd => true case _ => false}(e)
+  }
+  
+  /** Merges two set of identifiers.
+   *  None means that the attached expression is the original one,
+   *  Some(ids) means that it has been augmented with booleans and ids are the "monitoring" boolean flags. */
+  def merge(a: Option[Seq[Identifier]], b: Option[Seq[Identifier]]) = {
+    (a, b) match {
+      case (None, None) => None
+      case (a, None) => a
+      case (None, b) => b
+      case (Some(a), Some(b)) => Some(a ++ b)
+    }
+  }
+  
+  /** For each branch in the expression, adds a boolean variable such that the new type of the expression is (previousType, Boolean)
+   *  If no variable is output, then the type of the expression is not changed.
+    * If the expression is augmented with a boolean, returns the list of boolean variables which appear in the expression */
+  def markBranches(e: Expr): (Expr, Option[Seq[Identifier]]) =
+    if(!hasConditionals(e)) (e, None) else e match {
+    case IfExpr(cond, thenn, elze) =>
+      val (c1, cv1) = markBranches(cond)
+      val (t1, tv1) = wrapBranch(markBranches(thenn))
+      val (e1, ev1) = wrapBranch(markBranches(elze))
+      cv1 match {
+        case None =>
+          (IfExpr(c1, t1, e1).copiedFrom(e), merge(tv1, ev1))
+        case cv1 =>
+          val arg_id = FreshIdentifier("arg", BooleanType)
+          val arg_b = FreshIdentifier("bc", BooleanType)
+          (letTuple(Seq(arg_id, arg_b), c1, IfExpr(Variable(arg_id), t1, e1).copiedFrom(e)).copiedFrom(e), merge(merge(cv1, tv1), ev1))
+      }
+    case MatchExpr(scrut, cases) =>
+      val (c1, cv1) = markBranches(scrut)
+      val (new_cases, variables) = (cases map { case m@MatchCase(pattern, opt, rhs) =>
+        val (rhs_new, ids) = wrapBranch(markBranches(rhs))
+        (MatchCase(pattern, opt, rhs_new).copiedFrom(m), ids)
+      }).unzip // TODO: Check for unapply with function pattern ?
+      (MatchExpr(c1, new_cases).copiedFrom(e), variables.fold(None)(merge))
+    case Operator(lhsrhs, builder) =>
+      // The exprBuilder adds variable definitions needed to compute the arguments.
+      val (exprBuilder, children, tmpIds, ids) = (((e: Expr) => e, ListBuffer[Expr](), ListBuffer[Identifier](), None: Option[Seq[Identifier]]) /: lhsrhs) {
+        case ((exprBuilder, children, tmpIds, ids), arg) =>
+          val (arg1, argv1) = markBranches(arg)
+          if(argv1.nonEmpty || isNewFunCall(arg1)) {
+            val arg_id = FreshIdentifier("arg", arg.getType)
+            val arg_b = FreshIdentifier("ba", BooleanType)
+            val f = (body: Expr) => letTuple(Seq(arg_id, arg_b), arg1, body).copiedFrom(body)
+            (exprBuilder andThen f, children += Variable(arg_id), tmpIds += arg_b, merge(ids, argv1))
+          } else {
+            (exprBuilder, children += arg, tmpIds, ids)
+          }
+      }
+      e match {
+        case FunctionInvocation(tfd@TypedFunDef(fd, targs), args) if fds(fd) =>
+          val new_fd = wrapFunDef(fd)
+          // Is different since functions will return a boolean as well.
+          tmpIds match {
+            case Seq() =>
+              val funCall = FunctionInvocation(TypedFunDef(new_fd, targs).copiedFrom(tfd), children).copiedFrom(e)
+              (exprBuilder(funCall), if(new_fd != fd) merge(Some(Seq()), ids) else ids)
+            case idvars =>
+              val res_id = FreshIdentifier("res", fd.returnType)
+              val res_b = FreshIdentifier("bb", BooleanType)
+              val finalIds = idvars :+ res_b
+              val finalExpr = 
+                tupleWrap(Seq(Variable(res_id), or(finalIds.map(Variable(_)): _*))).copiedFrom(e)
+              val funCall = letTuple(Seq(res_id, res_b), FunctionInvocation(TypedFunDef(new_fd, targs), children).copiedFrom(e), finalExpr).copiedFrom(e)
+              (exprBuilder(funCall), merge(Some(Seq()), ids))
+          }
+        case _ =>
+          tmpIds match {
+            case Seq() =>
+              (e, ids)
+            case idvars =>
+              val finalExpr = tupleWrap(Seq(builder(children).copiedFrom(e), or(idvars.map(Variable): _*))).copiedFrom(e)
+              (exprBuilder(finalExpr), ids)
+          }
+      }
+  }
+  
+  /** The cache of transforming functions.*/
+  private var cache = Map[FunDef, FunDef]()
+  
+  /** Records all booleans serving to identify which part of the code should be executed.*/
+  private var booleanFlags = Seq[Identifier]()
+  
+  /** Augment function definitions which should have boolean markers, leave others untouched. */
+  def wrapFunDef(fd: FunDef): FunDef = {
+    if(!(cache contains fd)) {
+      if(fds(fd)) {
+        val new_fd = fd.duplicate(returnType = TupleType(Seq(fd.returnType, BooleanType)))
+        new_fd.body = None
+        cache += fd -> new_fd
+        val (new_body, bvars) = wrapBranch(markBranches(fd.body.get)) // Recursive call.
+        new_fd.body = Some(new_body) // TODO: Handle post-condition if they exist.
+        booleanFlags ++= bvars.get
+      } else {
+        cache += fd -> fd
+      }
+    }
+    cache(fd)
+  }
+  
+  /** Returns true if the expression is a function call with a new function already. */
+  def isNewFunCall(e: Expr): Boolean = e match {
+    case FunctionInvocation(TypedFunDef(fd, targs), args) =>
+      cache.values.exists { f => f == fd }
+    case _ => false
+  }
+  
+  /** Returns a stream of covering inputs for the function `f`,
+   *  such that if `f` is evaluated on each of these inputs, all parts of `{ f } U fds` will have been executed at least once.
+   *  
+   *  The number of expressions is the same as the number of arguments of `f` */
+  def result(): Stream[Seq[Expr]] = {
+    cache = Map()
+    booleanFlags = Seq()
+    /* Approximative algorithm Algorithm:
+     * In innermost branches, replace each result by (result, bi) where bi is a boolean described later.
+     * def f(x: Int, z: Boolean): (Int, Boolean) =
+     *   x match {
+     *     case 0 | 1 =>
+     *       if(z) {
+     *         ({val (r, b1) = if(z) (x, bt) else (-x, be)
+     *         val (res, b) = f(r, z)
+     *         (res, b || b1)
+     *     case _ =>
+     *       val (res, b) = if(z) (x, b2)
+     *       else (f(x-1,!z)+f(x-2,!z), b3)
+     *       (res*f(x-1,!z), b)
+     *   } 
+     * Let B be the set of bi.
+     *    For each b in B
+     *      Set all b' in B to false except b to true
+     *      Find a counter-example.
+     *      yield  it in the stream.
+     */
+    
+    /* Change all return types to accommodate the new covering boolean */
+    
+    val (program, idMap, fdMap, cdMap) = DefOps.replaceFunDefs(p)({
+      (f: FunDef) =>
+        if((fds contains   f) || f == fd) {
+          val new_fd = wrapFunDef(f)
+          if(f == fd) {
+            val h = FreshIdentifier("h", TupleType(Seq(fd.returnType, BooleanType)), false)
+            new_fd.postcondition = Some(Lambda(Seq(ValDef(h)), Not(TupleSelect(Variable(h), 2))))
+          }
+          Some(new_fd)
+        } else
+          None
+    }, {
+      (fi: FunctionInvocation, newFd: FunDef) => //if(cache contains fi.tfd.fd) {
+        Some(TupleSelect(FunctionInvocation(newFd.typed, fi.args), 1))
+      //} else None
+    })
+    
+    val start_fd = fdMap.getOrElse(fd, fd)
+    
+    var coveredBooleans = Set[Identifier]()
+    // For each boolean flag, set it to true, and find a counter-example which should reach this line.
+    // For each new counter-example, abstract evaluate the original function to remove booleans which have been reached.
+    val covering_examples =
+      for(bvar <- booleanFlags.toStream if !coveredBooleans(bvar)) yield {
+      val (program2, idMap2, fdMap2, cdMap2) = DefOps.replaceFunDefs(program)({
+        (f: FunDef) =>
+          if(ExprOps.exists(e => e match { case Variable(id) => booleanFlags contains id case _ => false })(f.fullBody)) {
+            val new_f = f.duplicate()
+            new_f.fullBody = ExprOps.preMap(e => {
+              e match {
+                case Variable(id) if id == bvar => Some(BooleanLiteral(true))
+                case Variable(id) if booleanFlags contains id => Some(BooleanLiteral(false))
+                case _ => None
+              }
+            })(f.fullBody)
+            Some(new_f)
+          } else None
+      })
+      val start_fd2 = fdMap2.getOrElse(start_fd, start_fd)
+      val tfactory = SolverFactory.getFromSettings(c, program2).withTimeout(5.seconds)
+      
+      val vctx = new VerificationContext(c, program2, tfactory)
+      val vcs = VerificationPhase.generateVCs(vctx, Seq(start_fd2))
+      VerificationPhase.checkVCs(vctx, vcs).results(vcs(0)) match {
+        case Some(VCResult(VCStatus.Invalid(model), _, _)) => 
+          val finalExprs = fd.paramIds.map(model)
+          val whoIsEvaluated = functionInvocation(start_fd, finalExprs)
+          val ae = new AbstractEvaluator(c, p)
+          val coveredBooleansForCE = ae.eval(whoIsEvaluated).result match {
+            case Some((Tuple(Seq(_, booleans)), _)) =>
+              val targettedIds = ExprOps.collect(e => e match { case Variable(id) => Set(id) case _ => Set[Identifier]() })(booleans)
+              coveredBooleans ++= targettedIds
+              targettedIds
+            case _ =>
+              Set(bvar)
+          }
+          finalExprs -> coveredBooleansForCE
+        case _ => Seq() -> Set(bvar)
+      }
+    }
+    
+    val covering_examples2 = if(minimizeExamples) {
+      // Remove examples whose coverage set is included in some other example.
+      for((covering_example, flags_met) <- covering_examples
+          if !covering_examples.exists{
+            case (other_example, other_flags) =>
+              other_example != covering_example &&
+              flags_met.subsetOf(other_flags)
+          }
+      ) yield covering_example
+    } else {
+      covering_examples.map(_._1)
+    }
+    
+    covering_examples2 filter (_.nonEmpty)
+  }
+}
\ No newline at end of file
diff --git a/src/test/scala/leon/integration/solvers/InputCoverageSuite.scala b/src/test/scala/leon/integration/solvers/InputCoverageSuite.scala
new file mode 100644
index 0000000000000000000000000000000000000000..c1c29acbbe91243f68315a94e6ba60cedc11b3a2
--- /dev/null
+++ b/src/test/scala/leon/integration/solvers/InputCoverageSuite.scala
@@ -0,0 +1,318 @@
+package leon.integration.solvers
+
+import org.scalatest.FunSuite
+import org.scalatest.Matchers
+import leon.test.helpers.ExpressionsDSL
+import leon.solvers.string.StringSolver
+import leon.purescala.Common.FreshIdentifier
+import leon.purescala.Common.Identifier
+import leon.purescala.Expressions._
+import leon.purescala.Definitions._
+import leon.purescala.DefOps
+import leon.purescala.ExprOps
+import leon.purescala.Types._
+import leon.purescala.TypeOps
+import leon.purescala.Constructors._
+import leon.synthesis.rules.{StringRender, TypedTemplateGenerator}
+import scala.collection.mutable.{HashMap => MMap}
+import scala.concurrent.Future
+import scala.concurrent.ExecutionContext.Implicits.global
+import org.scalatest.concurrent.Timeouts
+import org.scalatest.concurrent.ScalaFutures
+import org.scalatest.time.SpanSugar._
+import org.scalatest.FunSuite
+import org.scalatest.concurrent.Timeouts
+import org.scalatest.concurrent.ScalaFutures
+import org.scalatest.time.SpanSugar._
+import leon.purescala.Types.Int32Type
+import leon.test.LeonTestSuiteWithProgram
+import leon.synthesis.SourceInfo
+import leon.synthesis.CostModels
+import leon.synthesis.graph.AndNode
+import leon.synthesis.SearchContext
+import leon.synthesis.Synthesizer
+import leon.synthesis.SynthesisSettings
+import leon.synthesis.RuleApplication
+import leon.synthesis.RuleClosed
+import leon.evaluators._
+import leon.LeonContext
+import leon.synthesis.rules.DetupleInput
+import leon.synthesis.Rules
+import leon.solvers.ModelBuilder
+import scala.language.implicitConversions
+import leon.LeonContext
+import leon.test.LeonTestSuiteWithProgram
+import leon.test.helpers.ExpressionsDSL
+import leon.synthesis.disambiguation.InputCoverage
+import leon.test.helpers.ExpressionsDSLProgram
+import leon.test.helpers.ExpressionsDSLVariables
+import leon.purescala.Extractors._
+
+class InputCoverageSuite extends LeonTestSuiteWithProgram with Matchers with ScalaFutures with ExpressionsDSLProgram with ExpressionsDSLVariables {
+  val sources = List("""
+    |import leon.lang._
+    |import leon.collection._
+    |import leon.lang.synthesis._
+    |import leon.annotation._
+    |
+    |object InputCoverageSuite {
+    |  def dummy = 2
+    |  def withIf(cond: Boolean) = {
+    |    if(cond) {
+    |      1
+    |    } else {
+    |      2
+    |    }
+    |  }
+    |  
+    |  def withIfInIf(cond: Boolean) = {
+    |    if(if(cond) false else true) {
+    |      1
+    |    } else {
+    |      2
+    |    }
+    |  }
+    |  
+    |  sealed abstract class A
+    |  case class B() extends A
+    |  case class C(a: String, tail: A) extends A
+    |  case class D(a: String, tail: A, b: String) extends A
+    |  
+    |  def withMatch(a: A): String = {
+    |    a match {
+    |      case B() => "B"
+    |      case C(a, C(b, tail)) => b.toString + withMatch(tail) + a.toString
+    |      case C(a, tail) => withMatch(tail) + a.toString
+    |      case D(a, tail, b) => a + withMatch(tail) + b
+    |    }
+    |  }
+    |  
+    |  def withCoveredFun1(input: Int) = {
+    |    withCoveredFun2(input - 5) + withCoveredFun2(input + 5)
+    |  }
+    |  
+    |  def withCoveredFun2(input: Int) = {
+    |    if(input > 0) {
+    |      2
+    |    } else {
+    |      0
+    |    }
+    |  }
+    |  
+    |  def withCoveredFun3(input: Int) = {
+    |    withCoveredFun2(withCoveredFun2(input + 5))
+    |  }
+    |}""".stripMargin)
+    
+  test("wrapBranch should wrap expressions if they are not already containing wrapped calls"){ ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val dummy = funDef("InputCoverageSuite.dummy")
+    val coverage = new InputCoverage(dummy, Set(dummy))
+    val simpleExpr = Plus(IntLiteral(1), b)
+    coverage.wrapBranch((simpleExpr, Some(Seq(p.id, q.id)))) should equal ((simpleExpr, Some(Seq(p.id, q.id))))
+    coverage.wrapBranch((simpleExpr, None)) match {
+      case (covered, Some(ids)) =>
+        ids should have size 1
+        covered should equal (Tuple(Seq(simpleExpr, Variable(ids.head))))
+      case _ =>
+        fail("No ids added")
+    }
+  }
+  
+  test("If-coverage should work"){ ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val withIf = funDef("InputCoverageSuite.withIf")
+    val coverage = new InputCoverage(withIf, Set(withIf))
+    val expr = withIf.body.get
+    
+    coverage.markBranches(expr) match {
+      case (res, Some(ids)) =>
+        ids should have size 2
+        expr match {
+          case IfExpr(cond, thenn, elze) =>
+            res should equal (IfExpr(cond, Tuple(Seq(thenn, Variable(ids(0)))), Tuple(Seq(elze, Variable(ids(1))))))
+          case _ => fail(s"$expr is not an IfExpr")
+        }
+      case _ =>
+        fail("No ids added")
+    }
+  }
+  
+  test("If-cond-coverage should work"){ ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val withIfInIf = funDef("InputCoverageSuite.withIfInIf")
+    val coverage = new InputCoverage(withIfInIf, Set(withIfInIf))
+    val expr = withIfInIf.body.get
+    
+    coverage.markBranches(expr) match {
+      case (res, None) => fail("No ids added")
+      case (res, Some(ids)) =>
+        ids should have size 4
+        expr match {
+          case IfExpr(IfExpr(cond, t1, e1), t2, e2) =>
+            res match {
+              case MatchExpr(IfExpr(c, t1, e1), Seq(MatchCase(TuplePattern(None, s), None, IfExpr(c2, t2, e2)))) if s.size == 2 =>
+              case _ => fail("should have a shape like (if() else ) match { case (a, b) => if(...) else }")
+            }
+          case _ => fail(s"$expr is not an IfExpr")
+        }
+    }
+  }
+  
+  test("Match coverage should work with recursive functions") { ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val withMatch = funDef("InputCoverageSuite.withMatch")
+    val coverage = new InputCoverage(withMatch, Set(withMatch))
+    val expr = withMatch.body.get
+    
+    coverage.markBranches(expr) match {
+      case (res, None) => fail("No ids added")
+      case (res, Some(ids)) =>
+        withClue(res.toString) {
+          ids should have size 4
+          res match {
+            case MatchExpr(scrut,
+                   Seq(
+                       MatchCase(CaseClassPattern(_, _, Seq()), None, rhs1),
+                       MatchCase(CaseClassPattern(_, _, _), None, rhs2),
+                       MatchCase(CaseClassPattern(_, _, _), None, rhs3),
+                       MatchCase(CaseClassPattern(_, _, _), None, rhs4))
+            ) =>
+              rhs1 match {
+                case Tuple(Seq(_, Variable(b))) => b shouldEqual ids(0)
+                case _ => fail(s"$rhs1 should be a Tuple")
+              }
+              rhs2 match {
+                case LetTuple(_, _, Tuple(Seq(_, Or(Seq(_, Variable(b)))))) => b shouldEqual ids(1)
+                case _ => fail(s"$rhs2 should be a val + tuple like val ... = ... ; (..., ... || ${ids(1)})")
+              }
+              
+            case _ => fail(s"$res does not have the format a match { case B() => .... x 4 }")
+          }
+        }
+    }
+  }
+  
+  test("fundef combination-coverage should work"){ ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val withCoveredFun1 = funDef("InputCoverageSuite.withCoveredFun1")
+    val withCoveredFun2 = funDef("InputCoverageSuite.withCoveredFun2")
+    val coverage = new InputCoverage(withCoveredFun1, Set(withCoveredFun1, withCoveredFun2))
+    val expr = withCoveredFun1.body.get
+    
+    coverage.markBranches(expr) match {
+      case (res, Some(ids)) if ids.size > 0 =>
+        withClue(res.toString) {
+          fail(s"Should have not added any ids, but got $ids")
+        }
+      case (res, _) =>
+        res match {
+          case MatchExpr(funCall, Seq(
+                MatchCase(TuplePattern(None, Seq(WildcardPattern(Some(a1)), WildcardPattern(Some(b1)))), None,
+                  MatchExpr(funCall2, Seq(
+                    MatchCase(TuplePattern(None, Seq(WildcardPattern(Some(a2)), WildcardPattern(Some(b2)))), None,
+                      Tuple(Seq(BVPlus(Variable(ida1), Variable(ida2)), Or(Seq(Variable(idb1), Variable(idb2)))))
+                )
+              ))))) =>
+            withClue(res.toString) {
+              ida1.uniqueName shouldEqual a2.uniqueName
+              ida2.uniqueName shouldEqual a1.uniqueName
+              Set(idb1.uniqueName, idb2.uniqueName) shouldEqual Set(b1.uniqueName, b2.uniqueName)
+            }
+          case _ =>
+            fail(s"$res is not of type funCall() match { case (a1, b1) => funCall() match { case (a2, b2) => (a1 + a2, b1 || b2) } }")
+        }
+    }
+  }
+  
+  test("fundef composition-coverage should work"){ ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val withCoveredFun2 = funDef("InputCoverageSuite.withCoveredFun2")
+    val withCoveredFun3 = funDef("InputCoverageSuite.withCoveredFun3")
+    val coverage = new InputCoverage(withCoveredFun3, Set(withCoveredFun3, withCoveredFun2))
+    val expr = withCoveredFun3.body.get
+    
+    coverage.markBranches(expr) match {
+      case (res, None) => fail("No ids added")
+      case (res, Some(ids)) =>
+        res match {
+          case MatchExpr(funCall, Seq(
+                MatchCase(TuplePattern(None, Seq(WildcardPattern(Some(a)), WildcardPattern(Some(b1)))), None,
+                  MatchExpr(FunctionInvocation(_, Seq(Variable(ida))), Seq(
+                    MatchCase(TuplePattern(None, Seq(WildcardPattern(_), WildcardPattern(Some(b2)))), None,
+                      Tuple(Seq(p, Or(Seq(Variable(id1), Variable(id2)))))
+                )
+              ))))) if ida == a && id1 == b1 && id2 == b2 =>
+          case _ =>
+            fail(s"$res is not of type funCall() match { case (a, b1) => funCall(a) match { case (c, b2) => (c, b1 || b2) } }")
+        }
+    }
+  }
+  
+  test("input coverage for booleans should find all of them") { ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val withIf = funDef("InputCoverageSuite.withIf")
+    val coverage = new InputCoverage(withIf, Set(withIf))
+    coverage.result().toSet should equal (Set(Seq(b(true)), Seq(b(false))))
+  }
+  
+  test("input coverage for ADT should find all of them") { ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val withMatch = funDef("InputCoverageSuite.withMatch")
+    val coverage = new InputCoverage(withMatch, Set(withMatch))
+    coverage.minimizeExamples = false
+    val res = coverage.result().toSet
+    res should have size 4
+    
+    coverage.minimizeExamples = true
+    val res2 = coverage.result().toSet
+    res2 should have size 3
+  }
+  
+  test("input coverage for combined functions should find all of them") { ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val withCoveredFun1 = funDef("InputCoverageSuite.withCoveredFun1")
+    val withCoveredFun2 = funDef("InputCoverageSuite.withCoveredFun2")
+    val coverage = new InputCoverage(withCoveredFun1, Set(withCoveredFun1, withCoveredFun2))
+    val res = coverage.result().toSet.toSeq
+    if(res.size == 1) {
+      val Seq(IntLiteral(a)) = res(0)
+      withClue(s"a=$a") {
+        assert(a + 5 > 0 || a - 5 > 0, "At least one of the two examples should cover the positive case")
+        assert(a + 5 <= 0 || a - 5 <= 0, "At least one of the two examples should cover the negative case")
+      }
+    } else {
+      res should have size 2
+      val Seq(IntLiteral(a)) = res(0)
+      val Seq(IntLiteral(b)) = res(1)
+      withClue(s"a=$a, b=$b") {
+        assert(a + 5 > 0 || b + 5 > 0 || a - 5 > 0 || b - 5 > 0 , "At least one of the two examples should cover the positive case")
+        assert(a + 5 <= 0 || b + 5 <= 0 || a - 5 <= 0 || b - 5 <= 0 , "At least one of the two examples should cover the negative case")
+      }
+    }
+  }
+  
+  test("input coverage for composed functions should find all of them") { ctxprogram =>
+    implicit val (c, p) = ctxprogram
+    val withCoveredFun3 = funDef("InputCoverageSuite.withCoveredFun3")
+    val withCoveredFun2 = funDef("InputCoverageSuite.withCoveredFun2")
+    val coverage = new InputCoverage(withCoveredFun3, Set(withCoveredFun3, withCoveredFun2))
+    val res = coverage.result().toSet.toSeq
+    def withCoveredFun2Impl(i: Int) = if(i > 0) 2 else 0
+    if(res.size == 1) {
+      val Seq(IntLiteral(a)) = res(0)
+      withClue(s"a=$a") {
+        assert(a + 5 > 0 || withCoveredFun2Impl(a + 5) > 0, "At least one of the two examples should cover the positive case")
+        assert(a + 5 <= 0 || withCoveredFun2Impl(a + 5) <= 0, "At least one of the two examples should cover the negative case")
+      }
+    } else {
+      res should have size 2
+      val Seq(IntLiteral(a)) = res(0)
+      val Seq(IntLiteral(b)) = res(1)
+      withClue(s"a=$a, b=$b") {
+        assert(a + 5 > 0 || withCoveredFun2Impl(a + 5) > 0 || b + 5 > 0 || withCoveredFun2Impl(b + 5) > 0, "At least one of the two examples should cover the positive case")
+        assert(a + 5 <= 0 || withCoveredFun2Impl(a + 5) <= 0 || b + 5 <= 0 || withCoveredFun2Impl(b + 5) <= 0, "At least one of the two examples should cover the negative case")
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/test/scala/leon/test/helpers/ExpressionsDSL.scala b/src/test/scala/leon/test/helpers/ExpressionsDSL.scala
index 63469ead59c6c4441ce12a92fc92c4349ae99d5b..91b77284cc16518a4b86e0bdcb5ad7e98230061f 100644
--- a/src/test/scala/leon/test/helpers/ExpressionsDSL.scala
+++ b/src/test/scala/leon/test/helpers/ExpressionsDSL.scala
@@ -9,6 +9,10 @@ import leon.purescala.Common._
 import leon.purescala.Types._
 import leon.purescala.Expressions._
 
+trait ExpressionsDSLVariables_a {
+  val a = FreshIdentifier("a", Int32Type).toVariable
+}
+
 trait ExpressionsDSLVariables {
   val F = BooleanLiteral(false)
   val T = BooleanLiteral(true)
@@ -18,7 +22,6 @@ trait ExpressionsDSLVariables {
   def i(x: Int)     = IntLiteral(x)
   def r(n: BigInt, d: BigInt)  = FractionalLiteral(n, d)
 
-  val a = FreshIdentifier("a", Int32Type).toVariable
   val b = FreshIdentifier("b", Int32Type).toVariable
   val c = FreshIdentifier("c", Int32Type).toVariable
 
@@ -97,7 +100,7 @@ self: Assertions =>
   }
 }
 
-trait ExpressionsDSL extends ExpressionsDSLVariables with ExpressionsDSLProgram {
+trait ExpressionsDSL extends ExpressionsDSLVariables with ExpressionsDSLProgram with ExpressionsDSLVariables_a {
   self: Assertions =>
   
 }