diff --git a/build.sbt b/build.sbt
index ccace259172b0feb5b2c551c625e2ee8fbb8b44f..111613dd1cc2dbcc2c069b031b1866b302b8cd98 100644
--- a/build.sbt
+++ b/build.sbt
@@ -170,7 +170,7 @@ parallelExecution in GenCTest := false
 def ghProject(repo: String, version: String) = RootProject(uri(s"${repo}#${version}"))
 
 lazy val bonsai      = ghProject("git://github.com/colder/bonsai.git",     "10eaaee4ea0ff6567f4f866922cb871bae2da0ac")
-lazy val scalaSmtlib = ghProject("git://github.com/regb/scala-smtlib.git", "f3c5c174ff30c18e171f919ccc300d590e7762a0")
+lazy val scalaSmtlib = ghProject("git://github.com/regb/scala-smtlib.git", "57834acfe2e3bc36862be52e4d99829bb8ff0ca7")
 
 lazy val root = (project in file(".")).
   configs(RegressionTest, IsabelleTest, GenCTest, IntegrTest).
diff --git a/library/lang/Bag.scala b/library/lang/Bag.scala
new file mode 100644
index 0000000000000000000000000000000000000000..2825bd1fa4d5ca5136adb9dd0afc391b10ca5cbb
--- /dev/null
+++ b/library/lang/Bag.scala
@@ -0,0 +1,37 @@
+/* Copyright 2009-2016 EPFL, Lausanne */
+
+package leon.lang
+import leon.annotation._
+
+object Bag {
+  @library
+  def empty[T] = Bag[T]()
+
+  @ignore
+  def apply[T](elems: (T, BigInt)*) = {
+    new Bag[T](scala.collection.immutable.Map[T, BigInt](elems : _*))
+  }
+}
+
+@ignore
+case class Bag[T](theBag: scala.collection.immutable.Map[T, BigInt]) {
+  def +(a: T): Bag[T] = new Bag(theBag + (a -> (theBag.getOrElse(a, BigInt(0)) + 1)))
+  def ++(that: Bag[T]): Bag[T] = new Bag[T]((theBag.keys ++ that.theBag.keys).toSet.map { (k: T) =>
+    k -> (theBag.getOrElse(k, BigInt(0)) + that.theBag.getOrElse(k, BigInt(0)))
+  }.toMap)
+
+  def --(that: Bag[T]): Bag[T] = new Bag[T](theBag.flatMap { case (k,v) =>
+    val res = v - that.get(k)
+    if (res <= 0) Nil else List(k -> res)
+  })
+
+  def &(that: Bag[T]): Bag[T] = new Bag[T](theBag.flatMap { case (k,v) =>
+    val res = v min that.get(k)
+    if (res <= 0) Nil else List(k -> res)
+  })
+
+  def get(a: T): BigInt = theBag.getOrElse(a, BigInt(0))
+  def apply(a: T): BigInt = get(a)
+  def isEmpty: Boolean = theBag.isEmpty
+}
+
diff --git a/library/lang/Set.scala b/library/lang/Set.scala
index d27fd18bbab181e148c1246dd104f322a69e7c4a..351af3f6abb256229cfe27d3a13ce7ad9c191e17 100644
--- a/library/lang/Set.scala
+++ b/library/lang/Set.scala
@@ -4,25 +4,25 @@ package leon.lang
 import leon.annotation._
 
 object Set {
-   @library
-   def empty[T] = Set[T]()
+  @library
+  def empty[T] = Set[T]()
 
-   @ignore
-   def apply[T](elems: T*) = {
-     new Set[T](scala.collection.immutable.Set[T](elems : _*))
-   }
+  @ignore
+  def apply[T](elems: T*) = {
+    new Set[T](scala.collection.immutable.Set[T](elems : _*))
+  }
 }
 
 @ignore
 case class Set[T](val theSet: scala.collection.immutable.Set[T]) {
-   def +(a: T): Set[T] = new Set[T](theSet + a)
-   def ++(a: Set[T]): Set[T] = new Set[T](theSet ++ a.theSet)
-   def -(a: T): Set[T] = new Set[T](theSet - a)
-   def --(a: Set[T]): Set[T] = new Set[T](theSet -- a.theSet)
-   def size: BigInt = theSet.size
-   def contains(a: T): Boolean = theSet.contains(a)
-   def isEmpty: Boolean = theSet.isEmpty
-   def subsetOf(b: Set[T]): Boolean = theSet.subsetOf(b.theSet)
-   def &(a: Set[T]): Set[T] = new Set[T](theSet & a.theSet)
+  def +(a: T): Set[T] = new Set[T](theSet + a)
+  def ++(a: Set[T]): Set[T] = new Set[T](theSet ++ a.theSet)
+  def -(a: T): Set[T] = new Set[T](theSet - a)
+  def --(a: Set[T]): Set[T] = new Set[T](theSet -- a.theSet)
+  def size: BigInt = theSet.size
+  def contains(a: T): Boolean = theSet.contains(a)
+  def isEmpty: Boolean = theSet.isEmpty
+  def subsetOf(b: Set[T]): Boolean = theSet.subsetOf(b.theSet)
+  def &(a: Set[T]): Set[T] = new Set[T](theSet & a.theSet)
 }
 
diff --git a/library/theories/Bag.scala b/library/theories/Bag.scala
new file mode 100644
index 0000000000000000000000000000000000000000..53089dcd200b379277feae1c18d7bc98bfbeb581
--- /dev/null
+++ b/library/theories/Bag.scala
@@ -0,0 +1,24 @@
+/* Copyright 2009-2016 EPFL, Lausanne */
+
+package leon.theories
+import leon.lang.forall
+import leon.annotation._
+
+@library
+sealed case class Bag[T](f: T => BigInt) {
+  def get(x: T): BigInt = f(x)
+  def add(elem: T): Bag[T] = Bag((x: T) => f(x) + (if (x == elem) 1 else 0))
+  def union(that: Bag[T]): Bag[T] = Bag((x: T) => f(x) + that.f(x))
+  def difference(that: Bag[T]): Bag[T] = Bag((x: T) => {
+    val res = f(x) - that.f(x)
+    if (res < 0) 0 else res
+  })
+
+  def intersect(that: Bag[T]): Bag[T] = Bag((x: T) => {
+    val r1 = f(x)
+    val r2 = that.f(x)
+    if (r1 > r2) r2 else r1
+  })
+
+  def equals(that: Bag[T]): Boolean = forall((x: T) => f(x) == that.f(x))
+}
diff --git a/library/theories/String.scala b/library/theories/String.scala
new file mode 100644
index 0000000000000000000000000000000000000000..85e4d90c7e1eca5a72a2d7c74aa0c63437d6c872
--- /dev/null
+++ b/library/theories/String.scala
@@ -0,0 +1,32 @@
+/* Copyright 2009-2016 EPFL, Lausanne */
+
+package leon.theories
+import leon.annotation._
+
+@library
+sealed abstract class String {
+  def size: BigInt = (this match {
+    case StringCons(_, tail) => 1 + tail.size
+    case StringNil() => BigInt(0)
+  }) ensuring (_ >= 0)
+
+  def concat(that: String): String = this match {
+    case StringCons(head, tail) => StringCons(head, tail concat that)
+    case StringNil() => that
+  }
+
+  def take(i: BigInt): String = this match {
+    case StringCons(head, tail) if i > 0 => StringCons(head, tail take (i - 1))
+    case _ => StringNil()
+  }
+
+  def drop(i: BigInt): String = this match {
+    case StringCons(head, tail) if i > 0 => tail drop (i - 1)
+    case _ => this
+  }
+
+  def slice(from: BigInt, to: BigInt): String = drop(from).take(to - from)
+}
+
+case class StringCons(head: Char, tail: String) extends String
+case class StringNil() extends String
diff --git a/src/main/java/leon/codegen/runtime/Bag.java b/src/main/java/leon/codegen/runtime/Bag.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7404f522b8170523ff70e2a8e94059d05c1317b
--- /dev/null
+++ b/src/main/java/leon/codegen/runtime/Bag.java
@@ -0,0 +1,117 @@
+/* Copyright 2009-2016 EPFL, Lausanne */
+
+package leon.codegen.runtime;
+
+import java.util.Iterator;
+import java.util.HashMap;
+
+/** If someone wants to make it an efficient implementation of immutable
+ *  sets, go ahead. */
+public final class Bag {
+  private final HashMap<Object, BigInt> _underlying;
+
+  protected final HashMap<Object, BigInt> underlying() {
+    return _underlying;
+  }
+
+  public Bag() {
+    _underlying = new HashMap<Object, BigInt>();
+  }
+
+  private Bag(HashMap<Object, BigInt> u) {
+    _underlying = u;
+  }
+
+  // Uses mutation! Useful at building time.
+  public void add(Object e) {
+    add(e, BigInt.ONE);
+  }
+
+  // Uses mutation! Useful at building time.
+  public void add(Object e, BigInt count) {
+    _underlying.put(e, get(e).add(count));
+  }
+
+  public Iterator<java.util.Map.Entry<Object, BigInt>> getElements() {
+    return _underlying.entrySet().iterator();
+  }
+
+  public BigInt get(Object element) {
+    BigInt r = _underlying.get(element);
+    if (r == null) return BigInt.ZERO;
+    else return r;
+  }
+
+  public Bag plus(Object e) {
+    Bag n = new Bag(new HashMap<Object, BigInt>(_underlying));
+    n.add(e);
+    return n;
+  }
+
+  public Bag union(Bag b) {
+    Bag n = new Bag(new HashMap<Object, BigInt>(_underlying));
+    for (java.util.Map.Entry<Object, BigInt> entry : b.underlying().entrySet()) {
+      n.add(entry.getKey(), entry.getValue());
+    }
+    return n;
+  }
+
+  public Bag intersect(Bag b) {
+    Bag n = new Bag();
+    for (java.util.Map.Entry<Object, BigInt> entry : _underlying.entrySet()) {
+      BigInt b1 = entry.getValue(), b2 = b.get(entry.getKey());
+      BigInt m = b1.lessThan(b2) ? b1 : b2;
+      if (m.greaterThan(BigInt.ZERO)) n.add(entry.getKey(), m);
+    }
+    return n;
+  }
+
+  public Bag difference(Bag b) {
+    Bag n = new Bag();
+    for (java.util.Map.Entry<Object, BigInt> entry : _underlying.entrySet()) {
+      BigInt m = entry.getValue().sub(b.get(entry.getKey()));
+      if (m.greaterThan(BigInt.ZERO)) n.add(entry.getKey(), m);
+    }
+    return n;
+  }
+
+  @Override
+  public boolean equals(Object that) {
+    if(that == this) return true;
+    if(!(that instanceof Bag)) return false;
+
+    Bag other = (Bag) that;
+    for (Object key : _underlying.keySet()) {
+      if (!get(key).equals(other.get(key))) return false;
+    }
+
+    for (Object key : other.underlying().keySet()) {
+      if (!get(key).equals(other.get(key))) return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("Bag(");
+    boolean first = true;
+    for (java.util.Map.Entry<Object, BigInt> entry : _underlying.entrySet()) {
+      if(!first) {
+        sb.append(", ");
+        first = false;
+      }
+      sb.append(entry.getKey().toString());
+      sb.append(" -> ");
+      sb.append(entry.getValue().toString());
+    }
+    sb.append(")");
+    return sb.toString();
+  }
+
+  @Override
+  public int hashCode() {
+    return _underlying.hashCode();
+  }
+}
diff --git a/src/main/java/leon/codegen/runtime/BigInt.java b/src/main/java/leon/codegen/runtime/BigInt.java
index c4e3412b3539d56b21880734a8c63b36d06a38db..338419c11b75c058576d6630071f19e282086e8c 100644
--- a/src/main/java/leon/codegen/runtime/BigInt.java
+++ b/src/main/java/leon/codegen/runtime/BigInt.java
@@ -5,6 +5,8 @@ package leon.codegen.runtime;
 import java.math.BigInteger;
 
 public final class BigInt {
+  public static final BigInt ZERO = new BigInt(BigInteger.ZERO);
+  public static final BigInt ONE  = new BigInt(BigInteger.ONE);
 
   private final BigInteger _underlying;
 
diff --git a/src/main/java/leon/codegen/runtime/Set.java b/src/main/java/leon/codegen/runtime/Set.java
index 42cadce43616eeafaaf7133d3ac7b55d229c56fb..c361ba9e662a5b84bbd84391c856ab9853d66860 100644
--- a/src/main/java/leon/codegen/runtime/Set.java
+++ b/src/main/java/leon/codegen/runtime/Set.java
@@ -23,6 +23,10 @@ public final class Set {
     _underlying = new HashSet<Object>(Arrays.asList(elements));
   }
 
+  private Set(HashSet<Object> u) {
+    _underlying = u;
+  }
+
   // Uses mutation! Useful at building time.
   public void add(Object e) {
     _underlying.add(e);
@@ -32,14 +36,16 @@ public final class Set {
     return _underlying.iterator();
   }
 
-  private Set(HashSet<Object> u) {
-    _underlying = u;
-  }
-
   public boolean contains(Object element) {
     return _underlying.contains(element);
   }
 
+  public Set plus(Object e) {
+    Set n = new Set(new HashSet<Object>(_underlying));
+    n.add(e);
+    return n;
+  }
+
   public boolean subsetOf(Set s) {
     for(Object o : _underlying) {
       if(!s.underlying().contains(o)) {
diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala
index 960e57ff8179e4d3f96667bf0c73842754f91781..d7a3b12c13c9ebdf55e2217b32022e4901643d54 100644
--- a/src/main/scala/leon/codegen/CodeGeneration.scala
+++ b/src/main/scala/leon/codegen/CodeGeneration.scala
@@ -72,6 +72,7 @@ trait CodeGeneration {
 
   private[codegen] val TupleClass                = "leon/codegen/runtime/Tuple"
   private[codegen] val SetClass                  = "leon/codegen/runtime/Set"
+  private[codegen] val BagClass                  = "leon/codegen/runtime/Bag"
   private[codegen] val MapClass                  = "leon/codegen/runtime/Map"
   private[codegen] val BigIntClass               = "leon/codegen/runtime/BigInt"
   private[codegen] val RealClass                 = "leon/codegen/runtime/Real"
@@ -126,6 +127,9 @@ trait CodeGeneration {
     case _ : SetType =>
       "L" + SetClass + ";"
 
+    case _ : BagType =>
+      "L" + BagClass + ";"
+
     case _ : MapType =>
       "L" + MapClass + ";"
 
@@ -544,6 +548,11 @@ trait CodeGeneration {
           ch << InvokeVirtual(SetClass, "add", s"(L$ObjectClass;)V")
         }
 
+      case SetAdd(s, e) =>
+        mkExpr(s, ch)
+        mkBoxedExpr(e, ch)
+        ch << InvokeVirtual(SetClass, "plus", s"(L$ObjectClass;)L$SetClass;")
+
       case ElementOfSet(e, s) =>
         mkExpr(s, ch)
         mkBoxedExpr(e, ch)
@@ -573,6 +582,41 @@ trait CodeGeneration {
         mkExpr(s2, ch)
         ch << InvokeVirtual(SetClass, "minus", s"(L$SetClass;)L$SetClass;")
 
+      // Bags
+      case FiniteBag(els, _) =>
+        ch << DefaultNew(BagClass)
+        for((k,v) <- els) {
+          ch << DUP
+          mkBoxedExpr(k, ch)
+          mkExpr(v, ch)
+          ch << InvokeVirtual(BagClass, "add", s"(L$ObjectClass;L$BigIntClass;)V")
+        }
+
+      case BagAdd(b, e) =>
+        mkExpr(b, ch)
+        mkBoxedExpr(e, ch)
+        ch << InvokeVirtual(BagClass, "plus", s"(L$ObjectClass;)L$BagClass;")
+
+      case MultiplicityInBag(e, b) =>
+        mkExpr(b, ch)
+        mkBoxedExpr(e, ch)
+        ch << InvokeVirtual(BagClass, "get", s"(L$ObjectClass;)L$BigIntClass;")
+
+      case BagIntersection(b1, b2) =>
+        mkExpr(b1, ch)
+        mkExpr(b2, ch)
+        ch << InvokeVirtual(BagClass, "intersect", s"(L$BagClass;)L$BagClass;")
+
+      case BagUnion(b1, b2) =>
+        mkExpr(b1, ch)
+        mkExpr(b2, ch)
+        ch << InvokeVirtual(BagClass, "union", s"(L$BagClass;)L$BagClass;")
+
+      case BagDifference(b1, b2) =>
+        mkExpr(b1, ch)
+        mkExpr(b2, ch)
+        ch << InvokeVirtual(BagClass, "difference", s"(L$BagClass;)L$BagClass;")
+
       // Maps
       case FiniteMap(ss, _, _) =>
         ch << DefaultNew(MapClass)
diff --git a/src/main/scala/leon/codegen/CompilationUnit.scala b/src/main/scala/leon/codegen/CompilationUnit.scala
index e8bd40eb2302fd9ced5fc44d6c18848c4461b867..366feffafcb9c7b994d6ccefbc1ff2f0269626dd 100644
--- a/src/main/scala/leon/codegen/CompilationUnit.scala
+++ b/src/main/scala/leon/codegen/CompilationUnit.scala
@@ -232,6 +232,13 @@ class CompilationUnit(val ctx: LeonContext,
       }
       s
 
+    case b @ FiniteBag(els, _) =>
+      val b = new leon.codegen.runtime.Bag()
+      for ((k,v) <- els) {
+        b.add(valueToJVM(k), valueToJVM(v).asInstanceOf[leon.codegen.runtime.BigInt])
+      }
+      b
+
     case m @ FiniteMap(els, _, _) =>
       val m = new leon.codegen.runtime.Map()
       for ((k,v) <- els) {
@@ -362,6 +369,13 @@ class CompilationUnit(val ctx: LeonContext,
     case (set: runtime.Set, SetType(b)) =>
       FiniteSet(set.getElements.asScala.map(jvmToValue(_, b)).toSet, b)
 
+    case (bag: runtime.Bag, BagType(b)) =>
+      FiniteBag(bag.getElements.asScala.map { entry =>
+        val k = jvmToValue(entry.getKey, b)
+        val v = jvmToValue(entry.getValue, IntegerType)
+        (k, v)
+      }.toMap, b)
+
     case (map: runtime.Map, MapType(from, to)) =>
       val pairs = map.getElements.asScala.map { entry =>
         val k = jvmToValue(entry.getKey, from)
diff --git a/src/main/scala/leon/datagen/VanuatooDataGen.scala b/src/main/scala/leon/datagen/VanuatooDataGen.scala
index 0b533e631dee5b0a41181262e0d8c8702b40ea62..6e13cb030ad7df32b6a5ec1543e6d2c80915903d 100644
--- a/src/main/scala/leon/datagen/VanuatooDataGen.scala
+++ b/src/main/scala/leon/datagen/VanuatooDataGen.scala
@@ -106,6 +106,19 @@ class VanuatooDataGen(ctx: LeonContext, p: Program) extends DataGenerator {
         constructors += st -> cs
         cs
       })
+
+    case bt @ BagType(sub) =>
+      constructors.getOrElse(bt, {
+        val cs = for (size <- List(0, 1, 2, 5)) yield {
+          val subs = (1 to size).flatMap(i => List(sub, IntegerType)).toList
+          Constructor[Expr, TypeTree](subs, bt, s => FiniteBag(s.grouped(2).map {
+            case Seq(k, i @ InfiniteIntegerLiteral(v)) =>
+              k -> (if (v > 0) i else InfiniteIntegerLiteral(-v + 1))
+          }.toMap, sub), bt.asString(ctx)+"@"+size)
+        }
+        constructors += bt -> cs
+        cs
+      })
     
     case tt @ TupleType(parts) =>
       constructors.getOrElse(tt, {
@@ -117,7 +130,7 @@ class VanuatooDataGen(ctx: LeonContext, p: Program) extends DataGenerator {
     case mt @ MapType(from, to) =>
       constructors.getOrElse(mt, {
         val cs = for (size <- List(0, 1, 2, 5)) yield {
-          val subs   = (1 to size).flatMap(i => List(from, to)).toList
+          val subs = (1 to size).flatMap(i => List(from, to)).toList
           Constructor[Expr, TypeTree](subs, mt, s => FiniteMap(s.grouped(2).map(t => (t(0), t(1))).toMap, from, to), mt.asString(ctx)+"@"+size)
         }
         constructors += mt -> cs
@@ -347,8 +360,9 @@ class VanuatooDataGen(ctx: LeonContext, p: Program) extends DataGenerator {
 
       def computeNext(): Option[Seq[Expr]] = {
         //return None
-        while(total < maxEnumerated && found < maxValid && it.hasNext && !interrupted.get) {
+        while (total < maxEnumerated && found < maxValid && it.hasNext && !interrupted.get) {
           val model = it.next()
+          it.hasNext // FIXME: required for some reason by StubGenerator or will return false during loop check
 
           if (model eq null) {
             total = maxEnumerated
diff --git a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
index 418ac42e62409d18d7ebb39276b9fe40e85b063b..17b44ea45be7bced78fe23712878977633e17840 100644
--- a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
+++ b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
@@ -186,6 +186,7 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int
 
       (lv,rv) match {
         case (FiniteSet(el1, _),FiniteSet(el2, _)) => BooleanLiteral(el1 == el2)
+        case (FiniteBag(el1, _),FiniteBag(el2, _)) => BooleanLiteral(el1 == el2)
         case (FiniteMap(el1, _, _),FiniteMap(el2, _, _)) => BooleanLiteral(el1.toSet == el2.toSet)
         case (FiniteLambda(m1, d1, _), FiniteLambda(m2, d2, _)) => BooleanLiteral(m1.toSet == m2.toSet && d1 == d2)
         case _ => BooleanLiteral(lv == rv)
@@ -466,40 +467,40 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int
         case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type))
       }
 
+    case SetAdd(s1, elem) =>
+      (e(s1), e(elem)) match {
+        case (FiniteSet(els1, tpe), evElem) => FiniteSet(els1 + evElem, tpe)
+        case (le, re) => throw EvalError(typeErrorMsg(le, s1.getType))
+      }
+
     case SetUnion(s1,s2) =>
       (e(s1), e(s2)) match {
-        case (f@FiniteSet(els1, _),FiniteSet(els2, _)) =>
-          val SetType(tpe) = f.getType
-          FiniteSet(els1 ++ els2, tpe)
-        case (le,re) => throw EvalError(typeErrorMsg(le, s1.getType))
+        case (FiniteSet(els1, tpe), FiniteSet(els2, _)) => FiniteSet(els1 ++ els2, tpe)
+        case (le, re) => throw EvalError(typeErrorMsg(le, s1.getType))
       }
 
     case SetIntersection(s1,s2) =>
       (e(s1), e(s2)) match {
-        case (f @ FiniteSet(els1, _), FiniteSet(els2, _)) =>
-          val newElems = els1 intersect els2
-          val SetType(tpe) = f.getType
-          FiniteSet(newElems, tpe)
+        case (FiniteSet(els1, tpe), FiniteSet(els2, _)) => FiniteSet(els1 intersect els2, tpe)
         case (le,re) => throw EvalError(typeErrorMsg(le, s1.getType))
       }
 
     case SetDifference(s1,s2) =>
       (e(s1), e(s2)) match {
-        case (f @ FiniteSet(els1, _),FiniteSet(els2, _)) =>
-          val SetType(tpe) = f.getType
-          val newElems = els1 -- els2
-          FiniteSet(newElems, tpe)
+        case (FiniteSet(els1, tpe), FiniteSet(els2, _)) => FiniteSet(els1 -- els2, tpe)
         case (le,re) => throw EvalError(typeErrorMsg(le, s1.getType))
       }
 
     case ElementOfSet(el,s) => (e(el), e(s)) match {
-      case (e, f @ FiniteSet(els, _)) => BooleanLiteral(els.contains(e))
+      case (e, FiniteSet(els, _)) => BooleanLiteral(els.contains(e))
       case (l,r) => throw EvalError(typeErrorMsg(r, SetType(l.getType)))
     }
+
     case SubsetOf(s1,s2) => (e(s1), e(s2)) match {
-      case (f@FiniteSet(els1, _),FiniteSet(els2, _)) => BooleanLiteral(els1.subsetOf(els2))
+      case (FiniteSet(els1, _),FiniteSet(els2, _)) => BooleanLiteral(els1.subsetOf(els2))
       case (le,re) => throw EvalError(typeErrorMsg(le, s1.getType))
     }
+
     case SetCardinality(s) =>
       val sr = e(s)
       sr match {
@@ -510,6 +511,61 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int
     case f @ FiniteSet(els, base) =>
       FiniteSet(els.map(e), base)
 
+    case BagAdd(bag, elem) => (e(bag), e(elem)) match {
+      case (FiniteBag(els, tpe), evElem) => FiniteBag(els + (evElem -> (els.get(evElem) match {
+        case Some(InfiniteIntegerLiteral(i)) => InfiniteIntegerLiteral(i + 1)
+        case Some(i) => throw EvalError(typeErrorMsg(i, IntegerType))
+        case None => InfiniteIntegerLiteral(1)
+      })), tpe)
+
+      case (le, re) => throw EvalError(typeErrorMsg(le, bag.getType))
+    }
+
+    case MultiplicityInBag(elem, bag) => (e(elem), e(bag)) match {
+      case (evElem, FiniteBag(els, tpe)) => els.getOrElse(evElem, InfiniteIntegerLiteral(0))
+      case (le, re) => throw EvalError(typeErrorMsg(re, bag.getType))
+    }
+
+    case BagIntersection(b1, b2) => (e(b1), e(b2)) match {
+      case (FiniteBag(els1, tpe), FiniteBag(els2, _)) => FiniteBag(els1.flatMap { case (k, v) =>
+        val i = (v, els2.getOrElse(k, InfiniteIntegerLiteral(0))) match {
+          case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => i1 min i2
+          case (le, re) => throw EvalError(typeErrorMsg(le, IntegerType))
+        }
+
+        if (i <= 0) None else Some(k -> InfiniteIntegerLiteral(i))
+      }, tpe)
+
+      case (le, re) => throw EvalError(typeErrorMsg(le, b1.getType))
+    }
+
+    case BagUnion(b1, b2) => (e(b1), e(b2)) match {
+      case (FiniteBag(els1, tpe), FiniteBag(els2, _)) => FiniteBag((els1.keys ++ els2.keys).toSet.map { (k: Expr) =>
+        k -> ((els1.getOrElse(k, InfiniteIntegerLiteral(0)), els2.getOrElse(k, InfiniteIntegerLiteral(0))) match {
+          case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => InfiniteIntegerLiteral(i1 + i2)
+          case (le, re) => throw EvalError(typeErrorMsg(le, IntegerType))
+        })
+      }.toMap, tpe)
+
+      case (le, re) => throw EvalError(typeErrorMsg(le, b1.getType))
+    }
+
+    case BagDifference(b1, b2) => (e(b1), e(b2)) match {
+      case (FiniteBag(els1, tpe), FiniteBag(els2, _)) => FiniteBag(els1.flatMap { case (k, v) =>
+        val i = (v, els2.getOrElse(k, InfiniteIntegerLiteral(0))) match {
+          case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => i1 - i2
+          case (le, re) => throw EvalError(typeErrorMsg(le, IntegerType))
+        }
+
+        if (i <= 0) None else Some(k -> InfiniteIntegerLiteral(i))
+      }, tpe)
+
+      case (le, re) => throw EvalError(typeErrorMsg(le, b1.getType))
+    }
+
+    case FiniteBag(els, base) =>
+      FiniteBag(els.map{ case (k, v) => (e(k), e(v)) }, base)
+
     case l @ Lambda(_, _) =>
       val mapping = variablesOf(l).map(id => id -> e(Variable(id))).toMap
       val newLambda = replaceFromIDs(mapping, l).asInstanceOf[Lambda]
diff --git a/src/main/scala/leon/evaluators/StreamEvaluator.scala b/src/main/scala/leon/evaluators/StreamEvaluator.scala
index d53869f898288ba466b8d79729ba8964dbf06095..d36a4b73951ef113c9fe199676b977693c6c8f31 100644
--- a/src/main/scala/leon/evaluators/StreamEvaluator.scala
+++ b/src/main/scala/leon/evaluators/StreamEvaluator.scala
@@ -397,6 +397,7 @@ class StreamEvaluator(ctx: LeonContext, prog: Program)
     case (Equals(_, _), Seq(lv, rv)) =>
       (lv, rv) match {
         case (FiniteSet(el1, _), FiniteSet(el2, _)) => BooleanLiteral(el1 == el2)
+        case (FiniteBag(el1, _), FiniteBag(el2, _)) => BooleanLiteral(el1 == el2)
         case (FiniteMap(el1, _, _), FiniteMap(el2, _, _)) => BooleanLiteral(el1.toSet == el2.toSet)
         case (FiniteLambda(m1, d1, _), FiniteLambda(m2, d2, _)) => BooleanLiteral(m1.toSet == m2.toSet && d1 == d2)
         case _ => BooleanLiteral(lv == rv)
@@ -540,14 +541,23 @@ class StreamEvaluator(ctx: LeonContext, prog: Program)
       (el, er) match {
         case (IntLiteral(i1), IntLiteral(i2)) => BooleanLiteral(i1 >= i2)
         case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => BooleanLiteral(i1 >= i2)
-        case (a@FractionalLiteral(_, _), b@FractionalLiteral(_, _)) =>
+        case (a @ FractionalLiteral(_, _), b @ FractionalLiteral(_, _)) =>
           val FractionalLiteral(n, _) = e(RealMinus(a, b)).head
           BooleanLiteral(n >= 0)
         case (CharLiteral(c1), CharLiteral(c2)) => BooleanLiteral(c1 >= c2)
         case (le, re) => throw EvalError(typeErrorMsg(le, Int32Type))
       }
 
-    case (IsTyped(su@SetUnion(s1, s2), tpe), Seq(
+    case (IsTyped(sa @ SetAdd(_, _), tpe), Seq(
+      IsTyped(FiniteSet(els1, _), SetType(tpe1)),
+      IsTyped(elem, tpe2)
+    )) =>
+      FiniteSet(
+        els1 + elem,
+        leastUpperBound(tpe1, tpe2).getOrElse(throw EvalError(typeErrorMsg(sa, tpe)))
+      )
+
+    case (IsTyped(su @ SetUnion(s1, s2), tpe), Seq(
       IsTyped(FiniteSet(els1, _), SetType(tpe1)),
       IsTyped(FiniteSet(els2, _), SetType(tpe2))
     )) =>
@@ -556,7 +566,7 @@ class StreamEvaluator(ctx: LeonContext, prog: Program)
         leastUpperBound(tpe1, tpe2).getOrElse(throw EvalError(typeErrorMsg(su, tpe)))
       )
 
-    case (IsTyped(su@SetIntersection(s1, s2), tpe), Seq(
+    case (IsTyped(su @ SetIntersection(s1, s2), tpe), Seq(
       IsTyped(FiniteSet(els1, _), SetType(tpe1)),
       IsTyped(FiniteSet(els2, _), SetType(tpe2))
     )) =>
@@ -565,7 +575,7 @@ class StreamEvaluator(ctx: LeonContext, prog: Program)
         leastUpperBound(tpe1, tpe2).getOrElse(throw EvalError(typeErrorMsg(su, tpe)))
       )
 
-    case (IsTyped(su@SetDifference(s1, s2), tpe), Seq(
+    case (IsTyped(su @ SetDifference(s1, s2), tpe), Seq(
       IsTyped(FiniteSet(els1, _), SetType(tpe1)),
       IsTyped(FiniteSet(els2, _), SetType(tpe2))
     )) =>
@@ -586,6 +596,69 @@ class StreamEvaluator(ctx: LeonContext, prog: Program)
     case (FiniteSet(_, base), els) =>
       FiniteSet(els.toSet, base)
 
+    case (IsTyped(ba @ BagAdd(_, _), tpe), Seq(
+      IsTyped(FiniteBag(els1, _), BagType(tpe1)),
+      IsTyped(e, tpe2)
+    )) =>
+      FiniteBag(
+        els1 + (e -> (els1.getOrElse(e, InfiniteIntegerLiteral(0)) match {
+          case InfiniteIntegerLiteral(i) => InfiniteIntegerLiteral(i + 1)
+          case il => throw EvalError(typeErrorMsg(il, IntegerType))
+        })),
+        leastUpperBound(tpe1, tpe2).getOrElse(throw EvalError(typeErrorMsg(ba, tpe)))
+      )
+
+    case (IsTyped(bu @ BagUnion(b1, b2), tpe), Seq(
+      IsTyped(FiniteBag(els1, _), BagType(tpe1)),
+      IsTyped(FiniteBag(els2, _), BagType(tpe2))
+    )) =>
+      FiniteBag(
+        (els1.keys ++ els2.keys).map(k => k -> {
+          ((els1.getOrElse(k, InfiniteIntegerLiteral(0)), els2.getOrElse(k, InfiniteIntegerLiteral(0))) match {
+            case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => InfiniteIntegerLiteral(i1 + i2)
+            case (l, r) => throw EvalError(typeErrorMsg(l, IntegerType))
+          })
+        }).toMap,
+        leastUpperBound(tpe1, tpe2).getOrElse(throw EvalError(typeErrorMsg(bu, tpe)))
+      )
+
+    case (IsTyped(bi @ BagIntersection(s1, s2), tpe), Seq(
+      IsTyped(FiniteBag(els1, _), BagType(tpe1)),
+      IsTyped(FiniteBag(els2, _), BagType(tpe2))
+    )) =>
+      FiniteBag(
+        els1.flatMap { case (k, e) => 
+          val res = (e, els2.getOrElse(k, InfiniteIntegerLiteral(0))) match {
+            case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => i1 min i2
+            case (l, r) => throw EvalError(typeErrorMsg(l, IntegerType))
+          }
+          if (res <= 0) None else Some(k -> InfiniteIntegerLiteral(res))
+        },
+        leastUpperBound(tpe1, tpe2).getOrElse(throw EvalError(typeErrorMsg(bi, tpe)))
+      )
+
+    case (IsTyped(bd @ BagDifference(s1, s2), tpe), Seq(
+      IsTyped(FiniteBag(els1, _), BagType(tpe1)),
+      IsTyped(FiniteBag(els2, _), BagType(tpe2))
+    )) =>
+      FiniteBag(
+        els1.flatMap { case (k, e) =>
+          val res = (e, els2.getOrElse(k, InfiniteIntegerLiteral(0))) match {
+            case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => i1 - i2
+            case (l, r) => throw EvalError(typeErrorMsg(l, IntegerType))
+          }
+          if (res <= 0) None else Some(k -> InfiniteIntegerLiteral(res))
+        },
+        leastUpperBound(tpe1, tpe2).getOrElse(throw EvalError(typeErrorMsg(bd, tpe)))
+      )
+
+    case (MultiplicityInBag(_, _), Seq(e, FiniteBag(els, _))) =>
+      els.getOrElse(e, InfiniteIntegerLiteral(0))
+
+    case (fb @ FiniteBag(_, _), els) =>
+      val Operator(_, builder) = fb
+      builder(els)
+
     case (ArrayLength(_), Seq(FiniteArray(_, _, IntLiteral(length)))) =>
       IntLiteral(length)
 
@@ -602,15 +675,15 @@ class StreamEvaluator(ctx: LeonContext, prog: Program)
         .orElse(if (index >= 0 && index < length) default else None)
         .getOrElse(throw RuntimeError(s"Array out of bounds error during evaluation:\n array = $fa, index = $index"))
 
-    case (fa@FiniteArray(_, _, _), subs) =>
+    case (fa @ FiniteArray(_, _, _), subs) =>
       val Operator(_, builder) = fa
       builder(subs)
 
-    case (fm@FiniteMap(_, _, _), subs) =>
+    case (fm @ FiniteMap(_, _, _), subs) =>
       val Operator(_, builder) = fm
       builder(subs)
 
-    case (g@MapApply(_, _), Seq(FiniteMap(m, _, _), k)) =>
+    case (g @ MapApply(_, _), Seq(FiniteMap(m, _, _), k)) =>
       m.getOrElse(k, throw RuntimeError("Key not found: " + k.asString))
 
     case (u@IsTyped(MapUnion(_, _), MapType(kT, vT)), Seq(FiniteMap(m1, _, _), FiniteMap(m2, _, _))) =>
diff --git a/src/main/scala/leon/frontends/scalac/ASTExtractors.scala b/src/main/scala/leon/frontends/scalac/ASTExtractors.scala
index 7890d7a229da487e8ae8152ae92c7b0b066eb12e..1d107703b1bfe5dff1658bab08b44d0ae84fa2e8 100644
--- a/src/main/scala/leon/frontends/scalac/ASTExtractors.scala
+++ b/src/main/scala/leon/frontends/scalac/ASTExtractors.scala
@@ -44,6 +44,7 @@ trait ASTExtractors {
   protected lazy val scalaSetSym        = classFromName("scala.collection.immutable.Set")
   protected lazy val setSym             = classFromName("leon.lang.Set")
   protected lazy val mapSym             = classFromName("leon.lang.Map")
+  protected lazy val bagSym             = classFromName("leon.lang.Bag")
   protected lazy val realSym            = classFromName("leon.lang.Real")
   protected lazy val optionClassSym     = classFromName("scala.Option")
   protected lazy val arraySym           = classFromName("scala.Array")
@@ -80,6 +81,10 @@ trait ASTExtractors {
     getResolvedTypeSym(sym) == setSym
   }
 
+  def isBagSym(sym: Symbol) : Boolean = {
+    getResolvedTypeSym(sym) == bagSym
+  }
+
   def isRealSym(sym: Symbol) : Boolean = {
     getResolvedTypeSym(sym) == realSym
   }
@@ -1038,6 +1043,16 @@ trait ASTExtractors {
       }
     }
 
+    object ExFiniteBag {
+      def unapply(tree: Apply): Option[(Tree, List[Tree])] = tree match {
+        case Apply(TypeApply(ExSelected("Bag", "apply"), Seq(tpt)), args) =>
+          Some(tpt, args)
+        case Apply(TypeApply(ExSelected("leon", "lang", "Bag", "apply"), Seq(tpt)), args) =>
+          Some(tpt, args)
+        case _ => None
+      }
+    }
+
     object ExFiniteMap {
       def unapply(tree: Apply): Option[(Tree, Tree, List[Tree])] = tree match {
         case Apply(TypeApply(ExSelected("Map", "apply"), Seq(tptFrom, tptTo)), args) =>
diff --git a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala
index 993bc4fd0c0f48b56c18eae3b2889f303306027c..0a80b3b53933a6bb6f5c88d8785ea8f3eb1cebaa 100644
--- a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala
+++ b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala
@@ -1461,20 +1461,26 @@ trait CodeExtraction extends ASTExtractors {
           Forall(vds, exBody)
 
         case ExFiniteMap(tptFrom, tptTo, args) =>
-          val singletons = args.collect {
-            case ExTuple(tpes, trees) if trees.size == 2 =>
-              (extractTree(trees(0)), extractTree(trees(1)))
-          }.toMap
-
-          if (singletons.size != args.size) {
-            outOfSubsetError(tr, "Some map elements could not be extracted as Tuple2")
-          }
-
-          FiniteMap(singletons, extractType(tptFrom), extractType(tptTo))
+          FiniteMap(args.map {
+            case ExTuple(tpes, Seq(key, value)) =>
+              (extractTree(key), extractTree(value))
+            case tree =>
+              val ex = extractTree(tree)
+              (TupleSelect(ex, 1), TupleSelect(ex, 2))
+          }.toMap, extractType(tptFrom), extractType(tptTo))
 
         case ExFiniteSet(tpt, args) =>
           FiniteSet(args.map(extractTree).toSet, extractType(tpt))
 
+        case ExFiniteBag(tpt, args) =>
+          FiniteBag(args.map {
+            case ExTuple(tpes, Seq(key, value)) =>
+              (extractTree(key), extractTree(value))
+            case tree =>
+              val ex = extractTree(tree)
+              (TupleSelect(ex, 1), TupleSelect(ex, 2))
+          }.toMap, extractType(tpt))
+
         case ExCaseClassConstruction(tpt, args) =>
           extractType(tpt) match {
             case cct: CaseClassType =>
@@ -1669,6 +1675,7 @@ trait CodeExtraction extends ASTExtractors {
               val id = cct.classDef.fields.find(_.id.name == name.dropRight(2)).get.id
               FieldAssignment(rec, id, e1)
 
+
             //String methods
             case (IsTyped(a1, StringType), "toString", List()) =>
               a1
@@ -1686,6 +1693,8 @@ trait CodeExtraction extends ASTExtractors {
               SubString(a1, start, StringLength(a1))
             case (IsTyped(a1, StringType), "substring", List(IsTyped(start, IntegerType | Int32Type), IsTyped(end, IntegerType | Int32Type))) =>
               SubString(a1, start, end)
+
+
             //BigInt methods
             case (IsTyped(a1, IntegerType), "+", List(IsTyped(a2, IntegerType))) =>
               Plus(a1, a2)
@@ -1708,6 +1717,7 @@ trait CodeExtraction extends ASTExtractors {
             case (IsTyped(a1, IntegerType), "<=", List(IsTyped(a2, IntegerType))) =>
               LessEquals(a1, a2)
 
+
             //Real methods
             case (IsTyped(a1, RealType), "+", List(IsTyped(a2, RealType))) =>
               RealPlus(a1, a2)
@@ -1726,6 +1736,7 @@ trait CodeExtraction extends ASTExtractors {
             case (IsTyped(a1, RealType), "<=", List(IsTyped(a2, RealType))) =>
               LessEquals(a1, a2)
 
+
             // Int methods
             case (IsTyped(a1, Int32Type), "+", List(IsTyped(a2, Int32Type))) =>
               BVPlus(a1, a2)
@@ -1760,6 +1771,7 @@ trait CodeExtraction extends ASTExtractors {
             case (IsTyped(a1, Int32Type), "<=", List(IsTyped(a2, Int32Type))) =>
               LessEquals(a1, a2)
 
+
             // Boolean methods
             case (IsTyped(a1, BooleanType), "&&", List(IsTyped(a2, BooleanType))) =>
               and(a1, a2)
@@ -1767,6 +1779,7 @@ trait CodeExtraction extends ASTExtractors {
             case (IsTyped(a1, BooleanType), "||", List(IsTyped(a2, BooleanType))) =>
               or(a1, a2)
 
+
             // Set methods
             case (IsTyped(a1, SetType(b1)), "size", Nil) =>
               SetCardinality(a1)
@@ -1777,6 +1790,9 @@ trait CodeExtraction extends ASTExtractors {
             //case (IsTyped(a1, SetType(b1)), "max", Nil) =>
             //  SetMax(a1)
 
+            case (IsTyped(a1, SetType(b1)), "+", List(a2)) =>
+              SetAdd(a1, a2)
+
             case (IsTyped(a1, SetType(b1)), "++", List(IsTyped(a2, SetType(b2))))  if b1 == b2 =>
               SetUnion(a1, a2)
 
@@ -1795,6 +1811,27 @@ trait CodeExtraction extends ASTExtractors {
             case (IsTyped(a1, SetType(b1)), "isEmpty", List()) =>
               Equals(a1, FiniteSet(Set(), b1))
 
+
+            // Bag methods
+            case (IsTyped(a1, BagType(b1)), "+", List(a2)) =>
+              BagAdd(a1, a2)
+
+            case (IsTyped(a1, BagType(b1)), "++", List(IsTyped(a2, BagType(b2)))) if b1 == b2 =>
+              BagUnion(a1, a2)
+
+            case (IsTyped(a1, BagType(b1)), "&", List(IsTyped(a2, BagType(b2)))) if b1 == b2 =>
+              BagIntersection(a1, a2)
+
+            case (IsTyped(a1, BagType(b1)), "--", List(IsTyped(a2, BagType(b2)))) if b1 == b2 =>
+              BagDifference(a1, a2)
+
+            case (IsTyped(a1, BagType(b1)), "get", List(a2)) =>
+              MultiplicityInBag(a2, a1)
+
+            case (IsTyped(a1, BagType(b1)), "isEmpty", List()) =>
+              Equals(a1, FiniteBag(Map(), b1))
+
+
             // Array methods
             case (IsTyped(a1, ArrayType(vt)), "apply", List(a2)) =>
               ArraySelect(a1, a2)
@@ -1926,6 +1963,9 @@ trait CodeExtraction extends ASTExtractors {
       case TypeRef(_, sym, btt :: Nil) if isSetSym(sym) =>
         SetType(extractType(btt))
 
+      case TypeRef(_, sym, btt :: Nil) if isBagSym(sym) =>
+        BagType(extractType(btt))
+
       case TypeRef(_, sym, List(ftt,ttt)) if isMapSym(sym) =>
         MapType(extractType(ftt), extractType(ttt))
 
diff --git a/src/main/scala/leon/purescala/DefinitionTransformer.scala b/src/main/scala/leon/purescala/DefinitionTransformer.scala
index 89c5b613b426f8d6c9b6b2eeaa1273da2496ed40..6be2448adf41b1c2962ef458ca838d04c13b9bdb 100644
--- a/src/main/scala/leon/purescala/DefinitionTransformer.scala
+++ b/src/main/scala/leon/purescala/DefinitionTransformer.scala
@@ -97,7 +97,7 @@ class DefinitionTransformer(
 
     for (fd <- requiredFds) {
       val nfd = fdMap.toB(fd)
-      fd.fullBody = transform(fd.fullBody)((fd.params zip nfd.params).map(p => p._1.id -> p._2.id).toMap)
+      nfd.fullBody = transform(fd.fullBody)((fd.params zip nfd.params).map(p => p._1.id -> p._2.id).toMap)
     }
   }
 }
diff --git a/src/main/scala/leon/purescala/ExprOps.scala b/src/main/scala/leon/purescala/ExprOps.scala
index 4f7bc819650c5316ab4dc3ff3bf1cf1203cb9a1d..b917447942ad3996163f5e970e316d0e1aee4b67 100644
--- a/src/main/scala/leon/purescala/ExprOps.scala
+++ b/src/main/scala/leon/purescala/ExprOps.scala
@@ -856,6 +856,7 @@ object ExprOps extends { val Deconstructor = Operator } with SubTreeOps[Expr] {
     case BooleanType                => BooleanLiteral(false)
     case UnitType                   => UnitLiteral()
     case SetType(baseType)          => FiniteSet(Set(), baseType)
+    case BagType(baseType)          => FiniteBag(Map(), baseType)
     case MapType(fromType, toType)  => FiniteMap(Map(), fromType, toType)
     case TupleType(tpes)            => Tuple(tpes.map(simplestValue))
     case ArrayType(tpe)             => EmptyArray(tpe)
diff --git a/src/main/scala/leon/purescala/Expressions.scala b/src/main/scala/leon/purescala/Expressions.scala
index 79172eb7a538c298e5b5eb026eb3e8dfca397f3a..3855813de7e618bc272c6cc845cb24bb3983a5e3 100644
--- a/src/main/scala/leon/purescala/Expressions.scala
+++ b/src/main/scala/leon/purescala/Expressions.scala
@@ -821,9 +821,22 @@ object Expressions {
   case class FiniteSet(elements: Set[Expr], base: TypeTree) extends Expr {
     val getType = SetType(base).unveilUntyped
   }
+  /** $encodingof `set + elem` */
+  case class SetAdd(set: Expr, elem: Expr) extends Expr {
+    val getType = {
+      val base = set.getType match {
+        case SetType(base) => base
+        case _ => Untyped
+      }
+      checkParamTypes(Seq(elem.getType), Seq(base), SetType(base).unveilUntyped)
+    }
+  }
   /** $encodingof `set.contains(element)` or `set(element)` */
   case class ElementOfSet(element: Expr, set: Expr) extends Expr {
-    val getType = BooleanType
+    val getType = checkParamTypes(Seq(element.getType), Seq(set.getType match {
+      case SetType(base) => base
+      case _ => Untyped
+    }), BooleanType)
   }
   /** $encodingof `set.length` */
   case class SetCardinality(set: Expr) extends Expr {
@@ -831,9 +844,12 @@ object Expressions {
   }
   /** $encodingof `set.subsetOf(set2)` */
   case class SubsetOf(set1: Expr, set2: Expr) extends Expr {
-    val getType  = BooleanType
+    val getType = (set1.getType, set2.getType) match {
+      case (SetType(b1), SetType(b2)) if b1 == b2 => BooleanType
+      case _ => Untyped
+    }
   }
-  /** $encodingof `set.intersect(set2)` */
+  /** $encodingof `set & set2` */
   case class SetIntersection(set1: Expr, set2: Expr) extends Expr {
     val getType = leastUpperBound(Seq(set1, set2).map(_.getType)).getOrElse(Untyped).unveilUntyped
   }
@@ -848,26 +864,27 @@ object Expressions {
 
   /* Bag operations */
   /** $encodingof `Bag[base](elements)` */
-  case class FiniteBag(elements: Map[Expr, Int], base: TypeTree) extends Expr {
+  case class FiniteBag(elements: Map[Expr, Expr], base: TypeTree) extends Expr {
     val getType = BagType(base).unveilUntyped
   }
+  /** $encodingof `bag + elem` */
+  case class BagAdd(bag: Expr, elem: Expr) extends Expr {
+    val getType = {
+      val base = bag.getType match {
+        case BagType(base) => base
+        case _ => Untyped
+      }
+      checkParamTypes(Seq(base), Seq(elem.getType), BagType(base).unveilUntyped)
+    }
+  }
   /** $encodingof `bag.get(element)` or `bag(element)` */
   case class MultiplicityInBag(element: Expr, bag: Expr) extends Expr {
-    val getType = IntegerType
-  }
-  /** $encodingof `bag.length` */
-  /*
-  case class BagCardinality(bag: Expr) extends Expr {
-    val getType = IntegerType
-  }
-  */
-  /** $encodingof `bag1.subsetOf(bag2)` */
-  /*
-  case class SubbagOf(bag1: Expr, bag2: Expr) extends Expr {
-    val getType  = BooleanType
+    val getType = checkParamTypes(Seq(element.getType), Seq(bag.getType match {
+      case BagType(base) => base
+      case _ => Untyped
+    }), IntegerType)
   }
-  */
-  /** $encodingof `bag1.intersect(bag2)` */
+  /** $encodingof `bag1 & bag2` */
   case class BagIntersection(bag1: Expr, bag2: Expr) extends Expr {
     val getType = leastUpperBound(Seq(bag1, bag2).map(_.getType)).getOrElse(Untyped).unveilUntyped
   }
@@ -876,12 +893,10 @@ object Expressions {
     val getType = leastUpperBound(Seq(bag1, bag2).map(_.getType)).getOrElse(Untyped).unveilUntyped
   }
   /** $encodingof `bag1 -- bag2` */
-  /*
-  case class SetDifference(bag1: Expr, bag2: Expr) extends Expr {
-    val getType = leastUpperBound(Seq(set1, set2).map(_.getType)).getOrElse(Untyped).unveilUntyped
+  case class BagDifference(bag1: Expr, bag2: Expr) extends Expr {
+    val getType = leastUpperBound(Seq(bag1, bag2).map(_.getType)).getOrElse(Untyped).unveilUntyped
   }
-  */
-  
+
 
   // TODO: Add checks for these expressions too
 
diff --git a/src/main/scala/leon/purescala/Extractors.scala b/src/main/scala/leon/purescala/Extractors.scala
index 5c09c2d296bcbf7ddeb3518f2c42acdc6a695cb8..ea5b30430005fecbb8eb6c5d8082a415cb1e24e2 100644
--- a/src/main/scala/leon/purescala/Extractors.scala
+++ b/src/main/scala/leon/purescala/Extractors.scala
@@ -134,6 +134,8 @@ object Extractors {
         Some(Seq(t1, t2), (es: Seq[Expr]) => RealDivision(es(0), es(1)))
       case StringConcat(t1, t2) =>
         Some(Seq(t1, t2), (es: Seq[Expr]) => StringConcat(es(0), es(1)))
+      case SetAdd(t1, t2) =>
+        Some(Seq(t1, t2), (es: Seq[Expr]) => SetAdd(es(0), es(1)))
       case ElementOfSet(t1, t2) =>
         Some(Seq(t1, t2), (es: Seq[Expr]) => ElementOfSet(es(0), es(1)))
       case SubsetOf(t1, t2) =>
@@ -144,12 +146,16 @@ object Extractors {
         Some(Seq(t1, t2), (es: Seq[Expr]) => SetUnion(es(0), es(1)))
       case SetDifference(t1, t2) =>
         Some(Seq(t1, t2), (es: Seq[Expr]) => SetDifference(es(0), es(1)))
+      case BagAdd(e1, e2) =>
+        Some(Seq(e1, e2), (es: Seq[Expr]) => BagAdd(es(0), es(1)))
       case MultiplicityInBag(e1, e2) =>
         Some(Seq(e1, e2), (es: Seq[Expr]) => MultiplicityInBag(es(0), es(1)))
       case BagIntersection(e1, e2) =>
         Some(Seq(e1, e2), (es: Seq[Expr]) => BagIntersection(es(0), es(1)))
       case BagUnion(e1, e2) =>
         Some(Seq(e1, e2), (es: Seq[Expr]) => BagUnion(es(0), es(1)))
+      case BagDifference(e1, e2) =>
+        Some(Seq(e1, e2), (es: Seq[Expr]) => BagDifference(es(0), es(1)))
       case mg @ MapApply(t1, t2) =>
         Some(Seq(t1, t2), (es: Seq[Expr]) => MapApply(es(0), es(1)))
       case MapUnion(t1, t2) =>
@@ -180,13 +186,22 @@ object Extractors {
       case FiniteSet(els, base) =>
         Some((els.toSeq, els => FiniteSet(els.toSet, base)))
       case FiniteBag(els, base) =>
-        val seq = els.toSeq
-        Some((seq.map(_._1), els => FiniteBag((els zip seq.map(_._2)).toMap, base)))
+        val subArgs = els.flatMap { case (k, v) => Seq(k, v) }.toSeq
+        val builder = (as: Seq[Expr]) => {
+          def rec(kvs: Seq[Expr]): Map[Expr, Expr] = kvs match {
+            case Seq(k, v, t @ _*) =>
+              Map(k -> v) ++ rec(t)
+            case Seq() => Map()
+            case _ => sys.error("odd number of key/value expressions")
+          }
+          FiniteBag(rec(as), base)
+        }
+        Some((subArgs, builder))
       case FiniteMap(args, f, t) => {
         val subArgs = args.flatMap { case (k, v) => Seq(k, v) }.toSeq
         val builder = (as: Seq[Expr]) => {
           def rec(kvs: Seq[Expr]): Map[Expr, Expr] = kvs match {
-            case Seq(k, v, t@_*) =>
+            case Seq(k, v, t @ _*) =>
               Map(k -> v) ++ rec(t)
             case Seq() => Map()
             case _ => sys.error("odd number of key/value expressions")
diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala
index f1b80fd9de6df1996d33fdc7936669be6a997b73..38644fc4a896cb2f84eefac53eb6652dd041e8a1 100644
--- a/src/main/scala/leon/purescala/PrettyPrinter.scala
+++ b/src/main/scala/leon/purescala/PrettyPrinter.scala
@@ -321,16 +321,23 @@ class PrettyPrinter(opts: PrinterOptions,
       case RealTimes(l,r)            => optP { p"$l * $r" }
       case RealDivision(l,r)         => optP { p"$l / $r" }
       case fs @ FiniteSet(rs, _)     => p"{${rs.toSeq}}"
+      case fs @ FiniteBag(rs, _)     => p"{$rs}"
       case fm @ FiniteMap(rs, _, _)  => p"{$rs}"
       case Not(ElementOfSet(e,s))    => p"$e \u2209 $s"
       case ElementOfSet(e,s)         => p"$e \u2208 $s"
       case SubsetOf(l,r)             => p"$l \u2286 $r"
       case Not(SubsetOf(l,r))        => p"$l \u2288 $r"
+      case SetAdd(s,e)               => p"$s \u222A {$e}"
       case SetUnion(l,r)             => p"$l \u222A $r"
+      case BagUnion(l,r)             => p"$l \u222A $r"
       case MapUnion(l,r)             => p"$l \u222A $r"
       case SetDifference(l,r)        => p"$l \\ $r"
+      case BagDifference(l,r)        => p"$l \\ $r"
       case SetIntersection(l,r)      => p"$l \u2229 $r"
+      case BagIntersection(l,r)      => p"$l \u2229 $r"
       case SetCardinality(s)         => p"$s.size"
+      case BagAdd(b,e)               => p"$b + $e"
+      case MultiplicityInBag(e, b)   => p"$b($e)"
       case MapApply(m,k)             => p"$m($k)"
       case MapIsDefinedAt(m,k)       => p"$m.isDefinedAt($k)"
       case ArrayLength(a)            => p"$a.length"
@@ -464,6 +471,7 @@ class PrettyPrinter(opts: PrinterOptions,
       case StringType            => p"String"
       case ArrayType(bt)         => p"Array[$bt]"
       case SetType(bt)           => p"Set[$bt]"
+      case BagType(bt)           => p"Bag[$bt]"
       case MapType(ft,tt)        => p"Map[$ft, $tt]"
       case TupleType(tpes)       => p"($tpes)"
       case FunctionType(fts, tt) => p"($fts) => $tt"
diff --git a/src/main/scala/leon/purescala/ScalaPrinter.scala b/src/main/scala/leon/purescala/ScalaPrinter.scala
index 03c50eb2e752ad0dd3827703eff4fc44542e5b2c..40dcbdab8188f71988d78e58ffb200224de57891 100644
--- a/src/main/scala/leon/purescala/ScalaPrinter.scala
+++ b/src/main/scala/leon/purescala/ScalaPrinter.scala
@@ -28,6 +28,7 @@ class ScalaPrinter(opts: PrinterOptions,
       case Choose(pred)              => p"choose($pred)"
 
       case s @ FiniteSet(rss, t)     => p"Set[$t](${rss.toSeq})"
+      case SetAdd(s,e)               => optP { p"$s + $e" }
       case ElementOfSet(e,s)         => p"$s.contains($e)"
       case SetUnion(l,r)             => optP { p"$l ++ $r" }
       case SetDifference(l,r)        => optP { p"$l -- $r" }
@@ -35,6 +36,12 @@ class ScalaPrinter(opts: PrinterOptions,
       case SetCardinality(s)         => p"$s.size"
       case SubsetOf(subset,superset) => p"$subset.subsetOf($superset)"
 
+      case b @ FiniteBag(els, t)     => p"Bag[$t]($els)"
+      case BagAdd(s,e)               => optP { p"$s + $e" }
+      case BagUnion(l,r)             => optP { p"$l ++ $r" }
+      case BagDifference(l,r)        => optP { p"$l -- $r" }
+      case BagIntersection(l,r)      => optP { p"$l & $r" }
+
       case MapUnion(l,r)             => optP { p"$l ++ $r" }
       case m @ FiniteMap(els, k, v)  => p"Map[$k,$v]($els)"
 
diff --git a/src/main/scala/leon/purescala/Types.scala b/src/main/scala/leon/purescala/Types.scala
index e2838104fd704110fbb06e6234ea1ae2599a20e7..1536395e92798360c70b5ad8fcebf3520520768c 100644
--- a/src/main/scala/leon/purescala/Types.scala
+++ b/src/main/scala/leon/purescala/Types.scala
@@ -143,6 +143,7 @@ object Types {
       case TupleType(ts) => Some((ts, Constructors.tupleTypeWrap _))
       case ArrayType(t) => Some((Seq(t), ts => ArrayType(ts.head)))
       case SetType(t) => Some((Seq(t), ts => SetType(ts.head)))
+      case BagType(t) => Some((Seq(t), ts => BagType(ts.head)))
       case MapType(from,to) => Some((Seq(from, to), t => MapType(t(0), t(1))))
       case FunctionType(fts, tt) => Some((tt +: fts, ts => FunctionType(ts.tail.toList, ts.head)))
       /* n-ary operators */
diff --git a/src/main/scala/leon/solvers/cvc4/CVC4UnrollingSolver.scala b/src/main/scala/leon/solvers/cvc4/CVC4UnrollingSolver.scala
index 3ddfca8d9524f9052dc5e6e49266006e9ffa2e3b..97b5d4dc91a2efcf8c4c6446a7049f4ef28b42fa 100644
--- a/src/main/scala/leon/solvers/cvc4/CVC4UnrollingSolver.scala
+++ b/src/main/scala/leon/solvers/cvc4/CVC4UnrollingSolver.scala
@@ -10,4 +10,4 @@ import unrolling._
 import theories._
 
 class CVC4UnrollingSolver(context: LeonContext, program: Program, underlying: Solver)
-  extends UnrollingSolver(context, program, underlying, theories = new NoEncoder)
+  extends UnrollingSolver(context, program, underlying, theories = new BagEncoder(context, program))
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Solver.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Solver.scala
index 5de74510b465d76cfc152c476cff96321c4758e9..8838ae8ffc6443ba2961f51ecce795004dc98233 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Solver.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Solver.scala
@@ -9,7 +9,7 @@ import solvers.theories._
 import purescala.Definitions.Program
 
 class SMTLIBCVC4Solver(context: LeonContext, program: Program)
-  extends SMTLIBSolver(context, program, new NoEncoder)
+  extends SMTLIBSolver(context, program, new BagEncoder(context, program))
      with SMTLIBCVC4Target {
 
   def targetName = "cvc4"
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
index 7418526c9338fce9c558d118fb947af503ee53ec..cd7eae5e8330bac85f5a554b624bf98576655895 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
@@ -197,9 +197,15 @@ trait SMTLIBTarget extends Interruptible {
         unsupported(r, "Solver returned a co-finite set which is not supported.")
       }
       require(r.keyTpe == base, s"Type error in solver model, expected $base, found ${r.keyTpe}")
-
       FiniteSet(r.elems.keySet, base)
 
+    case BagType(base) =>
+      if (r.default != InfiniteIntegerLiteral(0)) {
+        unsupported(r, "Solver returned an infinite bag which is not supported.")
+      }
+      require(r.keyTpe == base, s"Type error in solver model, expected $base, found ${r.keyTpe}")
+      FiniteBag(r.elems, base)
+
     case RawArrayType(from, to) =>
       r
 
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala
index 6a58f9f1a294180182595bcb34d35d1a2ffe08a7..43c1643cf89bef425d30fa1c4e6e11eaa02cf3ed 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala
@@ -16,7 +16,7 @@ import _root_.smtlib.theories.Core.{Equals => _, _}
 import theories._
 
 class SMTLIBZ3Solver(context: LeonContext, program: Program)
-  extends SMTLIBSolver(context, program, new StringEncoder)
+  extends SMTLIBSolver(context, program, new StringEncoder(context, program))
      with SMTLIBZ3Target {
 
   def getProgram: Program = program
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
index 1be3f7ecf930990749565a1c7ca2181cd2a100dd..00b361323de76d5647a124eb65f449161390a15e 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
@@ -9,11 +9,12 @@ import purescala.Expressions._
 import purescala.Constructors._
 import purescala.Types._
 
-import _root_.smtlib.parser.Terms.{Identifier => SMTIdentifier, _}
+import _root_.smtlib.common._
+import _root_.smtlib.parser.Terms.{Identifier => SMTIdentifier, Let => SMTLet, _}
 import _root_.smtlib.parser.Commands.{FunDef => SMTFunDef, _}
 import _root_.smtlib.interpreters.Z3Interpreter
 import _root_.smtlib.theories.Core.{Equals => SMTEquals, _}
-import _root_.smtlib.theories.ArraysEx
+import _root_.smtlib.theories._
 
 trait SMTLIBZ3Target extends SMTLIBTarget {
 
@@ -44,6 +45,8 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
         case SetType(base) =>
           super.declareSort(BooleanType)
           declareSetSort(base)
+        case BagType(base) =>
+          declareSort(RawArrayType(base, IntegerType))
         case _ =>
           super.declareSort(t)
       }
@@ -112,6 +115,9 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
 
       SMTEquals(ArrayMap(SSymbol("implies"), toSMT(ss), toSMT(s)), allTrue)
 
+    case SetAdd(s, e) =>
+      ArraysEx.Store(toSMT(s), toSMT(e), True())
+
     case ElementOfSet(e, s) =>
       ArraysEx.Select(toSMT(s), toSMT(e))
 
@@ -128,6 +134,39 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
     case SetIntersection(l, r) =>
       ArrayMap(SSymbol("and"), toSMT(l), toSMT(r))
 
+    case fb @ FiniteBag(elems, base) =>
+      declareSort(fb.getType)
+
+      toSMT(RawArrayValue(base, elems, InfiniteIntegerLiteral(0)))
+
+    case BagAdd(b, e) =>
+      val bid = FreshIdentifier("b", b.getType, true)
+      val eid = FreshIdentifier("e", e.getType, true)
+      val (bSym, eSym) = (id2sym(bid), id2sym(eid))
+      SMTLet(VarBinding(bSym, toSMT(b)), Seq(VarBinding(eSym, toSMT(e))), ArraysEx.Store(bSym, eSym,
+        Ints.Add(ArraysEx.Select(bSym, eSym), Ints.NumeralLit(1))))
+
+    case MultiplicityInBag(e, b) =>
+      ArraysEx.Select(toSMT(b), toSMT(e))
+
+    case BagUnion(b1, b2) =>
+      val plus = SortedSymbol("+", List(IntegerType, IntegerType).map(declareSort), declareSort(IntegerType))
+      ArrayMap(plus, toSMT(b1), toSMT(b2))
+
+    case BagIntersection(b1, b2) =>
+      val abs   = SortedSymbol("abs", List(IntegerType).map(declareSort), declareSort(IntegerType))
+      val plus  = SortedSymbol("+", List(IntegerType, IntegerType).map(declareSort), declareSort(IntegerType))
+      val minus = SortedSymbol("-", List(IntegerType, IntegerType).map(declareSort), declareSort(IntegerType))
+      val div   = SortedSymbol("/", List(IntegerType, IntegerType).map(declareSort), declareSort(IntegerType))
+
+      val did = FreshIdentifier("d", b1.getType, true)
+      val dSym = id2sym(did)
+
+      val all2 = ArrayConst(declareSort(IntegerType), Ints.NumeralLit(2))
+
+      SMTLet(VarBinding(dSym, ArrayMap(minus, toSMT(b1), toSMT(b2))), Seq(),
+        ArrayMap(div, ArrayMap(plus, dSym, ArrayMap(abs, dSym)), all2))
+
     case _ =>
       super.toSMT(e)
   }
@@ -159,8 +198,16 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
       throw LeonFatalError("Unable to extract "+s)
   }
 
+  protected object SortedSymbol {
+    def apply(op: String, from: List[Sort], to: Sort) = {
+      def simpleSort(s: Sort): Boolean = s.subSorts.isEmpty && !s.id.isIndexed
+      assert(from.forall(simpleSort) && simpleSort(to), "SortedSymbol is only defined for simple sorts")
+      SList(SSymbol(op), SList(from.map(_.id.symbol): _*), to.id.symbol)
+    }
+  }
+
   protected object ArrayMap {
-    def apply(op: SSymbol, arrs: Term*) = {
+    def apply(op: SExpr, arrs: Term*) = {
       FunctionApplication(
         QualifiedIdentifier(SMTIdentifier(SSymbol("map"), List(op))),
         arrs
diff --git a/src/main/scala/leon/solvers/theories/BagEncoder.scala b/src/main/scala/leon/solvers/theories/BagEncoder.scala
index 4ba7fcaa42307ae9c1b65bd3b81c4da03ab62b22..2ae7f2ac8a59b0cc2e96a2cec06b22d1983b79da 100644
--- a/src/main/scala/leon/solvers/theories/BagEncoder.scala
+++ b/src/main/scala/leon/solvers/theories/BagEncoder.scala
@@ -6,9 +6,113 @@ package theories
 
 import purescala.Common._
 import purescala.Expressions._
+import purescala.Definitions._
 import purescala.Types._
 
-class BagEncoder(val context: LeonContext) extends TheoryEncoder {
-  val encoder = new Encoder
-  val decoder = new Decoder
+class BagEncoder(ctx: LeonContext, p: Program) extends TheoryEncoder {
+  val Bag = p.library.lookupUnique[CaseClassDef]("leon.theories.Bag")
+
+  val Get        = p.library.lookupUnique[FunDef]("leon.theories.Bag.get")
+  val Add        = p.library.lookupUnique[FunDef]("leon.theories.Bag.add")
+  val Union      = p.library.lookupUnique[FunDef]("leon.theories.Bag.union")
+  val Difference = p.library.lookupUnique[FunDef]("leon.theories.Bag.difference")
+  val Intersect  = p.library.lookupUnique[FunDef]("leon.theories.Bag.intersect")
+  val BagEquals  = p.library.lookupUnique[FunDef]("leon.theories.Bag.equals")
+
+  val encoder = new Encoder {
+    override def transform(e: Expr)(implicit binders: Map[Identifier, Identifier]): Expr = e match {
+      case FiniteBag(elems, tpe) =>
+        val newTpe = transform(tpe)
+        val id = FreshIdentifier("x", newTpe, true)
+        CaseClass(Bag.typed(Seq(newTpe)), Seq(Lambda(Seq(ValDef(id)),
+          elems.foldRight[Expr](InfiniteIntegerLiteral(0).copiedFrom(e)) { case ((k, v), ite) =>
+            IfExpr(Equals(Variable(id), transform(k)), transform(v), ite).copiedFrom(e)
+          }))).copiedFrom(e)
+
+      case BagAdd(bag, elem) =>
+        val BagType(base) = bag.getType
+        FunctionInvocation(Add.typed(Seq(transform(base))), Seq(transform(bag), transform(elem))).copiedFrom(e)
+
+      case MultiplicityInBag(elem, bag) =>
+        val BagType(base) = bag.getType
+        FunctionInvocation(Get.typed(Seq(transform(base))), Seq(transform(bag), transform(elem))).copiedFrom(e)
+
+      case BagIntersection(b1, b2) =>
+        val BagType(base) = b1.getType
+        FunctionInvocation(Intersect.typed(Seq(transform(base))), Seq(transform(b1), transform(b2))).copiedFrom(e)
+
+      case BagUnion(b1, b2) =>
+        val BagType(base) = b1.getType
+        FunctionInvocation(Union.typed(Seq(transform(base))), Seq(transform(b1), transform(b2))).copiedFrom(e)
+
+      case BagDifference(b1, b2) =>
+        val BagType(base) = b1.getType
+        FunctionInvocation(Difference.typed(Seq(transform(base))), Seq(transform(b1), transform(b2))).copiedFrom(e)
+
+      case Equals(b1, b2) if b1.getType.isInstanceOf[BagType] =>
+        val BagType(base) = b1.getType
+        FunctionInvocation(BagEquals.typed(Seq(transform(base))), Seq(transform(b1), transform(b2))).copiedFrom(e)
+
+      case _ => super.transform(e)
+    }
+
+    override def transform(tpe: TypeTree): TypeTree = tpe match {
+      case BagType(base) => Bag.typed(Seq(transform(base))).copiedFrom(tpe)
+      case _ => super.transform(tpe)
+    }
+  }
+
+  val decoder = new Decoder {
+    override def transform(e: Expr)(implicit binders: Map[Identifier, Identifier]): Expr = e match {
+      case cc @ CaseClass(CaseClassType(Bag, Seq(tpe)), args) =>
+        FiniteBag(args(0) match {
+          case FiniteLambda(mapping, dflt, tpe) =>
+            if (dflt != InfiniteIntegerLiteral(0))
+              throw new Unsupported(cc, "Bags can't have default value " + dflt.asString(ctx))(ctx)
+            mapping.map { case (ks, v) => transform(ks.head) -> transform(v) }.toMap
+
+          case Lambda(Seq(ValDef(id)), body) =>
+            def rec(expr: Expr): Map[Expr, Expr] = expr match {
+              case IfExpr(Equals(`id`, k), v, elze) => rec(elze) + (transform(k) -> transform(v))
+              case InfiniteIntegerLiteral(v) if v == 0 => Map.empty
+              case _ => throw new Unsupported(expr, "Bags can't have default value " + expr.asString(ctx))(ctx)
+            }
+
+            rec(body)
+
+          case f => scala.sys.error("Unexpected function " + f.asString(ctx))
+        }, transform(tpe)).copiedFrom(e)
+
+      case FunctionInvocation(TypedFunDef(Add, Seq(_)), Seq(bag, elem)) =>
+        BagAdd(transform(bag), transform(elem)).copiedFrom(e)
+
+      case FunctionInvocation(TypedFunDef(Get, Seq(_)), Seq(bag, elem)) =>
+        MultiplicityInBag(transform(elem), transform(bag)).copiedFrom(e)
+
+      case FunctionInvocation(TypedFunDef(Intersect, Seq(_)), Seq(b1, b2)) =>
+        BagIntersection(transform(b1), transform(b2)).copiedFrom(e)
+
+      case FunctionInvocation(TypedFunDef(Union, Seq(_)), Seq(b1, b2)) =>
+        BagUnion(transform(b1), transform(b2)).copiedFrom(e)
+
+      case FunctionInvocation(TypedFunDef(Difference, Seq(_)), Seq(b1, b2)) =>
+        BagDifference(transform(b1), transform(b2)).copiedFrom(e)
+
+      case FunctionInvocation(TypedFunDef(BagEquals, Seq(_)), Seq(b1, b2)) =>
+        Equals(transform(b1), transform(b2)).copiedFrom(e)
+
+      case _ => super.transform(e)
+    }
+
+    override def transform(tpe: TypeTree): TypeTree = tpe match {
+      case CaseClassType(Bag, Seq(base)) => BagType(transform(base)).copiedFrom(tpe)
+      case _ => super.transform(tpe)
+    }
+
+    override def transform(pat: Pattern): (Pattern, Map[Identifier, Identifier]) = pat match {
+      case CaseClassPattern(b, CaseClassType(Bag, Seq(tpe)), Seq(sub)) =>
+        throw new Unsupported(pat, "Can't translate Bag case class pattern")(ctx)
+      case _ => super.transform(pat)
+    }
+  }
 }
diff --git a/src/main/scala/leon/solvers/theories/StringEncoder.scala b/src/main/scala/leon/solvers/theories/StringEncoder.scala
index 8f33513a64898c17a7a4b2dfda13a037b2d93f5d..5af13c1c0e52e29d3f79654a6cbe30f009630d5d 100644
--- a/src/main/scala/leon/solvers/theories/StringEncoder.scala
+++ b/src/main/scala/leon/solvers/theories/StringEncoder.scala
@@ -10,114 +10,18 @@ import purescala.Constructors._
 import purescala.Types._
 import purescala.Definitions._
 import leon.utils.Bijection
-import leon.purescala.DefOps
 import leon.purescala.TypeOps
-import leon.purescala.Extractors.Operator
-import leon.evaluators.EvaluationResults
 
-object StringEcoSystem {
-  private def withIdentifier[T](name: String, tpe: TypeTree = Untyped)(f: Identifier => T): T = {
-    val id = FreshIdentifier(name, tpe)
-    f(id)
-  }
-
-  private def withIdentifiers[T](name: String, tpe: TypeTree, name2: String, tpe2: TypeTree = Untyped)(f: (Identifier, Identifier) => T): T = {
-    withIdentifier(name, tpe)(id => withIdentifier(name2, tpe2)(id2 => f(id, id2)))
-  }
-
-  val StringList = new AbstractClassDef(FreshIdentifier("StringList"), Seq(), None)
-  val StringListTyped = StringList.typed
-  val StringCons = withIdentifiers("head", CharType, "tail", StringListTyped){ (head, tail) =>
-    val d = new CaseClassDef(FreshIdentifier("StringCons"), Seq(), Some(StringListTyped), false)
-    d.setFields(Seq(ValDef(head), ValDef(tail)))
-    d
-  }
-
-  StringList.registerChild(StringCons)
-  val StringConsTyped = StringCons.typed
-  val StringNil  = new CaseClassDef(FreshIdentifier("StringNil"), Seq(), Some(StringListTyped), false)
-  val StringNilTyped = StringNil.typed
-  StringList.registerChild(StringNil)
-
-  val StringSize = withIdentifiers("l", StringListTyped, "StringSize"){ (lengthArg, id) =>
-    val fd = new FunDef(id, Seq(), Seq(ValDef(lengthArg)), IntegerType)
-    fd.body = Some(withIdentifiers("h", CharType, "t", StringListTyped){ (h, t) =>
-      MatchExpr(Variable(lengthArg), Seq(
-        MatchCase(CaseClassPattern(None, StringNilTyped, Seq()), None, InfiniteIntegerLiteral(BigInt(0))),  
-        MatchCase(CaseClassPattern(None, StringConsTyped, Seq(WildcardPattern(Some(h)), WildcardPattern(Some(t)))), None,
-            Plus(InfiniteIntegerLiteral(BigInt(1)), FunctionInvocation(fd.typed, Seq(Variable(t)))))
-      ))
-    })
-    fd
-  }
-
-  val StringListConcat = withIdentifiers("x", StringListTyped, "y", StringListTyped) { (x, y) =>
-    val fd = new FunDef(FreshIdentifier("StringListConcat"), Seq(), Seq(ValDef(x), ValDef(y)), StringListTyped)
-    fd.body = Some(
-        withIdentifiers("h", CharType, "t", StringListTyped){ (h, t) =>
-        MatchExpr(Variable(x), Seq(
-          MatchCase(CaseClassPattern(None, StringNilTyped, Seq()), None, Variable(y)),
-          MatchCase(CaseClassPattern(None, StringConsTyped, Seq(WildcardPattern(Some(h)), WildcardPattern(Some(t)))), None,
-              CaseClass(StringConsTyped, Seq(Variable(h), FunctionInvocation(fd.typed, Seq(Variable(t), Variable(y)))))
-          )))
-        }
-    )
-    fd
-  }
-
-  val StringTake = withIdentifiers("tt", StringListTyped, "it", StringListTyped) { (tt, it) =>
-    val fd = new FunDef(FreshIdentifier("StringTake"), Seq(), Seq(ValDef(tt), ValDef(it)), StringListTyped)
-    fd.body = Some{
-      withIdentifiers("h", CharType, "t", StringListTyped) { (h, t) =>
-        withIdentifier("i", IntegerType){ i =>
-        MatchExpr(Tuple(Seq(Variable(tt), Variable(it))), Seq(
-          MatchCase(TuplePattern(None, Seq(CaseClassPattern(None, StringNilTyped, Seq()), WildcardPattern(None))), None,
-              InfiniteIntegerLiteral(BigInt(0))),
-          MatchCase(TuplePattern(None, Seq(CaseClassPattern(None, StringConsTyped, Seq(WildcardPattern(Some(h)), WildcardPattern(Some(t)))), WildcardPattern(Some(i)))), None,
-              IfExpr(LessThan(Variable(i), InfiniteIntegerLiteral(BigInt(0))),
-                  CaseClass(StringNilTyped, Seq()),
-                  CaseClass(StringConsTyped, Seq(Variable(h),
-                      FunctionInvocation(fd.typed, Seq(Variable(t), Minus(Variable(i), InfiniteIntegerLiteral(BigInt(1)))))))
-          ))))
-        }
-      }
-    }
-    fd
-  }
-
-  val StringDrop = withIdentifiers("td", StringListTyped, "id", IntegerType) { (td, id) =>
-    val fd = new FunDef(FreshIdentifier("StringDrop"), Seq(), Seq(ValDef(td), ValDef(id)), StringListTyped)
-    fd.body = Some(
-      withIdentifiers("h", CharType, "t", StringListTyped) { (h, t) =>
-        withIdentifier("i", IntegerType){ i =>
-      MatchExpr(Tuple(Seq(Variable(td), Variable(id))), Seq(
-          MatchCase(TuplePattern(None, Seq(CaseClassPattern(None, StringNilTyped, Seq()), WildcardPattern(None))), None,
-              InfiniteIntegerLiteral(BigInt(0))),
-          MatchCase(TuplePattern(None, Seq(CaseClassPattern(None, StringConsTyped, Seq(WildcardPattern(Some(h)), WildcardPattern(Some(t)))), WildcardPattern(Some(i)))), None,
-              IfExpr(LessThan(Variable(i), InfiniteIntegerLiteral(BigInt(0))),
-                  CaseClass(StringConsTyped, Seq(Variable(h), Variable(t))),
-                  FunctionInvocation(fd.typed, Seq(Variable(t), Minus(Variable(i), InfiniteIntegerLiteral(BigInt(1)))))
-          ))))
-      }}
-    )
-    fd
-  }
-  
-  val StringSlice = withIdentifier("s", StringListTyped) { s => withIdentifiers("from", IntegerType, "to", IntegerType) { (from, to) =>
-    val fd = new FunDef(FreshIdentifier("StringSlice"), Seq(), Seq(ValDef(s), ValDef(from), ValDef(to)), StringListTyped)
-    fd.body = Some(
-        FunctionInvocation(StringTake.typed,
-            Seq(FunctionInvocation(StringDrop.typed, Seq(Variable(s), Variable(from))),
-                Minus(Variable(to), Variable(from)))))
-    fd
-  } }
-  
-  val classDefs = Seq(StringList, StringCons, StringNil)
-  val funDefs = Seq(StringSize, StringListConcat, StringTake, StringDrop, StringSlice)
-}
+class StringEncoder(ctx: LeonContext, p: Program) extends TheoryEncoder {
+  val String     = p.library.lookupUnique[ClassDef]("leon.theories.String").typed
+  val StringCons = p.library.lookupUnique[CaseClassDef]("leon.theories.StringCons").typed
+  val StringNil  = p.library.lookupUnique[CaseClassDef]("leon.theories.StringNil").typed
 
-class StringEncoder extends TheoryEncoder {
-  import StringEcoSystem._
+  val Size   = p.library.lookupUnique[FunDef]("leon.theories.String.size").typed
+  val Take   = p.library.lookupUnique[FunDef]("leon.theories.String.take").typed
+  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
 
   private val stringBijection = new Bijection[String, Expr]()
   
@@ -127,8 +31,8 @@ class StringEncoder extends TheoryEncoder {
   })
 
   private def convertFromString(v: String): Expr = stringBijection.cachedB(v) {
-    v.toList.foldRight(CaseClass(StringNilTyped, Seq())){
-      case (char, l) => CaseClass(StringConsTyped, Seq(CharLiteral(char), l))
+    v.toList.foldRight(CaseClass(StringNil, Seq())){
+      case (char, l) => CaseClass(StringCons, Seq(CharLiteral(char), l))
     }
   }
 
@@ -137,26 +41,26 @@ class StringEncoder extends TheoryEncoder {
       case StringLiteral(v)          =>
         convertFromString(v)
       case StringLength(a)           =>
-        FunctionInvocation(StringSize.typed, Seq(transform(a))).copiedFrom(e)
+        FunctionInvocation(Size, Seq(transform(a))).copiedFrom(e)
       case StringConcat(a, b)        =>
-        FunctionInvocation(StringListConcat.typed, Seq(transform(a), transform(b))).copiedFrom(e)
+        FunctionInvocation(Concat, Seq(transform(a), transform(b))).copiedFrom(e)
       case SubString(a, start, Plus(start2, length)) if start == start2  =>
-        FunctionInvocation(StringTake.typed, Seq(FunctionInvocation(StringDrop.typed, Seq(transform(a), transform(start))), transform(length))).copiedFrom(e)
+        FunctionInvocation(Take, Seq(FunctionInvocation(Drop, Seq(transform(a), transform(start))), transform(length))).copiedFrom(e)
       case SubString(a, start, end)  => 
-        FunctionInvocation(StringSlice.typed, Seq(transform(a), transform(start), transform(end))).copiedFrom(e)
+        FunctionInvocation(Slice, Seq(transform(a), transform(start), transform(end))).copiedFrom(e)
       case _ => super.transform(e)
     }
 
     override def transform(tpe: TypeTree): TypeTree = tpe match {
-      case StringType => StringListTyped
+      case StringType => String
       case _ => super.transform(tpe)
     }
 
     override def transform(pat: Pattern): (Pattern, Map[Identifier, Identifier]) = pat match {
       case LiteralPattern(binder, StringLiteral(s)) =>
         val newBinder = binder map transform
-        val newPattern = s.foldRight(CaseClassPattern(None, StringNilTyped, Seq())) {
-          case (elem, pattern) => CaseClassPattern(None, StringConsTyped, Seq(LiteralPattern(None, CharLiteral(elem)), pattern))
+        val newPattern = s.foldRight(CaseClassPattern(None, StringNil, Seq())) {
+          case (elem, pattern) => CaseClassPattern(None, StringCons, Seq(LiteralPattern(None, CharLiteral(elem)), pattern))
         }
         (newPattern.copy(binder = newBinder), (binder zip newBinder).filter(p => p._1 != p._2).toMap)
       case _ => super.transform(pat)
@@ -165,35 +69,42 @@ class StringEncoder extends TheoryEncoder {
 
   val decoder = new Decoder {
     override def transform(e: Expr)(implicit binders: Map[Identifier, Identifier]): Expr = e match {
-      case cc @ CaseClass(cct, args) if TypeOps.isSubtypeOf(cct, StringListTyped)=>
+      case cc @ CaseClass(cct, args) if TypeOps.isSubtypeOf(cct, String)=>
         StringLiteral(convertToString(cc)).copiedFrom(cc)
-      case FunctionInvocation(StringSize, Seq(a)) =>
+      case FunctionInvocation(Size, Seq(a)) =>
         StringLength(transform(a)).copiedFrom(e)
-      case FunctionInvocation(StringListConcat, Seq(a, b)) =>
+      case FunctionInvocation(Concat, Seq(a, b)) =>
         StringConcat(transform(a), transform(b)).copiedFrom(e)
-      case FunctionInvocation(StringTake, Seq(FunctionInvocation(StringDrop, Seq(a, start)), length)) =>
+      case FunctionInvocation(Slice, Seq(a, from, to)) =>
+        SubString(transform(a), transform(from), transform(to)).copiedFrom(e)
+      case FunctionInvocation(Take, Seq(FunctionInvocation(Drop, Seq(a, start)), length)) =>
         val rstart = transform(start)
         SubString(transform(a), rstart, plus(rstart, transform(length))).copiedFrom(e)
+      case FunctionInvocation(Take, Seq(a, length)) =>
+        SubString(transform(a), InfiniteIntegerLiteral(0), transform(length)).copiedFrom(e)
+      case FunctionInvocation(Drop, Seq(a, count)) =>
+        val ra = transform(a)
+        SubString(ra, transform(count), StringLength(ra)).copiedFrom(e)
       case _ => super.transform(e)
     }
 
 
     override def transform(tpe: TypeTree): TypeTree = tpe match {
-      case StringListTyped | StringConsTyped | StringNilTyped => StringType
+      case String | StringCons | StringNil => StringType
       case _ => super.transform(tpe)
     }
 
     override def transform(pat: Pattern): (Pattern, Map[Identifier, Identifier]) = pat match {
-      case CaseClassPattern(b, StringNilTyped, Seq()) =>
+      case CaseClassPattern(b, StringNil, Seq()) =>
         val newBinder = b map transform
         (LiteralPattern(newBinder , StringLiteral("")), (b zip newBinder).filter(p => p._1 != p._2).toMap)
 
-      case CaseClassPattern(b, StringConsTyped, Seq(LiteralPattern(_, CharLiteral(elem)), sub)) => transform(sub) match {
+      case CaseClassPattern(b, StringCons, Seq(LiteralPattern(_, CharLiteral(elem)), sub)) => transform(sub) match {
         case (LiteralPattern(_, StringLiteral(s)), binders) =>
           val newBinder = b map transform
           (LiteralPattern(newBinder, StringLiteral(elem + s)), (b zip newBinder).filter(p => p._1 != p._2).toMap ++ binders)
         case (e, binders) =>
-          (LiteralPattern(None, StringLiteral("Failed to parse pattern back as string:" + e)), binders)
+          throw new Unsupported(pat, "Failed to parse pattern back as string: " + e)(ctx)
       }
 
       case _ => super.transform(pat)
diff --git a/src/main/scala/leon/solvers/unrolling/UnrollingSolver.scala b/src/main/scala/leon/solvers/unrolling/UnrollingSolver.scala
index 852e125ed88db4327b18cfabc329d31e1366a2f6..403fb08fd20c9297b91cd6294cfc4a707e7ad40a 100644
--- a/src/main/scala/leon/solvers/unrolling/UnrollingSolver.scala
+++ b/src/main/scala/leon/solvers/unrolling/UnrollingSolver.scala
@@ -172,8 +172,12 @@ trait AbstractUnrollingSolver[T]
   trait ModelWrapper {
     def modelEval(elem: T, tpe: TypeTree): Option[Expr]
 
-    def eval(elem: T, tpe: TypeTree): Option[Expr] = modelEval(elem, theoryEncoder.encode(tpe)).map {
-      expr => theoryEncoder.decode(expr)(Map.empty)
+    def eval(elem: T, tpe: TypeTree): Option[Expr] = modelEval(elem, theoryEncoder.encode(tpe)).flatMap {
+      expr => try {
+        Some(theoryEncoder.decode(expr)(Map.empty))
+      } catch {
+        case u: Unsupported => None
+      }
     }
 
     def get(id: Identifier): Option[Expr] = eval(freeVars(id), theoryEncoder.encode(id.getType)).filter {
@@ -259,7 +263,9 @@ trait AbstractUnrollingSolver[T]
       var quantify = false
 
       def check[R](clauses: Seq[T])(block: Option[Boolean] => R) =
-        if (partialModels) solverCheckAssumptions(clauses)(block) else solverCheck(clauses)(block)
+        if (partialModels || templateGenerator.manager.quantifications.isEmpty)
+          solverCheckAssumptions(clauses)(block)
+        else solverCheck(clauses)(block)
 
       val timer = context.timers.solvers.check.start()
       check(encodedAssumptions.toSeq ++ unrollingBank.satisfactionAssumptions) { res =>
diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
index f8237a4885fdc459efe261bb4333afc36944b500..abf4c63d3d2c019a3a33e62fee88a5d663c4d1e8 100644
--- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
@@ -103,7 +103,7 @@ class FairZ3Solver(val context: LeonContext, val program: Program)
     def asString(implicit ctx: LeonContext) = z3.toString
   }
 
-  val theoryEncoder = new StringEncoder
+  val theoryEncoder = new StringEncoder(context, program) >> new BagEncoder(context, program)
 
   val templateEncoder = new TemplateEncoder[Z3AST] {
     def encodeId(id: Identifier): Z3AST = {
diff --git a/src/main/scala/leon/solvers/z3/Z3UnrollingSolver.scala b/src/main/scala/leon/solvers/z3/Z3UnrollingSolver.scala
index 99c75199a7d96b64ce42ba9039dd648032e60888..a1ed39dfe442044be38be88dac287cfd34aca391 100644
--- a/src/main/scala/leon/solvers/z3/Z3UnrollingSolver.scala
+++ b/src/main/scala/leon/solvers/z3/Z3UnrollingSolver.scala
@@ -10,4 +10,4 @@ import unrolling._
 import theories._
 
 class Z3UnrollingSolver(context: LeonContext, program: Program, underlying: Solver)
-  extends UnrollingSolver(context, program, underlying, theories = new StringEncoder)
+  extends UnrollingSolver(context, program, underlying, new StringEncoder(context, program))
diff --git a/src/main/scala/leon/termination/ChainBuilder.scala b/src/main/scala/leon/termination/ChainBuilder.scala
index 77b15659c3e2e7be97d36d9e5645af5daf9cfb58..daab94567d4ef6cb27f79d074ab58ea37d10a0b3 100644
--- a/src/main/scala/leon/termination/ChainBuilder.scala
+++ b/src/main/scala/leon/termination/ChainBuilder.scala
@@ -33,7 +33,7 @@ final case class Chain(relations: List[Relation]) {
     def rec(list: List[Relation], funDef: TypedFunDef, args: Seq[Expr]): Seq[(Seq[ValDef], Expr)] = list match {
       case Relation(_, _, fi @ FunctionInvocation(fitfd, nextArgs), _) :: xs =>
         val tfd = TypedFunDef(fitfd.fd, fitfd.tps.map(funDef.translated))
-        val subst = tfd.paramSubst(args)
+        val subst = funDef.paramSubst(args)
         val expr = replaceFromIDs(subst, hoistIte(expandLets(matchToIfThenElse(tfd.body.get))))
         val mappedArgs = nextArgs.map(e => replaceFromIDs(subst, tfd.translated(e)))
 
diff --git a/src/main/scala/leon/termination/StructuralSize.scala b/src/main/scala/leon/termination/StructuralSize.scala
index e075c374e8d4796680c940f3cf6e4d3ec455df79..e4b7d42139f5a921c23012c202c7d877422b1803 100644
--- a/src/main/scala/leon/termination/StructuralSize.scala
+++ b/src/main/scala/leon/termination/StructuralSize.scala
@@ -78,21 +78,25 @@ trait StructuralSize {
       }).foldLeft[Expr](InfiniteIntegerLiteral(0))(Plus)
       case IntegerType =>
         FunctionInvocation(typedAbsBigIntFun, Seq(expr)) 
+/*
+      case Int32Type =>
+        FunctionInvocation(typedAbsIntFun, Seq(expr))
+*/
       case _ => InfiniteIntegerLiteral(0)
     }
   }
 
   def lexicographicDecreasing(s1: Seq[Expr], s2: Seq[Expr], strict: Boolean, sizeOfOneExpr: Expr => Expr): Expr = {
     // Note: The Equal and GreaterThan ASTs work for both BigInt and Bitvector
-    
+
     val sameSizeExprs = for ((arg1, arg2) <- s1 zip s2) yield Equals(sizeOfOneExpr(arg1), sizeOfOneExpr(arg2))
-    
+
     val greaterBecauseGreaterAtFirstDifferentPos =
       orJoin(for (firstDifferent <- 0 until scala.math.min(s1.length, s2.length)) yield and(
           andJoin(sameSizeExprs.take(firstDifferent)),
           GreaterThan(sizeOfOneExpr(s1(firstDifferent)), sizeOfOneExpr(s2(firstDifferent)))
       ))
-      
+
     if (s1.length > s2.length || (s1.length == s2.length && !strict)) {
       or(andJoin(sameSizeExprs), greaterBecauseGreaterAtFirstDifferentPos)
     } else {
diff --git a/src/main/scala/leon/utils/Library.scala b/src/main/scala/leon/utils/Library.scala
index 18dc12938bd2dd55ff51e568e5af4bcd79cd245a..6bff50527120342bd5610c7e3ba9576a4bf2af95 100644
--- a/src/main/scala/leon/utils/Library.scala
+++ b/src/main/scala/leon/utils/Library.scala
@@ -7,6 +7,8 @@ import purescala.Definitions._
 import purescala.Types._
 import purescala.DefOps._
 
+import scala.reflect._
+
 case class Library(pgm: Program) {
   lazy val List = lookup("leon.collection.List").collectFirst { case acd : AbstractClassDef => acd }
   lazy val Cons = lookup("leon.collection.Cons").collectFirst { case ccd : CaseClassDef => ccd }
@@ -28,6 +30,13 @@ case class Library(pgm: Program) {
     pgm.lookupAll(name)
   }
 
+  def lookupUnique[D <: Definition : ClassTag](name: String): D = {
+    val ct = classTag[D]
+    val all = pgm.lookupAll(name).filter(d => ct.runtimeClass.isInstance(d))
+    assert(all.size == 1, "lookupUnique(\"name\") returned results " + all.map(_.id.uniqueName))
+    all.head.asInstanceOf[D]
+  }
+
   def optionType(tp: TypeTree) = AbstractClassType(Option.get, Seq(tp))
   def someType(tp: TypeTree) = CaseClassType(Some.get, Seq(tp))
   def noneType(tp: TypeTree) = CaseClassType(None.get, Seq(tp))
diff --git a/src/test/resources/regression/verification/purescala/valid/MergeSort2.scala b/src/test/resources/regression/verification/purescala/valid/MergeSort2.scala
new file mode 100644
index 0000000000000000000000000000000000000000..0bd0ab35ecaef991f618c0938f8446051eabf00e
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/MergeSort2.scala
@@ -0,0 +1,43 @@
+/* Copyright 2009-2016 EPFL, Lausanne */
+
+import leon.annotation._
+import leon.collection._
+import leon.lang._
+
+object MergeSort2 {
+
+  def bag[T](list: List[T]): Bag[T] = list match {
+    case Nil() => Bag.empty[T]
+    case Cons(x, xs) => bag(xs) + x
+  }
+
+  def isSorted(list: List[BigInt]): Boolean = list match {
+    case Cons(x1, tail @ Cons(x2, _)) => x1 <= x2 && isSorted(tail)
+    case _ => true
+  }
+
+  def merge(l1: List[BigInt], l2: List[BigInt]): List[BigInt] = {
+    require(isSorted(l1) && isSorted(l2))
+
+    (l1, l2) match {
+      case (Cons(x, xs), Cons(y, ys)) =>
+        if (x <= y) Cons(x, merge(xs, l2))
+        else Cons(y, merge(l1, ys))
+      case _ => l1 ++ l2
+    }
+  } ensuring (res => isSorted(res) && bag(res) == bag(l1) ++ bag(l2))
+
+  def split(list: List[BigInt]): (List[BigInt], List[BigInt]) = (list match {
+    case Cons(x1, Cons(x2, xs)) =>
+      val (s1, s2) = split(xs)
+      (Cons(x1, s1), Cons(x2, s2))
+    case _ => (list, Nil[BigInt]())
+  }) ensuring (res => bag(res._1) ++ bag(res._2) == bag(list))
+
+  def mergeSort(list: List[BigInt]): List[BigInt] = (list match {
+    case Cons(_, Cons(_, _)) =>
+      val (s1, s2) = split(list)
+      merge(mergeSort(s1), mergeSort(s2))
+    case _ => list
+  }) ensuring (res => isSorted(res) && bag(res) == bag(list))
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/Nested14.scala b/src/test/resources/regression/verification/purescala/valid/Nested14.scala
index 82f4fd1b965dc06c2458d237c84eb96d23ba8349..39e668aa208f1eeefd8257b359b3b5a5be51b39f 100644
--- a/src/test/resources/regression/verification/purescala/valid/Nested14.scala
+++ b/src/test/resources/regression/verification/purescala/valid/Nested14.scala
@@ -4,7 +4,11 @@ object Nested14 {
 
   def foo(i: Int): Int = {
     def rec1(j: Int): Int = {
-      def rec2(k: Int): Int = if(k == 0) 0 else rec1(j-1)
+      require(j >= 0)
+      def rec2(k: Int): Int = {
+        require(j > 0 || j == k)
+        if(k == 0) 0 else rec1(j-1)
+      }
       rec2(j)
     }
     rec1(3)
diff --git a/src/test/resources/regression/verification/purescala/valid/Nested16.scala b/src/test/resources/regression/verification/purescala/valid/Nested16.scala
new file mode 100644
index 0000000000000000000000000000000000000000..411e4a27f0fb918eba1cd5b8d31131f734d0142b
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/Nested16.scala
@@ -0,0 +1,17 @@
+/* Copyright 2009-2016 EPFL, Lausanne */
+
+object Nested16 {
+
+  def foo(i: BigInt): BigInt = {
+    def rec1(j: BigInt): BigInt = {
+      require(j >= 0)
+      def rec2(k: BigInt): BigInt = {
+        require(j > 0 || j == k)
+        if(k == 0) 0 else rec1(j-1)
+      }
+      rec2(j)
+    }
+    rec1(3)
+  } ensuring(0 == _)
+
+}
diff --git a/src/test/scala/leon/integration/evaluators/EvaluatorSuite.scala b/src/test/scala/leon/integration/evaluators/EvaluatorSuite.scala
index 5245c00c2b8147d62217d5d5bcecd89399427efe..bf828a9fb07ae255ad78c7ab71f3e76eb7cee02e 100644
--- a/src/test/scala/leon/integration/evaluators/EvaluatorSuite.scala
+++ b/src/test/scala/leon/integration/evaluators/EvaluatorSuite.scala
@@ -49,11 +49,30 @@ class EvaluatorSuite extends LeonTestSuiteWithProgram with ExpressionsDSL {
        |
        |  def finite() : Set[Int] = Set(1, 2, 3)
        |  def build(x : Int, y : Int, z : Int) : Set[Int] = Set(x, y, z)
+       |  def add(s1 : Set[Int], e: Int) : Set[Int] = s1 + e
        |  def union(s1 : Set[Int], s2 : Set[Int]) : Set[Int] = s1 ++ s2
        |  def inter(s1 : Set[Int], s2 : Set[Int]) : Set[Int] = s1 & s2
        |  def diff(s1 : Set[Int], s2 : Set[Int]) : Set[Int] = s1 -- s2
        |}""".stripMargin,
 
+    """|import leon.lang._
+       |object Bags {
+       |  sealed abstract class List
+       |  case class Nil() extends List
+       |  case class Cons(head : Int, tail : List) extends List
+       |
+       |  def content(l : List) : Bag[Int] = l match {
+       |    case Nil() => Bag.empty[Int]
+       |    case Cons(x, xs) => content(xs) + x
+       |  }
+       |
+       |  def finite() : Bag[Int] = Bag((1, 1), (2, 2), (3, 3))
+       |  def add(s1 : Bag[Int], e: Int) : Bag[Int] = s1 + e
+       |  def union(s1 : Bag[Int], s2 : Bag[Int]) : Bag[Int] = s1 ++ s2
+       |  def inter(s1 : Bag[Int], s2 : Bag[Int]) : Bag[Int] = s1 & s2
+       |  def diff(s1 : Bag[Int], s2 : Bag[Int]) : Bag[Int] = s1 -- s2
+       |}""".stripMargin,
+
     """|import leon.lang._
        |object Maps {
        |  sealed abstract class PList
@@ -295,6 +314,8 @@ class EvaluatorSuite extends LeonTestSuiteWithProgram with ExpressionsDSL {
       eval(e, fcall("Sets.content")(cons12))         === s12
       eval(e, fcall("Sets.build")(i(1), i(2), i(3))) === s123
       eval(e, fcall("Sets.build")(i(1), i(2), i(2))) === s12
+      eval(e, fcall("Sets.add")(s12, i(2)))          === s12
+      eval(e, fcall("Sets.add")(s12, i(3)))          === s123
       eval(e, fcall("Sets.union")(s123, s246))       === s12346
       eval(e, fcall("Sets.union")(s246, s123))       === s12346
       eval(e, fcall("Sets.inter")(s123, s246))       === s2
@@ -308,6 +329,39 @@ class EvaluatorSuite extends LeonTestSuiteWithProgram with ExpressionsDSL {
     }
   }
 
+  test("Bags") { implicit fix  =>
+    val nil = cc("Bags.Nil")()
+    def cons(es: Expr*) = cc("Bags.Cons")(es: _*)
+
+    val cons12 = cons(i(1), cons(i(2), nil))
+    val cons122 = cons(i(1), cons(i(2), cons(i(2), nil)))
+
+    def fb(is: (Int, Int)*) = FiniteBag(is.map(p => i(p._1) -> bi(p._2)).toMap, Int32Type)
+
+    val b12    = fb(1 -> 1, 2 -> 1)
+    val b123   = fb(1 -> 1, 2 -> 1, 3 -> 1)
+    val b246   = fb(2 -> 1, 4 -> 1, 6 -> 1)
+    val b1223  = fb(1 -> 1, 2 -> 2, 3 -> 1)
+
+    for(e <- allEvaluators) {
+      eval(e, fcall("Bags.finite")())                === fb(1 -> 1, 2 -> 2, 3 -> 3)
+      eval(e, fcall("Bags.content")(nil))            === fb()
+      eval(e, fcall("Bags.content")(cons12))         === fb(1 -> 1, 2 -> 1)
+      eval(e, fcall("Bags.content")(cons122))        === fb(1 -> 1, 2 -> 2)
+      eval(e, fcall("Bags.add")(b12, i(2)))          === fb(1 -> 1, 2 -> 2)
+      eval(e, fcall("Bags.add")(b12, i(3)))          === fb(1 -> 1, 2 -> 1, 3 -> 1)
+      eval(e, fcall("Bags.union")(b123, b246))       === fb(1 -> 1, 2 -> 2, 3 -> 1, 4 -> 1, 6 -> 1)
+      eval(e, fcall("Bags.union")(b246, b123))       === fb(1 -> 1, 2 -> 2, 3 -> 1, 4 -> 1, 6 -> 1)
+      eval(e, fcall("Bags.inter")(b123, b246))       === fb(2 -> 1)
+      eval(e, fcall("Bags.inter")(b246, b123))       === fb(2 -> 1)
+      eval(e, fcall("Bags.inter")(b1223, b123))      === b123
+      eval(e, fcall("Bags.diff")(b123, b246))        === fb(1 -> 1, 3 -> 1)
+      eval(e, fcall("Bags.diff")(b246, b123))        === fb(4 -> 1, 6 -> 1)
+      eval(e, fcall("Bags.diff")(b1223, b123))       === fb(2 -> 1)
+      eval(e, fcall("Bags.diff")(b123, b1223))       === fb()
+    }
+  }
+
   test("Maps") { implicit fix  =>
     val cons1223 = cc("Maps.PCons")(i(1), i(2), cc("Maps.PCons")(i(2), i(3), cc("Maps.PNil")()))
 
diff --git a/src/test/scala/leon/integration/solvers/SolversSuite.scala b/src/test/scala/leon/integration/solvers/SolversSuite.scala
index 8b0d8026e1540a170df577b3952140e4ef8fa910..f47f3c9b9e58f9eb44c601716d363cbeedc6b3d3 100644
--- a/src/test/scala/leon/integration/solvers/SolversSuite.scala
+++ b/src/test/scala/leon/integration/solvers/SolversSuite.scala
@@ -41,6 +41,7 @@ class SolversSuite extends LeonTestSuiteWithProgram {
     StringType,
     TypeParameter.fresh("T"),
     SetType(IntegerType),
+    BagType(IntegerType),
     MapType(IntegerType, IntegerType),
     FunctionType(Seq(IntegerType), IntegerType),
     TupleType(Seq(IntegerType, BooleanType, Int32Type))
@@ -54,6 +55,8 @@ class SolversSuite extends LeonTestSuiteWithProgram {
       Equals(v, simplestValue(v.getType))
     case SetType(base) =>
       Not(ElementOfSet(simplestValue(base), v))
+    case BagType(base) =>
+      Not(Equals(MultiplicityInBag(simplestValue(base), v), simplestValue(IntegerType)))
     case MapType(from, to) =>
       Not(Equals(MapApply(v, simplestValue(from)), simplestValue(to)))
     case FunctionType(froms, to) =>
diff --git a/src/test/scala/leon/regression/termination/TerminationSuite.scala b/src/test/scala/leon/regression/termination/TerminationSuite.scala
index 52984ac7a781fd1c8b4e058bbadd094337260f87..876ad77bde182b5fd380300a69b3963929eaee31 100644
--- a/src/test/scala/leon/regression/termination/TerminationSuite.scala
+++ b/src/test/scala/leon/regression/termination/TerminationSuite.scala
@@ -35,7 +35,8 @@ class TerminationSuite extends LeonRegressionSuite {
     val ignored = List(
       "termination/valid/NNF.scala",
       //"verification/purescala/valid/MergeSort.scala",
-      "verification/purescala/valid/Nested14.scala"
+      "verification/purescala/valid/Nested14.scala",
+      "verification/purescala/valid/MergeSort2.scala"
     )
 
     val t = if (ignored.exists(displayName.replaceAll("\\\\","/").endsWith)) {