diff --git a/src/multisets/ASTMapaFun.scala b/src/multisets/ASTMapaFun.scala
new file mode 100644
index 0000000000000000000000000000000000000000..74ed0240a1d0e69b8c704af374b30960329cb122
--- /dev/null
+++ b/src/multisets/ASTMapaFun.scala
@@ -0,0 +1,43 @@
+package mapaFun
+
+  sealed abstract class MAPAFunInt
+  case class MFIntVar(val i: String) extends MAPAFunInt
+  case class MFIntConst (val c: Int) extends MAPAFunInt
+  case class MFIPlus(val i1: MAPAFunInt, val i2: MAPAFunInt) extends MAPAFunInt
+  case class MFITimes(val c: Int, val i2: MAPAFunInt) extends MAPAFunInt
+  case class MFSCard(val s: MAPAFunSet) extends MAPAFunInt
+  case class MFMCard(val m: MAPAFunMultiset) extends MAPAFunInt
+
+  sealed abstract class MAPAFunMultiset
+  case class MFMSetVar(val m: String) extends MAPAFunMultiset
+  case object MFEmptyMSet extends MAPAFunMultiset
+  case class MFMUnion(val m1: MAPAFunMultiset, val m2: MAPAFunMultiset) extends MAPAFunMultiset
+  case class MFMIntersec(val m1: MAPAFunMultiset, val m2: MAPAFunMultiset) extends MAPAFunMultiset
+  case class MFMPlus(val m1: MAPAFunMultiset, val m2: MAPAFunMultiset) extends MAPAFunMultiset
+  case class MFMMinus(val m1: MAPAFunMultiset, val m2: MAPAFunMultiset) extends MAPAFunMultiset
+  case class MFSetMinus(val m1: MAPAFunMultiset, val m2: MAPAFunMultiset) extends MAPAFunMultiset
+  case class MFSSetOf(val m:MAPAFunMultiset) extends MAPAFunMultiset
+  case class MFFunction(val f: String, val s: MAPAFunSet) extends MAPAFunMultiset
+
+  sealed abstract class MAPAFunSet
+  case class MFSetVar(val s:String) extends MAPAFunSet
+  case object MFEmptySet extends MAPAFunSet
+  case object MFUnivSet extends MAPAFunSet
+  case class MFSUnion(val s1:MAPAFunSet, val s2:MAPAFunSet) extends MAPAFunSet
+  case class MFSIntersec(val s1:MAPAFunSet, val s2:MAPAFunSet) extends MAPAFunSet
+  case class MFSCompl(val s:MAPAFunSet) extends MAPAFunSet
+
+  sealed abstract class MAPAFunAtom
+  case class MFSetEqual(val s1:MAPAFunSet, val s2:MAPAFunSet) extends MAPAFunAtom
+  case class MFSetSubset(val s1:MAPAFunSet, val s2:MAPAFunSet) extends MAPAFunAtom
+  case class MFMSetEqual(val m1:MAPAFunMultiset, val m2:MAPAFunMultiset) extends MAPAFunAtom
+  case class MFMSetSubset(val m1:MAPAFunMultiset, val m2:MAPAFunMultiset) extends MAPAFunAtom
+  case class MFIntEqual(val i1:MAPAFunInt, val i2:MAPAFunInt) extends MAPAFunAtom
+  case class MFIntLessEqual(val i1:MAPAFunInt, val i2:MAPAFunInt) extends MAPAFunAtom
+  case class MFIntDivides(val c:Int, val i:MAPAFunInt) extends MAPAFunAtom
+
+  sealed abstract class MAPAFunFormula
+  case class MFAnd(val f1: MAPAFunFormula, val f2: MAPAFunFormula) extends MAPAFunFormula
+  case class MFOr(val f1: MAPAFunFormula, val f2: MAPAFunFormula) extends MAPAFunFormula
+  case class MFNot(val f: MAPAFunFormula) extends MAPAFunFormula
+  case class MFAtom(val a: MAPAFunAtom) extends MAPAFunFormula
diff --git a/src/multisets/ASTMultisets.scala b/src/multisets/ASTMultisets.scala
new file mode 100644
index 0000000000000000000000000000000000000000..891961b5002ee39598cc038c19edc9005f1a7d3c
--- /dev/null
+++ b/src/multisets/ASTMultisets.scala
@@ -0,0 +1,66 @@
+package multisets
+
+  sealed abstract class Multiset
+  case class MVariable(val v: String) extends Multiset
+  case object MEmpty extends Multiset
+  case class MUnion(val m1: Multiset, val m2: Multiset) extends Multiset
+  case class MIntersection(val m1: Multiset, val m2: Multiset) extends Multiset
+  case class MPlus(val m1: Multiset, val m2: Multiset) extends Multiset
+  case class MMinus(val m1: Multiset, val m2: Multiset) extends Multiset
+  case class MSetMinus(val m1: Multiset, val m2: Multiset) extends Multiset
+  case class MSetOf(val m: Multiset) extends Multiset
+
+  sealed abstract class TermIn
+  case class TIMultiplicity(val v: String) extends TermIn
+  case class TIConstant(val c: Int) extends TermIn
+  case class TIPlus(val t1: TermIn, val t2: TermIn) extends TermIn
+  case class TITimes(val c: Int, val t: TermIn) extends TermIn
+  case class TIIte(val f: FormulaIn, val t1: TermIn, val t2: TermIn) extends TermIn
+
+  sealed abstract class AtomIn
+  case class AILeq(val t1: TermIn, t2: TermIn) extends AtomIn
+  case class AIEq(val t1: TermIn, t2: TermIn) extends AtomIn
+
+  sealed abstract class FormulaIn
+  case class FIAtom(val a: AtomIn) extends FormulaIn
+  case class FIAnd(val f1: FormulaIn, val f2: FormulaIn) extends FormulaIn
+  case class FIOr(val f1: FormulaIn, val f2: FormulaIn) extends FormulaIn
+  case class FINot(val f: FormulaIn) extends FormulaIn
+  case object FITrue extends FormulaIn
+  case object FIFalse extends FormulaIn
+
+
+  sealed abstract class TermOut
+  case class TOConstant(val c: Int) extends TermOut
+  case class TOVariable(val v: String) extends TermOut
+  case class TOCard(val m: Multiset) extends TermOut
+  case class TOPlus(val t1: TermOut, val t2: TermOut) extends TermOut
+  case class TOTimes(val c: Int, val t: TermOut) extends TermOut
+  case class TOIte(val f: FormulaOut, val t1: TermOut, val t2: TermOut) extends TermOut
+
+  sealed abstract class AtomOut
+  case class AOLeq(val t1: TermOut, t2: TermOut) extends AtomOut
+  case class AOEq(val t1: TermOut, t2: TermOut) extends AtomOut
+  case class AOSum(val v1: List[TermOut], val f: FormulaIn, val v2: List[TermIn]) extends AtomOut
+
+  sealed abstract class FormulaOut
+  case class FOAtom(val a: AtomOut) extends FormulaOut
+  case class FOAnd(val f1: FormulaOut, val f2: FormulaOut) extends FormulaOut
+  case class FOOr(val f1: FormulaOut, val f2: FormulaOut) extends FormulaOut
+  case class FONot(val f: FormulaOut) extends FormulaOut
+  case object FOTrue extends FormulaOut
+  case object FOFalse extends FormulaOut
+
+  sealed abstract class Atom
+  case class AEqual(val m1:Multiset, val m2:Multiset) extends Atom
+  case class ASubset(val m1:Multiset, val m2:Multiset) extends Atom
+  case class AForAllElem(val f:FormulaIn) extends Atom
+  case class AAtomOut(val a:AtomOut) extends Atom
+
+  sealed abstract class Formula
+  case class FAnd(val f1: Formula, val f2: Formula) extends Formula
+  case class FOr(val f1: Formula, val f2: Formula) extends Formula
+  case class FNot(val f: Formula) extends Formula
+  case class FAtom(val a: Atom) extends Formula
+  case object FTrue extends Formula
+  case object FFalse extends Formula
diff --git a/src/multisets/ASTStars.scala b/src/multisets/ASTStars.scala
new file mode 100644
index 0000000000000000000000000000000000000000..81fcd4be953d81942099be0b4f9e285945c072d2
--- /dev/null
+++ b/src/multisets/ASTStars.scala
@@ -0,0 +1,23 @@
+package multisets
+
+  sealed abstract class TermQFPA
+  case class TVariable(val v: String) extends TermQFPA
+  case class TConstant(val c: Int) extends TermQFPA
+  case class TPlus(val t1: TermQFPA, val t2: TermQFPA) extends TermQFPA
+  case class TTimes(val c: Int, val t: TermQFPA) extends TermQFPA
+  case class TIte(val f: QFPAFormula, val t1: TermQFPA, val t2: TermQFPA) extends TermQFPA
+
+  sealed abstract class AtomQFPA
+  case class ALeq(val t1: TermQFPA, val t2: TermQFPA) extends AtomQFPA
+  case class AEq(val t1: TermQFPA, val t2: TermQFPA) extends AtomQFPA
+
+  sealed abstract class QFPAFormula
+  case class QFPAAnd(val f1: QFPAFormula, val f2: QFPAFormula) extends QFPAFormula
+  case class QFPAOr(val f1: QFPAFormula, val f2: QFPAFormula) extends QFPAFormula
+  case class QFPANot(val f: QFPAFormula) extends QFPAFormula
+  case class QFPAAtom(val a: AtomQFPA) extends QFPAFormula
+  case object QFPAFalse extends QFPAFormula
+  case object QFPATrue extends QFPAFormula
+
+  // f1 & l1 \in {l2 | f2}*
+  case class StarFormula(val f1: QFPAFormula, val l1: List[TermQFPA], val l2: List[TermQFPA], val f2: QFPAFormula)
diff --git a/src/multisets/BuildingModels.scala b/src/multisets/BuildingModels.scala
new file mode 100644
index 0000000000000000000000000000000000000000..b9e050953f4151127dc4203f6c888ceeca35ce8f
--- /dev/null
+++ b/src/multisets/BuildingModels.scala
@@ -0,0 +1,355 @@
+package multisets
+
+
+import scala.collection.mutable.Map
+import java.lang.Integer
+
+
+
+object reconstructingModels {
+
+  def addNewValuestoMap(l:List[String], i: Int, m: Map[String, Int]): Map[String, Int] = {
+    var mt = m
+    l.foreach(s => mt += (s -> i))
+    mt
+  }
+
+  def getIntValueFromString(s: String): Int = {
+   val s1 = s.replaceAll(":int", "")
+   val n = Integer.parseInt(s1)
+   n
+  }
+
+  def getAllVariablesFromString(s: String): List[String] = {
+    val i1 = s.indexOf('{') 
+    val i2 = s.indexOf('}')
+    val s1 = s.substring(i1 + 1, i2)
+    val vars = s1.split(" ")
+    val l1 = vars.toList 
+    l1
+  }
+
+
+  def extractModelAndAddtoMap(s: String, m: Map[String, Int]): Map[String, Int] = {
+    if (s.startsWith("*"))  {
+      val strings = s.split (" -> ");
+      val l = getAllVariablesFromString(strings(0))
+      val n = getIntValueFromString(strings(1))
+      val m1 = addNewValuestoMap(l, n, m)
+      m1
+    } else m
+  }
+
+  def createSatisfyingAssignmentforQFPA(ls: List[String]): Map[String, Int] = {
+    var tm = Map[String, Int]()
+    ls.foreach(s => {
+       tm = extractModelAndAddtoMap(s, tm)
+    })
+    tm
+  }
+
+// ======================
+
+
+  def replaceVectorsStartingWithSomeStringWithValuesinTerm(t: TermQFPA, m: Map[String, Int], s: String): TermQFPA = t match {
+    case TConstant(c) => t
+    case TVariable(v) => {
+      if (v.contains(s)) {
+        val nv = m(v)
+        TConstant(nv)
+      } else t
+    }
+    case TPlus(t1, t2) => {
+      val t1n = replaceVectorsStartingWithSomeStringWithValuesinTerm(t1, m, s)
+      val t2n = replaceVectorsStartingWithSomeStringWithValuesinTerm(t2, m, s)
+      TPlus(t1n, t2n)
+    }
+    case TTimes(c, t1) => {
+      val t1n = replaceVectorsStartingWithSomeStringWithValuesinTerm(t1, m, s)
+      TTimes(c, t1n)
+    }
+    case TIte(f, t1, t2) => {
+      val fn = replaceVectorsStartingWithSomeStringWithValues(f, m, s)
+      val t1n = replaceVectorsStartingWithSomeStringWithValuesinTerm(t1, m, s)
+      val t2n = replaceVectorsStartingWithSomeStringWithValuesinTerm(t2, m, s)
+      TIte(fn, t1n, t2n)
+    }
+  }
+
+
+  def replaceVectorsStartingWithSomeStringWithValuesinAtom(a: AtomQFPA, m: Map[String, Int], s: String): AtomQFPA = a match {
+    case ALeq(t1,t2) => {
+      val t1n = replaceVectorsStartingWithSomeStringWithValuesinTerm(t1, m, s)
+      val t2n = replaceVectorsStartingWithSomeStringWithValuesinTerm(t2, m, s)
+      ALeq(t1n, t2n)
+    }
+    case AEq(t1,t2) => {
+      val t1n = replaceVectorsStartingWithSomeStringWithValuesinTerm(t1, m, s)
+      val t2n = replaceVectorsStartingWithSomeStringWithValuesinTerm(t2, m, s)
+      AEq(t1n, t2n)
+    }
+  }
+
+  def replaceVectorsStartingWithSomeStringWithValues(f: QFPAFormula, m: Map[String, Int], s: String): QFPAFormula = f match {
+    case QFPAAnd(f1,f2) => {
+      val f1n = replaceVectorsStartingWithSomeStringWithValues(f1, m, s)
+      val f2n = replaceVectorsStartingWithSomeStringWithValues(f2, m, s)
+      QFPAAnd(f1n, f2n)
+    }
+    case QFPAOr(f1,f2) => {
+      val f1n = replaceVectorsStartingWithSomeStringWithValues(f1, m, s)
+      val f2n = replaceVectorsStartingWithSomeStringWithValues(f2, m, s)
+      QFPAOr(f1n, f2n)
+    }
+    case QFPANot(f1)  => {
+      val f1n = replaceVectorsStartingWithSomeStringWithValues(f1, m, s)
+      QFPANot(f1n)
+    }
+    case QFPAAtom(a)  => {
+      val a1 = replaceVectorsStartingWithSomeStringWithValuesinAtom(a, m, s)
+      QFPAAtom(a1)
+    }
+    case QFPAFalse => f
+    case QFPATrue  => f
+  }
+
+  def isNumericalTerm(t: TermQFPA): (Boolean, Int) = t match {
+    case TConstant(c) => (true, c)
+    case TVariable(v) => (false, 0)
+    case TPlus(t1, t2) => {
+      val (b1, c1) = isNumericalTerm(t1)
+      val (b2, c2) = isNumericalTerm(t2)
+      (b1 && b2, c1 + c2)
+    }
+    case TTimes(c, t1) => {
+      val (b1, c1) = isNumericalTerm(t1)
+      (b1, c * c1)
+    }
+    case TIte(f, t1, t2) => {
+      val f1 = evaluatePureNumericalExpressions(f)
+      val (b1, c1) = isNumericalTerm(t1)
+      val (b2, c2) = isNumericalTerm(t2)
+      val f2 = evaluatePureBooleanExpressions(f1)
+      if (f2 == QFPATrue) (b1, c1) else 
+        if (f2 == QFPANot(QFPATrue)) (b2, c2) else
+          (false, 0)
+    }
+  }
+
+  def evaluatePureNumericalExpressioninTerm(t: TermQFPA): TermQFPA = t match {
+    case TConstant(c) => t
+    case TVariable(v) => t
+    case TPlus(t1, t2) => {
+      val t1n = evaluatePureNumericalExpressioninTerm(t1)
+      val t2n = evaluatePureNumericalExpressioninTerm(t2)
+      val (b1, c1) = isNumericalTerm(t1n)
+      val (b2, c2) = isNumericalTerm(t2n)
+      if (b1 && b2) {
+        val c = c1 + c2
+        TConstant(c)
+      } else { if (b1 && c1 == 0) t2n
+          else if (b2 && c2 == 0) t1n else TPlus(t1n, t2n)
+      }
+    }
+    case TTimes(c, t1) => {
+      val t1n = evaluatePureNumericalExpressioninTerm(t1)
+      val (b1, c1) = isNumericalTerm(t1n)
+      if (b1) {
+        val cf = c * c1
+        TConstant(cf)
+      } else TTimes(c, t1n)
+    }
+    case TIte(f, t1, t2) => {
+      val f1 = evaluatePureNumericalExpressions(f)
+      val t1n = evaluatePureNumericalExpressioninTerm(t1)
+      val t2n = evaluatePureNumericalExpressioninTerm(t2)
+      val f2 = evaluatePureBooleanExpressions(f1)
+      if (f2 == QFPATrue) t1n else 
+        if (f2 == QFPANot(QFPATrue)) t2n else
+          TIte(f2, t1n, t2n)
+    }
+  }
+
+  def evaluatePureNumericalExpressioninAtom(a: AtomQFPA): AtomQFPA = a match {
+    case ALeq(t1,t2) => {
+      val t1n = evaluatePureNumericalExpressioninTerm(t1)
+      val t2n = evaluatePureNumericalExpressioninTerm(t2)
+      ALeq(t1n, t2n)
+    }
+    case AEq(t1,t2) => {
+      val t1n = evaluatePureNumericalExpressioninTerm(t1)
+      val t2n = evaluatePureNumericalExpressioninTerm(t2)
+      AEq(t1n, t2n)
+    }
+  }
+
+  def evaluatePureNumericalExpressions(f: QFPAFormula): QFPAFormula = f match {
+    case QFPAAnd(f1,f2) => {
+      val f1n = evaluatePureNumericalExpressions(f1)
+      val f2n = evaluatePureNumericalExpressions(f2)
+      QFPAAnd(f1n, f2n)
+    }
+    case QFPAOr(f1,f2) => {
+      val f1n = evaluatePureNumericalExpressions(f1)
+      val f2n = evaluatePureNumericalExpressions(f2)
+      QFPAOr(f1n, f2n)
+    }
+    case QFPANot(f1)  => {
+      val f1n = evaluatePureNumericalExpressions(f1)
+      QFPANot(f1n)
+    }
+    case QFPAAtom(a)  => {
+      val a1 = evaluatePureNumericalExpressioninAtom(a)
+      QFPAAtom(a1)
+    }
+    case QFPAFalse => f
+    case QFPATrue  => f
+  }
+
+
+
+  def evaluatePureBooleanExpressionsinAtom(a: AtomQFPA): QFPAFormula = a match {
+    case ALeq(t1, t2) => {
+      if (t1 == t2) QFPATrue else {
+        val (b1, c1) = isNumericalTerm(t1)
+        val (b2, c2) = isNumericalTerm(t2)
+        if (b1 && b2) {
+          if (c1 <= c2) QFPATrue else QFPANot(QFPATrue)
+        } else QFPAAtom(a)
+      }
+    }
+    case AEq(t1,t2) => {
+      if (t1 == t2) QFPATrue else {
+        val (b1, c1) = isNumericalTerm(t1)
+        val (b2, c2) = isNumericalTerm(t2)
+        if (b1 && b2) {
+          if (c1 == c2) QFPATrue else QFPANot(QFPATrue)
+        } else QFPAAtom(a)
+      }
+    }
+  }
+
+
+  def evaluatePureBooleanExpressions(f: QFPAFormula): QFPAFormula = f match {
+    case QFPAAnd(f1,f2) => {
+      val f1n = evaluatePureBooleanExpressions(f1)
+      val f2n = evaluatePureBooleanExpressions(f2)
+      if (f1n == QFPANot(QFPATrue) || f2n == QFPANot(QFPATrue)) QFPANot(QFPATrue) else
+        if (f1n == QFPATrue) f2n else
+          if (f2n == QFPATrue) f1n else
+            QFPAAnd(f1n, f2n)
+    }
+    case QFPAOr(f1,f2) => {
+      val f1n = evaluatePureBooleanExpressions(f1)
+      val f2n = evaluatePureBooleanExpressions(f2)
+      if (f1n == QFPATrue || f2n == QFPATrue) QFPATrue else
+        if (f1n == QFPANot(QFPATrue)) f2n else
+          if (f2n == QFPANot(QFPATrue)) f1n else
+            QFPAOr(f1n, f2n)
+    }
+    case QFPANot(f1)  => {
+      val f1n = evaluatePureBooleanExpressions(f1)
+      val f2n = f1n match {
+        case QFPANot(f3n) => f3n
+        case _ => QFPANot(f1n)
+      }
+      f2n
+    }
+    case QFPAAtom(a)  => evaluatePureBooleanExpressionsinAtom(a)
+    case QFPAFalse => f
+    case QFPATrue  => f
+  }
+
+
+  def simplifyArithmeticExpressionsInQFPA(f: QFPAFormula): QFPAFormula = {
+    val f1 = evaluatePureNumericalExpressions(f)
+    val f2 = evaluatePureBooleanExpressions(f1)
+    f2
+ }
+
+
+  def evaluateFormulaForVariablesStartingWith(f: QFPAFormula, m: Map[String, Int], s: String): QFPAFormula = {
+    val f1 = replaceVectorsStartingWithSomeStringWithValues(f, m, s)
+    val f2 = simplifyArithmeticExpressionsInQFPA(f1)
+    f2
+  }
+
+
+// ===========================
+
+  def deriveValueofVarTermInModel(t: TermQFPA, m: Map[String, Int]): Int  = t match {
+    case TConstant(c) => c
+    case TVariable(v) => m(v)
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def isNulVectorinGivenModel(t: List[TermQFPA], m: Map[String, Int]): Boolean = {
+    val t1 = t.map(tm => deriveValueofVarTermInModel(tm, m))
+    t1.forall(tm => (tm == 0))
+  }
+
+
+
+  def replaceAllTermsWithZeroinTerm(t: TermQFPA, l: List[TermQFPA]): TermQFPA = t match {
+    case TConstant(c) => t
+    case TVariable(v) => if (l.contains(t)) TConstant(0) else t
+    case TPlus(t1, t2) => {
+      val t1n = replaceAllTermsWithZeroinTerm(t1, l)
+      val t2n = replaceAllTermsWithZeroinTerm(t2, l)
+      TPlus(t1n, t2n)
+    }
+    case TTimes(c, t1) => {
+      val t1n = replaceAllTermsWithZeroinTerm(t1, l)
+      TTimes(c, t1n)
+    }
+    case TIte(f, t1, t2) => {
+      val fn = replaceAllTermsWithZero(f, l)
+      val t1n = replaceAllTermsWithZeroinTerm(t1, l)
+      val t2n = replaceAllTermsWithZeroinTerm(t2, l)
+      TIte(fn, t1n, t2n)
+    }
+  }
+
+  def replaceAllTermsWithZeroinAtom(a: AtomQFPA, t: List[TermQFPA]): AtomQFPA = a match {
+    case ALeq(t1,t2) => {
+      val t1n =  replaceAllTermsWithZeroinTerm(t1, t)
+      val t2n =  replaceAllTermsWithZeroinTerm(t2, t)
+      ALeq(t1n, t2n)
+    }
+    case AEq(t1,t2) => {
+      val t1n =  replaceAllTermsWithZeroinTerm(t1, t)
+      val t2n =  replaceAllTermsWithZeroinTerm(t2, t)
+      AEq(t1n, t2n)
+    }
+  }
+
+  def replaceAllTermsWithZero(f: QFPAFormula, t: List[TermQFPA]): QFPAFormula = f match {
+    case QFPAAnd(f1,f2) => {
+      val f1n = replaceAllTermsWithZero(f1, t)
+      val f2n = replaceAllTermsWithZero(f2, t)
+      QFPAAnd(f1n, f2n)
+    }
+    case QFPAOr(f1,f2) => {
+      val f1n = replaceAllTermsWithZero(f1, t)
+      val f2n = replaceAllTermsWithZero(f2, t)
+      QFPAOr(f1n, f2n)
+    }
+    case QFPANot(f1)  => {
+      val f1n = replaceAllTermsWithZero(f1, t)
+      QFPANot(f1n)
+    }
+    case QFPAAtom(a)  => {
+      val a1 = replaceAllTermsWithZeroinAtom(a, t)
+      QFPAAtom(a1)
+    }
+    case QFPAFalse => f
+    case QFPATrue  => f
+  }
+
+  def removeZeroVectorInFormula(f: QFPAFormula, t: List[TermQFPA]): QFPAFormula = {
+    val f1 = replaceAllTermsWithZero(f, t)
+    val f2 = simplifyArithmeticExpressionsInQFPA(f1) 
+    f2
+  }
+}
+
diff --git a/src/multisets/CheckingConsistency.scala b/src/multisets/CheckingConsistency.scala
new file mode 100644
index 0000000000000000000000000000000000000000..da91e6457bb711fbdddce42ff0de6a3ba906d351
--- /dev/null
+++ b/src/multisets/CheckingConsistency.scala
@@ -0,0 +1,357 @@
+package multisets
+import scala.collection.mutable.Map
+import scala.collection.mutable.Set
+//import java.io._
+
+import z3.scala._
+
+object CheckingConsistency {
+
+
+
+
+/*
+
+
+
+  def createVariableString(va:Array[String]):String = {
+   var s = ""
+   va.foreach(v => s = s + "(" + v + " Int) ")
+   s
+  }
+
+
+  def createSMTRepresentationOfTerm(t:TermQFPA):String = t match {
+    case TVariable(v) => v
+    case TConstant(c) =>  c.toString
+    case TPlus(t1, t2) => {
+      val s1 = createSMTRepresentationOfTerm(t1)
+      val s2 = createSMTRepresentationOfTerm(t2)
+      "(+ " + s1 + " " + s2 + ")"
+    }
+    case TTimes(c, t1) => {
+      val s1 = createSMTRepresentationOfTerm(t1)
+      "(* " + c.toString + " " + s1 + ")"
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def createSMTRepresentationOfAtom(a:AtomQFPA):String = a match {
+    case ALeq(t1, t2) => {
+      val s1 = createSMTRepresentationOfTerm(t1)
+      val s2 = createSMTRepresentationOfTerm(t2)
+      "(<= " + s1 + " " + s2 + ")"
+    }
+    case AEq(t1, t2) => {
+      val s1 = createSMTRepresentationOfTerm(t1)
+      val s2 = createSMTRepresentationOfTerm(t2)
+      "(= " + s1 + " " + s2 + ")"
+    }
+  }
+
+  def createSMTRepresentationOfFormula(f:QFPAFormula):String = {
+    val s = f match {
+      case QFPAAnd(f1, f2) => {
+        val s1 = createSMTRepresentationOfFormula(f1)
+        val s2 = createSMTRepresentationOfFormula(f2)
+        "and " + s1 + " " + s2
+      }
+      case QFPAOr(f1, f2) => {
+        val s1 = createSMTRepresentationOfFormula(f1)
+        val s2 = createSMTRepresentationOfFormula(f2)
+        "or " + s1 + " " + s2
+      }
+      case QFPANot(f1) => {
+        val s1 = createSMTRepresentationOfFormula(f1)
+        "not " + s1
+      }
+      case QFPAAtom(a) => createSMTRepresentationOfAtom(a)
+      case _ => " "
+    }
+    "( " + s + " )"
+  }
+
+
+  def callZ3toDetermineConsistency(c:List[QFPAFormula]):String = {
+    val smtfile = File.createTempFile("iteremove", ".smt");
+    val smtfileName = smtfile.getAbsolutePath
+
+    val vars = getAllVariablesFromListofFormulas(c)
+    val s1 = createVariableString(vars)
+
+    val out = new BufferedWriter(new FileWriter(smtfile))
+    out.write("(benchmark example")
+    out.newLine()
+    out.write(":logic QF_LIA")
+    out.newLine()
+    out.write(":extrafuns (")
+    out.write(s1)
+    out.write(")")
+    out.newLine()
+    out.write(":formula (and")
+    out.newLine()
+    vars.foreach (v => {
+      out.write("(<=  0 " + v + " )" )
+      out.newLine()
+    })
+    c.foreach(g => {
+      val sg = createSMTRepresentationOfFormula(g)
+      out.write(sg)
+      out.newLine()
+    })
+    out.write(")")
+    out.newLine()
+    out.write(")")
+    out.newLine()
+    out.close
+
+    val cmd =  Array("z3.exe.linux", smtfileName)
+    val p: Process = Runtime.getRuntime.exec(cmd)
+    val input: BufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()))
+    val line: String = input.readLine
+    p.waitFor
+    input.close
+
+    smtfile.deleteOnExit
+    line
+  }
+
+
+  def checkConsistencyofOneFormula(f:QFPAFormula): List[String] = {
+    val smtfile = File.createTempFile("finalFormula", ".smt");
+    val smtfileName = smtfile.getAbsolutePath
+
+    val vars = getAllVariablesFromOneFormula(f)
+    val s1 = createVariableString(vars)
+
+    val out = new BufferedWriter(new FileWriter(smtfile))
+    out.write("(benchmark example")
+    out.newLine()
+    out.write(":logic QF_LIA")
+    out.newLine()
+    out.write(":extrafuns (")
+    out.write(s1)
+    out.write(")")
+    out.newLine()
+    out.write(":formula (and")
+    out.newLine()
+    vars.foreach (v => {
+      out.write("(<=  0 " + v + " )" )
+      out.newLine()
+    })
+    val sg = createSMTRepresentationOfFormula(f)
+    out.write(sg)
+    out.newLine()
+    out.write(")")
+    out.newLine()
+    out.write(")")
+    out.newLine()
+    out.close
+
+    val cmd =  Array("z3", "-m", smtfileName)
+    val p: Process = Runtime.getRuntime.exec(cmd)
+    val input: BufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()))
+    var line = input.readLine()
+    var l: List[String] = Nil
+    while (line != null) {
+      l = line :: l
+      line = input.readLine()
+    }
+    p.waitFor
+    input.close
+
+    smtfile.deleteOnExit
+    l
+  }  */
+
+
+// start: getting out all variables
+
+  def getAllVariablesAndConstsFromTerm(t:TermQFPA):(Set[String], Set[Int]) = t match {
+    case TVariable(v) => (Set(v), Set[Int]())
+    case TConstant(c) =>  (Set[String](), Set(c))
+    case TPlus(t1, t2) => {
+      val p1 = getAllVariablesAndConstsFromTerm(t1)
+      val p2 = getAllVariablesAndConstsFromTerm(t2)
+      (p1._1 ++ p2._1, p1._2 ++ p2._2)
+    }
+    case TTimes(c, t1) => {
+      val p1 = getAllVariablesAndConstsFromTerm(t1)
+      (p1._1, p1._2 ++ Set(c))
+    }
+    case TIte(f, t1, t2) => {
+      val p0 = getAllVariablesAndConstsFromFormula(f)
+      val p1 = getAllVariablesAndConstsFromTerm(t1)
+      val p2 = getAllVariablesAndConstsFromTerm(t2)
+      (p0._1 ++ p1._1 ++ p2._1, p0._2 ++ p1._2 ++ p2._2)
+    }
+  }
+
+  def getAllVariablesAndConstsFromAtom(a:AtomQFPA):(Set[String], Set[Int]) = a match {
+    case ALeq(t1, t2) => {
+      val p1 = getAllVariablesAndConstsFromTerm(t1)
+      val p2 = getAllVariablesAndConstsFromTerm(t2)
+      (p1._1 ++ p2._1, p1._2 ++ p2._2)
+    }
+    case AEq(t1, t2) => {
+      val p1 = getAllVariablesAndConstsFromTerm(t1)
+      val p2 = getAllVariablesAndConstsFromTerm(t2)
+      (p1._1 ++ p2._1, p1._2 ++ p2._2)
+    }
+  }
+
+  def getAllVariablesAndConstsFromFormula(f:QFPAFormula):(Set[String], Set[Int]) = f match {
+    case QFPAAnd(f1, f2) => {
+      val p1 = getAllVariablesAndConstsFromFormula(f1)
+      val p2 = getAllVariablesAndConstsFromFormula(f2)
+      (p1._1 ++ p2._1, p1._2 ++ p2._2)
+    }
+    case QFPAOr(f1, f2) => {
+      val p1 = getAllVariablesAndConstsFromFormula(f1)
+      val p2 = getAllVariablesAndConstsFromFormula(f2)
+      (p1._1 ++ p2._1, p1._2 ++ p2._2)
+    }
+    case QFPANot(f1) => getAllVariablesAndConstsFromFormula(f1)
+    case QFPAAtom(a) => getAllVariablesAndConstsFromAtom(a)
+    case QFPAFalse => (Set[String](), Set[Int]())
+    case QFPATrue => (Set[String](), Set[Int]())
+  }
+
+
+  def getAllVariablesAndConstsFromListofFormulas(c:List[QFPAFormula]): (Set[String], Set[Int]) = {
+    var p = (Set[String](), Set[Int]())
+    c.foreach(g => {
+      val p1 = getAllVariablesAndConstsFromFormula(g)
+      p = (p._1 ++ p1._1, p._2 ++ p1._2) 
+    })
+    p
+  }
+
+// end
+
+
+
+  def mkASTTerm(t:TermQFPA, s: Z3Sort, z3: Z3Context): (Z3AST, Z3Sort, Z3Context) = t match {
+    case TConstant(c) => (z3.mkInt(c, s), s, z3)
+    case TVariable(v) => (z3.mkConst(z3.mkStringSymbol(v), s), s, z3)
+    case TPlus(t1, t2) =>  {
+      val t1N = mkASTTerm(t1, s, z3)._1
+      val t2N = mkASTTerm(t2, s, z3)._1
+      (z3.mkAdd(t1N, t2N), s, z3)
+    }
+    case TTimes(c, t1)=> {
+      val cN = z3.mkInt(c, s)
+      val t1N = mkASTTerm(t1, s, z3)._1
+      (z3.mkMul(cN, t1N), s, z3)
+    }
+    case TIte(f, t1, t2)=> {
+      val fN = mkAST(f, s, z3)._1
+      val t1N = mkASTTerm(t1, s, z3)._1
+      val t2N = mkASTTerm(t2, s, z3)._1
+      (z3.mkITE(fN, t1N, t2N), s, z3)
+    }
+  }
+
+  def mkASTAtom(a:AtomQFPA, s: Z3Sort, z3: Z3Context): (Z3AST, Z3Sort, Z3Context) = a match {
+    case ALeq(t1,t2) => {
+      val t1N = mkASTTerm(t1, s, z3)._1
+      val t2N = mkASTTerm(t2, s, z3)._1
+      (z3.mkLE(t1N, t2N), s, z3)
+    }
+    case AEq(t1,t2) => {
+      val t1N = mkASTTerm(t1, s, z3)._1
+      val t2N = mkASTTerm(t2, s, z3)._1
+      (z3.mkEq(t1N, t2N), s, z3)
+    }
+  }
+
+  def mkAST(f: QFPAFormula, s: Z3Sort, z3: Z3Context): (Z3AST, Z3Sort, Z3Context) = f match {
+    case QFPAAnd(f1,f2) => {
+      val f1N = mkAST(f1, s, z3)._1
+      val f2N = mkAST(f2, s, z3)._1
+      (z3.mkAnd(f1N, f2N), s, z3)
+    }
+    case QFPAOr(f1,f2) => {
+      val f1N = mkAST(f1, s, z3)._1
+      val f2N = mkAST(f2, s, z3)._1
+      (z3.mkOr(f1N, f2N), s, z3)
+    }
+    case QFPANot(f1)  => (z3.mkNot(mkAST(f1, s, z3)._1), s, z3)
+    case QFPAAtom(a)  => mkASTAtom(a, s, z3)
+    case QFPAFalse => (z3.mkFalse, s, z3)
+    case QFPATrue  => (z3.mkTrue, s, z3)
+  }
+
+
+  def callZ3NewWaytoDetermineConsistency(c:List[QFPAFormula]): Boolean = {
+    val z3 = new Z3Context((new Z3Config).setParamValue("MODEL", "false"))
+    val i = z3.mkIntSort
+
+    val z3formulasPairs = c.map(f => mkAST(f, i, z3))
+    val z3formulas = z3formulasPairs.map(f => f._1)
+    z3formulas.foreach(f => z3.assertCnstr(f))
+
+    val b = z3.check() match {
+      case Some(x) => x
+      case None => error("There was an error with Z3.")
+    }
+    z3.delete
+    b
+  }
+
+
+/////////
+
+
+  def callZ3NewWaytoCheckConsistencyofOneFormula(f:QFPAFormula):(Boolean, Map[String, Int]) = {
+    val z3 = new Z3Context((new Z3Config).setParamValue("MODEL", "true"))
+    val i = z3.mkIntSort
+
+    val vars = getAllVariablesAndConstsFromFormula(f)._1
+    val varMap = Map.empty[String,Z3AST]
+
+    vars.foreach(v => {
+      if(!varMap.keySet.contains(v)) {
+        val ast = z3.mkConst(z3.mkStringSymbol(v), i)
+        varMap(v) = ast
+        }
+    })
+
+    val z3formulaTuple = mkAST(f, i, z3)
+    val z3formula = z3formulaTuple._1
+    z3.assertCnstr(z3formula)
+
+    val (res, model) = z3.checkAndGetModel()
+
+    val out = res match {
+      case Some(false) => (false, Map.empty[String,Int]) 
+      case Some(true) => (true, Map.empty[String,Int] ++ varMap.map(p => (p._1, model.evalAsInt(p._2).get)))
+      case None => error("There was an error with Z3.")
+    }
+    out
+  }
+
+
+
+
+//------------------------------------------
+// old names keep consistency with old calls
+//------------------------------------------
+
+
+// calls Z3 on list of formulas and returns "sat" or "unsat"
+  def callZ3toDetermineConsistency(c:List[QFPAFormula]):String = {
+     val b = callZ3NewWaytoDetermineConsistency(c)
+     val s = if (b == true) "sat" else "unsat"
+     s
+  }
+
+
+// calls z3 on One formula and return a model and "sat" or "unsat"
+  def checkConsistencyofOneFormula(f:QFPAFormula): (String, Map[String, Int]) = {
+    val p = callZ3NewWaytoCheckConsistencyofOneFormula(f)
+    val res = if (p._1 == true) ("sat", p._2) else ("unsat", p._2)
+    res
+  }
+
+}
diff --git a/src/multisets/CreateDisjunctions.scala b/src/multisets/CreateDisjunctions.scala
new file mode 100644
index 0000000000000000000000000000000000000000..444de613ffa8a877e5a70a38f0baa5ad38fe4ee3
--- /dev/null
+++ b/src/multisets/CreateDisjunctions.scala
@@ -0,0 +1,729 @@
+package multisets
+
+
+import scala.collection.mutable.Set
+
+
+object CreateDisjunctions {
+
+// start: input formula
+// output: formula without ITE Expresssions and formula denoting ITE experssions
+
+  def flattenITEExpressionsTerm(t:TermQFPA, vc:Int, il:List[(String,TermQFPA)]):(TermQFPA,Int,List[(String,TermQFPA)]) = t match {
+     case TPlus(t1, t2) => {
+      val (t1N, vc1, il1) = flattenITEExpressionsTerm(t1, vc, il)
+      val (t2N, vc2, il2) = flattenITEExpressionsTerm(t2, vc1, il1)
+      (TPlus(t1N, t2N), vc2, il2)
+    }
+     case TTimes(c, t1) => {
+      val (t1N, vc1, il1) = flattenITEExpressionsTerm(t1, vc, il)
+      (TTimes(c, t1N), vc1, il1)
+     }
+     case TIte(f, t1, t2) => {
+       val newITEVar = "FRESHv" + vc
+       var il1 = (newITEVar, t)  :: il
+       (TVariable(newITEVar), vc + 1, il1)
+     }
+     case _ => (t, vc, il)
+  }
+
+  def flattenITEExpressionsAtom(a:AtomQFPA, vc:Int, il:List[(String,TermQFPA)]):(QFPAFormula,Int,List[(String,TermQFPA)]) = a match {
+     case ALeq(t1, t2) => {
+      val (t1N, vc1, il1) = flattenITEExpressionsTerm(t1, vc, il)
+      val (t2N, vc2, il2) = flattenITEExpressionsTerm(t2, vc1, il1)
+      (QFPAAtom(ALeq(t1N, t2N)), vc2, il2)
+    }
+     case AEq(t1, t2) => {
+      val (t1N, vc1, il1) = flattenITEExpressionsTerm(t1, vc, il)
+      val (t2N, vc2, il2) = flattenITEExpressionsTerm(t2, vc1, il1)
+      (QFPAAtom(AEq(t1N, t2N)), vc2, il2)
+    }
+  }
+
+  def flattenITEExpressionsFormula(f:QFPAFormula, vc:Int, il:List[(String,TermQFPA)]):(QFPAFormula,Int,List[(String,TermQFPA)]) = f match {
+    case QFPAAnd(f1, f2) => {
+      val (f1N, vc1, il1) = flattenITEExpressionsFormula(f1, vc, il)
+      val (f2N, vc2, il2) = flattenITEExpressionsFormula(f2, vc1, il1)
+      (QFPAAnd(f1N, f2N), vc2, il2)
+    }
+    case QFPAOr(f1, f2) => {
+      val (f1N, vc1, il1) = flattenITEExpressionsFormula(f1, vc, il)
+      val (f2N, vc2, il2) = flattenITEExpressionsFormula(f2, vc1, il1)
+      (QFPAOr(f1N, f2N), vc2, il2)
+    }
+    case QFPANot(f1) => {
+      val (f1N, vc1, il1) = flattenITEExpressionsFormula(f1, vc, il)
+      (QFPANot(f1N), vc1, il1)
+    }
+    case QFPAAtom(a) => flattenITEExpressionsAtom(a, vc, il)
+    case _ => (f, vc, il)
+  }
+
+ def flatten_ITEList(il:List[(String,TermQFPA)],ic:Int, toBeFlattened: Boolean):List[(String,TermQFPA)] = {
+    var addedFreshITEs = false
+    var ilN:List[(String,TermQFPA)] = Nil
+    var icN = ic
+    if (toBeFlattened) {
+      il.foreach(p => p._2 match {
+        case TIte(f, t1, t2) => {
+          var iltmp:List[(String,TermQFPA)] = Nil
+          val (fF, ic1, il1) = flattenITEExpressionsFormula(f, icN, iltmp)
+          val (t1F, ic2, il2) = flattenITEExpressionsTerm(t1, ic1, il1)
+          val (t2F, ic3, il3) = flattenITEExpressionsTerm(t2, ic2, il2)
+          if (il3.isEmpty) {
+            ilN = p :: ilN
+          } else {
+            val newITEVar = "FRESHv" + ic3
+            icN = ic3 + 1
+            ilN = il3 ::: ilN
+            ilN = (newITEVar, TIte(fF, t1F, t2F)) :: ilN 
+            addedFreshITEs = true
+          }
+        }
+        case _ => error("Impossible case ")
+      })
+      flatten_ITEList(ilN, icN, addedFreshITEs)
+    } else il
+  }
+
+
+  def flattenITEExpressions(f:QFPAFormula):(QFPAFormula, List[(String,TermQFPA)]) = {
+    var variableCount = 0
+    var iteList:List[(String,TermQFPA)] = Nil
+    val (f1, vc1, iteList1) = flattenITEExpressionsFormula(f, variableCount, iteList)
+    // every ITE is pulled out
+    val toBeFlattened = true
+    val iteListFinal = flatten_ITEList(iteList1, vc1, toBeFlattened)
+    (f1, iteListFinal)
+  }
+
+// end
+
+//--------------
+
+//start: v - list of (complex) terms
+// output: $1 - formula describing freshly introduced terms
+  def flattenComplexTerms(v:List[TermQFPA]):(QFPAFormula,List[TermQFPA]) =  {
+    var tc = 0
+    var tempForm:QFPAFormula = QFPATrue
+    var tempVector:List[TermQFPA] = Nil
+    v.foreach(t => t match {
+      case TVariable(v) => tempVector = t :: tempVector
+      case TConstant(c) => tempVector = t :: tempVector
+      case  _ => {
+        val newTermVar = "FRESHt" + tc
+        val fTemp = QFPAAtom(AEq(TVariable(newTermVar), t))
+        tempForm = QFPAAnd(tempForm, fTemp)
+        tempVector = TVariable(newTermVar) :: tempVector
+        tc = tc + 1
+      }
+      })
+    val fN = multisets.Multiset2StarsTranslator.removeTrueAndFalse(tempForm)
+    val tN = tempVector.reverse
+    (fN, tN)
+  }
+//end
+
+
+// ------------
+// start: input f AND l (l = list of conjunction of equlities about ITE)
+//output: DNF of f AND f1 in form List[List[formula]]
+  def nnform(f:QFPAFormula):QFPAFormula = f match {
+    case QFPANot(QFPANot(f1)) => nnform(f1)
+    case QFPANot(QFPAAnd(f1, f2)) => QFPAOr(QFPANot(nnform(f1)), QFPANot(nnform(f2)))
+    case QFPANot(QFPAOr(f1, f2)) => QFPAAnd(QFPANot(nnform(f1)), QFPANot(nnform(f2)))
+    case QFPAAnd(f1, f2) => QFPAAnd(nnform(f1), nnform(f2))
+    case QFPAOr(f1, f2) => QFPAOr(nnform(f1), nnform(f2))
+    case QFPANot(f1) => QFPANot(nnform(f1))
+    case _ => f
+  }
+
+  def removeNegationFromNegatedAtom(a:AtomQFPA):QFPAFormula = a match {
+    case ALeq(t1, t2) => QFPAAtom(ALeq(TPlus(t2, TConstant(1)), t1))
+    case AEq(t1, t2) => QFPAOr(
+      QFPAAtom(ALeq(TPlus(t1, TConstant(1)), t2)),
+      QFPAAtom(ALeq(TPlus(t2, TConstant(1)), t1))
+    )
+  }
+
+  def removeNegationCompletely(f:QFPAFormula):QFPAFormula = f match {
+    case QFPAAnd(f1, f2) => QFPAAnd(removeNegationCompletely(f1), removeNegationCompletely(f2))
+    case QFPAOr(f1, f2) => QFPAOr(removeNegationCompletely(f1), removeNegationCompletely(f2))
+    case QFPANot(QFPAAtom(a)) => removeNegationFromNegatedAtom(a)
+    case QFPANot(QFPATrue) => QFPAFalse
+    case QFPANot(QFPAFalse) => QFPATrue
+    case _ => f
+  }
+
+
+  def mergeTwoConjuntions(d1:List[QFPAFormula], d2:List[QFPAFormula]): List[List[QFPAFormula]] = {
+    val ln = d1 ::: d2
+    List(ln)
+  }
+
+  def addOneDisjuntToWholeFormula(l:List[List[QFPAFormula]], c:List[QFPAFormula]): List[List[QFPAFormula]] = {
+    var lt: List[List[QFPAFormula]] = Nil
+    l.foreach(s => {
+      val fn = mergeTwoConjuntions(s, c)
+      lt = fn ::: lt
+    })
+    lt
+  }
+
+  def mergeTwoDisjunctions(l1: List[List[QFPAFormula]], l2: List[List[QFPAFormula]]): List[List[QFPAFormula]] = {
+    var lt: List[List[QFPAFormula]] = Nil
+    l2.foreach(s => {
+      val ln = addOneDisjuntToWholeFormula(l1, s)
+      lt = ln ::: lt
+    })
+    lt
+  }
+
+
+  def disjuntiveNormalForm(f:QFPAFormula): List[List[QFPAFormula]] = {
+    val f1 = nnform(f)
+    val f2 = removeNegationCompletely(f1)
+    val f3 = f2 match {
+      case QFPAAnd(fa, fb) => {
+        val f1N = disjuntiveNormalForm(fa)
+        val f2N = disjuntiveNormalForm(fb)
+        mergeTwoDisjunctions(f1N, f2N)
+      }
+      case QFPAOr(fa, fb) => {
+        val f1N = disjuntiveNormalForm(fa)
+        val f2N = disjuntiveNormalForm(fb)
+        f1N ::: f2N
+      }
+      case  _ => List(List(f2))
+    }
+    f3
+  }
+
+
+// -------------------------
+
+
+  def mergeTogether(c:List[QFPAFormula],f:List[List[QFPAFormula]]):List[List[QFPAFormula]] = {
+    val list1 = f.map(d => c ::: d)
+    list1
+  }
+
+  def addITEExpressionToOneDisjunct(c:List[QFPAFormula], p:(String,TermQFPA)): List[List[QFPAFormula]] = {
+    val lN = p._2 match {
+      case TIte(f, t1, t2) => {
+         val f1 = disjuntiveNormalForm(f)
+         val f2 = disjuntiveNormalForm(QFPANot(f))
+         val c1 = QFPAAtom(AEq(TVariable(p._1), t1)) :: c
+         val c2 = QFPAAtom(AEq(TVariable(p._1), t2)) :: c
+         val l1 = mergeTogether(c1, f1)
+         val l2 = mergeTogether(c2, f2)
+         l1 ::: l2
+      }
+      case x@_ => error("Impossible case :" + x)
+    }
+    lN
+  }
+
+  def evaluateITEExpressionInListOfDisjunctions(l: List[List[QFPAFormula]], t:(String,TermQFPA)): List[List[QFPAFormula]] = {
+    var lt: List[List[QFPAFormula]] = Nil
+    l.foreach(s => {
+      val ln = addITEExpressionToOneDisjunct(s, t)
+      lt = ln ::: lt
+    })
+    lt
+  }
+
+  def unrollITEExpressions(f:QFPAFormula,lITE: List[(String,TermQFPA)]): List[List[QFPAFormula]] = {
+    val fN = disjuntiveNormalForm(f)
+    var lTemp = fN
+    lITE.foreach(t => {
+      val lNew = evaluateITEExpressionInListOfDisjunctions(lTemp, t)
+      lTemp = lNew
+    })
+    lTemp
+  }
+
+// end
+
+
+
+
+
+// ------------------
+
+/// STRT: to be considered!
+
+  def replaceInequalitiesWithEqualitiesinAtom(a:AtomQFPA, lc:Int):(AtomQFPA,Int) = a match {
+     case ALeq(t1, t2) => {
+     val newTermVar =  "FRESHl" + lc
+     val newRHS = TPlus(t1, TVariable(newTermVar))
+     (AEq(t2, newRHS), lc + 1)
+    }
+     case AEq(t1, t2) => (a, lc)
+  }
+
+  def replaceInequalitiesWithEqualitiesinOneSingleFormula(f:QFPAFormula, lc:Int):(QFPAFormula,Int) = f match {
+    case QFPAAtom(a) => {
+      val (a1, lc1) = replaceInequalitiesWithEqualitiesinAtom(a, lc)
+      (QFPAAtom(a1), lc1)
+    }
+    case QFPATrue => (f, lc)
+    case _ => error("Impossible case ")
+  }
+
+  def replaceInequalitiesWithEqualitiesinConjunct(l:List[QFPAFormula], lc:Int):(List[QFPAFormula],Int) = {
+    var lc1 = lc
+    var lTemp: List[QFPAFormula] = Nil
+    l.foreach(f => {
+      val (fT, lcT) = replaceInequalitiesWithEqualitiesinOneSingleFormula(f, lc1)
+      lc1 = lcT
+       lTemp = fT :: lTemp
+    })
+    (lTemp, lc1)
+  }
+
+
+  def replaceInequalitiesWithEqualities(l:List[List[QFPAFormula]]):List[List[QFPAFormula]] = {
+    var lTemp: List[List[QFPAFormula]] = Nil
+    var lc = 0
+    l.foreach(c => {
+      val (cT, lcT) = replaceInequalitiesWithEqualitiesinConjunct(c, lc)
+      lc = lcT
+      lTemp = cT :: lTemp
+    })
+    lTemp
+  }
+
+//// END
+
+  def consistentConjunctUsingZ3(c:List[QFPAFormula]):Boolean = {
+    val out = multisets.CheckingConsistency.callZ3toDetermineConsistency(c)
+    val res = if (out == "sat") true else false
+    res
+  }
+
+  def removeRedundantUsingZ3(c:List[QFPAFormula]):List[QFPAFormula] = {
+    var l1: List[QFPAFormula] = Nil
+    var l2 = c
+    while (! l2.isEmpty) {
+      val f = l2.head
+      l2 = l2.tail
+      if (consistentConjunctUsingZ3((QFPANot(f) :: l2) ::: l1) ) l1 = f :: l1
+    }
+    l1
+  }
+
+  def useAntisymmetryToDeriveEq(c:List[QFPAFormula]): List[QFPAFormula] = {
+    var l1: List[QFPAFormula] = Nil
+    var ltemp: List[QFPAFormula] = Nil
+    var l2 = c
+    while (! l2.isEmpty) {
+      val f = l2.head
+      l2 = l2.tail
+      f match {
+        case QFPAAtom(ALeq(t1, t2)) => {
+          if (l2.exists(fl => fl == QFPAAtom(ALeq(t2, t1)))) ltemp = f :: ltemp
+          else if (ltemp.exists(fl => fl == QFPAAtom(ALeq(t2, t1)))) l1 = QFPAAtom(AEq(t1, t2)) :: l1
+          else l1 = f :: l1 
+        }
+        case _ => l1 = f :: l1 
+      }
+    }
+    l1
+  }
+
+  def checkConsistencyAndRemoveRedundantUsingZ3(l:List[List[QFPAFormula]]): List[List[QFPAFormula]] = {
+    var lTemp: List[List[QFPAFormula]] = Nil
+    l.foreach(c => if (consistentConjunctUsingZ3(c)) {
+      val c1 = removeRedundantUsingZ3(c)
+      val c2 = useAntisymmetryToDeriveEq(c1)
+     // a <= b & b <= a ===> a = b
+      lTemp = c2 :: lTemp
+    })
+    lTemp
+  }
+
+// ----------------------
+
+/*
+
+  def checkIfTermIsAboutTempVVariable(t:TermQFPA):Boolean = t match {
+    case TVariable(v) => v.startsWith("FRESHv")
+    case TConstant(c) =>  false
+    case TPlus(t1, t2) => false
+    case TTimes(c, t1) => false
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def isAtomAboutTempVVariable(a:AtomQFPA):Boolean = a match {
+    case AEq(t1, t2) => checkIfTermIsAboutTempVVariable(t1)
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def isFormulaAboutTempVVariable(f:QFPAFormula):Boolean = f match {
+    case QFPAAtom(a) => isAtomAboutTempVVariable(a)
+    case QFPAEmpty => false
+    case QFPATrue => false
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def separateEqualitiesIntoTwoListsDepandingOnTempVarV(c:List[QFPAFormula]):(List[QFPAFormula],List[QFPAFormula]) = {
+    var l1T: List[QFPAFormula] = Nil
+    var l2T: List[QFPAFormula] = Nil
+    c.foreach(f => {
+      if (isFormulaAboutTempVVariable(f)) {
+        l2T = f :: l2T
+      } else l1T = f :: l1T
+    })
+    (l1T, l2T)
+  }
+
+
+  def getStringValueofTempVarV(t:TermQFPA):String = t match {
+    case TVariable(v) => v
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def createValueOfTempVarVAtom(a:AtomQFPA):(String,TermQFPA) = a match {
+    case AEq(t1, t2) => {
+      val s = getStringValueofTempVarV(t1)
+      (s, t2)
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def createValueOfTempVarV(f:QFPAFormula):(String,TermQFPA) = f match {
+    case QFPAAtom(a) => createValueOfTempVarVAtom(a)
+    case x@_ => error("Impossible case :" + x)
+  }
+
+   def updateValuesWitnNewVValueTerm(tt:TermQFPA, vu:String, tu: TermQFPA):TermQFPA = tt match {
+    case TVariable(v) => if (v == vu) tu else tt
+    case TConstant(c) =>  tt
+    case TPlus(t1, t2) => {
+      val t1N = updateValuesWitnNewVValueTerm(t1, vu, tu)
+      val t2N = updateValuesWitnNewVValueTerm(t2, vu, tu)
+      TPlus(t1N, t2N)
+    }
+    case TTimes(c, t1) => {
+      val t1N = updateValuesWitnNewVValueTerm(t1, vu, tu)
+      TTimes(c, t1N)
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+   def updateValuesWitnNewVValueAtom(a:AtomQFPA, v:String, t: TermQFPA):AtomQFPA = a match {
+    case AEq(t1, t2) => {
+      val t1N = updateValuesWitnNewVValueTerm(t1, v, t)
+      val t2N = updateValuesWitnNewVValueTerm(t2, v, t)
+      AEq(t1N, t2N)
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+   def updateValuesWitnNewVValueFormula(f:QFPAFormula, v:String, t: TermQFPA):QFPAFormula = f match {
+    case QFPAAtom(a) => QFPAAtom(updateValuesWitnNewVValueAtom(a, v, t))
+    case QFPAEmpty => f
+    case QFPATrue => f
+    case x@_ => error("Impossible case :" + x)
+  }
+
+
+   def updateValuesWitnNewVValue(l:List[QFPAFormula], v:String, t: TermQFPA):List[QFPAFormula] = {
+    var lTemp: List[QFPAFormula] = Nil
+    l.foreach(f => {
+      val fN = updateValuesWitnNewVValueFormula(f, v, t)
+      lTemp = fN :: lTemp
+    })
+    lTemp
+  }
+
+
+  def getRidOfTempVVariablesFromConjuntion(c:List[QFPAFormula]):List[QFPAFormula] = {
+    val (l1, l2) = separateEqualitiesIntoTwoListsDepandingOnTempVarV(c)
+    var l1T = l1
+    var l2T = l2
+    while (! l2T.isEmpty) {
+      val (v, t) = createValueOfTempVarV(l2T.head)
+      val lT = l2T.tail
+      l1T = updateValuesWitnNewVValue(l1T, v, t)
+      l2T = updateValuesWitnNewVValue(lT, v, t)
+    } 
+    l1T
+  }
+
+  def orientEqualities(c:List[QFPAFormula]):List[QFPAFormula] = {
+    var l1: List[QFPAFormula] = Nil
+    var l2 = c
+    while (! l2.isEmpty) {
+      val f = l2.head
+      l2 = l2.tail
+      f match {
+        case QFPAAtom(AEq(t1, TVariable(v))) =>  l1 = QFPAAtom(AEq(TVariable(v), t1)) :: l1 
+        case _ => l1 = f :: l1 
+      }
+    }
+    l1
+  }
+
+  def getRidOfTempVVariablesandOrientEqualities(l:List[List[QFPAFormula]]):List[List[QFPAFormula]] = {
+    var lTemp: List[List[QFPAFormula]] = Nil
+    l.foreach(c => {
+      val c1 = getRidOfTempVVariablesFromConjuntion(c)
+      val c2 = orientEqualities(c1)
+       lTemp = c2 :: lTemp
+    })
+    lTemp
+  }
+
+*/
+
+  def getVariablesfromFormula(f:QFPAFormula):Set[String] = {
+    val l1 = multisets.CheckingConsistency.getAllVariablesAndConstsFromFormula(f)
+    l1._1
+  } 
+
+  def getvariablesFromVector(l:List[TermQFPA]):Set[String] = {
+    var s1 = Set.empty[String]
+    l.foreach(t => s1 = s1 ++ multisets.RemoveStars.getAllVariablesFromTerm(t))
+    s1
+  }
+
+// start
+
+  def createZeroMap(vars:Set[String]):Map[String,Int] = {
+    var m = Map.empty[String,Int]
+    vars.foreach(v => m += (v -> 0))
+    m += ("CONST" -> 0)
+    m
+  }
+
+
+  def addVariableinMap(v:String,vars:Set[String]):Map[String,Int] = {
+    var m = createZeroMap(vars)
+    m += (v -> 1)
+    m
+  }
+
+  def addConstantInMap(c:Int,vars:Set[String]):Map[String,Int] = {
+    var m = createZeroMap(vars)
+    m += ("CONST" -> c)
+    m
+  }
+
+  def sumTwoMaps(m1:Map[String,Int],m2:Map[String,Int],vars:Set[String]):Map[String,Int] = {
+    var m3 = Map.empty[String,Int]
+    vars.foreach(v => {
+      val l = m1(v) + m2(v)
+      m3 += (v -> l)
+    })
+    val c = m1("CONST") + m2("CONST") 
+    m3 += ("CONST" -> c)
+    m3
+  }
+
+
+  def multiplyMap(c:Int,m:Map[String,Int],vars:Set[String]):Map[String,Int] = {
+    var mN = Map.empty[String,Int]
+    vars.foreach(v => {
+      val l = c * m(v)
+      mN += (v -> l)
+    })
+    val cn = c * m("CONST") 
+    mN += ("CONST" -> cn)
+    mN
+  }
+
+
+  def createMapRepresentingTerm(t:TermQFPA,vars:Set[String]):Map[String,Int] = t match {
+    case TVariable(v) => addVariableinMap(v,vars)
+    case TConstant(c) => addConstantInMap(c,vars)
+    case TPlus(t1, t2) => {
+      val m1 = createMapRepresentingTerm(t1, vars)
+      val m2 = createMapRepresentingTerm(t2, vars)
+      sumTwoMaps(m1, m2, vars)
+    }
+    case TTimes(c, t1) => {
+      val m1 = createMapRepresentingTerm(t1, vars)
+      multiplyMap(c, m1, vars)
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def createMapRepresentingFormula(f:QFPAFormula,vars:Set[String]):(String,Map[String,Int]) = {
+    val p = f match {
+      case QFPAAtom(ALeq(t1, t2)) => {
+        val s = "i"
+        val m1 = createMapRepresentingTerm(t1, vars)
+        val m2 = createMapRepresentingTerm(t2, vars)
+        val m3 = multiplyMap(-1, m1, vars)
+        val m = sumTwoMaps(m2, m3, vars)
+        (s, m)
+      }
+      case QFPAAtom(AEq(t1, t2)) => {
+        val s = "e"
+        val m1 = createMapRepresentingTerm(t1, vars)
+        val m2 = createMapRepresentingTerm(t2, vars)
+        val m3 = multiplyMap(-1, m1, vars)
+        val m = sumTwoMaps(m2, m3, vars)
+        (s, m)
+      }
+      case QFPATrue => {
+        val s = "t"
+        val m = createZeroMap(vars)
+        (s, m)
+      }
+      case x@_ => error("Impossible case :" + x)
+   }
+   p
+  }
+
+//  end
+
+ 
+  def updateOneMapWithOther(mTU:Map[String,Int],m:Map[String,Int],v:String):Map[String,Int] = {
+    val c = mTU(v)
+    val j = m(v)
+    val mT1 = mTU - v
+    val m1 = m - v
+//    val vars = m.keySet 
+// hell:
+    var vars = Set.empty[String]
+    vars = vars ++ m1.keySet
+    val m2 = if (j == 1) multiplyMap(-1,m1,vars) else m1
+    val m3 = multiplyMap(c,m2,vars)
+    sumTwoMaps(mT1, m3, vars)
+  }
+
+  def updateMapwhileQE(l:List[(String,Map[String,Int])],m:Map[String,Int],v:String):List[(String,Map[String,Int])] = {
+    var lt = List.empty[(String,Map[String,Int])]
+    l.foreach(p => {
+      if (p._2 != m) {
+        val m1 = updateOneMapWithOther(p._2, m, v)
+        lt = (p._1, m1) :: lt
+      }
+    })
+    lt
+  }
+
+  def eliminateVariable(v:String,l:List[(String,Map[String,Int])]):(List[(String,Map[String,Int])],Boolean) = {
+    val lf = l.filter(p => p._1 == "e" && (p._2(v) == 1 || p._2(v) == -1))
+    val res = if (lf.isEmpty) (l, false) else (updateMapwhileQE(l, lf.head._2, v), true)
+    res
+  }
+
+
+  def createOneTermFromMap(i:Int,v:String,m:Map[String,Int]):TermQFPA = {
+     val c = i * m(v)
+     val t = if (v == "CONST") TConstant(c) else 
+       if (c == 1) TVariable(v) else TTimes(c, TVariable(v))
+     t
+  }
+
+  def constructTermFromMap(i:Int,vars:Set[String],m:Map[String,Int]):TermQFPA = {
+    val t = if (vars.isEmpty) TConstant(0) else {
+      val l = vars.toList
+      var term = createOneTermFromMap(i, l.head, m)
+      val ltail = l.tail
+      ltail.foreach(v =>  {
+        val t1 = createOneTermFromMap(i, v, m)
+        term = TPlus(t1, term)
+      })
+      term
+    }
+    t
+  }
+
+  def constructPositiveTermFromMap(pVars:Set[String],m:Map[String,Int]):TermQFPA = 
+   constructTermFromMap(1, pVars, m)
+
+  def constructNegativeTermFromMap(nVars:Set[String],m:Map[String,Int]):TermQFPA =
+    constructTermFromMap(-1, nVars, m)
+
+
+  def getPositiveAndNegativeVarsandConstFromMap(m:Map[String,Int],vars:Set[String]):(Set[String],Set[String]) = {
+    var sp = Set.empty[String]
+    var sn = Set.empty[String]
+    vars.foreach(v => {
+      if (m(v) > 0) sp = sp + v
+      if (m(v) < 0) sn = sn + v
+    })
+    if (m("CONST") > 0) sp = sp + "CONST"
+    if (m("CONST") < 0) sn = sn + "CONST"
+    (sp, sn)
+  }
+
+
+  def reconstructEqualityFromMap(m:Map[String,Int],vars:Set[String]):QFPAFormula = {
+    val (pVars, nVars) = getPositiveAndNegativeVarsandConstFromMap(m, vars)
+    val tp = constructPositiveTermFromMap(pVars, m)
+    val tn = constructNegativeTermFromMap(nVars, m)
+    QFPAAtom(AEq(tp, tn))
+  }
+
+  def reconstructInequalityFromMap(m:Map[String,Int],vars:Set[String]):QFPAFormula = {
+    val (pVars, nVars) = getPositiveAndNegativeVarsandConstFromMap(m, vars)
+    val tp = constructPositiveTermFromMap(pVars, m)
+    val tn = constructNegativeTermFromMap(nVars, m)
+    QFPAAtom(ALeq(tn, tp))
+  }
+
+
+  def reconstructFormulaFromMaps(t:(String,Map[String,Int]),vars:Set[String]):QFPAFormula = {
+    val f = if (t._1 == "t") QFPATrue else
+      if (t._1 == "e") reconstructEqualityFromMap(t._2,vars)
+      else  reconstructInequalityFromMap(t._2,vars) 
+    f
+  }
+
+  def reconstructFormulasFromMaps(l:List[(String,Map[String,Int])],vars:Set[String]):List[QFPAFormula] = {
+    val list1 = l.map(e => reconstructFormulaFromMaps(e,vars))
+    list1
+  }
+
+
+
+  def doSimpleQE(v:List[TermQFPA],l:List[QFPAFormula]):List[QFPAFormula] = {
+   val inVars = getvariablesFromVector(v)
+   var allVars = Set.empty[String]
+   l.foreach(f => allVars = allVars ++ getVariablesfromFormula(f))
+   val varsForQE = allVars -- inVars
+   val listOfMaps = l.map(f => createMapRepresentingFormula(f, allVars))
+   var fmla = listOfMaps
+   var eliminated = Set.empty[String]
+   varsForQE.foreach(v => {
+      val p = eliminateVariable(v, fmla)
+      fmla = p._1
+      if (p._2) eliminated = eliminated + v
+   })
+   val l1 = reconstructFormulasFromMaps(fmla,allVars -- eliminated)
+   l1
+  } 
+
+
+ // def doEliminationOfConstants(v:List[TermQFPA],List[
+
+
+
+// -----------------------
+
+  def main(v:List[TermQFPA],f:QFPAFormula): (List[TermQFPA], List[List[QFPAFormula]]) = {
+    val (fTemp1, vN) = flattenComplexTerms(v)
+    val fNew1 = if (fTemp1 == QFPATrue) f else QFPAAnd(f, fTemp1)
+    val (fNew2, fl) = flattenITEExpressions(fNew1)
+    // fNew2 is a formula that doesn't contain ITE expressions, 
+    //fl is a list of a type (v, ITE(...)) no nested ITE expressions
+    val listDNFNoITEs = unrollITEExpressions(fNew2, fl)
+    // no more ITE expressions and listDNFNoITs is in DNF, does not contain ITEs
+    // listDNFNoITEs is a list of lists of formulas
+    val list1 = checkConsistencyAndRemoveRedundantUsingZ3(listDNFNoITEs)
+    // list1 contains only satisfiable constraints
+    val list2 = list1.map(f => doSimpleQE(vN,f))
+    val list3 = replaceInequalitiesWithEqualities(list2)
+/*    val list3 = getRidOfTempVVariablesandOrientEqualities(list2) */
+     // a + b = c ===> c = a + b
+    (vN, list3)
+    // vN is a term that contains only variables and list1 is a list of lists of formulas
+  }
+
+}
diff --git a/src/multisets/FormulaConstructor.scala b/src/multisets/FormulaConstructor.scala
new file mode 100644
index 0000000000000000000000000000000000000000..4c72b3c6962778f1e83b126a65d9fa2d5603a0b3
--- /dev/null
+++ b/src/multisets/FormulaConstructor.scala
@@ -0,0 +1,536 @@
+package multisets
+
+import scala.collection.mutable.Map
+import scala.collection.mutable.Set
+import java.util.NoSuchElementException
+import multisets.MultisetFormulaPrinter._
+
+
+
+object FormulaConstructor {
+
+
+// start: exists the execution with a message
+  def abort(msg: String) {
+    println(msg)
+    System.exit(-1)
+  }
+
+// start: parsing of NoSuchElementException message
+  def whichVarIsMissing(s: String): String = {
+      val strings = s.split (":");
+      strings(1)
+  }
+// end
+
+
+// Start: we check for atoms of a type a = b, whether it is about msets or integers
+  def checkTypesOfAtom(s: String, m: Map[String, String], a: Atom): Atom = {
+    try {
+      val af = a match {
+        case AEqual(MVariable(m1), MVariable(m2)) => {
+          val aN = if (m(m1) == "INT" && m(m2) == "INT") AAtomOut(AOEq(TOVariable(m1), TOVariable(m2)))
+          else a
+          aN
+        }
+        case AAtomOut(AOEq(TOVariable(v1), TOVariable(v2)))  => {
+          val aN = if (m(v1) == "INT" && m(v2) == "INT") a
+          else AEqual(MVariable(v1), MVariable(v2))
+          aN
+        }
+        case _ => a
+      }
+      af
+    } catch {
+       case ex: NoSuchElementException => {
+         val v = whichVarIsMissing(ex.getMessage)
+         abort("Program abort: in the problem " + s + " the variable " + v + " is not declared!")
+         AEqual(MEmpty, MEmpty)
+       }
+    }
+  }
+
+  def checkAtomsInFormula(s: String, p: (Map[String, String], Formula)): Formula = p._2 match {
+    case FAnd(f1, f2) => {
+      val f1N = checkAtomsInFormula(s, (p._1, f1))
+      val f2N = checkAtomsInFormula(s, (p._1, f2))
+      FAnd(f1N, f2N)
+    }
+    case FOr(f1, f2) => {
+      val f1N = checkAtomsInFormula(s, (p._1, f1))
+      val f2N = checkAtomsInFormula(s, (p._1, f2))
+      FOr(f1N, f2N)
+    }
+    case FNot(f1)  => {
+      val f1N = checkAtomsInFormula(s, (p._1, f1))
+      FNot(f1N)
+    }
+    case FAtom(a)  => {
+      val aN = checkTypesOfAtom(s, p._1, a)
+      FAtom(aN)
+    }
+    case FTrue  => p._2
+    case FFalse  => p._2
+  }
+// end
+
+// start: given a formula we derive two sets of variables: integer variables and set veriables
+  def getVariablesfromMultiset(m: Multiset): (Set[String], Set[String]) = m match {
+    case MVariable(v) => (Set[String](), Set(v))
+    case MEmpty => (Set[String](), Set[String]())
+    case MUnion(m1, m2) => {
+      val (s1, s2)  = getVariablesfromMultiset(m1)
+      val (p1, p2) = getVariablesfromMultiset(m2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case MIntersection(m1, m2) => {
+      val (s1, s2)  = getVariablesfromMultiset(m1)
+      val (p1, p2) = getVariablesfromMultiset(m2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case MPlus(m1, m2) => {
+      val (s1, s2)  = getVariablesfromMultiset(m1)
+      val (p1, p2) = getVariablesfromMultiset(m2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case MMinus(m1, m2) => {
+      val (s1, s2)  = getVariablesfromMultiset(m1)
+      val (p1, p2) = getVariablesfromMultiset(m2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case MSetMinus(m1, m2) => {
+      val (s1, s2)  = getVariablesfromMultiset(m1)
+      val (p1, p2) = getVariablesfromMultiset(m2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case MSetOf(m1) => getVariablesfromMultiset(m1)
+  }
+
+  def getVariablesfromTermIn(t: TermIn): (Set[String], Set[String]) = t match {
+    case TIMultiplicity(v) => (Set[String](), Set(v))
+    case TIConstant(c) => (Set[String](), Set[String]())
+    case TIPlus(t1, t2) => {
+      val (s1, s2)  = getVariablesfromTermIn(t1)
+      val (p1, p2) = getVariablesfromTermIn(t2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case TITimes(c, t1)=> getVariablesfromTermIn(t1)
+    case TIIte(f, t1, t2)=> {
+      val (s1, s2)  = getVariablesfromTermIn(t1)
+      val (p1, p2) = getVariablesfromTermIn(t2)
+      val (st, tt) = (s1 ++ p1, s2 ++ p2)
+      val (sf, tf) = getVariablesfromFormulaIn(f)
+      (sf ++ st, tf ++ tt)
+    }
+  }
+
+  def getVariablesfromAtomIn(a: AtomIn): (Set[String], Set[String]) = a match {
+    case AILeq(t1, t2) => {
+      val (s1, s2)  = getVariablesfromTermIn(t1)
+      val (p1, p2) = getVariablesfromTermIn(t2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case AIEq(t1,t2) => {
+      val (s1, s2)  = getVariablesfromTermIn(t1)
+      val (p1, p2) = getVariablesfromTermIn(t2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+  }
+
+  def getVariablesfromFormulaIn(f: FormulaIn): (Set[String], Set[String]) = f match {
+    case FIAnd(f1, f2) => {
+      val (s1, s2)  = getVariablesfromFormulaIn(f1)
+      val (t1, t2) = getVariablesfromFormulaIn(f2)
+      (s1 ++ t1, s2 ++ t2)
+    }
+    case FIOr(f1, f2) => {
+      val (s1, s2)  = getVariablesfromFormulaIn(f1)
+      val (t1, t2) = getVariablesfromFormulaIn(f2)
+      (s1 ++ t1, s2 ++ t2)
+    }
+    case FINot(f1)  => getVariablesfromFormulaIn(f1)
+    case FIAtom(a)  => getVariablesfromAtomIn(a)
+    case FITrue  => (Set[String](), Set[String]())
+    case FIFalse  => (Set[String](), Set[String]())
+  }
+
+  def getVariablesfromTermOut(t: TermOut): (Set[String], Set[String]) = t match {
+    case TOConstant(c) => (Set[String](), Set[String]())
+    case TOVariable(v) => (Set(v), Set[String]())
+    case TOCard(m) => getVariablesfromMultiset(m)
+    case TOPlus(t1, t2) => {
+      val (s1, s2)  = getVariablesfromTermOut(t1)
+      val (p1, p2) = getVariablesfromTermOut(t2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case TOTimes(c, t1)=> getVariablesfromTermOut(t1)
+    case TOIte(f, t1, t2)=> {
+      val (s1, s2)  = getVariablesfromTermOut(t1)
+      val (p1, p2) = getVariablesfromTermOut(t2)
+      val (st, tt) = (s1 ++ p1, s2 ++ p2)
+      val (sf, tf) = getVariablesfromFormulaOut(f)
+      (sf ++ st, tf ++ tt)
+    }
+  }
+
+  def getVariablesfromAtomOut(a: AtomOut): (Set[String], Set[String]) = a match {
+    case AOLeq(t1, t2) => {
+      val (s1, s2)  = getVariablesfromTermOut(t1)
+      val (p1, p2) = getVariablesfromTermOut(t2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case AOEq(t1,t2) => {
+      val (s1, s2)  = getVariablesfromTermOut(t1)
+      val (p1, p2) = getVariablesfromTermOut(t2)
+      (s1 ++ p1, s2 ++ p2)
+    }
+    case AOSum(l1, f, l2) => {
+      var s = Set[String]()
+      var t = Set[String]()
+      l1.foreach(v => {
+        val (st, tt) = getVariablesfromTermOut(v)
+        s = s ++ st
+        t = t ++ tt
+      })
+      l2.foreach(v => {
+        val (st, tt) = getVariablesfromTermIn(v)
+        s = s ++ st
+        t = t ++ tt
+      })
+      val (sf, tf) = getVariablesfromFormulaIn(f)
+      (s ++ sf, t ++ tf)
+    }
+  }
+
+  def getVariablesfromFormulaOut(f: FormulaOut): (Set[String], Set[String]) = f match {
+    case FOAnd(f1, f2) => {
+      val (s1, s2)  = getVariablesfromFormulaOut(f1)
+      val (t1, t2) = getVariablesfromFormulaOut(f2)
+      (s1 ++ t1, s2 ++ t2)
+    }
+    case FOOr(f1, f2) => {
+      val (s1, s2)  = getVariablesfromFormulaOut(f1)
+      val (t1, t2) = getVariablesfromFormulaOut(f2)
+      (s1 ++ t1, s2 ++ t2)
+    }
+    case FONot(f1)  => getVariablesfromFormulaOut(f1)
+    case FOAtom(a)  => getVariablesfromAtomOut(a)
+    case FOTrue  => (Set[String](), Set[String]())
+    case FOFalse  => (Set[String](), Set[String]())
+  }
+
+  def getVariablesfromAtom(a: Atom): (Set[String], Set[String]) = a match {
+    case AEqual(m1, m2) => {
+      val (s1, s2)  = getVariablesfromMultiset(m1)
+      val (t1, t2) = getVariablesfromMultiset(m2)
+      (s1 ++ t1, s2 ++ t2)
+    }
+    case ASubset(m1,m2) => {
+      val (s1, s2)  = getVariablesfromMultiset(m1)
+      val (t1, t2) = getVariablesfromMultiset(m2)
+      (s1 ++ t1, s2 ++ t2)
+    }
+    case AForAllElem(f1) => getVariablesfromFormulaIn(f1)
+    case AAtomOut(a1)  => getVariablesfromAtomOut(a1)
+  }
+
+  def getVariablesfromFormula(f: Formula): (Set[String], Set[String]) = f match {
+    case FAnd(f1, f2) => {
+      val (s1, s2)  = getVariablesfromFormula(f1)
+      val (t1, t2) = getVariablesfromFormula(f2)
+      (s1 ++ t1, s2 ++ t2)
+    }
+    case FOr(f1, f2) => {
+      val (s1, s2)  = getVariablesfromFormula(f1)
+      val (t1, t2) = getVariablesfromFormula(f2)
+      (s1 ++ t1, s2 ++ t2)
+    }
+    case FNot(f1)  => getVariablesfromFormula(f1)
+    case FAtom(a)  => getVariablesfromAtom(a)
+    case FTrue  => (Set[String](), Set[String]())
+    case FFalse  => (Set[String](), Set[String]())
+  }
+// end
+
+
+// start: checking that all types are correct
+  def checkTypesOfIntVariables(name: String, m: Map[String, String], ints: List[String]): Unit = {
+    try {
+      ints.foreach(v => if (m(v) != "INT") 
+        abort("Program abort: in the problem " + name + " the INT variable " + v + " is declared as" + m(v) +  "!")
+      )
+    } catch {
+       case ex: NoSuchElementException => {
+         val v = whichVarIsMissing(ex.getMessage)
+         abort("Program abort: in the problem " + name + " the variable " + v + " is not declared!")
+         AEqual(MEmpty, MEmpty)
+       }
+    }
+  }
+
+  def checkTypesOfMSetVariables(name: String, m: Map[String, String], msets: List[String]): Unit = {
+    try {
+      msets.foreach(v => if (m(v) == "INT") 
+        abort("Program abort: in the problem " + name + " the collection variable " + v + " is declared as INT!")
+      )
+    } catch {
+       case ex: NoSuchElementException => {
+         val v = whichVarIsMissing(ex.getMessage)
+         abort("Program abort: in the problem " + name + " the variable " + v + " is not declared!")
+         AEqual(MEmpty, MEmpty)
+       }
+    }
+  } 
+
+  def simpleTypeChecking(name: String, m: Map[String, String], ints: List[String], msets: List[String]): Unit = {
+    checkTypesOfIntVariables(name, m, ints)
+    checkTypesOfMSetVariables(name, m, msets)
+  }
+// end
+
+
+// start: here we construct formulas describing that S is a SET or e is an ELEM
+  def createConstraintAboutOneVar(t: String, v:String): Formula = {
+    val f = if (t == "SET") {
+      val f1in = FIAtom(AIEq(TIMultiplicity(v), TIConstant(0)))
+      val f2in = FIAtom(AIEq(TIMultiplicity(v), TIConstant(1)))
+      FAtom(AForAllElem(FIOr(f1in, f2in)))
+    } else FAtom(AAtomOut(AOEq(TOCard(MVariable(v)), TOConstant(1))))
+    f
+  }
+
+  def getAdditionalConstraints(m: Map[String, String], l: List[String]): Formula =  {
+    val ln = l.filter(v => m(v) != "MSET")
+    val f = if (ln.isEmpty) FTrue else {
+      var ft = createConstraintAboutOneVar(m(ln.head), ln.head)
+      val lnt = ln.tail
+      lnt.foreach(v =>  {
+        val fn = createConstraintAboutOneVar(m(v), v)
+        ft = FAnd(ft, fn)
+      })
+      ft
+    }
+    f
+  }
+// end
+
+
+// start:  translation to NNF
+  def nnfTermIn(t: TermIn): TermIn = t match {
+    case TIPlus(t1, t2) => {
+      val t1n  = nnfTermIn(t1)
+      val t2n  = nnfTermIn(t2)
+      TIPlus(t1n, t2n)
+    }
+    case TITimes(c, t1)=> {
+      val t1n  = nnfTermIn(t1)
+      TITimes(c, t1n)
+    }
+    case TIIte(f, t1, t2) => {
+      val t1n  = nnfTermIn(t1)
+      val t2n  = nnfTermIn(t2)
+      val f1 = nnfFormulaIn(f)
+      TIIte(f1, t1n, t2n)
+    }
+    case _ => t
+  }
+
+  def nnfAtomIn(a: AtomIn): AtomIn = a match {
+    case AILeq(t1, t2) => {
+      val t1n  = nnfTermIn(t1)
+      val t2n  = nnfTermIn(t2)
+      AILeq(t1n, t2n)
+    }
+    case AIEq(t1,t2) => {
+      val t1n  = nnfTermIn(t1)
+      val t2n  = nnfTermIn(t2)
+      AIEq(t1n, t2n)
+    }
+  }
+
+  def nnfFormulaIn(f: FormulaIn): FormulaIn =  f match {
+    case FIAnd(f1, f2) => {
+      val f1n  = nnfFormulaIn(f1)
+      val f2n  = nnfFormulaIn(f2)
+      FIAnd(f1n, f2n)
+    }
+    case FIOr(f1, f2) => {
+      val f1n  = nnfFormulaIn(f1)
+      val f2n  = nnfFormulaIn(f2)
+      FIOr(f1n, f2n)
+    }
+    case FINot(FIAnd(f1, f2)) => {
+      val f1n  = nnfFormulaIn(FINot(f1))
+      val f2n  = nnfFormulaIn(FINot(f2))
+      FIOr(f1n, f2n)
+    }
+    case FINot(FIOr(f1, f2)) => {
+      val f1n  = nnfFormulaIn(FINot(f1))
+      val f2n  = nnfFormulaIn(FINot(f2))
+      FIAnd(f1n, f2n)
+    }
+    case FINot(FINot(f1))  => nnfFormulaIn(f1)
+    case FINot(FIAtom(a)) => {
+      val a1 = nnfAtomIn(a)
+      FINot(FIAtom(a1))
+    }
+    case FINot(FITrue)  => FIFalse 
+    case FINot(FIFalse)  => FITrue
+    case FIAtom(a) => {
+      val a1 = nnfAtomIn(a)
+      FIAtom(a1)
+    }
+    case _  => f
+  }
+
+
+  def nnfTermOut(t: TermOut): TermOut = t match {
+    case TOPlus(t1, t2) => {
+      val t1n  = nnfTermOut(t1)
+      val t2n  = nnfTermOut(t2)
+      TOPlus(t1n, t2n)
+    }
+    case TOTimes(c, t1)=> {
+      val t1n  = nnfTermOut(t1)
+       TOTimes(c, t1n)
+    }
+    case TOIte(f, t1, t2) => {
+      val t1n  = nnfTermOut(t1)
+      val t2n  = nnfTermOut(t2)
+      val f1 = nnfFormulaOut(f)
+      TOIte(f1, t1n, t2n)
+    }
+    case _ => t
+  }
+
+  def nnfAtomOut(a: AtomOut): AtomOut = a match {
+    case AOLeq(t1, t2) => {
+      val t1n  = nnfTermOut(t1)
+      val t2n  = nnfTermOut(t2)
+      AOLeq(t1n, t2n)
+    }
+    case AOEq(t1,t2) => {
+      val t1n  = nnfTermOut(t1)
+      val t2n  = nnfTermOut(t2)
+      AOEq(t1n, t2n)
+    }
+    case AOSum(l1, f, l2) => {
+      val l1n = l1.map(v => nnfTermOut(v))
+      val l2n = l2.map(v => nnfTermIn(v))
+      val f1 = nnfFormulaIn(f)
+      AOSum(l1n, f1, l2n)
+    }
+  }
+
+  def nnfFormulaOut(f: FormulaOut): FormulaOut =  f match {
+    case FOAnd(f1, f2) => {
+      val f1n  = nnfFormulaOut(f1)
+      val f2n  = nnfFormulaOut(f2)
+      FOAnd(f1n, f2n)
+    }
+    case FOOr(f1, f2) => {
+      val f1n  = nnfFormulaOut(f1)
+      val f2n  = nnfFormulaOut(f2)
+      FOOr(f1n, f2n)
+    }
+    case FONot(FOAnd(f1, f2)) => {
+      val f1n  = nnfFormulaOut(FONot(f1))
+      val f2n  = nnfFormulaOut(FONot(f2))
+      FOOr(f1n, f2n)
+    }
+    case FONot(FOOr(f1, f2)) => {
+      val f1n  = nnfFormulaOut(FONot(f1))
+      val f2n  = nnfFormulaOut(FONot(f2))
+      FOAnd(f1n, f2n)
+    }
+    case FONot(FONot(f1))  => nnfFormulaOut(f1)
+    case FONot(FOAtom(a)) => {
+      val a1 = nnfAtomOut(a)
+      FONot(FOAtom(a1))
+    }
+    case FONot(FOTrue)  => FOFalse 
+    case FONot(FOFalse)  => FOTrue
+    case FOAtom(a) => {
+      val a1 = nnfAtomOut(a)
+      FOAtom(a1)
+    }
+    case _  => f
+  }
+
+  def nnfAtom(a: Atom): Atom = a match {
+    case AForAllElem(f1) => {
+      val f1n = nnfFormulaIn(f1)
+      AForAllElem(f1n)
+    }
+    case AAtomOut(a1)  => {
+      val a1n = nnfAtomOut(a1)
+      AAtomOut(a1n)
+    }
+    case _ => a
+  }
+
+  def nnf(f: Formula): Formula = f match {
+    case FAnd(f1, f2) => {
+      val f1n  = nnf(f1)
+      val f2n  = nnf(f2)
+      FAnd(f1n, f2n)
+    }
+    case FOr(f1, f2) => {
+      val f1n  = nnf(f1)
+      val f2n  = nnf(f2)
+      FOr(f1n, f2n)
+    }
+    case FNot(FAnd(f1, f2)) => {
+      val f1n  = nnf(FNot(f1))
+      val f2n  = nnf(FNot(f2))
+      FOr(f1n, f2n)
+    }
+    case FNot(FOr(f1, f2)) => {
+      val f1n  = nnf(FNot(f1))
+      val f2n  = nnf(FNot(f2))
+      FAnd(f1n, f2n)
+    }
+    case FNot(FNot(f1))  => nnf(f1)
+    case FNot(FAtom(a)) => {
+      val a1 = nnfAtom(a)
+      FNot(FAtom(a1))
+    }
+    case FNot(FTrue)  => FFalse 
+    case FNot(FFalse)  => FTrue
+    case FAtom(a) => {
+      val a1 = nnfAtom(a)
+      FAtom(a1)
+    }
+    case _  => f
+  }
+// end
+
+
+// start: input problem, output: (name, created-formula, negated-created-formula, constraints)
+// all output formulas are in NNF
+  def processOneProblem(p: (String, (Map[String, String], Formula))): (String, (Formula, Formula, Formula)) = {
+    val mf = p._2
+    val f1 = checkAtomsInFormula(p._1, mf)
+    val f1f = nnf(f1)
+    val (sInt, sMsets) = getVariablesfromFormula(f1)
+    val lInt = sInt.toList
+    val lMsets = sMsets.toList
+    val m  = mf._1
+    simpleTypeChecking(p._1, m, lInt, lMsets)
+    val fc = getAdditionalConstraints(m, lMsets)
+    val fcf = nnf(fc)
+    val fN = nnf(FNot(f1))
+    (p._1,  (f1f, fN, fcf))
+  }
+// end
+
+
+
+//------------------------------------------------
+
+  def main(problemList: List[(String, (Map[String, String], Formula))]) : List[(String, (Formula, Formula, Formula))] = {
+    val formulaList = problemList.map(p => processOneProblem(p))
+    formulaList
+  }
+}
+
diff --git a/src/multisets/MAPA-FunExamples.scala b/src/multisets/MAPA-FunExamples.scala
new file mode 100644
index 0000000000000000000000000000000000000000..4f7b651575049e95dbeac0e683b0a885fc94aa7e
--- /dev/null
+++ b/src/multisets/MAPA-FunExamples.scala
@@ -0,0 +1,65 @@
+package mapaFun
+
+import mapaFun.MAPAFunFormulaPrinter._
+import multisets.MultisetFormulaPrinter._
+
+
+object MAPAFunExamples {
+
+//    val m1 = MFMPlus(MFFunction("f", MFSetVar("D")), MFFunction("f", MFSetVar("F")))
+    val m1 = MFMPlus(MFFunction("f", MFSetVar("A")), MFFunction("f", MFSetVar("E")))
+    val a1 = MFMSetEqual(MFFunction("f", MFSUnion(MFSetVar("A"), MFSetVar("E"))), m1)
+    val s1 = MFSIntersec(MFSetVar("A"), MFSetVar("E"))
+    val f1 = MFAnd(MFAtom(MFSetEqual(s1, MFEmptySet)), MFNot(MFAtom(a1)))
+
+//---------------
+// the one from the VMCAI submission
+
+    val f21 = MFAtom(MFSetSubset(MFSetVar("N"), MFSetVar("A")))
+    val f22 = MFAtom(MFIntEqual(MFSCard(MFSetVar("T")), MFIntConst (1)))
+    val f23 = MFAtom(MFSetEqual(MFSIntersec(MFSetVar("T"), MFSetVar("A")), MFEmptySet))
+    val f24 = MFAtom(MFMSetEqual(MFFunction("d", MFSetVar("T")), MFMSetVar("E")))
+    val f25 = MFAtom(MFMSetEqual(MFFunction("d", MFSetVar("N")), MFMSetVar("C")))
+    val f26 = MFAtom(MFSetEqual(MFSUnion(MFSetVar("N"), MFSetVar("T")), MFSetVar("N1")))
+    val f27 = MFAtom(MFMSetEqual(MFFunction("d", MFSetVar("N1")), MFMSetVar("C1")))
+    val f28 = MFNot(MFAtom(MFIntLessEqual(MFMCard(MFMSetVar("C1")), MFIPlus(MFMCard(MFMSetVar("C")), MFIntConst (1)))))
+    val f2 = MFAnd(MFAnd(MFAnd(f21, f22), MFAnd(f23, f24)), MFAnd(MFAnd(f25, f26), MFAnd(f27, f28)))
+
+//---------------
+
+
+    def run (name: String, f: MAPAFunFormula): Unit = {
+      println("Formula " + name + ":")
+      print_MAPAFunFormula(f)
+      println("")
+      println("---------------------")
+      val f1n = mapaFun.SetExpansionAndCNF.noMoreSets(f)
+      print_MAPAFunFormula(f1n)
+      println("")
+      println("---------------------")
+      val f2n = mapaFun.FunctionElimination.noMoreFunctions(f1n)
+      print_MAPAFunFormula(f2n)
+      println("")
+      println("---------------------")
+      val f3n = mapaFun.MapaFunConversion.mapaFun2standardMAPA(f2n)
+      print_multisetFormula(f3n)
+      println("")
+      println("---------------------")
+      println("And now the original decision procedure:")
+      println("---------------------")
+//      guru.multisets.Examples.run("f", f3n)
+      println("---------------------")
+   }
+
+
+// -----
+
+  def runExamples() {
+    run("f1", f1)
+//    run("f2", f2)
+  }
+
+
+}
+
+
diff --git a/src/multisets/MAPA-FunFunctionEliminations.scala b/src/multisets/MAPA-FunFunctionEliminations.scala
new file mode 100644
index 0000000000000000000000000000000000000000..877da2fc5af6cd763d536bb3f4f780c023d652f6
--- /dev/null
+++ b/src/multisets/MAPA-FunFunctionEliminations.scala
@@ -0,0 +1,210 @@
+package mapaFun
+
+import scala.collection.mutable.Map
+
+
+object FunctionElimination {
+
+
+  def createSumOfMultisets(l: List[String]): MAPAFunMultiset = {
+    var mm = MFMSetVar(l.head):  MAPAFunMultiset
+    val t = l.tail
+    t.foreach(s => mm = MFMPlus(MFMSetVar(s), mm))
+    mm
+  }
+
+
+  def createMultisetVariableOutofSet(s: String): String = {
+    val s1 = s.replace('S', 'M')
+    s1
+  }
+
+
+  def createListOfFreshMultisetsAndSetMultisetEqualitySet(l: List[String]): (List[String], Set[(String, String)]) = {
+    var sn = Set[(String, String)]()
+    var ln: List[String] = Nil
+    l.foreach(e => {
+      val st = createMultisetVariableOutofSet(e)
+      ln = st :: ln
+      sn = sn ++ Set((e, st))
+    })
+    (ln, sn)
+  }
+
+
+
+  def listOfSetsInUnion(s: MAPAFunSet): List[String] = s match {
+    case MFSetVar(v) => List(v)
+    case MFSUnion(MFSetVar(v), s1) => {
+      val l1 = listOfSetsInUnion(s1)
+      val l2 = v :: l1
+      l2
+    }
+    case MFSUnion(s1, MFSetVar(v)) => {
+      val l1 = listOfSetsInUnion(s1)
+      val l2 = v :: l1
+      l2
+    }
+    case MFSUnion(s1, s2) => {
+      val l1 = listOfSetsInUnion(s1)
+      val l2 = listOfSetsInUnion(s2)
+      val l3 = l1 ::: l2
+      l3
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+
+
+
+  def pullOutAllFunctionsFromMultiset(m: MAPAFunMultiset): (MAPAFunMultiset, Set[(String, String)])  = m match {
+    case MFMSetVar(v) => (m, Set[(String, String)]())
+    case MFEmptyMSet => (m, Set[(String, String)]())
+    case MFMUnion(m1, m2) => {
+      val (m1n, s1) = pullOutAllFunctionsFromMultiset(m1)
+      val (m2n, s2) = pullOutAllFunctionsFromMultiset(m2)
+      (MFMUnion(m1n, m2n), s1 ++ s2)
+    }
+    case MFMIntersec(m1, m2) => {
+      val (m1n, s1) = pullOutAllFunctionsFromMultiset(m1)
+      val (m2n, s2) = pullOutAllFunctionsFromMultiset(m2)
+      (MFMIntersec(m1n, m2n), s1 ++ s2)
+    }
+    case MFMPlus(m1, m2) => {
+      val (m1n, s1) = pullOutAllFunctionsFromMultiset(m1)
+      val (m2n, s2) = pullOutAllFunctionsFromMultiset(m2)
+      (MFMPlus(m1n, m2n), s1 ++ s2)
+    }
+    case MFMMinus(m1, m2) => {
+      val (m1n, s1) = pullOutAllFunctionsFromMultiset(m1)
+      val (m2n, s2) = pullOutAllFunctionsFromMultiset(m2)
+      (MFMMinus(m1n, m2n), s1 ++ s2)
+    }
+    case MFSetMinus(m1, m2) => {
+      val (m1n, s1) = pullOutAllFunctionsFromMultiset(m1)
+      val (m2n, s2) = pullOutAllFunctionsFromMultiset(m2)
+      (MFSetMinus(m1n, m2n), s1 ++ s2)
+    }
+    case MFSSetOf(m1) => {
+      val (m1n, s1) = pullOutAllFunctionsFromMultiset(m1)
+      (MFSSetOf(m1n), s1)
+    }
+    case MFFunction(f, s) => {
+      val l = listOfSetsInUnion(s)
+      val (ml, smes) = createListOfFreshMultisetsAndSetMultisetEqualitySet(l)
+      val mf = createSumOfMultisets(ml)
+      (mf, smes)
+    }
+  }
+
+
+  def pullOutAllFunctionsFromInteger(i: MAPAFunInt): (MAPAFunInt, Set[(String, String)]) = i match {
+    case MFIntVar(v) => (i, Set[(String, String)]())
+    case MFIntConst(c) => (i, Set[(String, String)]())
+    case MFIPlus(i1, i2) => {
+      val (i1n, s1) = pullOutAllFunctionsFromInteger(i1)
+      val (i2n, s2) = pullOutAllFunctionsFromInteger(i2)
+      (MFIPlus(i1n, i2n), s1 ++ s2)
+    }
+    case MFITimes(c, i1) => {
+      val (i1n, s1) = pullOutAllFunctionsFromInteger(i1)
+      (MFITimes(c, i1n), s1)
+    }
+    case MFSCard(s) => (i, Set[(String, String)]())
+    case MFMCard(m) => {
+      val (m1, s1) = pullOutAllFunctionsFromMultiset(m)
+      (MFMCard(m1), s1)
+    }
+  }
+
+
+  def pullOutAllFunctionsFromAtom(a: MAPAFunAtom): (MAPAFunFormula, Set[(String, String)]) = a match {
+    case MFSetEqual(s1, s2) => (MFAtom(a), Set[(String, String)]())
+    case MFSetSubset(s1, s2) => (MFAtom(a), Set[(String, String)]())
+    case MFMSetEqual(m1, m2) => {
+      val (m1n, s1) = pullOutAllFunctionsFromMultiset(m1)
+      val (m2n, s2) = pullOutAllFunctionsFromMultiset(m2)
+      val an = MFMSetEqual(m1n, m2n)
+      (MFAtom(an), s1 ++ s2)
+    }
+    case MFMSetSubset(m1, m2) => {
+      val (m1n, s1) = pullOutAllFunctionsFromMultiset(m1)
+      val (m2n, s2) = pullOutAllFunctionsFromMultiset(m2)
+      val an = MFMSetSubset(m1n, m2n)
+      (MFAtom(an), s1 ++ s2)
+    }
+    case MFIntEqual(i1, i2) => {
+      val (i1n, s1) = pullOutAllFunctionsFromInteger(i1)
+      val (i2n, s2) = pullOutAllFunctionsFromInteger(i2)
+      val an = MFIntEqual(i1n, i2n)
+      (MFAtom(an), s1 ++ s2)
+    }
+    case MFIntLessEqual(i1, i2) => {
+      val (i1n, s1) = pullOutAllFunctionsFromInteger(i1)
+      val (i2n, s2) = pullOutAllFunctionsFromInteger(i2)
+      val an = MFIntLessEqual(i1n, i2n)
+      (MFAtom(an), s1 ++ s2)
+    }
+    case MFIntDivides(c, i) => {
+      val (in, s1) = pullOutAllFunctionsFromInteger(i)
+      val an = MFIntDivides(c, in)
+      (MFAtom(an), s1)
+    }
+  }
+
+
+  def pullOutAllFunctionsFromFormula(f: MAPAFunFormula): (MAPAFunFormula, Set[(String, String)])  = f match {
+    case MFAnd(f1, f2) => {
+      val (f1n, s1) = pullOutAllFunctionsFromFormula(f1)
+      val (f2n, s2) = pullOutAllFunctionsFromFormula(f2)
+      (MFAnd(f1n, f2n), s1 ++ s2)
+    }
+    case MFOr(f1, f2) => {
+      val (f1n, s1) = pullOutAllFunctionsFromFormula(f1)
+      val (f2n, s2) = pullOutAllFunctionsFromFormula(f2)
+      (MFOr(f1n, f2n), s1 ++ s2)
+    }
+    case MFNot(f1)  => {
+      val (f1n, s1) = pullOutAllFunctionsFromFormula(f1)
+      (MFNot(f1n), s1)
+    }
+    case MFAtom(a)  => pullOutAllFunctionsFromAtom(a)
+  }
+
+
+
+  def createOneCardinalityFormula(p: (String, String)): MAPAFunFormula = {
+    val s = p._1
+    val m = p._2
+    val f = MFAtom(MFIntEqual(MFSCard(MFSetVar(s)), MFMCard(MFMSetVar(m))))
+    f
+  }
+
+
+  def createCardinalityFormulas(l:  List[(String, String)]): MAPAFunFormula = {
+    var ft = createOneCardinalityFormula(l.head)
+    val t = l.tail
+    val ff = if (t.isEmpty) ft else {
+      t.foreach(p => {
+        val fp = createOneCardinalityFormula(p)
+        ft = MFAnd(fp, ft)
+      })
+      ft
+    }
+    ff
+  }
+
+
+
+
+//--------------------------------------
+
+
+  def noMoreFunctions(f: MAPAFunFormula): MAPAFunFormula  = {
+    val (f1, s) = pullOutAllFunctionsFromFormula(f)
+    val l = s.toList
+    val f2 = createCardinalityFormulas(l)
+    MFAnd(f1, f2)
+  }
+}
+
diff --git a/src/multisets/MAPA-FunPrinter.scala b/src/multisets/MAPA-FunPrinter.scala
new file mode 100644
index 0000000000000000000000000000000000000000..3cb7b593109c20f7a5624fd25e7df91c416a43d1
--- /dev/null
+++ b/src/multisets/MAPA-FunPrinter.scala
@@ -0,0 +1,153 @@
+package mapaFun
+
+
+object MAPAFunFormulaPrinter {
+
+  def print_MAPAFunInt(i: MAPAFunInt): Unit = i match {
+    case MFIntVar(v) => Console.print(v)
+    case MFIntConst(c) => Console.print(c)
+    case MFIPlus(i1, i2) => {
+      print_MAPAFunInt(i1)
+      Console.print(" + ")
+      print_MAPAFunInt(i2)
+    }
+    case MFITimes(c, i1) => {
+      Console.print(c + "*")
+      print_MAPAFunInt(i1)
+    }
+    case MFSCard(s) => {
+      Console.print("| ")
+      print_MAPAFunSet(s)
+      print(" |")
+    }
+    case MFMCard(m) => {
+      Console.print("| ")
+      print_MAPAFunMultiset(m)
+      print(" |")
+    }
+  }
+
+  def print_MAPAFunMultiset(m: MAPAFunMultiset):Unit = m match {
+    case MFMSetVar(v) => Console.print(v)
+    case MFEmptyMSet => Console.print("EMPTY MULTISET")
+    case MFMUnion(m1, m2) => {
+      print_MAPAFunMultiset(m1)
+      Console.print(" UNION ")
+      print_MAPAFunMultiset(m2)
+    }
+    case MFMIntersec(m1, m2) => {
+      print_MAPAFunMultiset(m1)
+      Console.print(" INTERSEC ")
+      print_MAPAFunMultiset(m2)
+    }
+    case MFMPlus(m1, m2) => {
+      print_MAPAFunMultiset(m1)
+      Console.print(" PLUS ")
+      print_MAPAFunMultiset(m2)
+    }
+    case MFMMinus(m1, m2) => {
+      print_MAPAFunMultiset(m1)
+      Console.print(" MINUS ")
+      print_MAPAFunMultiset(m2)
+    }
+    case MFSetMinus(m1, m2) => {
+      print_MAPAFunMultiset(m1)
+      Console.print(" SET MINUS ")
+      print_MAPAFunMultiset(m2)
+    }
+    case MFSSetOf(m1) => {
+      Console.print(" SETOf ( ")
+      print_MAPAFunMultiset(m1)
+      print(" )")
+    }
+    case MFFunction(f, s) => {
+      Console.print(f + "[ ")
+      print_MAPAFunSet(s)
+      print(" ]")
+    }
+  }
+
+  def print_MAPAFunSet(s: MAPAFunSet):Unit = s match {
+    case MFSetVar(v) => Console.print(v)
+    case MFEmptySet => Console.print("EMPTY SET")
+    case MFUnivSet => Console.print("UNIVERSAL SET")
+    case MFSUnion(s1, s2) => {
+      print_MAPAFunSet(s1)
+      Console.print(" UNION ")
+      print_MAPAFunSet(s2)
+    }
+    case MFSIntersec(s1, s2) => {
+      print_MAPAFunSet(s1)
+      Console.print(" INTERSEC ")
+      print_MAPAFunSet(s2)
+    }
+    case MFSCompl(s1) => {
+      Console.print("( ")
+      print_MAPAFunSet(s1)
+      print(" )^c ")
+    }
+  }
+
+
+  def print_MAPAFunAtom(a: MAPAFunAtom):Unit = a match {
+    case MFSetEqual(s1, s2) => {
+      print_MAPAFunSet(s1)
+      Console.print(" = ")
+      print_MAPAFunSet(s2)
+    }
+    case MFSetSubset(s1, s2) => {
+      print_MAPAFunSet(s1)
+      Console.print(" SUBSET ")
+      print_MAPAFunSet(s2)
+    }
+    case MFMSetEqual(m1, m2) => {
+      print_MAPAFunMultiset(m1)
+      Console.print(" = ")
+      print_MAPAFunMultiset(m2)
+    }
+    case MFMSetSubset(m1, m2) => {
+      print_MAPAFunMultiset(m1)
+      Console.print(" SUBSET ")
+      print_MAPAFunMultiset(m2)
+    }
+    case MFIntEqual(i1, i2) => {
+      print_MAPAFunInt(i1)
+      Console.print(" = ")
+      print_MAPAFunInt(i2)
+    }
+    case MFIntLessEqual(i1, i2) => {
+      print_MAPAFunInt(i1)
+      Console.print(" =< ")
+      print_MAPAFunInt(i2)
+    }
+    case MFIntDivides(c, i) => {
+      Console.print(c + " * ")
+      print_MAPAFunInt(i)
+    }
+  }
+
+
+  def print_MAPAFunFormula(f: MAPAFunFormula):Unit = f match {
+    case MFAnd(f1, f2) => {
+      Console.print(" ( ")
+      print_MAPAFunFormula(f1)
+      print(" ) AND ( ")
+      print_MAPAFunFormula(f2)
+      print(" ) ")
+    }
+    case MFOr(f1, f2) => {
+      Console.print(" ( ")
+      print_MAPAFunFormula(f1)
+      print(" ) OR ( ")
+      print_MAPAFunFormula(f2)
+      print(" ) ")
+    }
+    case MFNot(f1)  => {
+      Console.print(" NOT ( ")
+      print_MAPAFunFormula(f1)
+      print(" ) ")
+    }
+    case MFAtom(a)  => print_MAPAFunAtom(a)
+  }
+
+}
\ No newline at end of file
diff --git a/src/multisets/MAPA-FunSetExpansionTranslator.scala b/src/multisets/MAPA-FunSetExpansionTranslator.scala
new file mode 100644
index 0000000000000000000000000000000000000000..7962f98ff51cbd2bac9ec90a29b99a999ee2f0c0
--- /dev/null
+++ b/src/multisets/MAPA-FunSetExpansionTranslator.scala
@@ -0,0 +1,397 @@
+package mapaFun
+
+
+import scala.collection.mutable.Map
+import scala.collection.immutable.Set
+import java.lang.Integer
+
+
+
+object SetExpansionAndCNF {
+
+
+
+
+
+
+
+
+// ---- getRidOfSetVariables
+
+
+  def simplifySetAtoms(s1: Set[String], s2: Set[String]): (Set[String], Set[String]) = {
+    val si = s1.intersect(s2)
+    val s1n = s1 -- si
+    val s2n = s2 -- si
+    (s1n, s2n)
+  }
+
+
+  def getRidOfSetVariablesinSet(s: MAPAFunSet, m: Map[String,Set[String]]): Set[String] = s match {
+    case MFSetVar(v) => m(v)
+    case MFEmptySet => Set[String]()
+    case MFUnivSet => m("ALL")
+    case MFSUnion(s1, s2) => {
+      val ss1 = getRidOfSetVariablesinSet(s1, m)
+      val ss2 = getRidOfSetVariablesinSet(s2, m)
+      ss1 ++ ss2
+    }
+    case MFSIntersec(s1, s2) => {
+      val ss1 = getRidOfSetVariablesinSet(s1, m)
+      val ss2 = getRidOfSetVariablesinSet(s2, m)
+      val ss3 = ss1.intersect(ss2)
+      ss3
+    }
+    case MFSCompl(s1) => {
+      val ss1 = getRidOfSetVariablesinSet(s1, m)
+      val ss2 = m("ALL") -- ss1
+      ss2
+    }
+  }
+
+  def createSetUnion(s: Set[String]): MAPAFunSet =  {
+    val l = s.toList
+    if (l.isEmpty) MFEmptySet else {
+       var ts =  MFSetVar(l.head): MAPAFunSet
+       val t = l.tail
+       t.foreach(e => {
+         val ns = MFSetVar(e)
+         ts = MFSUnion(ts, ns)
+       })
+       ts
+    }
+  }
+
+  def getRidOfSetVariablesinInt(i: MAPAFunInt, m: Map[String,Set[String]]): MAPAFunInt  = i match {
+    case MFIntVar(v) => i
+    case MFIntConst(c) => i
+    case MFIPlus(i1, i2) => {
+      val i1n = getRidOfSetVariablesinInt(i1, m)
+      val i2n = getRidOfSetVariablesinInt(i2, m)
+      MFIPlus(i1n, i2n)
+    }
+    case MFITimes(c, i1) => {
+      val i1n = getRidOfSetVariablesinInt(i1, m)
+      MFITimes(c, i1n)
+    }
+    case MFSCard(s) => {
+      val sl = getRidOfSetVariablesinSet(s, m)
+      val sn = createSetUnion(sl)
+      MFSCard(sn)
+    }
+    case MFMCard(ms) => {
+      val msn = getRidOfSetVariablesinMultiset(ms, m)
+      MFMCard(msn)
+    }
+  }
+
+  def getRidOfSetVariablesinMultiset(mm: MAPAFunMultiset, m: Map[String,Set[String]]): MAPAFunMultiset  = mm match {
+    case MFMSetVar(v) => mm
+    case MFEmptyMSet => mm
+    case MFMUnion(m1, m2) => {
+      val m1n = getRidOfSetVariablesinMultiset(m1, m)
+      val m2n = getRidOfSetVariablesinMultiset(m2, m)
+      MFMUnion(m1n, m2n)
+    }
+    case MFMIntersec(m1, m2) => {
+      val m1n = getRidOfSetVariablesinMultiset(m1, m)
+      val m2n = getRidOfSetVariablesinMultiset(m2, m)
+      MFMIntersec(m1n, m2n)
+    }
+    case MFMPlus(m1, m2) => {
+      val m1n = getRidOfSetVariablesinMultiset(m1, m)
+      val m2n = getRidOfSetVariablesinMultiset(m2, m)
+      MFMPlus(m1n, m2n)
+    }
+    case MFMMinus(m1, m2) => {
+      val m1n = getRidOfSetVariablesinMultiset(m1, m)
+      val m2n = getRidOfSetVariablesinMultiset(m2, m)
+      MFMMinus(m1n, m2n)
+    }
+    case MFSetMinus(m1, m2) => {
+      val m1n = getRidOfSetVariablesinMultiset(m1, m)
+      val m2n = getRidOfSetVariablesinMultiset(m2, m)
+      MFSetMinus(m1n, m2n)
+    }
+    case MFSSetOf(m1) => {
+      val m1n = getRidOfSetVariablesinMultiset(m1, m)
+      MFSSetOf(m1n)
+    }
+    case MFFunction(f, s) => {
+      val sl = getRidOfSetVariablesinSet(s, m)
+      val sn = createSetUnion(sl)
+      MFFunction(f, sn)
+    }
+  }
+
+
+  def getRidOfSetVariablesinAtom(a:MAPAFunAtom, m: Map[String,Set[String]]): MAPAFunAtom  = a match {
+    case MFSetEqual(s1, s2) => {
+      val ss1l = getRidOfSetVariablesinSet(s1, m)
+      val ss2l = getRidOfSetVariablesinSet(s2, m)
+      val (ss1ln, ss2ln) = simplifySetAtoms(ss1l, ss2l)
+      val s1n = createSetUnion(ss1ln)
+      val s2n = createSetUnion(ss2ln)
+      MFSetEqual(s1n, s2n)
+    }
+    case MFSetSubset(s1, s2) => {
+      val ss1l = getRidOfSetVariablesinSet(s1, m)
+      val ss2l = getRidOfSetVariablesinSet(s2, m)
+      val (ss1ln, ss2ln) = simplifySetAtoms(ss1l, ss2l)
+      val s1n = createSetUnion(ss1ln)
+      val s2n = createSetUnion(ss2ln)
+      MFSetSubset(s1n, s2n)
+    }
+    case MFMSetEqual(m1, m2) => {
+      val m1n = getRidOfSetVariablesinMultiset(m1, m)
+      val m2n = getRidOfSetVariablesinMultiset(m2, m)
+      MFMSetEqual(m1n, m2n)
+    }
+    case MFMSetSubset(m1, m2) => {
+      val m1n = getRidOfSetVariablesinMultiset(m1, m)
+      val m2n = getRidOfSetVariablesinMultiset(m2, m)
+      MFMSetSubset(m1n, m2n)
+    }
+    case MFIntEqual(i1, i2) => {
+      val i1n = getRidOfSetVariablesinInt(i1, m)
+      val i2n = getRidOfSetVariablesinInt(i2, m)
+      MFIntEqual(i1n, i2n)
+    }
+    case MFIntLessEqual(i1, i2) => {
+      val i1n = getRidOfSetVariablesinInt(i1, m)
+      val i2n = getRidOfSetVariablesinInt(i2, m)
+      MFIntLessEqual(i1n, i2n)
+    }
+    case MFIntDivides(c, i) => {
+      val in = getRidOfSetVariablesinInt(i, m)
+      MFIntDivides(c, in)
+    }
+  }
+
+
+  def getRidOfSetVariables(f: MAPAFunFormula, m: Map[String,Set[String]]): MAPAFunFormula = f match {
+    case MFAnd(f1, f2) => {
+      val f1n = getRidOfSetVariables(f1, m)
+      val f2n = getRidOfSetVariables(f2, m)
+      MFAnd(f1n, f2n)
+    }
+    case MFOr(f1, f2) => {
+      val f1n = getRidOfSetVariables(f1, m)
+      val f2n = getRidOfSetVariables(f2, m)
+      MFOr(f1n, f2n)
+    }
+    case MFNot(f1) => {
+      val f1n = getRidOfSetVariables(f1, m)
+      MFNot(f1n)
+    }
+    case MFAtom(a) =>{
+      val an = getRidOfSetVariablesinAtom(a, m)
+      MFAtom(an)
+    } 
+  }
+
+
+
+
+
+
+
+// ---- list of all sets 
+
+  def setofAllSetsinInt(i: MAPAFunInt): Set[String] = i match {
+    case MFIntVar(v) => Set[String]()
+    case MFIntConst(c) => Set[String]()
+    case MFIPlus(i1, i2) => {
+      val l1 = setofAllSetsinInt(i1)
+      val l2 = setofAllSetsinInt(i2)
+      l1 ++ l2
+    }
+    case MFITimes(c, i1) => setofAllSetsinInt(i1)
+    case MFSCard(s) => setofAllSetsinSet(s)
+    case MFMCard(m) => setofAllSetsinMultiset(m)
+  }
+
+  def setofAllSetsinMultiset(m: MAPAFunMultiset): Set[String] = m match {
+    case MFMSetVar(v) => Set[String]()
+    case MFEmptyMSet => Set[String]()
+    case MFMUnion(m1, m2) => {
+      val l1 = setofAllSetsinMultiset(m1)
+      val l2 = setofAllSetsinMultiset(m2)
+      l1 ++ l2
+    }
+    case MFMIntersec(m1, m2) => {
+      val l1 = setofAllSetsinMultiset(m1)
+      val l2 = setofAllSetsinMultiset(m2)
+      l1 ++ l2
+    }
+    case MFMPlus(m1, m2) => {
+      val l1 = setofAllSetsinMultiset(m1)
+      val l2 = setofAllSetsinMultiset(m2)
+      l1 ++ l2
+    }
+    case MFMMinus(m1, m2) => {
+      val l1 = setofAllSetsinMultiset(m1)
+      val l2 = setofAllSetsinMultiset(m2)
+      l1 ++ l2
+    }
+    case MFSetMinus(m1, m2) => {
+      val l1 = setofAllSetsinMultiset(m1)
+      val l2 = setofAllSetsinMultiset(m2)
+      l1 ++ l2
+    }
+    case MFSSetOf(m1) => setofAllSetsinMultiset(m1)
+    case MFFunction(f, s) => setofAllSetsinSet(s)
+  }
+
+  def setofAllSetsinSet(s: MAPAFunSet): Set[String]  = s match {
+    case MFSetVar(v) => Set(v)
+    case MFEmptySet => Set[String]()
+    case MFUnivSet => Set[String]()
+    case MFSUnion(s1, s2) => {
+      val l1 = setofAllSetsinSet(s1)
+      val l2 = setofAllSetsinSet(s2)
+      l1 ++ l2
+    }
+    case MFSIntersec(s1, s2) => {
+      val l1 = setofAllSetsinSet(s1)
+      val l2 = setofAllSetsinSet(s2)
+      l1 ++ l2
+    }
+    case MFSCompl(s1) => setofAllSetsinSet(s1)
+  }
+
+  def setofAllSetsinAtom(a: MAPAFunAtom): Set[String] = a match {
+    case MFSetEqual(s1, s2) => {
+      val l1 = setofAllSetsinSet(s1)
+      val l2 = setofAllSetsinSet(s2)
+      l1 ++ l2
+    }
+    case MFSetSubset(s1, s2) => {
+      val l1 = setofAllSetsinSet(s1)
+      val l2 = setofAllSetsinSet(s2)
+      l1 ++ l2
+    }
+    case MFMSetEqual(m1, m2) => {
+      val l1 = setofAllSetsinMultiset(m1)
+      val l2 = setofAllSetsinMultiset(m2)
+      l1 ++ l2
+    }
+    case MFMSetSubset(m1, m2) => {
+      val l1 = setofAllSetsinMultiset(m1)
+      val l2 = setofAllSetsinMultiset(m2)
+      l1 ++ l2
+    }
+    case MFIntEqual(i1, i2) => {
+      val l1 = setofAllSetsinInt(i1)
+      val l2 = setofAllSetsinInt(i2)
+      l1 ++ l2
+    }
+    case MFIntLessEqual(i1, i2) => {
+      val l1 = setofAllSetsinInt(i1)
+      val l2 = setofAllSetsinInt(i2)
+      l1 ++ l2
+    }
+    case MFIntDivides(c, i) => setofAllSetsinInt(i)
+  }
+
+  def setofAllSets(f: MAPAFunFormula): Set[String] = f match {
+    case MFAnd(f1, f2) => {
+      val s1 = setofAllSets(f1)
+      val s2 = setofAllSets(f2)
+      s1 ++ s2
+    }
+    case MFOr(f1, f2) => {
+      val s1 = setofAllSets(f1)
+      val s2 = setofAllSets(f2)
+      s1 ++ s2
+    }
+    case MFNot(f1)  => setofAllSets(f1)
+    case MFAtom(a)  => setofAllSetsinAtom(a)
+  }
+
+  def power2(n: Int): Int = {
+    var i = 1
+    for(k <- 1 to n) i = i * 2
+    i
+  }
+
+  def createListOfExponentialSize(n: Int): List[List[String]] = {
+    if (n == 0) Nil
+    else {
+      val ub = power2 (n - 1)
+      var l1: List[List[String]] = Nil
+      for (i <- 0 to (ub - 1) ) {
+        val s = (Integer.toBinaryString(i)).toList
+        var s1 = s.map (_.toString)
+        while (s1.length < (n - 1)) {
+          s1 = "0" :: s1
+        }
+        l1 = s1 :: l1
+      }
+      l1
+    }
+  }
+
+  def createStringfromList(i: Int, l: List[String]): String = {
+    val ln = l.take(i) ::: ( "1" :: l.drop(i) )
+    ln.mkString("S", "", "")
+  }
+
+
+  def createCubesForSet(i: Int, l: List[List[String]]): Set[String] = {
+    var s = Set[String]()
+    l.foreach(l1 => {
+      val st = createStringfromList(i, l1)
+      s = s ++ Set(st)
+    })
+    s
+  }
+
+
+  def createUniversalSetCubes(l: List[List[String]]): Set[String] = {
+    var s = Set[String]()
+    l.foreach(e => {
+      val l0 = "0" :: e
+      val s0 = l0.mkString("S", "", "")
+      s = s ++ Set(s0)
+      val l1 = "1" :: e
+      val s1 = l1.mkString("S", "", "")
+      s = s ++ Set(s1)
+    })
+    s
+  }
+
+  def createMapOfNewCubes(l: List[String]): Map[String,Set[String]] = {
+    val tm = Map[String, Set[String]]()
+    val n = l.length
+    var i = 0
+    val ls = createListOfExponentialSize(n)
+    l.foreach(e => {
+      val nl = createCubesForSet(i, ls)
+      i = i + 1
+      tm += (e -> nl)
+      }
+    )
+    val us = createUniversalSetCubes(ls)
+    tm += ("ALL" -> us)
+    tm
+  }
+
+  def listOfAllSets(f: MAPAFunFormula): Map[String,Set[String]] = {
+    val s1 = setofAllSets(f)
+    val l1 = s1.toList
+    val m1 = createMapOfNewCubes(l1)
+    m1
+  }
+
+
+//--------------------------------------
+
+  def noMoreSets(f: MAPAFunFormula): MAPAFunFormula = {
+    val l1 = listOfAllSets(f)
+    val f1 = getRidOfSetVariables(f, l1)
+    f1
+  }
+
+}
+
diff --git a/src/multisets/MAPA-FunTranslation2MAPA.scala b/src/multisets/MAPA-FunTranslation2MAPA.scala
new file mode 100644
index 0000000000000000000000000000000000000000..5ebb931b476fd89986e14764e609288bc61c1d05
--- /dev/null
+++ b/src/multisets/MAPA-FunTranslation2MAPA.scala
@@ -0,0 +1,214 @@
+package mapaFun
+
+import multisets._
+
+
+object MapaFunConversion {
+
+
+  def createFormulaThatTwoAreDisjoint(s1: String, s2: String): Formula = {
+    val a = AEqual(MIntersection(MVariable(s1), MVariable(s2)), MEmpty)
+    FAtom(a)
+  }
+
+  def createFormulaThatOneIsDisjoint(s: String, l: List[String]): Formula = {
+   val h = l.head
+   val t = l.tail
+   var ft = createFormulaThatTwoAreDisjoint(s, h)
+   t.foreach(e => {
+     val f1 = createFormulaThatTwoAreDisjoint(s, e)
+     ft = FAnd(f1, ft)
+   })
+   ft
+  }
+
+  def createFormulaForDisjointness(l: List[String]): Formula = {
+    var h = l.head
+    var t = l.tail
+    var ft = createFormulaThatOneIsDisjoint(h, t)
+    while (t.length > 1) {
+      h = t.head
+      t = t.tail
+      val f1 = createFormulaThatOneIsDisjoint(h, t)
+      ft = FAnd(f1, ft)
+    }
+    ft
+  }
+
+  def createFormulaInItIsSet(s: String): FormulaIn = {
+    val a0 = AIEq(TIMultiplicity(s), TIConstant(0))
+    val a1 = AIEq(TIMultiplicity(s), TIConstant(1))
+    FIOr(FIAtom(a0), FIAtom(a1))
+  }
+
+  def createFormulaInTheyAreSets(l: List[String]): FormulaIn = {
+    var f1 = createFormulaInItIsSet(l.head)
+    val t = l.tail
+    t.foreach(s => {
+      val ft = createFormulaInItIsSet(s)
+      f1 = FIAnd(ft, f1)
+    })
+    f1
+  }
+
+  def createFormulaTheyAreSets(l: List[String]): Formula = {
+    val f1 = createFormulaInTheyAreSets(l)
+    FAtom(AForAllElem(f1))
+  }
+
+  def createFormulaAboutSets(l: List[String]): Formula = {
+    val f1 = createFormulaTheyAreSets(l)
+    if (l.length == 1) f1 else {
+      val f2 = createFormulaForDisjointness(l)
+      FAnd(f1, f2)
+    }
+  }
+
+//-------------------
+
+  def convertMAPAFunSet2MapaMset(s: MAPAFunSet): (Multiset, Set[String])  = s match {
+    case MFSetVar(v) => (MVariable(v), Set(v))
+    case MFEmptySet => (MEmpty, Set[String]())
+    case MFSUnion(s1, s2) => {
+      val (m1, l1) = convertMAPAFunSet2MapaMset(s1)
+      val (m2, l2) = convertMAPAFunSet2MapaMset(s2)
+      (MPlus(m1, m2), l1 ++ l2)
+    }
+    case x@_ => error("Impossible case :" + x)  
+  }
+
+  def convertMAPAFunMset2MapaMset(m: MAPAFunMultiset): (Multiset, Set[String])  = m match {
+    case MFMSetVar(v) => (MVariable(v), Set[String]())
+    case MFEmptyMSet => (MEmpty, Set[String]())
+    case MFMUnion(m1, m2) => {
+      val (m1n, l1) = convertMAPAFunMset2MapaMset(m1)
+      val (m2n, l2) = convertMAPAFunMset2MapaMset(m2)
+      (MUnion(m1n, m2n), l1 ++ l2)
+    }
+    case MFMIntersec(m1, m2) => {
+      val (m1n, l1) = convertMAPAFunMset2MapaMset(m1)
+      val (m2n, l2) = convertMAPAFunMset2MapaMset(m2)
+      (MIntersection(m1n, m2n), l1 ++ l2)
+    }
+    case MFMPlus(m1, m2) => {
+      val (m1n, l1) = convertMAPAFunMset2MapaMset(m1)
+      val (m2n, l2) = convertMAPAFunMset2MapaMset(m2)
+      (MPlus(m1n, m2n), l1 ++ l2)
+    }
+    case MFMMinus(m1, m2) => {
+      val (m1n, l1) = convertMAPAFunMset2MapaMset(m1)
+      val (m2n, l2) = convertMAPAFunMset2MapaMset(m2)
+      (MMinus(m1n, m2n), l1 ++ l2)
+    }
+    case MFSetMinus(m1, m2) => {
+      val (m1n, l1) = convertMAPAFunMset2MapaMset(m1)
+      val (m2n, l2) = convertMAPAFunMset2MapaMset(m2)
+      (MSetMinus(m1n, m2n), l1 ++ l2)
+    }
+    case MFSSetOf(m1) => {
+      val (m1n, l1) = convertMAPAFunMset2MapaMset(m1)
+      (MSetOf(m1n), l1)
+    }
+    case x@_ => error("Impossible case :" + x)  
+  }
+
+
+  def convertMAPAFunint2MapaTO(i: MAPAFunInt): (TermOut, Set[String])  = i match {
+    case MFIntVar(v) => (TOVariable(v), Set[String]())
+    case MFIntConst(c) => (TOConstant(c), Set[String]())
+    case MFIPlus(i1, i2) => {
+      val (t1, l1) = convertMAPAFunint2MapaTO(i1)
+      val (t2, l2) = convertMAPAFunint2MapaTO(i2)
+      (TOPlus(t1, t2), l1 ++ l2)
+    }
+    case MFITimes(c, i1) => {
+      val (t1, l1) = convertMAPAFunint2MapaTO(i1)
+      (TOTimes(c, t1), l1)
+    }
+    case MFSCard(s) => {
+      val (m1, l1) = convertMAPAFunSet2MapaMset(s)
+      (TOCard(m1), l1)
+    }
+    case MFMCard(m) => {
+      val (m1, l1) = convertMAPAFunMset2MapaMset(m)
+      (TOCard(m1), l1)
+    }
+  }
+
+  def createFreshTO(n: Int): TermOut = {
+    val s = "FRESHInt" + n
+    TOVariable(s)
+  }
+
+  def convertAtomAndGetSets(a: MAPAFunAtom, i: Int): (Formula, Set[String], Int)  = a match {
+    case MFSetEqual(s1, s2) => {
+      val (m1, sl1) = convertMAPAFunSet2MapaMset(s1)
+      val (m2, sl2) = convertMAPAFunSet2MapaMset(s2)
+      (FAtom(AEqual(m1, m2)), sl1 ++ sl2, i)
+    }
+    case MFSetSubset(s1, s2) => {
+      val (m1, sl1) = convertMAPAFunSet2MapaMset(s1)
+      val (m2, sl2) = convertMAPAFunSet2MapaMset(s2)
+      (FAtom(ASubset(m1, m2)), sl1 ++ sl2, i)
+    }
+    case MFMSetEqual(m1, m2) => {
+      val (m1n, sl1) = convertMAPAFunMset2MapaMset(m1)
+      val (m2n, sl2) = convertMAPAFunMset2MapaMset(m2)
+      (FAtom(AEqual(m1n, m2n)), sl1 ++ sl2, i)
+    }
+    case MFMSetSubset(m1, m2) => {
+      val (m1n, sl1) = convertMAPAFunMset2MapaMset(m1)
+      val (m2n, sl2) = convertMAPAFunMset2MapaMset(m2)
+      (FAtom(ASubset(m1n, m2n)), sl1 ++ sl2, i)
+    }
+    case MFIntEqual(i1, i2) => {
+      val (i1n, sl1) = convertMAPAFunint2MapaTO(i1)
+      val (i2n, sl2) = convertMAPAFunint2MapaTO(i2)
+      (FAtom(AAtomOut(AOEq(i1n, i2n))), sl1 ++ sl2, i)
+    }
+    case MFIntLessEqual(i1, i2) => {
+      val (i1n, sl1) = convertMAPAFunint2MapaTO(i1)
+      val (i2n, sl2) = convertMAPAFunint2MapaTO(i2)
+      (FAtom(AAtomOut(AOLeq(i1n, i2n))), sl1 ++ sl2, i)
+    }
+    case MFIntDivides(c, i1) => {
+      val (i1n, sl1) = convertMAPAFunint2MapaTO(i1)
+      val ft = createFreshTO(i)
+      (FAtom(AAtomOut(AOEq(ft, TOTimes(c, i1n)))), sl1, i + 1)
+    }
+  }
+
+  def convertFormulaAndGetSets(f: MAPAFunFormula, i: Int): (Formula, Set[String], Int)  = f match {
+    case MFAnd(f1, f2) => {
+      val (f1n, s1, i1) = convertFormulaAndGetSets(f1, i)
+      val (f2n, s2, i2) = convertFormulaAndGetSets(f2, i1)
+      (FAnd(f1n, f2n), s1 ++ s2, i2)
+    }
+    case MFOr(f1, f2) => {
+      val (f1n, s1, i1) = convertFormulaAndGetSets(f1, i)
+      val (f2n, s2, i2) = convertFormulaAndGetSets(f2, i1)
+      (FOr(f1n, f2n), s1 ++ s2, i2)
+    }
+    case MFNot(f1)  => {
+      val (f1n, s1, i1) = convertFormulaAndGetSets(f1, i)
+      (FNot(f1n), s1, i1)
+    }
+    case MFAtom(a)  => convertAtomAndGetSets(a, i)
+  }
+
+
+//--------------------------------
+
+  def mapaFun2standardMAPA(f: MAPAFunFormula): Formula  = {
+    val (f1, s, _) = convertFormulaAndGetSets(f, 0)
+// i counts fresh variables introduced for divides
+    val l = s.toList
+    if (l.isEmpty) f1 else {
+      val f2 = createFormulaAboutSets(l)
+      val ff = FAnd(f1, f2)
+      ff
+    }
+  }
+
+
+}
\ No newline at end of file
diff --git a/src/multisets/MAPAParser.scala b/src/multisets/MAPAParser.scala
new file mode 100644
index 0000000000000000000000000000000000000000..0e032cd440c79a261dee669c3672ad9438a058a3
--- /dev/null
+++ b/src/multisets/MAPAParser.scala
@@ -0,0 +1,213 @@
+package multisets
+
+import scala.util.parsing.combinator.syntactical.StandardTokenParsers
+import scala.util.parsing.combinator._
+import scala.util.parsing.input._
+import scala.util.parsing.syntax._
+import scala.collection.mutable.Map
+import java.io.FileReader
+
+
+object MAPAParser extends StandardTokenParsers {
+
+  lexical.delimiters ++= List( "(", ")", ",",  ".", ":", "=", "<", "_", "{", "}", "+", "|", "-", "*" );
+  lexical.reserved ++= List( "Problem", "Variables", "Formula", "And", "Or", 
+     "Implies", "Equiv", "Not", "true", "false", "SUB", "ALLe", "VEC", "ite", "e", 
+      "empty", "INTR", "UN", "PLUS", "SETof", "SUM" );
+
+
+  def inputFile: Parser[ List[(String, (Map[String, String], Formula))] ] = (
+     rep(oneProblemInFile) 
+    | failure( "Cannot parse the input file." ))
+
+
+  def oneProblemInFile: Parser[(String, (Map[String, String], Formula))] = (
+     ("Problem" ~> "(" ~>  ident <~ ",") ~ ("Variables" ~> "(" ~> myVars <~ ")" <~ ",") ~ ("Formula" ~> "(" ~> myFla <~ ")" <~ ")" <~ "." ) ^^ 
+        { case name ~ vars ~ fla  =>  (name.toString, (vars, fla) ) }
+    | failure( "Cannot parse this problem." ))
+
+
+  def myVars: Parser[ Map[String, String] ] = (
+    repsep(oneVar, ",") ^^ createMap
+    | failure( "Cannot parse this Variables string." ))
+
+  def oneVar: Parser[ (String, String) ] = (
+    (ident ~ ":" ~ ident)^^ { case name ~ ":" ~ typeV  => (name.toString, typeV.toString ) }
+    | failure( "Cannot parse this variable." ))
+
+  def createMap(l: List[(String, String)]):  Map[String, String] = {
+    val m = Map[String, String]()
+    l.foreach(p => m += (p._1 -> p._2))
+    m
+  }
+
+
+  def myFla: Parser[ Formula ]  = (
+      myAtom ^^ (FAtom(_))
+    | ("And" ~> "(" ~> myFla  <~ ",") ~ (myFla <~ ")")^^ {case f1 ~ f2 => FAnd(f1, f2)}
+    | ("Or" ~> "(" ~> myFla <~ ",") ~ (myFla <~ ")")^^ {case f1 ~ f2 => FOr(f1, f2)}
+    | ("Implies" ~> "(" ~> myFla <~ ",") ~ (myFla <~ ")")^^ {case f1 ~ f2 => FOr(FNot(f1), f2)}
+    | ("Equiv" ~> "(" ~> myFla <~ ",") ~ (myFla <~ ")")^^ {case f1 ~ f2 => FOr(FAnd(f1, f2), FAnd(FNot(f1), FNot(f2)))}
+    | ("Not" ~> "(" ~> myFla <~ ")") ^^ {case f1  => FNot(f1)}
+    | "true" ^^ (f => FTrue)
+    | "false" ^^ (f => FFalse)
+    | failure( "Cannot parse this Formula string." ))
+
+
+  def myAtom: Parser[ Atom ]  = (
+      myAtomOut ^^ (AAtomOut(_))
+    | ("=" ~> "(" ~> myMset <~ ",") ~ (myMset <~ ")")^^ { case m1 ~ m2  => AEqual(m1, m2) }
+    | ("SUB" ~> "(" ~> myMset <~ ",") ~ (myMset <~ ")")^^ { case m1 ~ m2  => ASubset(m1, m2) }
+    | ("ALLe" ~> "." ~> myFlaIn)^^ { case f1   => AForAllElem(f1) }
+    | failure( "Cannot parse this atom." ))
+
+
+  def myFlaOut: Parser[ FormulaOut ]  = (
+      myAtomOut ^^ (FOAtom(_))
+    | ("And" ~> "(" ~> myFlaOut  <~ ",") ~ (myFlaOut <~ ")")^^ {case f1 ~ f2 => FOAnd(f1, f2)}
+    | ("Or" ~> "(" ~> myFlaOut <~ ",") ~ (myFlaOut <~ ")")^^ {case f1 ~ f2 => FOOr(f1, f2)}
+    | ("Implies" ~> "(" ~> myFlaOut <~ ",") ~ (myFlaOut <~ ")")^^ {case f1 ~ f2 => FOOr(FONot(f1), f2)}
+    | ("Equiv" ~> "(" ~> myFlaOut <~ ",") ~ (myFlaOut <~ ")")^^ {case f1 ~ f2 => FOOr(FOAnd(f1, f2), FOAnd(FONot(f1), FONot(f2)))}
+    | ("Not" ~> "(" ~> myFlaOut <~ ")") ^^ {case f1  => FONot(f1)}
+    | "true" ^^ (f => FOTrue)
+    | "false" ^^ (f => FOFalse)
+    | failure( "Cannot parse this formula." ))
+
+
+  def myAtomOut: Parser[ AtomOut ]  = (
+      ("=" ~> "(" ~> myTrmOut <~ ",") ~ (myTrmOut <~ ")")^^ { case i1 ~ i2  => AOEq(i1, i2) }
+    | ("<" ~> "=" ~> "(" ~> myTrmOut <~ ",") ~ (myTrmOut <~ ")")^^ { case i1 ~ i2  => AOLeq(i1, i2) }
+    | ("=" ~> "(" ~> "VEC" ~> "(" ~> myListTrmOut <~ ")" <~"," ) ~ ("SUM" ~> "_" ~> "{" ~> myFlaIn <~ "}") ~ 
+        ("VEC" ~> "(" ~> myListTrmIn <~ ")" <~ ")") ^^ { case l1 ~ f ~ l2   => AOSum(l1, f, l2) }
+    | failure( "Cannot parse this atom." ))
+
+
+  def  myListTrmOut: Parser[ List[TermOut] ]  = (
+      repsep(myTrmOut, ",") 
+    | failure( "Cannot parse this vector." ))
+
+
+  def myTrmOut: Parser[ TermOut ]  = (
+      myInt ^^ {case n  =>  TOConstant(n) }
+    | ident ^^ {case s =>  TOVariable(s.toString) }
+    | ("*" ~> "(" ~> myInt <~ ",") ~ (myTrmOut <~ ")") ^^ {case n ~ t => TOTimes(n, t) }
+    | ("|" ~> myMset <~ "|") ^^ { case m => TOCard(m) }
+    | ("+" ~> "(" ~> myListTrmOut <~ ")") ^^  createSumOfOutterTerms
+    | ("ite" ~> "(" ~> myFlaOut <~ ",") ~ myTrmOut ~ ("," ~> myTrmOut <~ ")")   ^^ { case f ~ t1 ~ t2 => TOIte(f, t1, t2) }
+    | failure( "Cannot parse this term." ))
+
+
+  def createSumOfOutterTerms(l: List[TermOut]):  TermOut = {
+    if (l.isEmpty) TOConstant(0) else {
+      var t = l.head
+      val l1 = l.tail
+      l1.foreach(e => t = TOPlus(t, e))
+      t
+    }
+  }
+
+
+  def myFlaIn: Parser[ FormulaIn ]  = (
+      myAtomIn ^^ (FIAtom(_))
+    | ("And" ~> "(" ~> myFlaIn  <~ ",") ~ (myFlaIn <~ ")")^^ {case f1 ~ f2 => FIAnd(f1, f2)}
+    | ("Or" ~> "(" ~> myFlaIn <~ ",") ~ (myFlaIn <~ ")")^^ {case f1 ~ f2 => FIOr(f1, f2)}
+    | ("Implies" ~> "(" ~> myFlaIn <~ ",") ~ (myFlaIn <~ ")")^^ {case f1 ~ f2 => FIOr(FINot(f1), f2)}
+    | ("Equiv" ~> "(" ~> myFlaIn <~ ",") ~ (myFlaIn <~ ")")^^ {case f1 ~ f2 => FIOr(FIAnd(f1, f2), FIAnd(FINot(f1), FINot(f2)))}
+    | ("Not" ~> "(" ~> myFlaIn <~ ")") ^^ {case f1  => FINot(f1)}
+    | "true" ^^ (f => FITrue)
+    | "false" ^^ (f => FIFalse)
+    | failure( "Cannot parse this formula." ))
+
+
+  def myAtomIn: Parser[ AtomIn ]  = (
+      ("=" ~> "(" ~> myTrmIn <~ ",") ~ (myTrmIn <~ ")") ^^ { case i1 ~ i2  => AIEq(i1, i2) }
+    | ("<" ~> "=" ~> "(" ~> myTrmIn <~ ",") ~ (myTrmIn <~ ")") ^^ { case i1 ~ i2  => AILeq(i1, i2) }
+    | failure( "Cannot parse this atom." ))
+
+
+  def myListTrmIn: Parser[ List[TermIn] ]  = (
+      repsep(myTrmIn, ",") 
+    | failure( "Cannot parse this vector." ))
+
+
+  def myTrmIn: Parser[ TermIn ]  = (
+      myInt ^^ {case n  =>  TIConstant(n) }
+    | (ident <~ "(" <~ "e" <~ ")") ^^ { case s => TIMultiplicity(s.toString) }
+    | ("*" ~> "(" ~> myInt <~ ",") ~ (myTrmIn <~ ")") ^^ {case n ~ t => TITimes(n, t) }
+    | ("+" ~> "(" ~> myListTrmIn <~ ")") ^^  createSumOfInnerTerms
+    | ("ite" ~> "(" ~> myFlaIn <~ ",") ~ myTrmIn ~ ("," ~> myTrmIn <~ ")")   ^^ { case f ~ t1 ~ t2 => TIIte(f, t1, t2) }
+    | failure( "Cannot parse this term." ))
+
+  def createSumOfInnerTerms(l: List[TermIn]):  TermIn = {
+    if (l.isEmpty) TIConstant(0) else {
+      var t = l.head
+      val l1 = l.tail
+      l1.foreach(e => t = TIPlus(t, e))
+      t
+    }
+  }
+
+
+ def myInt: Parser[ Int ] = (
+    "-" ~> numericLit ^^ (x => x.toInt * -1)
+  | numericLit ^^ ( x => x.toInt )
+  | failure( "Cannot parse this number." ))
+
+
+  def myMset: Parser[ Multiset ]  = (
+      ident ^^ { case s => MVariable(s.toString) }
+    | "empty" ^^ { x => MEmpty}
+    | ("INTR" ~> "(" ~> myListMset <~ ")") ^^  createIntersectionOfMSets
+    | ("UN" ~> "(" ~> myListMset <~ ")") ^^  createUnionOfMSets
+    | ("PLUS" ~> "(" ~> myListMset <~ ")") ^^  createSumOfMSets
+    | ("-" ~> "(" ~> myMset <~ ",") ~ (myMset <~ ")") ^^ {case m1 ~ m2 => MMinus(m1, m2) }
+    | ("-" ~> "-" ~> "(" ~> myMset <~ ",") ~ (myMset <~ ")") ^^ {case m1 ~ m2 => MSetMinus(m1, m2) }
+    | ("SETof" ~> "(" ~> myMset <~ ")") ^^ {case m =>  MSetOf(m) }
+    | failure( "Cannot parse this multiset." ))
+
+  def createIntersectionOfMSets(l: List[Multiset]):  Multiset = {
+    if (l.isEmpty) MEmpty else {
+      var t = l.head
+      val l1 = l.tail
+      l1.foreach(e => t = MIntersection(t, e))
+      t
+    }
+  }
+
+  def createUnionOfMSets(l: List[Multiset]):  Multiset = {
+    if (l.isEmpty) MEmpty else {
+      var t = l.head
+      val l1 = l.tail
+      l1.foreach(e => t = MUnion(t, e))
+      t
+    }
+  }
+
+  def createSumOfMSets(l: List[Multiset]):  Multiset = {
+    if (l.isEmpty) MEmpty else {
+      var t = l.head
+      val l1 = l.tail
+      l1.foreach(e => t = MPlus(t, e))
+      t
+    }
+  }
+
+
+  def myListMset: Parser[ List[Multiset] ]  = (
+      repsep(myMset, ",") 
+    | failure( "Cannot parse this vector." ))
+
+
+
+//------------------------------------------------
+
+ def main(fileName: String) : List[(String, (Map[String, String], Formula))] = {
+  val reader = StreamReader(new FileReader(fileName))
+  val tokens = new lexical.Scanner(reader)
+  phrase(inputFile)(tokens) match {
+    case Success( mapping, _ ) =>  mapping
+    case e => throw(new Exception("Error = " + e))
+  }
+  }
+}
+
diff --git a/src/multisets/MAPARun.scala b/src/multisets/MAPARun.scala
new file mode 100644
index 0000000000000000000000000000000000000000..7bbf5b98231e349198bfedf5aff660c86cff26bf
--- /dev/null
+++ b/src/multisets/MAPARun.scala
@@ -0,0 +1,131 @@
+package multisets
+
+
+import multisets.MultisetFormulaPrinter._
+import multisets.StarFormulaPrinter._
+
+
+
+object MAPARun {
+
+// start: describes the execution of checking satisfiability of one formula
+   def executeOneFormula (name: String, f: Formula): Boolean = {
+      println("Formula " + name + ":")
+      print_multisetFormula(f)
+      println("")
+      val (x, y, z) = multisets.NormalFormTranslator.main(f)
+      val fF = FAnd(x, FAnd(y, z))
+      println("Normalized formula " + name + ":")
+      print_multisetFormula(fF)
+      println("")
+      val (fS1, lS1, lS2, fS2) = multisets.Multiset2StarsTranslator.main(x, y, z)
+      val fS = StarFormula(fS1, lS1, lS2, fS2)
+      println("Translated formula " + name + ":")
+      print_starFormula(fS)
+      println("")
+      val (lS2N, listDNFfS2) = multisets.CreateDisjunctions.main(lS2, fS2)
+      val (ff, lpf) = multisets.RemoveDisjunctions.main(fS1, lS1, lS2N, listDNFfS2)
+      println("No more disjunctions:")
+      print_QFPAFormula(ff)
+      println(" AND " )
+      lpf.foreach(t => { 
+        print_PAVector(t._1)
+        print( " IN { ")
+        print_PAVector(t._2)
+        print( " |  ")
+        (t._3).foreach(c => {
+          print_QFPAFormula(c)
+          print(" AND ")
+        })
+        print( " } ^*  ")
+        println(" AND " )
+      })
+      println("Semilinear set computation :")
+      val ff1 = multisets.RemoveStars.removeStarsMain(ff, lpf)
+      println("No more stars: ")
+      print_QFPAFormula(ff1)
+      val l = multisets.CheckingConsistency.checkConsistencyofOneFormula(ff1)
+      val bs = l._1
+      val b = if (bs == "sat") true else false
+      println("")
+      println("---------------------")
+      if (b) {
+        println ("This formula is " + bs)
+        println("")
+        println("---------------------")
+/*        println("Here is the satisfying assignment:")
+        val m1 = guru.multisets.reconstructingModels.createSatisfyingAssignmentforQFPA(l)
+        println(m1)
+        println("")
+        println("After removing mu's and nu's : ")
+        val ff1t = guru.multisets.reconstructingModels.evaluateFormulaForVariablesStartingWith(ff1, m1, "FRESHnu")
+        val ff1s = guru.multisets.reconstructingModels.evaluateFormulaForVariablesStartingWith(ff1t, m1, "FRESHmu")
+        print_QFPAFormula(ff1s)
+        println("")
+        println("")
+        println("After removing obsolete disjuntions: ")
+        var ff2s = ff1s
+        var ltm: List[(List[TermQFPA], List[TermQFPA], List[QFPAFormula])] = Nil
+        lpf.foreach(t => {
+          if (guru.multisets.reconstructingModels.isNulVectorinGivenModel(t._1, m1)) {
+             val ff3s = guru.multisets.reconstructingModels.removeZeroVectorInFormula(ff2s, t._1)
+             ff2s = ff3s
+          } else ltm = t :: ltm
+        })
+        print_QFPAFormula(ff2s)
+        println("")
+        println("")
+        println("Star formulas and no disjunctions:")
+        print_QFPAFormula(ff)
+        println(" AND " )
+        ltm.foreach(t => { 
+          print_PAVector(t._1)
+          print( " IN { ")
+          print_PAVector(t._2)
+          print( " |  ")
+          (t._3).foreach(c => {
+            print_QFPAFormula(c)
+            print(" AND ")
+          })
+          print( " } ^*  ")
+          println(" AND " )
+        })
+        println("")
+
+        println("Introduce the real values of vectors : ")
+        val ff4 = guru.multisets.reconstructingModels.evaluateFormulaForVariablesStartingWith(ff2s, m1, "FRESHu") 
+        print_QFPAFormula(ff4) */
+      } else { println("")
+        println ("This formula is " + bs)
+        println("")
+        println("---------------------")
+      }
+      b
+   }
+// end
+
+
+
+  def run(fileName: String): Unit = {
+   val problemList = multisets.MAPAParser.main(fileName)
+   val formulasList = multisets.FormulaConstructor.main(problemList)
+   // all returned formulas are in NNF
+   formulasList.foreach(p => {
+     val flas = p._2
+     val fOrig = flas._1
+     val fOrigNeg = flas._2
+     val fCons = flas._3
+     val isValid = (executeOneFormula(p._1, FAnd(fOrigNeg, fCons)) == false)
+     if (isValid) println("This means that the original problem " + p._1 + " is valid.") else {
+       println("This was a model for the negated formula. Now we check the original formula:")
+       val isUnsat = (executeOneFormula(p._1, FAnd(fOrig, fCons)) == false)
+       if (isUnsat) println("This means, that the original problem " + p._1 + " is unsatisfiable.") else {
+         println("This means that the original problem " + p._1 + " is satisfiable, but not valid.")
+       }
+     }
+   })
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/multisets/Main.scala b/src/multisets/Main.scala
index 3da74362d84ccc9d7bc38ba4bb24b0aee393a0e0..a44d23e4a3815adb42f77eb144a62c443ff9f59b 100644
--- a/src/multisets/Main.scala
+++ b/src/multisets/Main.scala
@@ -4,12 +4,59 @@ import purescala.Extensions.Solver
 import purescala.Reporter
 import purescala.Trees._
 
+import scala.collection.mutable.Set
+
+
+
 class Main(reporter: Reporter) extends Solver(reporter) {
   val description = "Multiset Solver"
-  override def shortDescription = "MUNCH"
+  Global.reporter = reporter
 
-  def solve(expr: Expr) : Option[Boolean] = {
-    reporter.info("Don't know how to solve anything.")
-    None
+
+
+  def createFormulaThatSomethingsIsSet(s:String):FormulaIn = {
+    val a1 = FIAtom(AIEq(TIMultiplicity(s), TIConstant(1)))
+    val a0 = FIAtom(AIEq(TIMultiplicity(s), TIConstant(0)))
+    FIOr(a1, a0)
+  }
+
+
+  def constructFormulaInAboutSets(s:Set[String]):FormulaIn = {
+    val sl = s.toList
+    val h = sl.head
+    val t = sl.tail
+    var f = createFormulaThatSomethingsIsSet(h)
+    t.foreach(e => {
+      val ft = createFormulaThatSomethingsIsSet(e)
+      f = FIAnd(f, ft)
+    })
+    f
   }
+
+  def constructFormulaAboutSets(s:Set[String]):Formula = {
+    val f1 = constructFormulaInAboutSets(s)
+    FAtom(AForAllElem(f1))
+  }
+
+  def createFormula(p:(Formula,Set[String])):Formula = {
+    val f1 = p._1
+    val s = p._2
+    val f = if (s.isEmpty) f1 else {
+      val f2 = constructFormulaAboutSets(s)
+      FAnd(f1, f2) 
+    }
+    f
+  }
+
+
+  def solve(expr: Expr) : Option[Boolean] = {
+    val mt = multisets.MainAST2MultisetsTranslator.translate(negate(expr))
+    val mf = mt.map(p => createFormula(p))
+    val res = mf.map(f => !MAPARun.executeOneFormula("f", f))
+    res
+    }
+}
+
+object Global {
+  var reporter: Reporter = null
 }
diff --git a/src/multisets/MainAST2MultisetsTranslator.scala b/src/multisets/MainAST2MultisetsTranslator.scala
new file mode 100644
index 0000000000000000000000000000000000000000..1ee14440de20fab2d647c0eb5d4be64675660df1
--- /dev/null
+++ b/src/multisets/MainAST2MultisetsTranslator.scala
@@ -0,0 +1,226 @@
+package multisets
+
+import purescala.Trees._
+import purescala.TypeTrees._
+
+import scala.collection.mutable.Set
+
+
+
+object MainAST2MultisetsTranslator {
+
+
+  def translate(expr: Expr) : Option[(Formula, Set[String])] = {
+    case class CantTranslateExpression() extends Exception
+
+
+   def multisetTranslate(m: Expr): (Multiset, Set[String]) = m match {
+     case v @ Variable(id) if v.getType.isInstanceOf[MultisetType] => (MVariable(id.uniqueName), Set.empty[String])
+     case EmptyMultiset(_) => (MEmpty, Set.empty[String])
+     case MultisetIntersection(m1, m2) => {
+        val p1 = multisetTranslate(m1)
+        val p2 = multisetTranslate(m2)
+        (MIntersection(p1._1, p2._1), p1._2 ++ p2._2)
+     }
+     case MultisetUnion(m1, m2) => {
+        val p1 = multisetTranslate(m1)
+        val p2 = multisetTranslate(m2)
+        (MUnion(p1._1, p2._1), p1._2 ++ p2._2)
+     }
+     case MultisetPlus(m1, m2) => {
+        val p1 = multisetTranslate(m1)
+        val p2 = multisetTranslate(m2)
+        (MPlus(p1._1, p2._1), p1._2 ++ p2._2)
+     }
+     case MultisetDifference(m1, m2) => {
+        val p1 = multisetTranslate(m1)
+        val p2 = multisetTranslate(m2)
+        (MMinus(p1._1, p2._1), p1._2 ++ p2._2)
+     }
+     case MultisetToSet(m1) => {
+        val p1 = multisetTranslate(m1)
+        (MSetOf(p1._1), p1._2)
+     }
+  }
+
+  def termOutTranslate(exp: Expr): (TermOut, Set[String]) = exp match {
+    case v @ Variable(id) if v.getType == Int32Type => (TOVariable(id.uniqueName), Set.empty[String])
+    case IntLiteral(v) => (TOConstant(v), Set.empty[String])
+    case MultisetCardinality(m) => {
+      val mN = multisetTranslate(m)
+      (TOCard(mN._1), mN._2)
+    }
+    case SetCardinality(s) => {
+      val mN = setTranslate(s)
+      (TOCard(mN._1), mN._2)
+    }
+    case Plus(t1, t2) => {
+      val p1 = termOutTranslate(t1)
+      val p2 = termOutTranslate(t2)
+      (TOPlus(p1._1, p2._1), p1._2 ++ p2._2)
+    }
+    case Minus(t1, t2) => {
+      val p1 = termOutTranslate(t1)
+      val p2 = termOutTranslate(t2)
+      (TOPlus(p1._1, TOTimes(-1, p2._1)), p1._2 ++ p2._2)
+    }
+  }
+
+   def setTranslate(s: Expr): (Multiset, Set[String]) = s match {
+     case v @ Variable(id) if v.getType.isInstanceOf[SetType] => (MVariable(id.uniqueName), Set(id.uniqueName))
+     case EmptySet(_) => (MEmpty, Set.empty[String])
+     case SetIntersection(s1, s2) => {
+        val p1 = setTranslate(s1)
+        val p2 = setTranslate(s2)
+        (MIntersection(p1._1, p2._1), p1._2 ++ p2._2)
+     }
+     case SetUnion(s1, s2) => {
+        val p1 = setTranslate(s1)
+        val p2 = setTranslate(s2)
+        (MUnion(p1._1, p2._1), p1._2 ++ p2._2)
+     }
+     case SetDifference(s1, s2) => {
+        val p1 = setTranslate(s1)
+        val p2 = setTranslate(s2)
+        (MMinus(p1._1, p2._1), p1._2 ++ p2._2)
+     }
+     case MultisetToSet(m1) => {
+        val p1 = multisetTranslate(m1)
+        (MSetOf(p1._1), p1._2)
+     }
+  }
+
+
+
+
+
+
+  def createFormulaFromAndSeq(fs: Seq[Formula]): Formula = {
+    val f = if (fs.isEmpty) FTrue else {
+      var ft = fs.head
+      val t = fs.tail
+      t.foreach(f1 => ft = FAnd(f1, ft))
+      ft
+    }
+    f
+  }
+
+  def createFormulaFromOrSeq(fs: Seq[Formula]): Formula = {
+    val f = if (fs.isEmpty) FTrue else {
+      var ft = fs.head
+      val t = fs.tail
+      t.foreach(f1 => ft = FOr(f1, ft))
+      ft
+    }
+    f
+  }
+
+
+  def createUnionOfAllSets(s: Seq[Set[String]]): Set[String] = {
+    val sr = if (s.isEmpty) Set.empty[String] else {
+      var h = s.head
+      val t = s.tail
+      t.foreach(v => h = h ++ v)
+      h
+    }
+    sr
+  }
+
+/*
+  case class UMinus(expr: Expr) extends Expr with FixedType { 
+    val fixedType = Int32Type
+  }
+  case class Times(lhs: Expr, rhs: Expr) extends Expr with FixedType { 
+    val fixedType = Int32Type
+  }
+  case class Division(lhs: Expr, rhs: Expr) extends Expr with FixedType { 
+    val fixedType = Int32Type
+  } */
+
+
+  def rec(ex: Expr) : (Formula, Set[String]) = ex match {
+    case MultisetEquals(m1,m2) => {
+      val p1 = multisetTranslate(m1)
+      val p2 = multisetTranslate(m2)
+      (FAtom(AEqual(p1._1, p2._1)), p1._2 ++ p2._2)
+    }
+    case SubmultisetOf(m1,m2) => {
+      val p1 = multisetTranslate(m1)
+      val p2 = multisetTranslate(m2)
+      (FAtom(ASubset(p1._1, p2._1)), p1._2 ++ p2._2)
+    }
+    case SetEquals(s1,s2) => {
+      val p1 = setTranslate(s1)
+      val p2 = setTranslate(s2)
+      (FAtom(AEqual(p1._1, p2._1)), p1._2 ++ p2._2)
+    }
+    case SubsetOf(s1,s2) => {
+      val p1 = setTranslate(s1)
+      val p2 = setTranslate(s2)
+      (FAtom(ASubset(p1._1, p2._1)), p1._2 ++ p2._2)
+    }
+    case And(expS) => {
+      val pl = expS.map(e => rec(e))
+      val fl = pl.map(p => p._1)
+      val sl = pl.map(p => p._2)
+      val f1 = createFormulaFromAndSeq(fl)
+      val s1 = createUnionOfAllSets(sl)
+      (f1, s1)
+    }
+    case Or(expS) => {
+      val pl = expS.map(e => rec(e))
+      val fl = pl.map(p => p._1)
+      val sl = pl.map(p => p._2)
+      val f1 = createFormulaFromOrSeq(fl)
+      val s1 = createUnionOfAllSets(sl)
+      (f1, s1)
+    }
+    case Iff(f1, f2) => {
+      val p1 = rec(f1)
+      val p2 = rec(f2)
+      (FOr(FAnd(FNot(p1._1), FNot(p2._1)), FAnd(p1._1, p2._1)), p1._2 ++ p2._2)
+    }
+    case Implies(f1, f2) => {
+      val p1 = rec(f1)
+      val p2 = rec(f2)
+      (FOr(FNot(p1._1), p2._1), p1._2 ++ p2._2)
+    }
+    case Not(f1) => {
+      val p1 = rec(f1)
+      (FNot(p1._1), p1._2)
+    }
+    case LessThan(t1, t2) => {
+      val p1 = termOutTranslate(t1)
+      val p2 = termOutTranslate(t2)
+      (FAnd(FAtom(AAtomOut(AOLeq(p1._1, p2._1))), FNot(FAtom(AAtomOut(AOEq(p1._1, p2._1))))), p1._2 ++ p2._2)
+    }
+    case GreaterThan(t1, t2) => rec(LessThan(t2, t1))
+    case LessEquals(t1, t2) => {
+      val p1 = termOutTranslate(t1)
+      val p2 = termOutTranslate(t2)
+      (FAtom(AAtomOut(AOLeq(p1._1, p2._1))), p1._2 ++ p2._2)
+    }
+    case GreaterEquals(t1, t2) => rec(LessEquals(t2, t1))
+    case Equals(t1, t2) => {
+      val p1 = termOutTranslate(t1)
+      val p2 = termOutTranslate(t2)
+      (FAtom(AAtomOut(AOEq(p1._1, p2._1))), p1._2 ++ p2._2)
+    }
+    case unhandled => {
+      Global.reporter.warning("Can't translate this in Munch : " + unhandled)
+      throw CantTranslateExpression()
+    }
+    }
+
+
+    try {
+      Some(rec(expandLets(expr)))
+    } catch {
+      case CantTranslateExpression() => None
+    }
+
+  }
+
+
+}
+
diff --git a/src/multisets/Multiset.scala b/src/multisets/Multiset.scala
new file mode 100644
index 0000000000000000000000000000000000000000..1fd8d77982fc1db010c6aed7b767e5496131abe7
--- /dev/null
+++ b/src/multisets/Multiset.scala
@@ -0,0 +1,20 @@
+//	piskac@larapc01:~/guru$ pwd
+//	/home/piskac/guru
+//	piskac@larapc01:~/guru$ scalac -d bin/ src/guru/multisets/*.scala
+//	piskac@larapc01:~/guru$ scala -cp bin/ guru.multisets.Main
+
+package multisets
+
+
+object Multisets  {
+
+  def main(args: Array[String]) : Unit = {
+    if (args.length == 0) {
+      println("Usage: scala -cp bin/ guru.multisets.Main fileName ")
+    } else {
+      val fileName = args(0)
+      multisets.MAPARun.run(fileName)
+    }
+  }
+}
+
diff --git a/src/multisets/Multiset2StarsTranslator.scala b/src/multisets/Multiset2StarsTranslator.scala
new file mode 100644
index 0000000000000000000000000000000000000000..82c372b7e159efe4bd4bc13121a153c77b75c91e
--- /dev/null
+++ b/src/multisets/Multiset2StarsTranslator.scala
@@ -0,0 +1,246 @@
+package multisets
+
+object Multiset2StarsTranslator {
+
+
+// start:
+
+  def translate2QFPAfromFormulaOut(f:FormulaOut):QFPAFormula = f match {
+    case FOAnd(f1,f2) => {
+      val f1n = translate2QFPAfromFormulaOut(f1)
+      val f2n = translate2QFPAfromFormulaOut(f2)
+      QFPAAnd(f1n, f2n)
+    }
+    case FOOr(f1,f2) => {
+      val f1n = translate2QFPAfromFormulaOut(f1)
+      val f2n = translate2QFPAfromFormulaOut(f2)
+      QFPAOr(f1n, f2n)
+    }
+    case FONot(f1)  => {
+      val f1n = translate2QFPAfromFormulaOut(f1)
+      QFPANot(f1n)
+    }
+    case FOAtom(a)  => {
+      val a1 = translate2QFPAAtomfromAtomOut(a)
+      QFPAAtom(a1)
+    }
+    case FOTrue => QFPATrue
+    case FOFalse => QFPAFalse
+  }
+
+
+  def translate2QFPATermfromTermOut(t:TermOut):TermQFPA  = t match {
+    case TOConstant(c) => TConstant(c)
+    case TOVariable(v) => TVariable(v)
+    case TOPlus(t1, t2) => {
+      val t1n = translate2QFPATermfromTermOut(t1)
+      val t2n = translate2QFPATermfromTermOut(t2)
+      TPlus(t1n, t2n)
+    }
+    case TOTimes(c, t1)=> {
+      val t1n = translate2QFPATermfromTermOut(t1)
+      TTimes(c, t1n)
+    }
+    case TOIte(f, t1, t2)=> {
+      val f1 = translate2QFPAfromFormulaOut(f)
+      val t1n = translate2QFPATermfromTermOut(t1)
+      val t2n = translate2QFPATermfromTermOut(t2)
+      TIte(f1,t1n, t2n)
+    }
+    case _ => error("Impossible case ")
+  }
+
+  def translate2QFPAAtomfromAtomOut(a:AtomOut):AtomQFPA = a match {
+    case AOLeq(t1,t2) => {
+      val t1n = translate2QFPATermfromTermOut(t1)
+      val t2n = translate2QFPATermfromTermOut(t2)
+      ALeq(t1n, t2n)
+    }
+    case AOEq(t1,t2) => {
+      val t1n = translate2QFPATermfromTermOut(t1)
+      val t2n = translate2QFPATermfromTermOut(t2)
+      AEq(t1n, t2n)
+    }
+    case _ => error("Impossible case ")
+  }
+
+  def translate2QFPAfromFormula(f:Formula):QFPAFormula = f match {
+    case FAnd(f1,f2) => {
+      val f1n = translate2QFPAfromFormula(f1)
+      val f2n = translate2QFPAfromFormula(f2)
+      QFPAAnd(f1n, f2n)
+    }
+    case FOr(f1,f2) => {
+      val f1n = translate2QFPAfromFormula(f1)
+      val f2n = translate2QFPAfromFormula(f2)
+      QFPAOr(f1n, f2n)
+    }
+    case FNot(f1)  => {
+      val f1n = translate2QFPAfromFormula(f1)
+      QFPANot(f1n)
+    }
+    case FAtom(AAtomOut(a))  => {
+      val a1 = translate2QFPAAtomfromAtomOut(a)
+      QFPAAtom(a1)
+    }
+    case FFalse => QFPAFalse
+    case FTrue => QFPATrue
+    case _ => error("Impossible case ")
+  }
+
+
+  def translate2QFPATermfromTermIn(t:TermIn):TermQFPA  = t match {
+    case TIMultiplicity(v) => TVariable(v)
+    case TIConstant(c) => TConstant(c)
+    case TIPlus(t1, t2) => {
+      val t1n = translate2QFPATermfromTermIn(t1)
+      val t2n = translate2QFPATermfromTermIn(t2)
+      TPlus(t1n, t2n)
+    }
+    case TITimes(c, t1)=> {
+      val t1n = translate2QFPATermfromTermIn(t1)
+      TTimes(c, t1n)
+    }
+    case TIIte(f, t1, t2)=> {
+      val f1 = translate2QFPAfromFormulaIn(f)
+      val t1n = translate2QFPATermfromTermIn(t1)
+      val t2n = translate2QFPATermfromTermIn(t2)
+      TIte(f1,t1n, t2n)
+    }
+  }
+
+  def translate2QFPAAtomfromAtomIn(a:AtomIn):AtomQFPA = a match {
+    case AILeq(t1,t2) => {
+      val t1n = translate2QFPATermfromTermIn(t1)
+      val t2n = translate2QFPATermfromTermIn(t2)
+      ALeq(t1n, t2n)
+    }
+    case AIEq(t1,t2) => {
+      val t1n = translate2QFPATermfromTermIn(t1)
+      val t2n = translate2QFPATermfromTermIn(t2)
+      AEq(t1n, t2n)
+    }
+  }
+
+  def translate2QFPAfromFormulaIn(f:FormulaIn):QFPAFormula = f match {
+    case FIAnd(f1,f2) => {
+      val f1n = translate2QFPAfromFormulaIn(f1)
+      val f2n = translate2QFPAfromFormulaIn(f2)
+      QFPAAnd(f1n, f2n)
+    }
+    case FIOr(f1,f2) => {
+      val f1n = translate2QFPAfromFormulaIn(f1)
+      val f2n = translate2QFPAfromFormulaIn(f2)
+      QFPAOr(f1n, f2n)
+    }
+    case FINot(f1)  => {
+      val f1n = translate2QFPAfromFormulaIn(f1)
+      QFPANot(f1n)
+    }
+    case FIAtom(a)  => {
+      val a1 = translate2QFPAAtomfromAtomIn(a)
+      QFPAAtom(a1)
+    }
+    case FITrue => QFPATrue
+    case FIFalse => QFPAFalse
+  }
+
+  def translate2QFPAfromForAll(f:Formula):QFPAFormula = f match {
+    case FAtom(AForAllElem(f1)) => translate2QFPAfromFormulaIn(f1)
+    case FFalse => QFPAFalse
+    case FTrue => QFPATrue
+    case _ => error("Impossible case ")
+  }
+
+  def translateListofTermsOut(v1:List[TermOut]):List[TermQFPA] = {
+    var l1: List[TermQFPA] = Nil
+    v1.foreach(t => {
+        val tN = translate2QFPATermfromTermOut(t)
+        l1 = tN :: l1
+    })
+    l1.reverse
+  }
+
+  def translateListofTermsIn(v1:List[TermIn]):List[TermQFPA] = {
+    var l1: List[TermQFPA] = Nil
+    v1.foreach(t => {
+        val tN = translate2QFPATermfromTermIn(t)
+        l1 = tN :: l1
+    })
+    l1.reverse
+  }
+
+
+  def getVectorValuesFromSumFormula(f:Formula):(List[TermQFPA], List[TermQFPA]) = f match {
+    case FAtom(AAtomOut(AOSum(v1, FITrue, v2))) => {
+      val l1 = translateListofTermsOut(v1)
+      val l2 = translateListofTermsIn(v2)
+      (l1, l2)
+    }
+    case _ => error("Impossible case ")
+  }
+
+
+  def nnf(f:QFPAFormula): QFPAFormula = f match {
+    case QFPAAnd(f1, f2) => {
+      val f1N = nnf(f1)
+      val f2N = nnf(f2)
+      QFPAAnd(f1N, f2N)
+    }
+    case QFPAOr(f1, f2) => {
+      val f1N = nnf(f1)
+      val f2N = nnf(f2)
+      QFPAOr(f1N, f2N)
+    }
+    case QFPANot(QFPANot(f1)) => nnf(f1)
+    case QFPANot(QFPAAnd(f1, f2)) => QFPAOr(nnf(QFPANot(f1)), nnf(QFPANot(f2)))
+    case QFPANot(QFPAOr(f1, f2)) => QFPAAnd(nnf(QFPANot(f1)), nnf(QFPANot(f2)))
+    case QFPANot(QFPAFalse) => QFPATrue
+    case QFPANot(QFPATrue) => QFPAFalse
+    case _ => f
+  }
+
+
+
+  def removeTrueAndFalse(f:QFPAFormula): QFPAFormula = f match {
+    case QFPAAnd(QFPATrue, f2) => removeTrueAndFalse(f2)
+    case QFPAAnd(f1, QFPATrue) => removeTrueAndFalse(f1)
+    case QFPAAnd(QFPAFalse, f2) => QFPAFalse
+    case QFPAAnd(f1, QFPAFalse) => QFPAFalse
+    case QFPAAnd(f1, f2) => {
+      val f1N = removeTrueAndFalse(f1)
+      val f2N = removeTrueAndFalse(f2)
+      QFPAAnd(f1N, f2N)
+    }
+    case QFPAOr(QFPATrue, f2) => QFPATrue
+    case QFPAOr(f1, QFPATrue) => QFPATrue
+    case QFPAOr(QFPAFalse, f2) => removeTrueAndFalse(f2)
+    case QFPAOr(f1, QFPAFalse) => removeTrueAndFalse(f1)
+    case QFPAOr(f1, f2) => {
+      val f1N = removeTrueAndFalse(f1)
+      val f2N = removeTrueAndFalse(f2)
+      QFPAOr(f1N, f2N)
+    }
+    case QFPANot(f1)  => {
+      val f1N = removeTrueAndFalse(f1)
+      val f1NN = if (f1N == QFPATrue) QFPAFalse else 
+        if (f1N == QFPAFalse) QFPATrue else QFPANot(f1N)
+      f1NN
+    }
+    case _ => f
+  }
+
+
+//  start: input fPA - presburger arithmetic formula, fForAll- for all formula, fSum-sumfourmula
+// output: $s1 AND $2 IN { $3 | $4} *
+
+
+  def main(fPA:Formula, fForAll: Formula, fSum:Formula):(QFPAFormula, List[TermQFPA], List[TermQFPA], QFPAFormula) = {
+    val f1 = removeTrueAndFalse(nnf(translate2QFPAfromFormula(fPA)))
+    val f2 = removeTrueAndFalse(nnf(translate2QFPAfromForAll(fForAll)))
+    val (l1, l2) = getVectorValuesFromSumFormula(fSum)
+    (f1, l1, l2, f2)
+  } 
+
+}
+
diff --git a/src/multisets/MultisetFormulaPrinter.scala b/src/multisets/MultisetFormulaPrinter.scala
new file mode 100644
index 0000000000000000000000000000000000000000..26e33f473f63205e8d67dd7bc913b66907f1bcf7
--- /dev/null
+++ b/src/multisets/MultisetFormulaPrinter.scala
@@ -0,0 +1,237 @@
+package multisets
+
+object MultisetFormulaPrinter {
+ 
+  def print_multiset(m:Multiset):Unit = m match {
+    case MVariable(v) => Console.print(v)
+    case MEmpty => Console.print("EMPTY")
+    case MUnion(m1, m2) => {
+      print_multiset(m1)
+      Console.print(" UNION ")
+      print_multiset(m2)
+    }
+    case MIntersection(m1, m2) => {
+      print_multiset(m1)
+      Console.print(" INTERSECT ")
+      print_multiset(m2)
+    }
+    case MPlus(m1, m2) => {
+      print_multiset(m1)
+      Console.print(" PLUS ")
+      print_multiset(m2)
+    }
+    case MMinus(m1, m2) => {
+      print_multiset(m1)
+      Console.print(" MINUS ")
+      print_multiset(m2)
+    }
+    case MSetMinus(m1, m2) => {
+      print_multiset(m1)
+      Console.print(" SetMINUS ")
+      print_multiset(m2)
+    }
+    case MSetOf(m1) => {
+      Console.print(" SetOf( ")
+      print_multiset(m1)
+      print(" )")
+    }
+  }
+
+  def print_termIn(t:TermIn):Unit = t match {
+    case TIMultiplicity(v) => Console.print(v + "(e)")
+    case TIConstant(c) => Console.print(c)
+    case TIPlus(t1, t2) => {
+      print_termIn(t1)
+      Console.print(" + ")
+      print_termIn(t2)
+    }
+    case TITimes(c, t1)=> {
+      Console.print(c + "*")
+      print_termIn(t1)
+    }
+    case TIIte(f, t1, t2)=> {
+      Console.print("ITE(")
+      print_formulaIn(f)
+      print("; ")
+      print_termIn(t1)
+      print(", ")
+      print_termIn(t2)
+      print(")")
+    }
+  }
+
+
+  def print_atomIn(a:AtomIn):Unit = a match {
+    case AILeq(t1,t2) => {
+      print_termIn(t1)
+      Console.print(" =< ")
+      print_termIn(t2)
+    }
+    case AIEq(t1,t2) => {
+      print_termIn(t1)
+      Console.print(" = ")
+      print_termIn(t2)
+    }
+  }
+
+  def print_formulaIn(f:FormulaIn):Unit = f match {
+    case FIAnd(f1,f2) => {
+      Console.print(" ( ")
+      print_formulaIn(f1)
+      print(" ) AND ( ")
+      print_formulaIn(f2)
+      print(" ) ")
+    }
+    case FIOr(f1,f2) => {
+      Console.print(" ( ")
+      print_formulaIn(f1)
+      print(" ) OR ( ")
+      print_formulaIn(f2)
+      print(" ) ")
+    }
+    case FINot(f1)  => {
+      Console.print(" NOT ( ")
+      print_formulaIn(f1)
+      print(" ) ")
+    }
+    case FIAtom(a) => print_atomIn(a)
+    case FITrue => Console.print(" TRUE ")
+    case FIFalse => Console.print(" FALSE ")
+  }
+
+
+ 
+  def print_termOut(t:TermOut):Unit = t match {
+    case TOConstant(c) => Console.print(c)
+    case TOVariable(v) => Console.print(v)
+    case TOCard(m) => {
+      Console.print("| ")
+      print_multiset(m)
+      Console.print("| ")
+    }
+    case TOPlus(t1, t2) => {
+      print_termOut(t1)
+      Console.print(" + ")
+      print_termOut(t2)
+    }
+    case TOTimes(c, t1)=> {
+      Console.print(c + "*")
+      print_termOut(t1)
+    }
+    case TOIte(f, t1, t2)=> {
+      Console.print("ITE(")
+      print_formulaOut(f)
+      print("; ")
+      print_termOut(t1)
+      print(", ")
+      print_termOut(t2)
+      print(")")
+    }
+  }
+
+  def print_atomOut(a:AtomOut):Unit = a match {
+    case AOLeq(t1,t2) => {
+      print_termOut(t1)
+      Console.print(" =< ")
+      print_termOut(t2)
+    }
+    case AOEq(t1,t2) => {
+      print_termOut(t1)
+      Console.print(" = ")
+      print_termOut(t2)
+    }
+    case AOSum(l1, f, l2) => {
+      Console.print(" ( ")
+      l1.foreach(x => {
+        print_termOut(x)
+        print(", ")
+      })
+      print(") = SUM {e in E, ")
+      print_formulaIn(f)
+      print("} (")
+      l2.foreach(x => {
+        print_termIn(x)
+        print(", ")
+      })
+      print(")")
+    }
+  }
+
+
+  def print_formulaOut(f:FormulaOut):Unit = f match {
+    case FOAnd(f1,f2) => {
+      Console.print(" ( ")
+      print_formulaOut(f1)
+      print(" ) AND ( ")
+      print_formulaOut(f2)
+      print(" ) ")
+    }
+    case FOOr(f1,f2) => {
+      Console.print(" ( ")
+      print_formulaOut(f1)
+      print(" ) OR ( ")
+      print_formulaOut(f2)
+      print(" ) ")
+    }
+    case FONot(f1)  => {
+      Console.print(" NOT ( ")
+      print_formulaOut(f1)
+      print(" ) ")
+    }
+    case FOAtom(a)  => print_atomOut(a)
+    case FOTrue => Console.print(" TRUE ")
+    case FOFalse => Console.print(" FALSE ")
+  }
+
+  def print_atom(a:Atom):Unit = a match {
+    case AEqual(m1,m2) => {
+      print_multiset(m1)
+      Console.print(" = ")
+      print_multiset(m2)
+    }
+    case ASubset(m1,m2) => {
+      print_multiset(m1)
+      Console.print(" SUBSET ")
+      print_multiset(m2)
+    }
+    case AForAllElem(f) => {
+      Console.print(" FOR ALL e IN E. ( ")
+      print_formulaIn(f)
+      print(" ) ")
+    }
+    case AAtomOut(a1)  => print_atomOut(a1)
+  }
+
+  def print_multisetFormula(f:Formula):Unit = f match {
+    case FAnd(f1,f2) => {
+      Console.print(" ( ")
+      print_multisetFormula(f1)
+      print(" ) AND ( ")
+      print_multisetFormula(f2)
+      print(" ) ")
+    }
+    case FOr(f1,f2) => {
+      Console.print(" ( ")
+      print_multisetFormula(f1)
+      print(" ) OR ( ")
+      print_multisetFormula(f2)
+      print(" ) ")
+    }
+    case FNot(FAnd(FNot(f1),FNot(f2)))   => {
+      Console.print(" ( ")
+      print_multisetFormula(f1)
+      print(" ) OR ( ")
+      print_multisetFormula(f2)
+      print(" ) ")
+    }
+    case FNot(f1)  => {
+      Console.print(" NOT ( ")
+      print_multisetFormula(f1)
+      print(" ) ")
+    }
+    case FAtom(a)  => print_atom(a)
+    case FTrue  => Console.print(" TRUE ")
+    case FFalse  => Console.print(" FALSE ")
+  }
+
+}
\ No newline at end of file
diff --git a/src/multisets/NormalFormTranslator.scala b/src/multisets/NormalFormTranslator.scala
new file mode 100644
index 0000000000000000000000000000000000000000..cdc0f30fc6a0c23a99f13a685dbea823ef01917f
--- /dev/null
+++ b/src/multisets/NormalFormTranslator.scala
@@ -0,0 +1,924 @@
+package multisets
+
+
+import multisets.MultisetFormulaPrinter._
+
+
+object NormalFormTranslator {
+
+
+
+// start: this part extraxts all complex (diff. than a variable) expressions
+//input: f - Formula, mc - counter for fresh, mm - list containing (var, Multiset)
+//output : Formula - containing only variables as multisets, Int-counter  List - variable, multiset
+  def extractMsetsExpr_termOut(t:TermOut, mc:Int, mm:List[(String,Multiset)]):(TermOut,Int,List[(String,Multiset)]) = t match {
+    case TOConstant(c) => (TOConstant(c), mc, mm)
+    case TOVariable(v) => (TOVariable(v), mc, mm)
+    case TOCard(MVariable(m)) => (TOCard(MVariable(m)), mc, mm)
+    case TOCard(m) => {
+      val newMulVar = "FRESHm" + mc
+      var mm1 = (newMulVar, m)  :: mm
+      (TOCard(MVariable(newMulVar)), mc + 1, mm1)
+    }
+    case TOPlus(t1, t2) => {
+      val (t1n, mc1, mm1) = extractMsetsExpr_termOut(t1, mc, mm)
+      val (t2n, mc2, mm2) = extractMsetsExpr_termOut(t2, mc1, mm1)
+      (TOPlus(t1n, t2n), mc2, mm2)
+    }
+    case TOTimes(c, t1)=> {
+      val (t1n, mc1, mm1) = extractMsetsExpr_termOut(t1, mc, mm)
+      (TOTimes(c, t1n), mc1, mm1)
+    }
+    case TOIte(f, t1, t2)=> {
+      val (f1, mc1, mm1) = extractMsetsExpr_formulaOut(f, mc, mm)
+      val (t1n, mc2, mm2) = extractMsetsExpr_termOut(t1, mc1, mm1)
+      val (t2n, mc3, mm3) = extractMsetsExpr_termOut(t2, mc2, mm2)
+      (TOIte(f1,t1n, t2n), mc3, mm3)
+    }
+  }
+
+  def extractMsetsExpr_atomOut(a:AtomOut, mc:Int, mm:List[(String,Multiset)]):(AtomOut,Int,List[(String,Multiset)]) = a match {
+    case AOLeq(t1,t2) => {
+      val (t1n, mc1, mm1) = extractMsetsExpr_termOut(t1, mc, mm)
+      val (t2n, mc2, mm2) = extractMsetsExpr_termOut(t2, mc1, mm1)
+      (AOLeq(t1n, t2n), mc2, mm2)
+    }
+    case AOEq(t1,t2) => {
+      val (t1n, mc1, mm1) = extractMsetsExpr_termOut(t1, mc, mm)
+      val (t2n, mc2, mm2) = extractMsetsExpr_termOut(t2, mc1, mm1)
+      (AOEq(t1n, t2n), mc2, mm2)
+    }
+    case AOSum(l1, f, l2) => {
+      var l3: List[TermOut] = Nil
+      var mcN = mc
+      var mmN = mm
+      l1.foreach(t => {
+        val (t1, mc1, mm1) = extractMsetsExpr_termOut(t, mcN, mmN)
+        l3 = t1 :: l3 
+        mcN = mc1
+        mmN = mm1
+      })
+      (AOSum(l3.reverse, f, l2), mcN, mmN)
+    }
+  }
+
+  def extractMsetsExpr_formulaOut(f:FormulaOut, mc:Int, mm:List[(String,Multiset)]):(FormulaOut,Int,List[(String,Multiset)]) = f match {
+    case FOAnd(f1,f2) => {
+	val (f1n, mc1, mm1) = extractMsetsExpr_formulaOut(f1, mc, mm)
+	val (f2n, mc2, mm2) = extractMsetsExpr_formulaOut(f2, mc1, mm1)
+	(FOAnd(f1n, f2n), mc2, mm2)
+    }
+    case FOOr(f1,f2) => {
+	val (f1n, mc1, mm1) = extractMsetsExpr_formulaOut(f1, mc, mm)
+	val (f2n, mc2, mm2) = extractMsetsExpr_formulaOut(f2, mc1, mm1)
+	(FOOr(f1n, f2n), mc2, mm2)
+    }
+    case FONot(f1)  => {
+      val (f1n, mc1, mm1) = extractMsetsExpr_formulaOut(f1, mc, mm)
+      (FONot(f1n), mc1, mm1)
+    }
+    case FOAtom(a)  => {
+     val (a1, mc1, mm1) = extractMsetsExpr_atomOut(a, mc, mm)
+     (FOAtom(a1), mc1, mm1)
+    }
+    case FOTrue => (f, mc, mm)
+    case FOFalse => (f, mc, mm)
+  }
+
+  def extractMsetsExpr_atom(a:Atom, mc:Int, mm:List[(String,Multiset)]):(Atom,Int,List[(String,Multiset)]) = a match {
+    case AEqual(MVariable(v1),MVariable(v2)) => (AEqual(MVariable(v1),MVariable(v2)), mc, mm)
+    case AEqual(MVariable(v1),m2) => {
+      val newMulVar = "FRESHm" + mc
+      var mm1 = (newMulVar, m2)  :: mm
+      (AEqual(MVariable(v1),MVariable(newMulVar)), mc + 1, mm1)
+    }
+    case AEqual(m1, MVariable(v2)) => {
+      val newMulVar = "FRESHm" + mc
+      var mm1 = (newMulVar, m1)  :: mm
+      (AEqual(MVariable(newMulVar),MVariable(v2)), mc + 1, mm1)
+    }
+    case AEqual(m1,m2) => {
+      val newMulVar1 = "FRESHm" + mc
+      var mm1 = (newMulVar1, m1)  :: mm
+      val mcN = mc + 1
+      val newMulVar2 = "FRESHm" + mcN
+      var mm2 = (newMulVar2, m2)  :: mm1
+      (AEqual(MVariable(newMulVar1),MVariable(newMulVar2)), mcN + 1, mm2)
+    }
+    case ASubset(MVariable(v1),MVariable(v2)) => (ASubset(MVariable(v1),MVariable(v2)), mc, mm)
+    case ASubset(MVariable(v1),m2) => {
+      val newMulVar = "FRESHm" + mc
+      var mm1 = (newMulVar, m2)  :: mm
+      (ASubset(MVariable(v1),MVariable(newMulVar)), mc + 1, mm1)
+    }
+    case ASubset(m1, MVariable(v2)) => {
+      val newMulVar = "FRESHm" + mc
+      var mm1 = (newMulVar, m1)  :: mm
+      (ASubset(MVariable(newMulVar),MVariable(v2)), mc + 1, mm1)
+    }
+    case ASubset(m1,m2) => {
+      val newMulVar1 = "FRESHm" + mc
+      var mm1 = (newMulVar1, m1)  :: mm
+      val mcN = mc + 1
+      val newMulVar2 = "FRESHm" + mcN
+      var mm2 = (newMulVar2, m2)  :: mm1
+      (ASubset(MVariable(newMulVar1),MVariable(newMulVar2)), mcN + 1, mm2)
+    }
+    case AForAllElem(f) => (AForAllElem(f), mc, mm)
+    case AAtomOut(a1)  => {
+     val (a2, mc1, mm1) = extractMsetsExpr_atomOut(a1, mc, mm)
+     (AAtomOut(a2), mc1, mm1)
+    }
+  }
+
+  def extractMsetsExpr_formula(f:Formula, mc:Int, mm:List[(String,Multiset)]):(Formula,Int,List[(String,Multiset)]) = f match {
+    case FAnd(f1,f2) => {
+	val (f1n, mc1, mm1) = extractMsetsExpr_formula(f1, mc, mm)
+	val (f2n, mc2, mm2) = extractMsetsExpr_formula(f2, mc1, mm1)
+	(FAnd(f1n, f2n), mc2, mm2)
+    }
+    case FOr(f1,f2) => {
+	val (f1n, mc1, mm1) = extractMsetsExpr_formula(f1, mc, mm)
+	val (f2n, mc2, mm2) = extractMsetsExpr_formula(f2, mc1, mm1)
+	(FOr(f1n, f2n), mc2, mm2)
+    }
+    case FNot(f1)  => {
+      val (f1n, mc1, mm1) = extractMsetsExpr_formula(f1, mc, mm)
+      (FNot(f1n), mc1, mm1)
+    }
+    case FAtom(a)  => {
+     val (a1, mc1, mm1) = extractMsetsExpr_atom(a, mc, mm)
+     (FAtom(a1), mc1, mm1)
+    }
+    case FTrue  => (f, mc, mm)
+    case FFalse => (f, mc, mm)
+  }
+// end 
+
+
+// start: list(var, multiset), can contain complex multiset expressions
+// output: list(var, multiset), simple multiset expressions
+  def flatten_multisetList(mc:Int, mm:List[(String,Multiset)], toBeChecked: Boolean):List[(String,Multiset)] = {
+    var addedFreshMultisets = false
+    var ml: List[(String,Multiset)] = Nil
+    var mc1 = mc
+    if (toBeChecked) {
+      mm.foreach(p => p._2 match {
+         case MVariable(v) => ml = p :: ml
+         case MEmpty =>  ml = p :: ml
+         case MUnion(MVariable(v1),MVariable(v2)) =>  ml = p :: ml
+         case MUnion(MVariable(v1),m2) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MUnion(MVariable(v1),MVariable(newMulVar))) :: ((newMulVar, m2)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MUnion(m1,MVariable(v2)) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MUnion(MVariable(newMulVar),MVariable(v2))) :: ((newMulVar, m1)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MUnion(m1,m2) => {
+           val newMulVar1 = "FRESHm" + mc1
+           ml = (newMulVar1, m1)  :: ml
+           mc1 = mc1 + 1
+           val newMulVar2 = "FRESHm" + mc1
+           ml = (newMulVar2, m2)  :: ml
+           mc1 = mc1 + 1
+           ml = (p._1, MUnion(MVariable(newMulVar1),MVariable(newMulVar2))) :: ml
+           addedFreshMultisets = true
+         }
+         case MIntersection(MVariable(v1),MVariable(v2)) => ml = p :: ml
+         case MIntersection(MVariable(v1),m2) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MIntersection(MVariable(v1),MVariable(newMulVar))) :: ((newMulVar, m2)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MIntersection(m1,MVariable(v2)) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MIntersection(MVariable(newMulVar),MVariable(v2))) :: ((newMulVar, m1)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MIntersection(m1,m2) => {
+           val newMulVar1 = "FRESHm" + mc1
+           ml = (newMulVar1, m1)  :: ml
+           mc1 = mc1 + 1
+           val newMulVar2 = "FRESHm" + mc1
+           ml = (newMulVar2, m2)  :: ml
+           mc1 = mc1 + 1
+           ml = (p._1, MIntersection(MVariable(newMulVar1),MVariable(newMulVar2))) :: ml
+           addedFreshMultisets = true
+         }
+         case MPlus(MVariable(v1),MVariable(v2)) => ml = p :: ml
+         case MPlus(MVariable(v1),m2) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MPlus(MVariable(v1),MVariable(newMulVar))) :: ((newMulVar, m2)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MPlus(m1,MVariable(v2)) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MPlus(MVariable(newMulVar),MVariable(v2))) :: ((newMulVar, m1)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MPlus(m1,m2) => {
+           val newMulVar1 = "FRESHm" + mc1
+           ml = (newMulVar1, m1)  :: ml
+           mc1 = mc1 + 1
+           val newMulVar2 = "FRESHm" + mc1
+           ml = (newMulVar2, m2)  :: ml
+           mc1 = mc1 + 1
+           ml = (p._1, MPlus(MVariable(newMulVar1),MVariable(newMulVar2))) :: ml
+           addedFreshMultisets = true
+         }
+         case MMinus(MVariable(v1),MVariable(v2)) => ml = p :: ml 
+         case MMinus(MVariable(v1),m2) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MMinus(MVariable(v1),MVariable(newMulVar))) :: ((newMulVar, m2)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MMinus(m1,MVariable(v2)) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MMinus(MVariable(newMulVar),MVariable(v2))) :: ((newMulVar, m1)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MMinus(m1,m2) => {
+           val newMulVar1 = "FRESHm" + mc1
+           ml = (newMulVar1, m1)  :: ml
+           mc1 = mc1 + 1
+           val newMulVar2 = "FRESHm" + mc1
+           ml = (newMulVar2, m2)  :: ml
+           mc1 = mc1 + 1
+           ml = (p._1, MMinus(MVariable(newMulVar1),MVariable(newMulVar2))) :: ml
+           addedFreshMultisets = true
+         }
+         case MSetMinus(MVariable(v1),MVariable(v2)) => ml = p :: ml 
+         case MSetMinus(MVariable(v1),m2) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MSetMinus(MVariable(v1),MVariable(newMulVar))) :: ((newMulVar, m2)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MSetMinus(m1,MVariable(v2)) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (p._1, MSetMinus(MVariable(newMulVar),MVariable(v2))) :: ((newMulVar, m1)  :: ml)
+           mc1 = mc1 + 1
+           addedFreshMultisets = true
+         }
+         case MSetMinus(m1,m2) => {
+           val newMulVar1 = "FRESHm" + mc1
+           ml = (newMulVar1, m1)  :: ml
+           mc1 = mc1 + 1
+           val newMulVar2 = "FRESHm" + mc1
+           ml = (newMulVar2, m2)  :: ml
+           mc1 = mc1 + 1
+           ml = (p._1, MSetMinus(MVariable(newMulVar1),MVariable(newMulVar2))) :: ml
+           addedFreshMultisets = true
+         }
+         case MSetOf(MVariable(v)) => ml = p :: ml  
+         case MSetOf(m) => {
+           val newMulVar = "FRESHm" + mc1
+           ml = (newMulVar, m)  :: ml
+           mc1 = mc1 + 1
+           ml = (p._1, MSetOf(MVariable(newMulVar))) :: ml
+           addedFreshMultisets = true
+         }
+      })
+      flatten_multisetList(mc1, ml, addedFreshMultisets)
+    }
+    else mm
+  }
+// end
+
+
+
+// start: input list(string, multiset) (m1, m2 un m3),...
+// output: formula: Forall e.(m1 (e) = ... AND ..)
+  def createFormulafromPair(p:(String,Multiset)):FormulaIn = p._2 match {
+    case MEmpty => 
+      FIAtom(AIEq(TIMultiplicity(p._1),TIConstant(0)))
+    case MUnion(MVariable(v1),MVariable(v2)) => 
+      FIAtom(AIEq(TIMultiplicity(p._1),
+        TIIte(FIAtom(AILeq(TIMultiplicity(v1),TIMultiplicity(v2))), TIMultiplicity(v2), TIMultiplicity(v1))))
+    case MIntersection(MVariable(v1),MVariable(v2)) => 
+      FIAtom(AIEq(TIMultiplicity(p._1),
+        TIIte(FIAtom(AILeq(TIMultiplicity(v1),TIMultiplicity(v2))), TIMultiplicity(v1), TIMultiplicity(v2))))
+    case MPlus(MVariable(v1),MVariable(v2)) => 
+      FIAtom(AIEq(TIMultiplicity(p._1),
+        TIPlus(TIMultiplicity(v1), TIMultiplicity(v2))))
+    case MMinus(MVariable(v1),MVariable(v2)) => 
+      FIAtom(AIEq(TIMultiplicity(p._1),
+        TIIte(FIAtom(AILeq(TIMultiplicity(v1),TIMultiplicity(v2))), TIConstant(0), 
+        TIPlus(TIMultiplicity(v1), TITimes(-1, TIMultiplicity(v2))))))
+    case MSetMinus(MVariable(v1),MVariable(v2)) => 
+      FIAtom(AIEq(TIMultiplicity(p._1),
+        TIIte(FIAtom(AIEq(TIMultiplicity(v2),TIConstant(0))), TIMultiplicity(v1), TIConstant(0))))
+    case MSetOf(MVariable(v)) => 
+      FIAtom(AIEq(TIMultiplicity(p._1),
+        TIIte(FIAtom(AILeq(TIConstant(1),TIMultiplicity(v))), TIConstant(1), TIConstant(0))))
+    case _ => error("Impossible case, canot get this here, but got " + p)
+    }
+
+  def createFormulafromMultisetList(mlist:List[(String,Multiset)]):Formula = {
+    if (mlist.isEmpty) FAtom(AForAllElem(FITrue)) else {
+      val firstPair = mlist.head
+      val theRest = mlist.tail
+      var fN = createFormulafromPair(firstPair)
+      theRest.foreach(p => {
+        val f = createFormulafromPair(p)
+        fN = FIAnd(fN, f)
+      })
+      FAtom(AForAllElem(fN))
+    } 
+  } 
+// end
+
+
+// start: formula with m1 SUB m2 and m1 = m2
+// output formula with forall e. m1(e) <= m2(e) and m1(e) = m2(e)
+  def redefineMultisetAtom(a:Atom):Formula = a match {
+    case AEqual(MVariable(v1),MVariable(v2)) => 
+      FAtom(AForAllElem(FIAtom(AIEq(TIMultiplicity(v1), TIMultiplicity(v2)))))
+    case ASubset(MVariable(v1),MVariable(v2)) => 
+      FAtom(AForAllElem(FIAtom(AILeq(TIMultiplicity(v1), TIMultiplicity(v2)))))
+    case AForAllElem(f) => FAtom(AForAllElem(f))
+    case AAtomOut(a1)  => FAtom(AAtomOut(a1))
+    case _ => error("Impossible case ")
+  }
+
+  def redefineMultisetAtoms(f:Formula):Formula = f match {
+    case FAnd(f1,f2) => {
+	val f1n = redefineMultisetAtoms(f1)
+	val f2n = redefineMultisetAtoms(f2)
+	FAnd(f1n, f2n)
+    }
+    case FOr(f1,f2) => {
+	val f1n = redefineMultisetAtoms(f1)
+	val f2n = redefineMultisetAtoms(f2)
+	FOr(f1n, f2n)
+    }
+    case FNot(f1)  => {
+      val f1n = redefineMultisetAtoms(f1)
+      FNot(f1n)
+    }
+    case FAtom(a)  => {
+     val a1 = redefineMultisetAtom(a)
+     a1
+    }
+    case FTrue => f
+    case FFalse => f
+  }
+// end
+
+
+// start: input formula with cardinalities
+// output: new formula where each cardinality is replaced with a fresh int var + List(intVar, msetVar) <-both strings 
+
+  def extractCardExpr_termOut(t:TermOut, ic:Int, cl:List[(String,String)]):(TermOut,Int,List[(String,String)]) = t match {
+    case TOConstant(c) => (TOConstant(c), ic, cl)
+    case TOVariable(v) => (TOVariable(v), ic, cl)
+    case TOCard(MVariable(m)) => {
+      val newIntVar = "FRESHk" + ic
+      var cl1 = (newIntVar, m)  :: cl
+      (TOVariable(newIntVar), ic + 1, cl1)
+    }
+    case TOPlus(t1, t2) => {
+      val (t1n, ic1, cl1) = extractCardExpr_termOut(t1, ic, cl)
+      val (t2n, ic2, cl2) = extractCardExpr_termOut(t2, ic1, cl1)
+      (TOPlus(t1n, t2n), ic2, cl2)
+    }
+    case TOTimes(c, t1)=> {
+      val (t1n, ic1, cl1) = extractCardExpr_termOut(t1, ic, cl)
+      (TOTimes(c, t1n), ic1, cl1)
+    }
+    case TOIte(f, t1, t2)=> {
+      val (f1, ic1, cl1) = extractCardExpr_formulaOut(f, ic, cl)
+      val (t1n, ic2, cl2) = extractCardExpr_termOut(t1, ic1, cl1)
+      val (t2n, ic3, cl3) = extractCardExpr_termOut(t2, ic2, cl2)
+      (TOIte(f1,t1n, t2n), ic3, cl3)
+    }
+    case _ => error("Impossible case ")
+  }
+
+  def extractCardExpr_atomOut(a:AtomOut, ic:Int, cl:List[(String,String)]):(AtomOut,Int,List[(String,String)]) = a match {
+    case AOLeq(t1,t2) => {
+      val (t1n, ic1, cl1) = extractCardExpr_termOut(t1, ic, cl)
+      val (t2n, ic2, cl2) = extractCardExpr_termOut(t2, ic1, cl1)
+      (AOLeq(t1n, t2n), ic2, cl2)
+    }
+    case AOEq(t1,t2) => {
+      val (t1n, ic1, cl1) = extractCardExpr_termOut(t1, ic, cl)
+      val (t2n, ic2, cl2) = extractCardExpr_termOut(t2, ic1, cl1)
+      (AOEq(t1n, t2n), ic2, cl2)
+    }
+    case AOSum(l1, f, l2) => {
+      var l3: List[TermOut] = Nil
+      var icN = ic
+      var clN = cl
+      l1.foreach(t => {
+        val (t1, ic1, cl1) = extractCardExpr_termOut(t, icN, clN)
+        l3 = t1 :: l3 
+        icN = ic1
+        clN = cl1
+      })
+      (AOSum(l3.reverse, f, l2), icN, clN)
+    }
+  }
+
+  def extractCardExpr_formulaOut(f:FormulaOut, ic:Int, cl:List[(String,String)]):(FormulaOut,Int,List[(String,String)]) = f match {
+    case FOAnd(f1,f2) => {
+	val (f1n, ic1, cl1) = extractCardExpr_formulaOut(f1, ic, cl)
+	val (f2n, ic2, cl2) = extractCardExpr_formulaOut(f2, ic1, cl1)
+	(FOAnd(f1n, f2n), ic2, cl2)
+    }
+    case FOOr(f1,f2) => {
+	val (f1n, ic1, cl1) = extractCardExpr_formulaOut(f1, ic, cl)
+	val (f2n, ic2, cl2) = extractCardExpr_formulaOut(f2, ic1, cl1)
+	(FOOr(f1n, f2n), ic2, cl2)
+    }
+    case FONot(f1)  => {
+      val (f1n, ic1, cl1) = extractCardExpr_formulaOut(f1, ic, cl)
+      (FONot(f1n), ic1, cl1)
+    }
+    case FOAtom(a)  => {
+     val (a1, ic1, cl1) = extractCardExpr_atomOut(a, ic, cl)
+     (FOAtom(a1), ic1, cl1)
+    }
+    case FOTrue => (f, ic, cl)
+    case FOFalse => (f, ic, cl)
+  }
+
+
+  def extractCardExpr_atom(a:Atom, ic:Int, cl:List[(String,String)]):(Atom,Int,List[(String,String)]) = a match {
+    case AEqual(m1,m2) => (AEqual(m1,m2), ic, cl)
+    case ASubset(m1,m2) => (ASubset(m1,m2), ic, cl)
+    case AForAllElem(f) => (AForAllElem(f), ic, cl)
+    case AAtomOut(a1)  => {
+     val (a2, ic1, cl1) = extractCardExpr_atomOut(a1, ic, cl)
+     (AAtomOut(a2), ic1, cl1)
+    }
+  }
+
+  def extractCardExpr_formula(f:Formula, ic:Int, cl:List[(String,String)]):(Formula,Int,List[(String,String)]) = f match {
+    case FAnd(f1,f2) => {
+	val (f1n, ic1, cl1) = extractCardExpr_formula(f1, ic, cl)
+	val (f2n, ic2, cl2) = extractCardExpr_formula(f2, ic1, cl1)
+	(FAnd(f1n, f2n), ic2, cl2)
+    }
+    case FOr(f1,f2) => {
+	val (f1n, ic1, cl1) = extractCardExpr_formula(f1, ic, cl)
+	val (f2n, ic2, cl2) = extractCardExpr_formula(f2, ic1, cl1)
+	(FOr(f1n, f2n), ic2, cl2)
+    }
+    case FNot(f1)  => {
+      val (f1n, ic1, cl1) = extractCardExpr_formula(f1, ic, cl)
+      (FNot(f1n), ic1, cl1)
+    }
+    case FAtom(a)  => {
+     val (a1, ic1, cl1) = extractCardExpr_atom(a, ic, cl)
+     (FAtom(a1), ic1, cl1)
+    }
+    case FTrue => (f, ic, cl)
+    case FFalse => (f, ic, cl)
+  }
+// end 
+
+// start: input list(var, mset), output: (var) = SUM_{} mset
+  def createFormulafromCardinalityList(cl:List[(String,String)]):Formula = {
+  var l1: List[TermOut] = Nil
+  var l2: List[TermIn] = Nil
+  if (cl.isEmpty) FAtom(AAtomOut(AOSum(List(TOConstant(0)), FITrue, List(TIConstant(0))))) else {
+    cl.foreach(p => {
+      l1 = TOVariable(p._1) :: l1
+      l2 = TIMultiplicity(p._2) :: l2 
+     })
+     FAtom(AAtomOut((AOSum(l1, FITrue, l2))))
+   }
+  }
+
+// end 
+
+
+// start
+// input: f- formula, fFA - allready existing formula of the form forall e.f(e)
+//output:  $1 - formula without top-level forall, $2-forall e. f(e)
+  def uniteForAll(fI:FormulaIn,f:Formula):Formula = f match {
+    case FAtom(AForAllElem(f1))  => {
+      val fn = if (f1 == FITrue) fI else FIAnd(fI, f1)
+      FAtom(AForAllElem(fn))
+    }
+    case _ => error("Impossible case ")
+  }
+
+
+  def topLevelForAll(f:Formula,fFA:Formula):(Formula,Formula) = f match {
+    case FAnd(FAtom(AForAllElem(fI)),f2) => {
+       val (f2N, fFAN) = topLevelForAll(f2, fFA)
+       (f2N, uniteForAll(fI, fFAN))
+    }
+    case FAnd(f1, FAtom(AForAllElem(fI))) => {
+       val (f1N, fFAN) = topLevelForAll(f1, fFA)
+       (f1N, uniteForAll(fI, fFAN))
+    }
+    case FAnd(f1,f2) => {
+	val (f1n, fFA1) = topLevelForAll(f1, fFA)
+	val (f2n, fFA2) = topLevelForAll(f2, fFA1)
+        val f3n = if (f1n == FTrue) f2n else
+          if (f2n == FTrue) f1n else FAnd(f1n, f2n)
+	(f3n, fFA2)
+    }
+    case FOr(f1,f2) => (f, fFA)
+    case FNot(f1)  => (f, fFA)
+    case FAtom(AForAllElem(fI))  =>  (FTrue, uniteForAll(fI, fFA))
+    case FAtom(a)  => (f, fFA)
+    case FTrue => (f, fFA)
+    case FFalse => (f, fFA)
+  }
+// end
+
+
+// start
+// input formula f - output f1 where every forall e. f is replaced with a sum: 
+// forall e. f(e)  <=> 0 = sum_{true} ite(f(e); 0, 1)
+  def replaceForAllWithSums(f:Formula):Formula = f match {
+    case FAnd(f1,f2) => {
+      val f1n = replaceForAllWithSums(f1)
+      val f2n = replaceForAllWithSums(f2)
+      FAnd(f1n, f2n)
+    }
+    case FOr(f1,f2) => {
+      val f1n = replaceForAllWithSums(f1)
+      val f2n = replaceForAllWithSums(f2)
+      FOr(f1n, f2n)
+    }
+    case FNot(f1)  => {
+      val f1n = replaceForAllWithSums(f1)
+      FNot(f1n)
+    }
+    case FAtom(AForAllElem(f1))  => 
+      FAtom(AAtomOut(AOSum(List(TOConstant(0)), FITrue, List(TIIte(f1,TIConstant(0),TIConstant(1))))))
+    case FAtom(a)  => f
+    case FTrue => f
+    case FFalse => f
+  }
+
+  def notTopLevelForAll(f:Formula):Formula = f match {
+    case FAnd(f1,f2) => {
+      val f1n = notTopLevelForAll(f1)
+      val f2n = notTopLevelForAll(f2)
+     FAnd(f1n, f2n)
+    }
+    case FOr(f1,f2) => {
+      val f1n = replaceForAllWithSums(f1)
+      val f2n = replaceForAllWithSums(f2)
+     FOr(f1n, f2n)
+    }
+    case FNot(f1)  => FNot(replaceForAllWithSums(f1))
+    case FAtom(a)  => f
+    case FTrue  => f
+    case FFalse  => f
+  }
+// end
+
+
+
+// start: input formula f and fS which is already a sum atom
+// output: $1 without top level sums, $2 is a sum atom
+  def eliminateConditions(f:FormulaIn, lIn: List[TermIn]):List[TermIn] = {
+    var ltemp: List[TermIn] = Nil
+    lIn.foreach(t => {
+       val t1 = TIIte(f, t, TIConstant(0))
+       ltemp = t1 :: ltemp
+    })
+    ltemp.reverse
+  }
+
+
+  def uniteSums(lTO:List[TermOut], lTI: List[TermIn], fD:FormulaIn,f:Formula):Formula = f match {
+    case FAtom(AAtomOut(AOSum(lT0o, FITrue, lTIo)))  => fD match {
+      case FITrue => FAtom(AAtomOut(AOSum(lTO ::: lT0o, FITrue, lTI ::: lTIo)))
+      case _ => {
+        val ltN = eliminateConditions(fD, lTI)
+        FAtom(AAtomOut(AOSum(lTO ::: lT0o, FITrue, ltN ::: lTIo)))
+      }
+    }  
+    case _ => error("Impossible case ")
+  }
+
+  def topLevelSums(f:Formula,fS:Formula):(Formula,Formula) = f match {
+    case FAnd(FAtom(AAtomOut(AOSum(lTO, ff, lTI))), f2) => {
+       val (f2N, fSN) = topLevelSums(f2, fS)
+       (f2N, uniteSums(lTO, lTI, ff, fSN))
+    }
+    case FAnd(f1, FAtom(AAtomOut(AOSum(lTO, ff, lTI)))) => {
+       val (f1N, fSN) = topLevelSums(f1, fS)
+       (f1N, uniteSums(lTO, lTI, ff, fSN))
+    }
+    case FAnd(f1,f2) => {
+	val (f1n, fS1) = topLevelForAll(f1, fS)
+	val (f2n, fS2) = topLevelForAll(f2, fS1)
+        val f3n = if (f1n == FTrue) f2n else
+          if (f2n == FTrue) f1n else FAnd(f1n, f2n)
+	(f3n, fS2)
+    }
+    case FOr(f1,f2) => (f, fS)
+    case FNot(f1)  => (f, fS)
+    case FAtom(AAtomOut(AOSum(lTO, ff, lTI)))  =>  (FTrue, uniteSums(lTO, lTI, ff, fS))
+    case FAtom(a)  => (f, fS)
+    case FTrue  => (f, fS)
+    case FFalse  => (f, fS)
+  }
+// end
+
+
+// start: input f - formula fs- sum atom, sc -counter
+// outputs: $1 - formula without sums, $s2 - sum atom $3 -counter
+  def createEqualityAtom(to:TermOut, sc:Int):(Atom,TermOut,Int) = {
+    val newVar = "FRESHs" + sc
+    val scN = sc + 1
+    val a = AAtomOut(AOEq(to, TOVariable(newVar)))
+    (a, TOVariable(newVar), scN)
+  } 
+
+  def createEqualityFormula(lTO:List[TermOut], sc:Int):(Formula,List[TermOut],Int) = {
+    var tList: List[TermOut] = Nil
+    val t1 = lTO.head
+    val theRest = lTO.tail
+    var (aN, vN, scN) = createEqualityAtom(t1, sc)
+    var fN : Formula = FAtom(aN)
+    tList = vN :: tList
+    theRest.foreach(t => {
+      val (aN1, vN1, scN1) = createEqualityAtom(t, scN)
+      scN = scN1
+      fN = FAnd(fN, FAtom(aN1))
+      tList = vN1 :: tList
+    })
+    (fN, tList.reverse, scN)
+  } 
+
+  def notTopLevelSums(f:Formula,fS:Formula,sc:Int):(Formula,Formula,Int) = f match {
+    case FAnd(f1,f2) => {
+      val (f1n, fS1, sc1) = notTopLevelSums(f1, fS, sc)
+      val (f2n, fS2, sc2) = notTopLevelSums(f2, fS1, sc1)
+      (FAnd(f1n, f2n), fS2, sc2)
+    }
+    case FOr(f1,f2) => {
+      val (f1n, fS1, sc1) = notTopLevelSums(f1, fS, sc)
+      val (f2n, fS2, sc2) = notTopLevelSums(f2, fS1, sc1)
+      (FOr(f1n, f2n), fS2, sc2)
+    }
+    case FNot(f1)  => {
+      val (f1n, fS1, sc1) = notTopLevelSums(f1, fS, sc)
+      (FNot(f1n), fS1, sc1)
+    }
+    case FAtom(AAtomOut(AOSum(lTO, ff, lTI))) => {
+      val (f1, l1, scN) = createEqualityFormula(lTO, sc)
+      val fN = uniteSums(l1, lTI, ff, fS)
+      (f1, fN, scN)
+    }
+    case FAtom(a)  => (f, fS, sc)
+    case FTrue  => (f, fS, sc)
+    case FFalse  => (f, fS, sc)
+  }
+// end
+
+
+// start: input formula F, output: formula F' which does not contain True and False
+// only can contain either pure TRUE or FALSE
+  def removeTrueandFalsefromTermIn(t: TermIn): TermIn = t match {
+    case TIPlus(t1, t2) => {
+      val t1n  = removeTrueandFalsefromTermIn(t1)
+      val t2n  = removeTrueandFalsefromTermIn(t2)
+      TIPlus(t1n, t2n)
+    }
+    case TITimes(c, t1)=> {
+      val t1n  = removeTrueandFalsefromTermIn(t1)
+      TITimes(c, t1n)
+    }
+    case TIIte(f, t1, t2) => {
+      val t1n  = removeTrueandFalsefromTermIn(t1)
+      val t2n  = removeTrueandFalsefromTermIn(t2)
+      val f1 = removeTrueandFalsefromFormulaIn(f)
+      TIIte(f1, t1n, t2n)
+    }
+    case _ => t
+  }
+
+  def removeTrueandFalsefromAtomIn(a: AtomIn): AtomIn = a match {
+    case AILeq(t1, t2) => {
+      val t1n  = removeTrueandFalsefromTermIn(t1)
+      val t2n  = removeTrueandFalsefromTermIn(t2)
+      AILeq(t1n, t2n)
+    }
+    case AIEq(t1,t2) => {
+      val t1n  = removeTrueandFalsefromTermIn(t1)
+      val t2n  = removeTrueandFalsefromTermIn(t2)
+      AIEq(t1n, t2n)
+    }
+  }
+
+  def removeTrueandFalsefromFormulaIn(f: FormulaIn): FormulaIn =  f match {
+    case FIAnd(FIFalse, f2) => FIFalse
+    case FIAnd(f1, FIFalse) => FIFalse
+    case FIAnd(FITrue, f2) => removeTrueandFalsefromFormulaIn(f2)
+    case FIAnd(f1, FITrue) => removeTrueandFalsefromFormulaIn(f1)
+    case FIAnd(f1, f2) => {
+      val f1n  = removeTrueandFalsefromFormulaIn(f1)
+      val f2n  = removeTrueandFalsefromFormulaIn(f2)
+      val f3 = if (f1n == FIFalse || f2n == FIFalse) FIFalse else 
+        if (f1n == FITrue) f2n else
+          if (f2n == FITrue) f1n else FIAnd(f1n, f2n)
+      f3
+    }
+    case FIOr(FITrue, f2) => FITrue
+    case FIOr(f1, FITrue) => FITrue
+    case FIOr(FIFalse, f2) => removeTrueandFalsefromFormulaIn(f2)
+    case FIOr(f1, FIFalse) => removeTrueandFalsefromFormulaIn(f1)
+    case FIOr(f1, f2) => {
+      val f1n  = removeTrueandFalsefromFormulaIn(f1)
+      val f2n  = removeTrueandFalsefromFormulaIn(f2)
+      val f3 = if (f1n == FITrue || f2n == FITrue) FITrue else 
+        if (f1n == FIFalse) f2n else
+          if (f2n == FIFalse) f1n else FIOr(f1n, f2n)
+      f3
+    }
+    case FINot(f1) => {
+      val f1n  = removeTrueandFalsefromFormulaIn(f1)
+      val f3 = if (f1n == FITrue) FIFalse else 
+        if (f1n == FIFalse) FITrue else FINot(f1n)
+      f3
+    }
+    case FIAtom(a) => {
+      val a1 = removeTrueandFalsefromAtomIn(a)
+      FIAtom(a1)
+    }
+    case _  => f
+  }
+
+  def removeTrueandFalsefromTermOut(t: TermOut): TermOut = t match {
+    case TOPlus(t1, t2) => {
+      val t1n  = removeTrueandFalsefromTermOut(t1)
+      val t2n  = removeTrueandFalsefromTermOut(t2)
+      TOPlus(t1n, t2n)
+    }
+    case TOTimes(c, t1)=> {
+      val t1n  = removeTrueandFalsefromTermOut(t1)
+      TOTimes(c, t1n)
+    }
+    case TOIte(f, t1, t2) => {
+      val t1n  = removeTrueandFalsefromTermOut(t1)
+      val t2n  = removeTrueandFalsefromTermOut(t2)
+      val f1 = removeTrueandFalsefromFormulaOut(f)
+      TOIte(f1, t1n, t2n)
+    }
+    case _ => t
+  }
+
+  def removeTrueandFalsefromAtomOut(a: AtomOut): AtomOut = a match {
+    case AOLeq(t1, t2) => {
+      val t1n  = removeTrueandFalsefromTermOut(t1)
+      val t2n  = removeTrueandFalsefromTermOut(t2)
+      AOLeq(t1n, t2n)
+    }
+    case AOEq(t1,t2) => {
+      val t1n  = removeTrueandFalsefromTermOut(t1)
+      val t2n  = removeTrueandFalsefromTermOut(t2)
+      AOEq(t1n, t2n)
+    }
+    case AOSum(l1, f, l2) => {
+      val l1n = l1.map(v => removeTrueandFalsefromTermOut(v))
+      val l2n = l2.map(v => removeTrueandFalsefromTermIn(v))
+      val f1 = removeTrueandFalsefromFormulaIn(f)
+      AOSum(l1n, f1, l2n)
+    }
+  }
+
+  def removeTrueandFalsefromFormulaOut(f: FormulaOut): FormulaOut =  f match {
+    case FOAnd(FOFalse, f2) => FOFalse
+    case FOAnd(f1, FOFalse) => FOFalse
+    case FOAnd(FOTrue, f2) => removeTrueandFalsefromFormulaOut(f2)
+    case FOAnd(f1, FOTrue) => removeTrueandFalsefromFormulaOut(f1)
+    case FOAnd(f1, f2) => {
+      val f1n  = removeTrueandFalsefromFormulaOut(f1)
+      val f2n  = removeTrueandFalsefromFormulaOut(f2)
+      val f3 = if (f1n == FOFalse || f2n == FOFalse) FOFalse else 
+        if (f1n == FOTrue) f2n else
+          if (f2n == FOTrue) f1n else FOAnd(f1n, f2n)
+      f3
+    }
+    case FOOr(FOTrue, f2) => FOTrue
+    case FOOr(f1, FOTrue) => FOTrue
+    case FOOr(FOFalse, f2) => removeTrueandFalsefromFormulaOut(f2)
+    case FOOr(f1, FOFalse) => removeTrueandFalsefromFormulaOut(f1)
+    case FOOr(f1, f2) => {
+      val f1n  = removeTrueandFalsefromFormulaOut(f1)
+      val f2n  = removeTrueandFalsefromFormulaOut(f2)
+      val f3 = if (f1n == FOTrue || f2n == FOTrue) FOTrue else 
+        if (f1n == FOFalse) f2n else
+          if (f2n == FOFalse) f1n else FOOr(f1n, f2n)
+      f3
+    }
+    case FONot(f1) => {
+      val f1n  = removeTrueandFalsefromFormulaOut(f1)
+      val f3 = if (f1n == FOTrue) FOFalse else 
+        if (f1n == FOFalse) FOTrue else FONot(f1n)
+      f3
+    }
+    case FOAtom(a) => {
+      val a1 = removeTrueandFalsefromAtomOut(a)
+      FOAtom(a1)
+    }
+    case _  => f
+  }
+
+  def removeTrueandFalsefromAtom(a: Atom): Atom = a match {
+    case AForAllElem(f1) => {
+      val f1n = removeTrueandFalsefromFormulaIn(f1)
+      AForAllElem(f1n)
+    }
+    case AAtomOut(a1)  => {
+      val a1n = removeTrueandFalsefromAtomOut(a1)
+      AAtomOut(a1n)
+    }
+    case _ => a
+  }
+
+  def removeTrueandFalsefromFormulas(f:Formula): Formula = f match {
+    case FAnd(FFalse, f2) => FFalse
+    case FAnd(f1, FFalse) => FFalse
+    case FAnd(FTrue, f2) => removeTrueandFalsefromFormulas(f2)
+    case FAnd(f1, FTrue) => removeTrueandFalsefromFormulas(f1)
+    case FAnd(f1, f2) => {
+      val f1n  = removeTrueandFalsefromFormulas(f1)
+      val f2n  = removeTrueandFalsefromFormulas(f2)
+      val f3 = if (f1n == FFalse || f2n == FFalse) FFalse else 
+        if (f1n == FTrue) f2n else
+          if (f2n == FTrue) f1n else FAnd(f1n, f2n)
+      f3
+    }
+    case FOr(FTrue, f2) => FTrue
+    case FOr(f1, FTrue) => FTrue
+    case FOr(FFalse, f2) => removeTrueandFalsefromFormulas(f2)
+    case FOr(f1, FFalse) => removeTrueandFalsefromFormulas(f1)
+    case FOr(f1, f2) => {
+      val f1n  = removeTrueandFalsefromFormulas(f1)
+      val f2n  = removeTrueandFalsefromFormulas(f2)
+      val f3 = if (f1n == FTrue || f2n == FTrue) FTrue else 
+        if (f1n == FFalse) f2n else
+          if (f2n == FFalse) f1n else FOr(f1n, f2n)
+      f3
+    }
+    case FNot(f1) => {
+      val f1n  = removeTrueandFalsefromFormulas(f1)
+      val f3 = if (f1n == FTrue) FFalse else 
+        if (f1n == FFalse) FTrue else FNot(f1n)
+      f3
+    }
+    case FAtom(a) => {
+      val a1 = removeTrueandFalsefromAtom(a)
+      FAtom(a1)
+    }
+    case _  => f
+  }
+// end
+
+
+// ------------- MAIN -------------
+
+  def main(f:Formula): (Formula,Formula,Formula) = {
+    val f0 = removeTrueandFalsefromFormulas(f)
+    // formula f0 does not contain true or false but it could be only true or false
+    val msetCounter = 0
+    var msets: List[(String,Multiset)] = Nil
+    val (f1, mc, mcm) = extractMsetsExpr_formula(f0, msetCounter, msets)
+    // formula f1 does not contain complex multisets, they are all in mcm
+    val toBeChecked = true
+    val mlist = flatten_multisetList(mc, mcm, toBeChecked)
+    val fAll = createFormulafromMultisetList(mlist)
+    // fAll is a formula All e.m1(e) =  ,.. AND ... <- all complex multiset experssions as a formula
+    val f2 = redefineMultisetAtoms(f1)  //replace m1 = m2 and m1 SubSET m2 with for all e....
+    val intCounter = 0
+    var cards: List[(String,String)] = Nil
+    val (f3, ic, il) = extractCardExpr_formula(f2, intCounter, cards)
+    // f3 = new formula without cardinalities, il = list of the form (intVar, msetVar)
+    val fSum = createFormulafromCardinalityList(il)
+    // fSum <- atom about all cardinalities that were pulled out of the original formula
+    val (f4, fAll1) = topLevelForAll(f3, fAll)
+    // all top level forall are united in formula fAll1 and f4 does not contain top-level forall e...
+    val f5 = notTopLevelForAll(f4)
+    // f5 does not contain any forall e. f(e) expression - they are converted using sums
+    val (f6, fSum1) = topLevelSums(f5, fSum)
+    // all top level sums are united in formula fSum1 and f6 does not contain top-level sum
+    val sumCounter = 0
+    val (f7, fSum2, _) = notTopLevelSums(f6, fSum1, sumCounter)
+    (f7, fAll1, fSum2)
+  } 
+
+
+}
diff --git a/src/multisets/RemoveDisjunctions.scala b/src/multisets/RemoveDisjunctions.scala
new file mode 100644
index 0000000000000000000000000000000000000000..ab33790314a4f6062733c0ff9f5bf87aaa697bc8
--- /dev/null
+++ b/src/multisets/RemoveDisjunctions.scala
@@ -0,0 +1,83 @@
+package multisets
+
+
+object RemoveDisjunctions {
+
+//
+
+  def createListofFreshVectors(n:Int, m:Int): List[List[TermQFPA]] = {
+    var i = 0
+    var lOut: List[List[TermQFPA]] = Nil
+    while (i < n) {
+      var j = 0
+      var  lIn: List[TermQFPA] = Nil
+      while (j < m) {
+        var num = i * m + j
+        var newUVar = "FRESHu" + num
+        var tmpTermVar = TVariable(newUVar)
+        lIn = tmpTermVar :: lIn
+        j += 1
+      }
+      var lInN = lIn.reverse
+      lOut = lInN :: lOut
+      i += 1
+    }
+    lOut
+  }
+
+  def createSumOfAllUVecs(i:Int, u:List[List[TermQFPA]]):TermQFPA = {
+   val n = u.length
+   var j = 0
+   var tt = (u(j))(i)
+   j += 1
+   while (j < n) {
+     var tn = (u(j))(i)
+     tt = TPlus(tt, tn) 
+     j += 1
+   }
+   tt
+  }
+
+
+
+  def createFormulaWithFreshUsVariables(u:List[TermQFPA], uVec:List[List[TermQFPA]]):QFPAFormula = {
+    val m = u.length
+    var j = 0
+    var tR = createSumOfAllUVecs(j, uVec)
+    var tL = u(j)
+    var eq = AEq(tL, tR)
+    var f:QFPAFormula = QFPAAtom(eq)
+    j += 1
+    while (j < m) {
+      tR = createSumOfAllUVecs(j, uVec)
+      tL = u(j)
+      eq = AEq(tL, tR)
+      f = QFPAAnd(f, QFPAAtom(eq))
+      j += 1
+    }
+    f
+  }
+
+
+//-------------------------------------
+// main creates List of LIAStar Formulas 
+// input f0 AND u IN { v | lDNF} ^*
+// output $1 AND List($2, $3, $4) where $2 IN { $3 | $4 } ^*
+
+
+  def main (f0:QFPAFormula, u:List[TermQFPA], v:List[TermQFPA], lDNF:List[List[QFPAFormula]]):
+   (QFPAFormula, List[(List[TermQFPA], List[TermQFPA], List[QFPAFormula])]) = {
+    val n = lDNF.length
+    val m = u.length
+    val listofFreshUs = createListofFreshVectors(n, m)
+    var i = 0
+    var listLIAS: List[(List[TermQFPA], List[TermQFPA], List[QFPAFormula])] = Nil
+    lDNF.foreach(c => {
+      listLIAS = (listofFreshUs(i), v, c) :: listLIAS
+      i += 1
+    })
+    val fPA = createFormulaWithFreshUsVariables(u, listofFreshUs)
+    (QFPAAnd(f0, fPA), listLIAS)
+  }
+}
+
diff --git a/src/multisets/RemoveStars.scala b/src/multisets/RemoveStars.scala
new file mode 100644
index 0000000000000000000000000000000000000000..0a9753032c815e5caa264f224e03be29b8948747
--- /dev/null
+++ b/src/multisets/RemoveStars.scala
@@ -0,0 +1,422 @@
+package multisets
+
+import scala.collection.mutable.Set
+
+
+object RemoveStars {
+
+// start: will be needed later
+
+  def createFormulafromConjunctions(l:List[QFPAFormula]):QFPAFormula = {
+    if (l.isEmpty) QFPATrue else {
+      var ff = l.head
+      val fr = l.tail
+      fr.foreach (f => ff = QFPAAnd(ff, f))
+      ff
+     }
+  }
+
+
+  def getAllVariablesFromTerm(t:TermQFPA): Set[String] = {
+    val p = multisets.CheckingConsistency.getAllVariablesAndConstsFromTerm(t)
+    p._1
+  }
+// end
+
+
+  def updateWithNewEqualityTerm(v:String, t:TermQFPA, tt:TermQFPA):TermQFPA  = tt match {
+    case TVariable(v1) => if (v == v1) t else tt
+    case TConstant(c) => tt
+    case TPlus(t1, t2) => {
+      val t1N = updateWithNewEqualityTerm(v, t, t1)
+      val t2N = updateWithNewEqualityTerm(v, t, t2)
+      TPlus(t1N, t2N) 
+    }
+    case TTimes(c, t1) => {
+      val t1N = updateWithNewEqualityTerm(v, t, t1)
+      TTimes(c, t1N)
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def updateWithNewEqualityOneEquality(v:String, t:TermQFPA, e:QFPAFormula):QFPAFormula = e match {
+    case QFPAAtom(AEq(t1, t2)) => {
+      val t1N = updateWithNewEqualityTerm(v, t, t1)
+      val t2N = updateWithNewEqualityTerm(v, t, t2)
+      QFPAAtom(AEq(t1N, t2N)) 
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+  def updateWithNewEqualityVector(va:String, t:TermQFPA, v:List[TermQFPA]):List[TermQFPA] = 
+    v.map(tt => updateWithNewEqualityTerm(va, t, tt))
+
+  def updateWithNewEqualityEqualities(va:String, t:TermQFPA, c:List[QFPAFormula]):List[QFPAFormula] = 
+    c.map(f => updateWithNewEqualityOneEquality(va, t, f))
+
+
+  def isGroundTerm(t:TermQFPA):Boolean = t match {
+    case TVariable(v) => false
+    case TConstant(c) => true
+    case TPlus(t1, t2) => {
+      val b1 = isGroundTerm(t1)
+      val b2 = isGroundTerm(t2)
+      b1 && b2
+    }
+    case TTimes(c, t1) => isGroundTerm(t1)
+    case TIte(f, t1, t2) => {
+      val b0 = isGroundFormula(f)
+      val b1 = isGroundTerm(t1)
+      val b2 = isGroundTerm(t2)
+      b0 && b1 && b2
+    }
+  }
+
+  def isGroundAtom(a:AtomQFPA):Boolean = a match {
+    case ALeq(t1, t2) => {
+      val b1 = isGroundTerm(t1)
+      val b2 = isGroundTerm(t2)
+      b1 && b2
+    }
+    case AEq(t1, t2) => {
+      val b1 = isGroundTerm(t1)
+      val b2 = isGroundTerm(t2)
+      b1 && b2
+    }
+  }
+
+  def isGroundFormula(f:QFPAFormula):Boolean = f match {
+    case QFPAAnd(f1, f2) => {
+      val b1 = isGroundFormula(f1)
+      val b2 = isGroundFormula(f2)
+      b1 && b2
+    }
+    case QFPAOr(f1, f2) => {
+      val b1 = isGroundFormula(f1)
+      val b2 = isGroundFormula(f2)
+      b1 && b2
+    }
+    case QFPANot(f1) => isGroundFormula(f1)
+    case QFPAAtom(a) => isGroundAtom(a)
+    case QFPAFalse => true
+    case QFPATrue => true
+  }
+
+
+  def createTermThatIsSumOfAllTermsInList(l:List[TermQFPA]):TermQFPA = {
+    val t = if (l.isEmpty) TConstant(0) else {
+      var t1 = l.head
+      val r = l.tail
+      r.foreach(tt => t1 = TPlus(tt, t1))
+      t1
+    }
+    t
+  }
+
+
+  def createTermBasedonListofValues(n:Int, l:List[(String,Int)]):TermQFPA = {
+   var lt: List[TermQFPA] = Nil
+   l.foreach(p => if (p._2 != 0) {
+     if (p._1 == "const") {
+       val m = -1 * n * p._2
+       val t = TConstant(m)
+       lt = t :: lt
+     } else {
+       val m = -1 * n * p._2
+       val t = if (m == 1) TVariable(p._1) else TTimes(m, TVariable(p._1))
+       lt = t :: lt
+     }
+   })
+   val tN = createTermThatIsSumOfAllTermsInList(lt)
+   tN
+  }
+
+  def createNewEqualityBasedOnListofValues(l:List[(String,Int)]):(String, TermQFPA) = {
+   var notFound = true
+   var lt: List[(String,Int)] = Nil
+   var n = 0
+   var v = ""
+   l.foreach(p => if (notFound && p._1 != "const" && (p._2 == 1 || p._2 == -1)) {
+     notFound = false
+     v = p._1
+     n = p._2
+   } else lt = p :: lt)
+   if (notFound) error("I am incomplete and dunno how to solve :" + lt)
+   val t = createTermBasedonListofValues(n, lt)
+   (v, t)
+  }
+
+  def reExpressEqualityandFindNewEquality(f:QFPAFormula):(String, TermQFPA) = f match {
+    case QFPAAtom(AEq(t1, t2)) => {
+      val s1 = getAllVariablesFromTerm(t1)
+      val s2 = getAllVariablesFromTerm(t2)
+      val s = s1 ++ s2
+      val vars = s.toList
+      var lt = createInitialZeroValuesList(vars)
+      val l1 = addValuesofTermToList(t1, lt)
+      val l2 = addValuesofTermToList(t2, lt)
+      val l2N = multiplyListWithConstant(-1, l2)
+      val l = sumTwoLists(l1, l2N)
+      val (v, t) = createNewEqualityBasedOnListofValues(l)
+      (v, t)
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+
+  def updateVectorVwithFormulas(v:List[TermQFPA], c:List[QFPAFormula]):List[TermQFPA] = {
+   var vTemp = v
+   var cTemp = c
+   while (! cTemp.isEmpty) {
+     val f = cTemp.head
+     val cRest = cTemp.tail
+     f match {
+       case QFPAAtom(AEq(TVariable(va), t)) => {
+         vTemp = updateWithNewEqualityVector(va, t, vTemp)
+         cTemp = updateWithNewEqualityEqualities(va, t, cRest)
+       }
+       case QFPAAtom(AEq(t, TVariable(va))) => {
+         vTemp = updateWithNewEqualityVector(va, t, vTemp)
+         cTemp = updateWithNewEqualityEqualities(va, t, cRest)
+       }
+       case _ => {
+         if (! isGroundFormula(f)) {
+           val (va, t) = reExpressEqualityandFindNewEquality(f)
+           vTemp = updateWithNewEqualityVector(va, t, vTemp)
+           cTemp = updateWithNewEqualityEqualities(va, t, cRest)
+         }
+       }
+     }
+   }
+   vTemp
+  }
+
+
+  def getAllVariablesFromVector(v:List[TermQFPA]):List[String] = {
+    var s = Set[String]()
+    v.foreach(t => {
+      val s1 = getAllVariablesFromTerm(t)
+      s = s ++ s1
+    })
+    s.toList
+  }
+
+  def createInitialZeroValuesList(v:List[String]):List[(String,Int)] = {
+    var l = List(("const", 0))
+    v.foreach(s => l = (s, 0) :: l)
+    l.reverse
+  }
+
+  def increaseConstantCount(c:Int, l:List[(String,Int)]):List[(String,Int)] = {
+    var lt: List[(String,Int)] = Nil
+    l.foreach(p => if (p._1 == "const") {
+      val k = p._2 + c
+      lt = ("const", k) :: lt
+    } else lt = p :: lt
+    )
+    lt.reverse
+  }
+
+  def increaseVariableCount(v:String, l:List[(String,Int)]):List[(String,Int)] = {
+    var lt: List[(String,Int)] = Nil
+    l.foreach(p => if (p._1 == v) {
+      val c = p._2 + 1
+      lt = (v, c) :: lt
+    } else lt = p :: lt
+    )
+    lt.reverse
+  }
+
+  def sumTwoLists(l1:List[(String,Int)], l2:List[(String,Int)]):List[(String,Int)] = {
+    var l: List[(String,Int)] = Nil
+    val n = l1.length
+    var i = 0
+    while (i < n) {
+      val p = l1(i)
+      val n = l2(i)._2
+      val s = p._2 + n
+      l = (p._1, s) :: l
+      i = i + 1
+    }
+    l.reverse
+  }
+
+  def multiplyListWithConstant(c:Int, l:List[(String,Int)]):List[(String,Int)] = {
+    var lt: List[(String,Int)] = Nil
+    val n = l.length
+    var i = 0
+    while (i < n) {
+      val p = l(i)
+      val s = c * p._2
+      lt = (p._1, s) :: lt
+      i = i + 1
+    }
+    lt.reverse
+  }
+
+  def addValuesofTermToList(t:TermQFPA, l:List[(String,Int)]):List[(String,Int)] = t match {
+    case TVariable(v) => increaseVariableCount(v, l)
+    case TConstant(c) => increaseConstantCount(c, l)
+    case TPlus(t1, t2) => {
+      val l1 = addValuesofTermToList(t1, l)
+      val l2 = addValuesofTermToList(t2, l)
+      val l3 = sumTwoLists(l1, l2)
+      l3
+    }
+    case TTimes(c, t1) => {
+      val l1 = addValuesofTermToList(t1, l)
+      val l2 = multiplyListWithConstant(c, l1)
+      l2
+    }
+    case x@_ => error("Impossible case :" + x)
+  }
+
+
+  def listContainingOccurancesOfVariables(t:TermQFPA, v:List[String]):List[(String,Int)] = {
+    var l = createInitialZeroValuesList(v)
+    val l1 = addValuesofTermToList(t, l)
+    l1
+  }
+
+  def isZeroVector(v:List[Int]):Boolean = v.forall(n => (n == 0))
+
+  def getValueinOneList(v:String, l:List[(String,Int)]):Int = {
+    var n = 0
+    l.foreach(p => if (p._1 == v) n = p._2)
+    n
+  }
+
+  def constructIntVectorforSLS(v:String, l:List[List[(String,Int)]]):List[Int] = {
+    var lt: List[Int] = Nil
+    l.foreach(s => {
+      val n = getValueinOneList(v, s)
+      lt = n :: lt
+    })
+    lt
+  }
+
+  def constructLinearSetFromList(l:List[List[(String,Int)]], v:List[String]):(List[Int], List[List[Int]]) = {
+    val baseVector = constructIntVectorforSLS("const", l)
+    var stepVectors: List[List[Int]] = Nil
+    v.foreach(s => {
+      val sV = constructIntVectorforSLS(s, l)
+      if (! isZeroVector(sV)) stepVectors = sV :: stepVectors
+    })
+    (baseVector, stepVectors)
+  }
+
+
+  def constructLinearSetFromThisNewVector(v:List[TermQFPA]):(List[Int], List[List[Int]]) = {
+   val a1 = getAllVariablesFromVector(v)
+   val n = v.length
+   var i = 0
+   var lB: List[List[(String,Int)]] = Nil
+   while (i < n) {
+     val ls = listContainingOccurancesOfVariables(v(i), a1)
+     lB = ls :: lB
+     i = i + 1 
+   }
+   val sls = constructLinearSetFromList(lB, a1)
+   sls 
+  }
+
+
+
+  def createSemilinearSet(v:List[TermQFPA], c:List[QFPAFormula]):(List[Int], List[List[Int]]) = {
+    val v1 = updateVectorVwithFormulas(v, c)
+    val sls = constructLinearSetFromThisNewVector(v1)
+    sls
+  }
+
+///////////////////
+
+  def createTermSumFromTermList(l:List[TermQFPA]):TermQFPA = {
+    val t1 = if (l.isEmpty) TConstant(0) else {
+      var th = l.head
+      val tt = l.tail
+      tt.foreach (t => th = TPlus(th, t))
+      th
+    }
+    t1
+  }
+
+  def createFormulaThatAllNusAreZero(s: Int, e:Int):QFPAFormula = {
+    var i = s
+    var lTemp: List[QFPAFormula] = Nil
+    while (i < e) {
+      val newNu = "FRESHnu" + i
+      val eq = QFPAAtom(AEq(TVariable(newNu), TConstant(0)))
+      lTemp = eq :: lTemp
+      i = i + 1 
+    }
+    val f = createFormulafromConjunctions(lTemp)
+    f
+  }
+
+  def createFormulaFromSemilinearSet(u:List[TermQFPA], slset:(List[Int], List[List[Int]]), mc:Int, nc:Int):
+   (QFPAFormula, Int, Int) = {
+    val n = (slset._1).length
+    var i = 0
+    var lTemp: List[QFPAFormula] = Nil
+    val m = (slset._2).length
+    val newMu = "FRESHmu" + mc
+    while (i < n) {
+      val t1 = if ((slset._1)(i) == 0) TConstant(0) else
+        TTimes((slset._1)(i), TVariable(newMu))
+      var j = 0
+      var l2Temp: List[TermQFPA] = Nil 
+      while (j < m) {
+        val nuN = nc + j
+        val newNu = "FRESHnu" + nuN
+        val termTemp = if (((slset._2)(j))(i) == 0) TConstant(0) else
+        TTimes(((slset._2)(j))(i), TVariable(newNu))
+        l2Temp = termTemp :: l2Temp
+        j = j + 1
+      }
+      val t2 = createTermSumFromTermList(l2Temp)
+      val eq = QFPAAtom(AEq(u(i), TPlus(t1, t2)))
+      lTemp = eq :: lTemp
+      i = i + 1
+    }
+    val fNew = createFormulafromConjunctions(lTemp)
+    val fMu = QFPANot(QFPAAtom(AEq(TVariable(newMu), TConstant(0))))
+    val fNu = createFormulaThatAllNusAreZero(nc, nc + m)
+    val constraints = QFPAOr(fMu, fNu)
+    val ff = if (slset._2 == Nil) fNew else QFPAAnd(fNew, constraints)
+    val mcN = mc + 1
+    val ncN = nc + m
+    (ff, mcN, ncN)
+  }
+
+
+  def createQFPAFormulaFromLIAStarFormula(u:List[TermQFPA], v:List[TermQFPA], c:List[QFPAFormula], mc: Int, nc: Int):
+   (QFPAFormula, Int, Int) = {
+    val slset = createSemilinearSet(v, c)
+    multisets.StarFormulaPrinter.print_PAVector(v)
+    print(" | ")
+    c.foreach(f => {
+      multisets.StarFormulaPrinter.print_QFPAFormula(f)
+      print(", ")})
+    println(" ")
+    println("semilinear set describing it is: " + slset)
+    val (fNew, m, n) = createFormulaFromSemilinearSet(u, slset, mc, nc)
+    (fNew, m, n)
+  }
+
+  def removeStarsMain(f:QFPAFormula, l:List[(List[TermQFPA], List[TermQFPA], List[QFPAFormula])]):QFPAFormula = {
+    var lTemp: List[QFPAFormula] = Nil
+    var mc = 0
+    var nc = 0
+    l.foreach(t => {
+      val (f1, m, n) = createQFPAFormulaFromLIAStarFormula(t._1, t._2, t._3, mc, nc)
+      lTemp = f1 :: lTemp
+      mc = m
+      nc = n
+    })
+    val fTemp = createFormulafromConjunctions(lTemp)
+    val g = multisets.Multiset2StarsTranslator.removeTrueAndFalse(QFPAAnd(f, fTemp))
+    g
+  }
+
+}
+
diff --git a/src/multisets/StarFormulaPrinter.scala b/src/multisets/StarFormulaPrinter.scala
new file mode 100644
index 0000000000000000000000000000000000000000..57a0304b28c6d15ebd75b5a60a8dc6c289a6c374
--- /dev/null
+++ b/src/multisets/StarFormulaPrinter.scala
@@ -0,0 +1,90 @@
+package multisets
+
+object StarFormulaPrinter {
+
+  def print_QFPAterm(t:TermQFPA):Unit = t match {
+    case TConstant(c) => Console.print(c)
+    case TVariable(v) => Console.print(v)
+    case TPlus(t1, t2) => {
+      print_QFPAterm(t1)
+      Console.print(" + ")
+      print_QFPAterm(t2)
+    }
+    case TTimes(c, t1)=> {
+      Console.print(c + "*")
+      print_QFPAterm(t1)
+    }
+    case TIte(f, t1, t2)=> {
+      Console.print("ITE(")
+      print_QFPAFormula(f)
+      print("; ")
+      print_QFPAterm(t1)
+      print(", ")
+      print_QFPAterm(t2)
+      print(")")
+    }
+  }
+
+  def print_QFPAatom(a:AtomQFPA):Unit = a match {
+    case ALeq(t1,t2) => {
+      print_QFPAterm(t1)
+      Console.print(" =< ")
+      print_QFPAterm(t2)
+    }
+    case AEq(t1,t2) => {
+      print_QFPAterm(t1)
+      Console.print(" = ")
+      print_QFPAterm(t2)
+    }
+  }
+
+  def print_QFPAFormula(f:QFPAFormula):Unit = f match {
+    case QFPAAnd(f1,f2) => {
+      Console.print(" ( ")
+      print_QFPAFormula(f1)
+      print(" ) AND ( ")
+      print_QFPAFormula(f2)
+      print(" ) ")
+    }
+    case QFPAOr(f1,f2) => {
+      Console.print(" ( ")
+      print_QFPAFormula(f1)
+      print(" ) OR ( ")
+      print_QFPAFormula(f2)
+      print(" ) ")
+    }
+    case QFPANot(f1)  => {
+      Console.print(" NOT ( ")
+      print_QFPAFormula(f1)
+      print(" ) ")
+    }
+    case QFPAAtom(a)  => print_QFPAatom(a)
+    case QFPAFalse => Console.print(" FALSE ")
+    case QFPATrue  => Console.print(" TRUE ")
+  }
+
+
+  def print_PAVector(l:List[TermQFPA]):Unit = {
+    Console.print(" ( ")
+    l.foreach(t => {
+      print_QFPAterm(t)
+      print(", ")
+    })
+    print(") ")
+  }
+
+  def print_starFormula(f:StarFormula):Unit = f match {
+    case StarFormula(f1, l1, l2, f2) => {
+      print_QFPAFormula(f1)
+      Console.print(" AND ")
+      print_PAVector(l1)
+      print(" IN { ")
+      print_PAVector(l2)
+      print(" |  ")
+      print_QFPAFormula(f2)
+      print(" }*")
+    }
+  }
+
+}
+