From a80dd23df7375e4f148b0c8a0f33d1648fcf41c3 Mon Sep 17 00:00:00 2001 From: Philippe Suter <philippe.suter@gmail.com> Date: Fri, 26 Oct 2012 18:04:10 +0200 Subject: [PATCH] Refactoring of solvers. --- src/main/scala/leon/AbstractZ3Solver.scala | 97 --- src/main/scala/leon/Analysis.scala | 4 + src/main/scala/leon/Extensions.scala | 8 +- .../leon/{ => solvers}/ParallelSolver.scala | 1 + .../leon/{ => solvers}/RandomSolver.scala | 1 + .../leon/{ => solvers}/TimeoutSolver.scala | 1 + .../leon/{ => solvers}/TrivialSolver.scala | 3 +- .../leon/solvers/z3/AbstractZ3Solver.scala | 765 ++++++++++++++++++ .../leon/{ => solvers/z3}/FairZ3Solver.scala | 536 +----------- .../z3}/Z3ModelReconstruction.scala | 1 + .../scala/leon/synthesis/SynthesisPhase.scala | 3 + src/main/scala/leon/testgen/CallGraph.scala | 2 +- .../scala/leon/testgen/TestGeneration.scala | 2 +- 13 files changed, 791 insertions(+), 633 deletions(-) delete mode 100644 src/main/scala/leon/AbstractZ3Solver.scala rename src/main/scala/leon/{ => solvers}/ParallelSolver.scala (99%) rename src/main/scala/leon/{ => solvers}/RandomSolver.scala (99%) rename src/main/scala/leon/{ => solvers}/TimeoutSolver.scala (97%) rename src/main/scala/leon/{ => solvers}/TrivialSolver.scala (91%) create mode 100644 src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala rename src/main/scala/leon/{ => solvers/z3}/FairZ3Solver.scala (63%) rename src/main/scala/leon/{ => solvers/z3}/Z3ModelReconstruction.scala (99%) diff --git a/src/main/scala/leon/AbstractZ3Solver.scala b/src/main/scala/leon/AbstractZ3Solver.scala deleted file mode 100644 index 5c1fc48fa..000000000 --- a/src/main/scala/leon/AbstractZ3Solver.scala +++ /dev/null @@ -1,97 +0,0 @@ -package leon - -import z3.scala._ -import purescala.Common._ -import purescala.Definitions._ -import purescala.Trees._ -import purescala.TypeTrees._ -import Extensions._ - -import scala.collection.mutable.{Map => MutableMap} -import scala.collection.mutable.{Set => MutableSet} - -// This is just to factor out the things that are common in "classes that deal -// with a Z3 instance" -trait AbstractZ3Solver { - self: Solver => - - val reporter: Reporter - - class CantTranslateException(t: Z3AST) extends Exception("Can't translate from Z3 tree: " + t) - - protected[leon] var z3 : Z3Context - protected[leon] var program : Program - - def typeToSort(tt: TypeTree): Z3Sort - protected[leon] var adtTesters: Map[CaseClassDef, Z3FuncDecl] - protected[leon] var adtConstructors: Map[CaseClassDef, Z3FuncDecl] - protected[leon] var adtFieldSelectors: Map[Identifier, Z3FuncDecl] - - protected[leon] val mapRangeSorts: MutableMap[TypeTree, Z3Sort] - protected[leon] val mapRangeSomeConstructors: MutableMap[TypeTree, Z3FuncDecl] - protected[leon] val mapRangeNoneConstructors: MutableMap[TypeTree, Z3FuncDecl] - protected[leon] val mapRangeSomeTesters: MutableMap[TypeTree, Z3FuncDecl] - protected[leon] val mapRangeNoneTesters: MutableMap[TypeTree, Z3FuncDecl] - protected[leon] val mapRangeValueSelectors: MutableMap[TypeTree, Z3FuncDecl] - - protected[leon] var funSorts: Map[TypeTree, Z3Sort] - protected[leon] var funDomainConstructors: Map[TypeTree, Z3FuncDecl] - protected[leon] var funDomainSelectors: Map[TypeTree, Seq[Z3FuncDecl]] - - protected[leon] var exprToZ3Id : Map[Expr,Z3AST] - protected[leon] def fromZ3Formula(model: Z3Model, tree : Z3AST, expectedType: Option[TypeTree]) : Expr - - protected[leon] def softFromZ3Formula(model: Z3Model, tree : Z3AST, expectedType: TypeTree) : Option[Expr] = { - try { - Some(fromZ3Formula(model, tree, Some(expectedType))) - } catch { - case e: CantTranslateException => None - } - } - - protected[leon] def solveWithBounds(vc: Expr, forValidity: Boolean) : (Option[Boolean], Map[Identifier, Expr]) - - protected[leon] def boundValues : Unit = { - val lowerBound: Z3AST = z3.mkInt(Settings.testBounds._1, z3.mkIntSort) - val upperBound: Z3AST = z3.mkInt(Settings.testBounds._2, z3.mkIntSort) - - def isUnbounded(field: VarDecl) : Boolean = field.getType match { - case Int32Type => true - case _ => false - } - - def boundConstraint(boundVar: Z3AST) : Z3AST = { - z3.mkAnd(z3.mkLE(lowerBound, boundVar), z3.mkLE(boundVar, upperBound)) - } - - // for all recursive type roots - // for all child ccd of a root - // if ccd contains unbounded types - // create bound vars (mkBound) for each field - // create pattern that says (valueBounds(ccd(f1, ..))) - // create axiom tree that says "values of unbounded types are within bounds" - // assert axiom for the tree above - - val roots = program.classHierarchyRoots - for (root <- roots) { - val children: List[CaseClassDef] = (root match { - case c: CaseClassDef => List(c) - case a: AbstractClassDef => a.knownChildren.filter(_.isInstanceOf[CaseClassDef]).map(_.asInstanceOf[CaseClassDef]).toList - }) - for (child <- children) child match { - case CaseClassDef(id, parent, fields) => - val unboundedFields = fields.filter(isUnbounded(_)) - if (!unboundedFields.isEmpty) { - val boundVars = fields.zipWithIndex.map{case (f, i) => z3.mkBound(i, typeToSort(f.getType))} - val term = adtConstructors(child)(boundVars : _*) - val pattern = z3.mkPattern(term) - //val constraint = (fields zip boundVars).filter((p: (VarDecl, Z3AST)) => isUnbounded(p._1)).map((p: (VarDecl, Z3AST)) => boundConstraint(p._2)).foldLeft(z3.mkTrue)((a, b) => a && b) - val constraint = (fields zip boundVars).filter((p: (VarDecl, Z3AST)) => isUnbounded(p._1)).map((p: (VarDecl, Z3AST)) => boundConstraint(adtFieldSelectors(p._1.id)(term))).foldLeft(z3.mkTrue)((a, b) => z3.mkAnd(a, b)) - val axiom = z3.mkForAll(0, List(pattern), fields.zipWithIndex.map{case (f, i) => (z3.mkIntSymbol(i), typeToSort(f.getType))}, constraint) - //println("Asserting: " + axiom) - z3.assertCnstr(axiom) - } - } - } - } -} diff --git a/src/main/scala/leon/Analysis.scala b/src/main/scala/leon/Analysis.scala index 62ea2a39b..e1fc9fb1f 100644 --- a/src/main/scala/leon/Analysis.scala +++ b/src/main/scala/leon/Analysis.scala @@ -5,7 +5,11 @@ import purescala.Definitions._ import purescala.Trees._ import purescala.TreeOps._ import purescala.TypeTrees._ + import Extensions._ + +import solvers.TrivialSolver + import scala.collection.mutable.{Set => MutableSet} class Analysis(val program : Program, val reporter: Reporter = Settings.reporter) { diff --git a/src/main/scala/leon/Extensions.scala b/src/main/scala/leon/Extensions.scala index 1d6bb8198..4b54a3855 100644 --- a/src/main/scala/leon/Extensions.scala +++ b/src/main/scala/leon/Extensions.scala @@ -95,7 +95,7 @@ object Extensions { } // these extensions are always loaded, unless specified otherwise val defaultExtensions: Seq[Extension] = if(Settings.runDefaultExtensions) { - val z3 : Solver = new FairZ3Solver(extensionsReporter) + val z3 : Solver = new solvers.z3.FairZ3Solver(extensionsReporter) z3 :: Nil } else { Nil @@ -106,14 +106,14 @@ object Extensions { //analysisExtensions = new TestGeneration(extensionsReporter) +: analysisExtensions val solverExtensions0 = allLoaded.filter(_.isInstanceOf[Solver]).map(_.asInstanceOf[Solver]) - val solverExtensions1 = if(Settings.useQuickCheck) new RandomSolver(extensionsReporter) +: solverExtensions0 else solverExtensions0 - val solverExtensions2 = if(Settings.useParallel) Seq(new ParallelSolver(solverExtensions1: _*)) else solverExtensions1 + val solverExtensions1 = if(Settings.useQuickCheck) new solvers.RandomSolver(extensionsReporter) +: solverExtensions0 else solverExtensions0 + val solverExtensions2 = if(Settings.useParallel) Seq(new solvers.ParallelSolver(solverExtensions1: _*)) else solverExtensions1 val solverExtensions3 = if(Settings.solverTimeout == None) { solverExtensions2 } else { val t = Settings.solverTimeout.get - solverExtensions2.map(s => new TimeoutSolver(s, t)) + solverExtensions2.map(s => new solvers.TimeoutSolver(s, t)) } solverExtensions = solverExtensions3 loaded diff --git a/src/main/scala/leon/ParallelSolver.scala b/src/main/scala/leon/solvers/ParallelSolver.scala similarity index 99% rename from src/main/scala/leon/ParallelSolver.scala rename to src/main/scala/leon/solvers/ParallelSolver.scala index 1a3e1d7c4..9a9e39829 100644 --- a/src/main/scala/leon/ParallelSolver.scala +++ b/src/main/scala/leon/solvers/ParallelSolver.scala @@ -1,4 +1,5 @@ package leon +package solvers import purescala.Common._ import purescala.Definitions._ diff --git a/src/main/scala/leon/RandomSolver.scala b/src/main/scala/leon/solvers/RandomSolver.scala similarity index 99% rename from src/main/scala/leon/RandomSolver.scala rename to src/main/scala/leon/solvers/RandomSolver.scala index 778a44e59..89c0c6752 100644 --- a/src/main/scala/leon/RandomSolver.scala +++ b/src/main/scala/leon/solvers/RandomSolver.scala @@ -1,4 +1,5 @@ package leon +package solvers import purescala.Common._ import purescala.Definitions._ diff --git a/src/main/scala/leon/TimeoutSolver.scala b/src/main/scala/leon/solvers/TimeoutSolver.scala similarity index 97% rename from src/main/scala/leon/TimeoutSolver.scala rename to src/main/scala/leon/solvers/TimeoutSolver.scala index 1785aec5e..6b08a36f7 100644 --- a/src/main/scala/leon/TimeoutSolver.scala +++ b/src/main/scala/leon/solvers/TimeoutSolver.scala @@ -1,4 +1,5 @@ package leon +package solvers import purescala.Common._ import purescala.Definitions._ diff --git a/src/main/scala/leon/TrivialSolver.scala b/src/main/scala/leon/solvers/TrivialSolver.scala similarity index 91% rename from src/main/scala/leon/TrivialSolver.scala rename to src/main/scala/leon/solvers/TrivialSolver.scala index 0b05bbb59..054ae3f93 100644 --- a/src/main/scala/leon/TrivialSolver.scala +++ b/src/main/scala/leon/solvers/TrivialSolver.scala @@ -1,6 +1,6 @@ package leon +package solvers -import z3.scala._ import purescala.Common._ import purescala.Definitions._ import purescala.Trees._ @@ -16,6 +16,7 @@ class TrivialSolver(reporter: Reporter) extends Solver(reporter) { case Not(BooleanLiteral(v)) => Some(!v) case Or(exs) if exs.contains(BooleanLiteral(true)) => Some(true) case And(exs) if exs.contains(BooleanLiteral(false)) => Some(false) + case Equals(l,r) if l == r => Some(true) case _ => None } } diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala new file mode 100644 index 000000000..a2a78f952 --- /dev/null +++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala @@ -0,0 +1,765 @@ +package leon +package solvers.z3 + +import z3.scala._ +import purescala.Common._ +import purescala.Definitions._ +import purescala.Trees._ +import purescala.TreeOps._ +import purescala.TypeTrees._ +import Extensions._ + +import scala.collection.mutable.{Map => MutableMap} +import scala.collection.mutable.{Set => MutableSet} + +// This is just to factor out the things that are common in "classes that deal +// with a Z3 instance" +trait AbstractZ3Solver { + self: Solver => + + val reporter: Reporter + + protected[leon] val USEBV : Boolean = Settings.bitvectorBitwidth.isDefined + protected[leon] val BVWIDTH : Int = Settings.bitvectorBitwidth.getOrElse(-1) + + class CantTranslateException(t: Z3AST) extends Exception("Can't translate from Z3 tree: " + t) + + protected[leon] var z3 : Z3Context = null + protected[leon] var program : Program = null + protected[leon] val z3cfg : Z3Config + + override def setProgram(prog: Program): Unit = { + program = prog + } + + protected[leon] def prepareFunctions : Unit + protected[leon] def functionDefToDecl(funDef: FunDef) : Z3FuncDecl + protected[leon] def functionDeclToDef(decl: Z3FuncDecl) : FunDef + protected[leon] def isKnownDecl(decl: Z3FuncDecl) : Boolean + + // Lifting of common parts starts here + protected[leon] var exprToZ3Id : Map[Expr,Z3AST] = Map.empty + protected[leon] var z3IdToExpr : Map[Z3AST,Expr] = Map.empty + + protected[leon] var intSort: Z3Sort = null + protected[leon] var boolSort: Z3Sort = null + protected[leon] var setSorts: Map[TypeTree, Z3Sort] = Map.empty + protected[leon] var mapSorts: Map[TypeTree, Z3Sort] = Map.empty + protected[leon] var unitSort: Z3Sort = null + protected[leon] var unitValue: Z3AST = null + + protected[leon] var funSorts: Map[TypeTree, Z3Sort] = Map.empty + protected[leon] var funDomainConstructors: Map[TypeTree, Z3FuncDecl] = Map.empty + protected[leon] var funDomainSelectors: Map[TypeTree, Seq[Z3FuncDecl]] = Map.empty + + protected[leon] var tupleSorts: Map[TypeTree, Z3Sort] = Map.empty + protected[leon] var tupleConstructors: Map[TypeTree, Z3FuncDecl] = Map.empty + protected[leon] var tupleSelectors: Map[TypeTree, Seq[Z3FuncDecl]] = Map.empty + + protected[leon] var arraySorts: Map[TypeTree, Z3Sort] = Map.empty + protected[leon] var arrayTupleCons: Map[TypeTree, Z3FuncDecl] = Map.empty + protected[leon] var arrayTupleSelectorArray: Map[TypeTree, Z3FuncDecl] = Map.empty + protected[leon] var arrayTupleSelectorLength: Map[TypeTree, Z3FuncDecl] = Map.empty + + protected[leon] var reverseTupleConstructors: Map[Z3FuncDecl, TupleType] = Map.empty + protected[leon] var reverseTupleSelectors: Map[Z3FuncDecl, (TupleType, Int)] = Map.empty + + protected[leon] var intSetMinFun: Z3FuncDecl = null + protected[leon] var intSetMaxFun: Z3FuncDecl = null + protected[leon] var setCardFuns: Map[TypeTree, Z3FuncDecl] = Map.empty + protected[leon] var adtSorts: Map[ClassTypeDef, Z3Sort] = Map.empty + protected[leon] var fallbackSorts: Map[TypeTree, Z3Sort] = Map.empty + + protected[leon] var adtTesters: Map[CaseClassDef, Z3FuncDecl] = Map.empty + protected[leon] var adtConstructors: Map[CaseClassDef, Z3FuncDecl] = Map.empty + protected[leon] var adtFieldSelectors: Map[Identifier, Z3FuncDecl] = Map.empty + + protected[leon] var reverseADTTesters: Map[Z3FuncDecl, CaseClassDef] = Map.empty + protected[leon] var reverseADTConstructors: Map[Z3FuncDecl, CaseClassDef] = Map.empty + protected[leon] var reverseADTFieldSelectors: Map[Z3FuncDecl, (CaseClassDef,Identifier)] = Map.empty + + protected[leon] val mapRangeSorts: MutableMap[TypeTree, Z3Sort] = MutableMap.empty + protected[leon] val mapRangeSomeConstructors: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty + protected[leon] val mapRangeNoneConstructors: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty + protected[leon] val mapRangeSomeTesters: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty + protected[leon] val mapRangeNoneTesters: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty + protected[leon] val mapRangeValueSelectors: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty + + private var neverInitialized = true + private var counter = 0 + private object nextIntForSymbol { + def apply(): Int = { + val res = counter + counter = counter + 1 + res + } + } + + protected[leon] def restartZ3 : Unit = { + counter = 0 + if (neverInitialized) { + neverInitialized = false + } else { + z3.delete + } + z3 = new Z3Context(z3cfg) + + exprToZ3Id = Map.empty + z3IdToExpr = Map.empty + + fallbackSorts = Map.empty + + mapSorts = Map.empty + arraySorts = Map.empty + funSorts = Map.empty + funDomainConstructors = Map.empty + funDomainSelectors = Map.empty + + tupleSorts = Map.empty + tupleConstructors = Map.empty + tupleSelectors = Map.empty + + mapRangeSorts.clear + mapRangeSomeConstructors.clear + mapRangeNoneConstructors.clear + mapRangeSomeTesters.clear + mapRangeNoneTesters.clear + mapRangeValueSelectors.clear + + prepareSorts + + prepareFunctions + } + protected[leon] def mapRangeSort(toType : TypeTree) : Z3Sort = mapRangeSorts.get(toType) match { + case Some(z3sort) => z3sort + case None => { + import Z3Context.{ADTSortReference, RecursiveType, RegularSort} + intSort = if(USEBV) { + z3.mkBVSort(BVWIDTH) + } else { + z3.mkIntSort + } + boolSort = z3.mkBoolSort + + def typeToSortRef(tt: TypeTree): ADTSortReference = tt match { + case BooleanType => RegularSort(boolSort) + case Int32Type => RegularSort(intSort) + case AbstractClassType(d) => RegularSort(adtSorts(d)) + case CaseClassType(d) => RegularSort(adtSorts(d)) + case SetType(d) => RegularSort(setSorts(d)) + case mt @ MapType(d,r) => RegularSort(mapSorts(mt)) + case _ => throw UntranslatableTypeException("Can't handle type " + tt) + } + + val z3info = z3.mkADTSorts( + Seq( + ( + toType.toString + "Option", + Seq(toType.toString + "Some", toType.toString + "None"), + Seq( + Seq(("value", typeToSortRef(toType))), + Seq() + ) + ) + ) + ) + + z3info match { + case Seq((optionSort, Seq(someCons, noneCons), Seq(someTester, noneTester), Seq(Seq(valueSelector), Seq()))) => + mapRangeSorts += ((toType, optionSort)) + mapRangeSomeConstructors += ((toType, someCons)) + mapRangeNoneConstructors += ((toType, noneCons)) + mapRangeSomeTesters += ((toType, someTester)) + mapRangeNoneTesters += ((toType, noneTester)) + mapRangeValueSelectors += ((toType, valueSelector)) + optionSort + } + } + } + + case class UntranslatableTypeException(msg: String) extends Exception(msg) + // Prepares some of the Z3 sorts, but *not* the tuple sorts; these are created on-demand. + private def prepareSorts: Unit = { + import Z3Context.{ADTSortReference, RecursiveType, RegularSort} + // NOTE THAT abstract classes that extend abstract classes are not + // currently supported in the translation + intSort = if(USEBV) { + z3.mkBVSort(BVWIDTH) + } else { + z3.mkIntSort + } + boolSort = z3.mkBoolSort + setSorts = Map.empty + setCardFuns = Map.empty + + //unitSort = z3.mkUninterpretedSort("unit") + //unitValue = z3.mkFreshConst("Unit", unitSort) + //val bound = z3.mkBound(0, unitSort) + //val eq = z3.mkEq(bound, unitValue) + //val decls = Seq((z3.mkFreshStringSymbol("u"), unitSort)) + //val unitAxiom = z3.mkForAll(0, Seq(), decls, eq) + //println(unitAxiom) + //println(unitValue) + //z3.assertCnstr(unitAxiom) + val Seq((us, Seq(unitCons), Seq(unitTester), _)) = z3.mkADTSorts( + Seq( + ( + "Unit", + Seq("Unit"), + Seq(Seq()) + ) + ) + ) + unitSort = us + unitValue = unitCons() + + val intSetSort = typeToSort(SetType(Int32Type)) + intSetMinFun = z3.mkFreshFuncDecl("setMin", Seq(intSetSort), intSort) + intSetMaxFun = z3.mkFreshFuncDecl("setMax", Seq(intSetSort), intSort) + + val roots = program.classHierarchyRoots + val indexMap: Map[ClassTypeDef, Int] = Map(roots.zipWithIndex: _*) + //println("indexMap: " + indexMap) + + def typeToSortRef(tt: TypeTree): ADTSortReference = tt match { + // case BooleanType => RegularSort(boolSort) + // case Int32Type => RegularSort(intSort) + case AbstractClassType(d) => RecursiveType(indexMap(d)) + case CaseClassType(d) => indexMap.get(d) match { + case Some(i) => RecursiveType(i) + case None => RecursiveType(indexMap(d.parent.get)) + } + // case _ => throw UntranslatableTypeException("Can't handle type " + tt) + case _ => RegularSort(typeToSort(tt)) + } + + val childrenLists: Seq[List[CaseClassDef]] = roots.map(_ match { + case c: CaseClassDef => List(c) + case a: AbstractClassDef => a.knownChildren.filter(_.isInstanceOf[CaseClassDef]).map(_.asInstanceOf[CaseClassDef]).toList + }) + //println("children lists: " + childrenLists.toList.mkString("\n")) + + val rootsAndChildren = (roots zip childrenLists) + + val defs = rootsAndChildren.map(p => { + val (root, childrenList) = p + + root match { + case c: CaseClassDef => { + // we create a recursive type with exactly one constructor + (c.id.uniqueName, List(c.id.uniqueName), List(c.fields.map(f => (f.id.uniqueName, typeToSortRef(f.tpe))))) + } + case a: AbstractClassDef => { + (a.id.uniqueName, childrenList.map(ccd => ccd.id.uniqueName), childrenList.map(ccd => ccd.fields.map(f => (f.id.uniqueName, typeToSortRef(f.tpe))))) + } + } + }) + + //println(defs) + // everything should be alright now... + val resultingZ3Info = z3.mkADTSorts(defs) + + adtSorts = Map.empty + adtTesters = Map.empty + adtConstructors = Map.empty + adtFieldSelectors = Map.empty + reverseADTTesters = Map.empty + reverseADTConstructors = Map.empty + reverseADTFieldSelectors = Map.empty + + for ((z3Inf, (root, childrenList)) <- (resultingZ3Info zip rootsAndChildren)) { + adtSorts += (root -> z3Inf._1) + assert(childrenList.size == z3Inf._2.size) + for ((child, (consFun, testFun)) <- childrenList zip (z3Inf._2 zip z3Inf._3)) { + adtTesters += (child -> testFun) + adtConstructors += (child -> consFun) + } + for ((child, fieldFuns) <- childrenList zip z3Inf._4) { + assert(child.fields.size == fieldFuns.size) + for ((fid, selFun) <- (child.fields.map(_.id) zip fieldFuns)) { + adtFieldSelectors += (fid -> selFun) + reverseADTFieldSelectors += (selFun -> (child, fid)) + } + } + } + + reverseADTTesters = adtTesters.map(_.swap) + reverseADTConstructors = adtConstructors.map(_.swap) + // ...and now everything should be in there... + } + + // assumes prepareSorts has been called.... + protected[leon] def typeToSort(tt: TypeTree): Z3Sort = tt match { + case Int32Type => intSort + case BooleanType => boolSort + case UnitType => unitSort + case AbstractClassType(cd) => adtSorts(cd) + case CaseClassType(cd) => { + if (cd.hasParent) { + adtSorts(cd.parent.get) + } else { + adtSorts(cd) + } + } + case SetType(base) => setSorts.get(base) match { + case Some(s) => s + case None => { + val newSetSort = z3.mkSetSort(typeToSort(base)) + setSorts = setSorts + (base -> newSetSort) + val newCardFun = z3.mkFreshFuncDecl("card", Seq(newSetSort), intSort) + setCardFuns = setCardFuns + (base -> newCardFun) + newSetSort + } + } + case mt @ MapType(fromType, toType) => mapSorts.get(mt) match { + case Some(s) => s + case None => { + val fromSort = typeToSort(fromType) + val toSort = mapRangeSort(toType) + val ms = z3.mkArraySort(fromSort, toSort) + mapSorts += ((mt, ms)) + ms + } + } + case at @ ArrayType(base) => arraySorts.get(at) match { + case Some(s) => s + case None => { + val intSort = typeToSort(Int32Type) + val toSort = typeToSort(base) + val as = z3.mkArraySort(intSort, toSort) + val tupleSortSymbol = z3.mkFreshStringSymbol("Array") + val (arrayTupleSort, arrayTupleCons_, Seq(arrayTupleSelectorArray_, arrayTupleSelectorLength_)) = z3.mkTupleSort(tupleSortSymbol, as, intSort) + arraySorts += (at -> arrayTupleSort) + arrayTupleCons += (at -> arrayTupleCons_) + arrayTupleSelectorArray += (at -> arrayTupleSelectorArray_) + arrayTupleSelectorLength += (at -> arrayTupleSelectorLength_) + arrayTupleSort + } + } + case ft @ FunctionType(fts, tt) => funSorts.get(ft) match { + case Some(s) => s + case None => { + val fss = fts map typeToSort + val ts = typeToSort(tt) + val (tupleSort, consFuncDecl, projFuncDecls) = z3.mkTupleSort(fts.map(_.toString).mkString("(",", ", ")"), fss: _*) + val funSort = z3.mkArraySort(tupleSort, ts) + funSorts += (ft -> funSort) + funDomainConstructors += (ft -> consFuncDecl) + funDomainSelectors += (ft -> projFuncDecls) + funSort + } + } + case tt @ TupleType(tpes) => tupleSorts.get(tt) match { + case Some(s) => s + case None => { + val tpesSorts = tpes.map(typeToSort) + val sortSymbol = z3.mkFreshStringSymbol("Tuple") + val (tupleSort, consTuple, projsTuple) = z3.mkTupleSort(sortSymbol, tpesSorts: _*) + tupleSorts += (tt -> tupleSort) + tupleConstructors += (tt -> consTuple) + reverseTupleConstructors += (consTuple -> tt) + tupleSelectors += (tt -> projsTuple) + projsTuple.zipWithIndex.foreach{ case (proj, i) => reverseTupleSelectors += (proj -> (tt, i)) } + tupleSort + } + } + case other => fallbackSorts.get(other) match { + case Some(s) => s + case None => { + reporter.warning("Resorting to uninterpreted type for : " + other) + val symbol = z3.mkIntSymbol(nextIntForSymbol()) + val newFBSort = z3.mkUninterpretedSort(symbol) + fallbackSorts = fallbackSorts + (other -> newFBSort) + newFBSort + } + } + } + + protected[leon] def toZ3Formula(z3: Z3Context, expr: Expr, initialMap: Map[Identifier,Z3AST] = Map.empty) : Option[Z3AST] = { + class CantTranslateException extends Exception + + val varsInformula: Set[Identifier] = variablesOf(expr) + + var z3Vars: Map[Identifier,Z3AST] = if(!initialMap.isEmpty) { + initialMap + } else { + // FIXME TODO pleeeeeeeease make this cleaner. Ie. decide what set of + // variable has to remain in a map etc. + exprToZ3Id.filter(p => p._1.isInstanceOf[Variable]).map(p => (p._1.asInstanceOf[Variable].id -> p._2)) + } + + def rec(ex: Expr): Z3AST = { + //println("Stacking up call for:") + //println(ex) + val recResult = (ex match { + case tu @ Tuple(args) => { + // This call is required, because the Z3 sort may not have been generated yet. + // If it has, it's just a map lookup and instant return. + typeToSort(tu.getType) + val constructor = tupleConstructors(tu.getType) + constructor(args.map(rec(_)): _*) + } + case ts @ TupleSelect(tu, i) => { + // See comment above for similar code. + typeToSort(tu.getType) + val selector = tupleSelectors(tu.getType)(i-1) + selector(rec(tu)) + } + case Let(i, e, b) => { + val re = rec(e) + z3Vars = z3Vars + (i -> re) + val rb = rec(b) + z3Vars = z3Vars - i + rb + } + case Waypoint(_, e) => rec(e) + case e @ Error(_) => { + val tpe = e.getType + val newAST = z3.mkFreshConst("errorValue", typeToSort(tpe)) + exprToZ3Id += (e -> newAST) + z3IdToExpr += (newAST -> e) + newAST + } + case v @ Variable(id) => z3Vars.get(id) match { + case Some(ast) => ast + case None => { + // if (id.isLetBinder) { + // scala.sys.error("Error in formula being translated to Z3: identifier " + id + " seems to have escaped its let-definition") + // } + val newAST = z3.mkFreshConst(id.uniqueName/*name*/, typeToSort(v.getType)) + z3Vars = z3Vars + (id -> newAST) + exprToZ3Id += (v -> newAST) + z3IdToExpr += (newAST -> v) + newAST + } + } + + case ite @ IfExpr(c, t, e) => z3.mkITE(rec(c), rec(t), rec(e)) + case And(exs) => z3.mkAnd(exs.map(rec(_)): _*) + case Or(exs) => z3.mkOr(exs.map(rec(_)): _*) + case Implies(l, r) => z3.mkImplies(rec(l), rec(r)) + case Iff(l, r) => { + val rl = rec(l) + val rr = rec(r) + // z3.mkIff used to trigger a bug + z3.mkAnd(z3.mkImplies(rl, rr), z3.mkImplies(rr, rl)) + } + case Not(Iff(l, r)) => z3.mkXor(rec(l), rec(r)) + case Not(Equals(l, r)) => z3.mkDistinct(rec(l), rec(r)) + case Not(e) => z3.mkNot(rec(e)) + case IntLiteral(v) => z3.mkInt(v, intSort) + case BooleanLiteral(v) => if (v) z3.mkTrue() else z3.mkFalse() + case UnitLiteral => unitValue + case Equals(l, r) => z3.mkEq(rec(l), rec(r)) + case Plus(l, r) => if(USEBV) z3.mkBVAdd(rec(l), rec(r)) else z3.mkAdd(rec(l), rec(r)) + case Minus(l, r) => if(USEBV) z3.mkBVSub(rec(l), rec(r)) else z3.mkSub(rec(l), rec(r)) + case Times(l, r) => if(USEBV) z3.mkBVMul(rec(l), rec(r)) else z3.mkMul(rec(l), rec(r)) + case Division(l, r) => if(USEBV) z3.mkBVSdiv(rec(l), rec(r)) else z3.mkDiv(rec(l), rec(r)) + case Modulo(l, r) => if(USEBV) sys.error("I don't know what to do here!") else z3.mkMod(rec(l), rec(r)) + case UMinus(e) => if(USEBV) z3.mkBVNeg(rec(e)) else z3.mkUnaryMinus(rec(e)) + case LessThan(l, r) => if(USEBV) z3.mkBVSlt(rec(l), rec(r)) else z3.mkLT(rec(l), rec(r)) + case LessEquals(l, r) => if(USEBV) z3.mkBVSle(rec(l), rec(r)) else z3.mkLE(rec(l), rec(r)) + case GreaterThan(l, r) => if(USEBV) z3.mkBVSgt(rec(l), rec(r)) else z3.mkGT(rec(l), rec(r)) + case GreaterEquals(l, r) => if(USEBV) z3.mkBVSge(rec(l), rec(r)) else z3.mkGE(rec(l), rec(r)) + case c @ CaseClass(cd, args) => { + val constructor = adtConstructors(cd) + constructor(args.map(rec(_)): _*) + } + case c @ CaseClassSelector(_, cc, sel) => { + val selector = adtFieldSelectors(sel) + selector(rec(cc)) + } + case c @ CaseClassInstanceOf(ccd, e) => { + val tester = adtTesters(ccd) + tester(rec(e)) + } + case f @ FunctionInvocation(fd, args) => { + z3.mkApp(functionDefToDecl(fd), args.map(rec(_)): _*) + } + case e @ EmptySet(_) => z3.mkEmptySet(typeToSort(e.getType.asInstanceOf[SetType].base)) + + case SetEquals(s1, s2) => z3.mkEq(rec(s1), rec(s2)) + case ElementOfSet(e, s) => z3.mkSetSubset(z3.mkSetAdd(z3.mkEmptySet(typeToSort(e.getType)), rec(e)), rec(s)) + case SubsetOf(s1, s2) => z3.mkSetSubset(rec(s1), rec(s2)) + case SetIntersection(s1, s2) => z3.mkSetIntersect(rec(s1), rec(s2)) + case SetUnion(s1, s2) => z3.mkSetUnion(rec(s1), rec(s2)) + case SetDifference(s1, s2) => z3.mkSetDifference(rec(s1), rec(s2)) + case f @ FiniteSet(elems) => elems.foldLeft(z3.mkEmptySet(typeToSort(f.getType.asInstanceOf[SetType].base)))((ast, el) => z3.mkSetAdd(ast, rec(el))) + case SetCardinality(s) => { + val rs = rec(s) + setCardFuns(s.getType.asInstanceOf[SetType].base)(rs) + } + case SetMin(s) => intSetMinFun(rec(s)) + case SetMax(s) => intSetMaxFun(rec(s)) + case s @ SingletonMap(from,to) => s.getType match { + case MapType(fromType, toType) => + val fromSort = typeToSort(fromType) + val toSort = typeToSort(toType) + val constArray = z3.mkConstArray(fromSort, mapRangeNoneConstructors(toType)()) + z3.mkStore(constArray, rec(from), mapRangeSomeConstructors(toType)(rec(to))) + case errorType => scala.sys.error("Unexpected type for singleton map: " + (ex, errorType)) + } + case e @ EmptyMap(fromType, toType) => { + typeToSort(e.getType) //had to add this here because the mapRangeNoneConstructors was not yet constructed... + val fromSort = typeToSort(fromType) + val toSort = typeToSort(toType) + z3.mkConstArray(fromSort, mapRangeNoneConstructors(toType)()) + } + case f @ FiniteMap(elems) => f.getType match { + case MapType(fromType, toType) => + val fromSort = typeToSort(fromType) + val toSort = typeToSort(toType) + elems.foldLeft(z3.mkConstArray(fromSort, mapRangeNoneConstructors(toType)())){ case (ast, SingletonMap(k,v)) => z3.mkStore(ast, rec(k), mapRangeSomeConstructors(toType)(rec(v))) } + case errorType => scala.sys.error("Unexpected type for finite map: " + (ex, errorType)) + } + case mg @ MapGet(m,k) => m.getType match { + case MapType(fromType, toType) => + val selected = z3.mkSelect(rec(m), rec(k)) + mapRangeValueSelectors(toType)(selected) + case errorType => scala.sys.error("Unexpected type for map: " + (ex, errorType)) + } + case MapUnion(m1,m2) => m1.getType match { + case MapType(ft, tt) => m2 match { + case FiniteMap(ss) => + ss.foldLeft(rec(m1)){ + case (ast, SingletonMap(k, v)) => z3.mkStore(ast, rec(k), mapRangeSomeConstructors(tt)(rec(v))) + } + case SingletonMap(k, v) => z3.mkStore(rec(m1), rec(k), mapRangeSomeConstructors(tt)(rec(v))) + case _ => scala.sys.error("map updates can only be applied with concrete map instances") + } + case errorType => scala.sys.error("Unexpected type for map: " + (ex, errorType)) + } + case MapIsDefinedAt(m,k) => m.getType match { + case MapType(ft, tt) => z3.mkDistinct(z3.mkSelect(rec(m), rec(k)), mapRangeNoneConstructors(tt)()) + case errorType => scala.sys.error("Unexpected type for map: " + (ex, errorType)) + } + case fill @ ArrayFill(length, default) => { + val at@ArrayType(base) = fill.getType + typeToSort(at) + val cons = arrayTupleCons(at) + val ar = z3.mkConstArray(typeToSort(base), rec(default)) + val res = cons(ar, rec(length)) + res + } + case ArraySelect(a, index) => { + typeToSort(a.getType) + val ar = rec(a) + val getArray = arrayTupleSelectorArray(a.getType) + val res = z3.mkSelect(getArray(ar), rec(index)) + res + } + case ArrayUpdated(a, index, newVal) => { + typeToSort(a.getType) + val ar = rec(a) + val getArray = arrayTupleSelectorArray(a.getType) + val getLength = arrayTupleSelectorLength(a.getType) + val cons = arrayTupleCons(a.getType) + val store = z3.mkStore(getArray(ar), rec(index), rec(newVal)) + val res = cons(store, getLength(ar)) + res + } + case ArrayLength(a) => { + typeToSort(a.getType) + val ar = rec(a) + val getLength = arrayTupleSelectorLength(a.getType) + val res = getLength(ar) + res + } + case AnonymousFunctionInvocation(id, args) => id.getType match { + case ft @ FunctionType(fts, tt) => { + val consFD = funDomainConstructors(ft) + val rid = rec(Variable(id)) + val rargs = args map rec + z3.mkSelect(rid, consFD(rargs: _*)) + } + case errorType => scala.sys.error("Unexpected type for function: " + (ex, errorType)) + } + + case Distinct(exs) => z3.mkDistinct(exs.map(rec(_)): _*) + + case _ => { + reporter.warning("Can't handle this in translation to Z3: " + ex) + throw new CantTranslateException + } + }) + recResult + } + + try { + val res = Some(rec(expr)) + res + } catch { + case e: CantTranslateException => None + } + } + + protected[leon] def fromZ3Formula(model: Z3Model, tree : Z3AST, expectedType: Option[TypeTree] = None) : Expr = { + def rec(t: Z3AST, expType: Option[TypeTree] = None) : Expr = expType match { + case Some(MapType(kt,vt)) => + model.getArrayValue(t) match { + case None => throw new CantTranslateException(t) + case Some((map, elseValue)) => + val singletons = map.map(e => (e, z3.getASTKind(e._2))).collect { + case ((index, value), Z3AppAST(someCons, arg :: Nil)) if someCons == mapRangeSomeConstructors(vt) => SingletonMap(rec(index, Some(kt)), rec(arg, Some(vt))) + } + (if (singletons.isEmpty) EmptyMap(kt, vt) else FiniteMap(singletons.toSeq)).setType(expType.get) + } + case funType @ Some(FunctionType(fts, tt)) => + model.getArrayValue(t) match { + case None => throw new CantTranslateException(t) + case Some((es, ev)) => + val entries: Seq[(Seq[Expr], Expr)] = es.toSeq.map(e => (e, z3.getASTKind(e._1))).collect { + case ((key, value), Z3AppAST(cons, args)) if cons == funDomainConstructors(funType.get) => ((args zip fts) map (p => rec(p._1, Some(p._2))), rec(value, Some(tt))) + } + val elseValue = rec(ev, Some(tt)) + AnonymousFunction(entries, elseValue).setType(expType.get) + } + case Some(SetType(dt)) => + model.getSetValue(t) match { + case None => throw new CantTranslateException(t) + case Some(set) => { + val elems = set.map(e => rec(e, Some(dt))) + (if (elems.isEmpty) EmptySet(dt) else FiniteSet(elems.toSeq)).setType(expType.get) + } + } + case Some(ArrayType(dt)) => { + val Z3AppAST(decl, args) = z3.getASTKind(t) + assert(args.size == 2) + val IntLiteral(length) = rec(args(1), Some(Int32Type)) + val array = model.getArrayValue(args(0)) match { + case None => throw new CantTranslateException(t) + case Some((map, elseValue)) => { + val exprs = map.foldLeft((1 to length).map(_ => rec(elseValue, Some(dt))).toSeq)((acc, p) => { + val IntLiteral(index) = rec(p._1, Some(Int32Type)) + if(index >= 0 && index < length) + acc.updated(index, rec(p._2, Some(dt))) + else acc + }) + FiniteArray(exprs) + } + } + array + } + case other => + if(t == unitValue) + UnitLiteral + else z3.getASTKind(t) match { + case Z3AppAST(decl, args) => { + val argsSize = args.size + if(argsSize == 0 && z3IdToExpr.isDefinedAt(t)) { + val toRet = z3IdToExpr(t) + // println("Map says I should replace " + t + " by " + toRet) + toRet + } else if(isKnownDecl(decl)) { + val fd = functionDeclToDef(decl) + assert(fd.args.size == argsSize) + FunctionInvocation(fd, (args zip fd.args).map(p => rec(p._1,Some(p._2.tpe)))) + } else if(argsSize == 1 && reverseADTTesters.isDefinedAt(decl)) { + CaseClassInstanceOf(reverseADTTesters(decl), rec(args(0))) + } else if(argsSize == 1 && reverseADTFieldSelectors.isDefinedAt(decl)) { + val (ccd, fid) = reverseADTFieldSelectors(decl) + CaseClassSelector(ccd, rec(args(0)), fid) + } else if(reverseADTConstructors.isDefinedAt(decl)) { + val ccd = reverseADTConstructors(decl) + assert(argsSize == ccd.fields.size) + CaseClass(ccd, (args zip ccd.fields).map(p => rec(p._1, Some(p._2.tpe)))) + } else if(reverseTupleConstructors.isDefinedAt(decl)) { + val TupleType(subTypes) = reverseTupleConstructors(decl) + val rargs = args.zip(subTypes).map(p => rec(p._1, Some(p._2))) + Tuple(rargs) + } else { + import Z3DeclKind._ + val rargs = args.map(rec(_)) + z3.getDeclKind(decl) match { + case OpTrue => BooleanLiteral(true) + case OpFalse => BooleanLiteral(false) + case OpEq => Equals(rargs(0), rargs(1)) + case OpITE => { + assert(argsSize == 3) + val r0 = rargs(0) + val r1 = rargs(1) + val r2 = rargs(2) + try { + IfExpr(r0, r1, r2).setType(leastUpperBound(r1.getType, r2.getType).get) + } catch { + case e => { + println("I was asking for lub because of this.") + println(t) + println("which was translated as") + println(IfExpr(r0,r1,r2)) + throw e + } + } + } + case OpAnd => And(rargs) + case OpOr => Or(rargs) + case OpIff => Iff(rargs(0), rargs(1)) + case OpXor => Not(Iff(rargs(0), rargs(1))) + case OpNot => Not(rargs(0)) + case OpImplies => Implies(rargs(0), rargs(1)) + case OpLE => LessEquals(rargs(0), rargs(1)) + case OpGE => GreaterEquals(rargs(0), rargs(1)) + case OpLT => LessThan(rargs(0), rargs(1)) + case OpGT => GreaterThan(rargs(0), rargs(1)) + case OpAdd => { + assert(argsSize == 2) + Plus(rargs(0), rargs(1)) + } + case OpSub => { + assert(argsSize == 2) + Minus(rargs(0), rargs(1)) + } + case OpUMinus => UMinus(rargs(0)) + case OpMul => { + assert(argsSize == 2) + Times(rargs(0), rargs(1)) + } + case OpDiv => { + assert(argsSize == 2) + Division(rargs(0), rargs(1)) + } + case OpIDiv => { + assert(argsSize == 2) + Division(rargs(0), rargs(1)) + } + case OpMod => { + assert(argsSize == 2) + Modulo(rargs(0), rargs(1)) + } + case OpAsArray => { + assert(argsSize == 0) + throw new Exception("encountered OpAsArray") + } + case other => { + System.err.println("Don't know what to do with this declKind : " + other) + System.err.println("The arguments are : " + args) + throw new CantTranslateException(t) + } + } + } + } + + case Z3NumeralAST(Some(v)) => IntLiteral(v) + case Z3NumeralAST(None) => { + reporter.info("Cannot read exact model from Z3: Integer does not fit in machine word") + reporter.info("Exiting procedure now") + sys.exit(0) + } + case other @ _ => { + System.err.println("Don't know what this is " + other) + throw new CantTranslateException(t) + } + } + } + rec(tree, expectedType) + } + + protected[leon] def softFromZ3Formula(model: Z3Model, tree : Z3AST, expectedType: TypeTree) : Option[Expr] = { + try { + Some(fromZ3Formula(model, tree, Some(expectedType))) + } catch { + case e: CantTranslateException => None + } + } + +} diff --git a/src/main/scala/leon/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala similarity index 63% rename from src/main/scala/leon/FairZ3Solver.scala rename to src/main/scala/leon/solvers/z3/FairZ3Solver.scala index 23f93d497..b0d7ba9d2 100644 --- a/src/main/scala/leon/FairZ3Solver.scala +++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala @@ -1,4 +1,5 @@ package leon +package solvers.z3 import z3.scala._ import purescala.Common._ @@ -16,15 +17,13 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S // have to comment this to use the solver for constraint solving... // assert(Settings.useFairInstantiator) - private final val UNKNOWNASSAT : Boolean = !Settings.noForallAxioms - private final val USEBV : Boolean = Settings.bitvectorBitwidth.isDefined - private final val BVWIDTH : Int = Settings.bitvectorBitwidth.getOrElse(-1) + private val UNKNOWNASSAT : Boolean = !Settings.noForallAxioms val description = "Fair Z3 Solver" override val shortDescription = "Z3-f" // this is fixed - private val z3cfg = new Z3Config( + protected[leon] val z3cfg = new Z3Config( "MODEL" -> true, "MBQI" -> false, // "SOFT_TIMEOUT" -> 100, @@ -33,53 +32,13 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S ) toggleWarningMessages(true) - protected[leon] var z3: Z3Context = null - protected[leon] var program: Program = null - private var neverInitialized = true - private var unrollingBank: UnrollingBank = null private var blockingSet: Set[Expr] = Set.empty private var toCheckAgainstModels: Expr = BooleanLiteral(true) private var varsInVC: Set[Identifier] = Set.empty - override def setProgram(prog: Program): Unit = { - program = prog - } - - def restartZ3: Unit = { - if (neverInitialized) { - neverInitialized = false - } else { - z3.delete - } - z3 = new Z3Context(z3cfg) - // z3.traceToStdout - - exprToZ3Id = Map.empty - z3IdToExpr = Map.empty - - fallbackSorts = Map.empty - - mapSorts = Map.empty - arraySorts = Map.empty - funSorts = Map.empty - funDomainConstructors = Map.empty - funDomainSelectors = Map.empty - - tupleSorts = Map.empty - tupleConstructors = Map.empty - tupleSelectors = Map.empty - - mapRangeSorts.clear - mapRangeSomeConstructors.clear - mapRangeNoneConstructors.clear - mapRangeSomeTesters.clear - mapRangeNoneTesters.clear - mapRangeValueSelectors.clear - - counter = 0 - prepareSorts - prepareFunctions + override def restartZ3 : Unit = { + super.restartZ3 unrollingBank = new UnrollingBank blockingSet = Set.empty @@ -87,218 +46,6 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S varsInVC = Set.empty } - private var counter = 0 - private object nextIntForSymbol { - def apply(): Int = { - val res = counter - counter = counter + 1 - res - } - } - - private var intSort: Z3Sort = null - private var boolSort: Z3Sort = null - private var setSorts: Map[TypeTree, Z3Sort] = Map.empty - private var mapSorts: Map[TypeTree, Z3Sort] = Map.empty - - private var unitSort: Z3Sort = null - private var unitValue: Z3AST = null - - protected[leon] var funSorts: Map[TypeTree, Z3Sort] = Map.empty - protected[leon] var funDomainConstructors: Map[TypeTree, Z3FuncDecl] = Map.empty - protected[leon] var funDomainSelectors: Map[TypeTree, Seq[Z3FuncDecl]] = Map.empty - - protected[leon] var tupleSorts: Map[TypeTree, Z3Sort] = Map.empty - protected[leon] var tupleConstructors: Map[TypeTree, Z3FuncDecl] = Map.empty - protected[leon] var tupleSelectors: Map[TypeTree, Seq[Z3FuncDecl]] = Map.empty - - private var arraySorts: Map[TypeTree, Z3Sort] = Map.empty - protected[leon] var arrayTupleCons: Map[TypeTree, Z3FuncDecl] = Map.empty - protected[leon] var arrayTupleSelectorArray: Map[TypeTree, Z3FuncDecl] = Map.empty - protected[leon] var arrayTupleSelectorLength: Map[TypeTree, Z3FuncDecl] = Map.empty - - private var reverseTupleConstructors: Map[Z3FuncDecl, TupleType] = Map.empty - private var reverseTupleSelectors: Map[Z3FuncDecl, (TupleType, Int)] = Map.empty - - private var intSetMinFun: Z3FuncDecl = null - private var intSetMaxFun: Z3FuncDecl = null - private var setCardFuns: Map[TypeTree, Z3FuncDecl] = Map.empty - private var adtSorts: Map[ClassTypeDef, Z3Sort] = Map.empty - private var fallbackSorts: Map[TypeTree, Z3Sort] = Map.empty - - protected[leon] var adtTesters: Map[CaseClassDef, Z3FuncDecl] = Map.empty - protected[leon] var adtConstructors: Map[CaseClassDef, Z3FuncDecl] = Map.empty - protected[leon] var adtFieldSelectors: Map[Identifier, Z3FuncDecl] = Map.empty - - private var reverseADTTesters: Map[Z3FuncDecl, CaseClassDef] = Map.empty - private var reverseADTConstructors: Map[Z3FuncDecl, CaseClassDef] = Map.empty - private var reverseADTFieldSelectors: Map[Z3FuncDecl, (CaseClassDef,Identifier)] = Map.empty - - protected[leon] val mapRangeSorts: MutableMap[TypeTree, Z3Sort] = MutableMap.empty - protected[leon] val mapRangeSomeConstructors: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty - protected[leon] val mapRangeNoneConstructors: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty - protected[leon] val mapRangeSomeTesters: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty - protected[leon] val mapRangeNoneTesters: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty - protected[leon] val mapRangeValueSelectors: MutableMap[TypeTree, Z3FuncDecl] = MutableMap.empty - - private def mapRangeSort(toType : TypeTree) : Z3Sort = mapRangeSorts.get(toType) match { - case Some(z3sort) => z3sort - case None => { - import Z3Context.{ADTSortReference, RecursiveType, RegularSort} - intSort = if(USEBV) { - z3.mkBVSort(BVWIDTH) - } else { - z3.mkIntSort - } - boolSort = z3.mkBoolSort - - def typeToSortRef(tt: TypeTree): ADTSortReference = tt match { - case BooleanType => RegularSort(boolSort) - case Int32Type => RegularSort(intSort) - case AbstractClassType(d) => RegularSort(adtSorts(d)) - case CaseClassType(d) => RegularSort(adtSorts(d)) - case SetType(d) => RegularSort(setSorts(d)) - case mt @ MapType(d,r) => RegularSort(mapSorts(mt)) - case _ => throw UntranslatableTypeException("Can't handle type " + tt) - } - - val z3info = z3.mkADTSorts( - Seq( - ( - toType.toString + "Option", - Seq(toType.toString + "Some", toType.toString + "None"), - Seq( - Seq(("value", typeToSortRef(toType))), - Seq() - ) - ) - ) - ) - - z3info match { - case Seq((optionSort, Seq(someCons, noneCons), Seq(someTester, noneTester), Seq(Seq(valueSelector), Seq()))) => - mapRangeSorts += ((toType, optionSort)) - mapRangeSomeConstructors += ((toType, someCons)) - mapRangeNoneConstructors += ((toType, noneCons)) - mapRangeSomeTesters += ((toType, someTester)) - mapRangeNoneTesters += ((toType, noneTester)) - mapRangeValueSelectors += ((toType, valueSelector)) - optionSort - } - } - } - - case class UntranslatableTypeException(msg: String) extends Exception(msg) - // Prepares some of the Z3 sorts, but *not* the tuple sorts; these are created on-demand. - private def prepareSorts: Unit = { - import Z3Context.{ADTSortReference, RecursiveType, RegularSort} - // NOTE THAT abstract classes that extend abstract classes are not - // currently supported in the translation - intSort = if(USEBV) { - z3.mkBVSort(BVWIDTH) - } else { - z3.mkIntSort - } - boolSort = z3.mkBoolSort - setSorts = Map.empty - setCardFuns = Map.empty - - //unitSort = z3.mkUninterpretedSort("unit") - //unitValue = z3.mkFreshConst("Unit", unitSort) - //val bound = z3.mkBound(0, unitSort) - //val eq = z3.mkEq(bound, unitValue) - //val decls = Seq((z3.mkFreshStringSymbol("u"), unitSort)) - //val unitAxiom = z3.mkForAll(0, Seq(), decls, eq) - //println(unitAxiom) - //println(unitValue) - //z3.assertCnstr(unitAxiom) - val Seq((us, Seq(unitCons), Seq(unitTester), _)) = z3.mkADTSorts( - Seq( - ( - "Unit", - Seq("Unit"), - Seq(Seq()) - ) - ) - ) - unitSort = us - unitValue = unitCons() - - val intSetSort = typeToSort(SetType(Int32Type)) - intSetMinFun = z3.mkFreshFuncDecl("setMin", Seq(intSetSort), intSort) - intSetMaxFun = z3.mkFreshFuncDecl("setMax", Seq(intSetSort), intSort) - - val roots = program.classHierarchyRoots - val indexMap: Map[ClassTypeDef, Int] = Map(roots.zipWithIndex: _*) - //println("indexMap: " + indexMap) - - def typeToSortRef(tt: TypeTree): ADTSortReference = tt match { - // case BooleanType => RegularSort(boolSort) - // case Int32Type => RegularSort(intSort) - case AbstractClassType(d) => RecursiveType(indexMap(d)) - case CaseClassType(d) => indexMap.get(d) match { - case Some(i) => RecursiveType(i) - case None => RecursiveType(indexMap(d.parent.get)) - } - // case _ => throw UntranslatableTypeException("Can't handle type " + tt) - case _ => RegularSort(typeToSort(tt)) - } - - val childrenLists: Seq[List[CaseClassDef]] = roots.map(_ match { - case c: CaseClassDef => List(c) - case a: AbstractClassDef => a.knownChildren.filter(_.isInstanceOf[CaseClassDef]).map(_.asInstanceOf[CaseClassDef]).toList - }) - //println("children lists: " + childrenLists.toList.mkString("\n")) - - val rootsAndChildren = (roots zip childrenLists) - - val defs = rootsAndChildren.map(p => { - val (root, childrenList) = p - - root match { - case c: CaseClassDef => { - // we create a recursive type with exactly one constructor - (c.id.uniqueName, List(c.id.uniqueName), List(c.fields.map(f => (f.id.uniqueName, typeToSortRef(f.tpe))))) - } - case a: AbstractClassDef => { - (a.id.uniqueName, childrenList.map(ccd => ccd.id.uniqueName), childrenList.map(ccd => ccd.fields.map(f => (f.id.uniqueName, typeToSortRef(f.tpe))))) - } - } - }) - - //println(defs) - // everything should be alright now... - val resultingZ3Info = z3.mkADTSorts(defs) - - adtSorts = Map.empty - adtTesters = Map.empty - adtConstructors = Map.empty - adtFieldSelectors = Map.empty - reverseADTTesters = Map.empty - reverseADTConstructors = Map.empty - reverseADTFieldSelectors = Map.empty - - for ((z3Inf, (root, childrenList)) <- (resultingZ3Info zip rootsAndChildren)) { - adtSorts += (root -> z3Inf._1) - assert(childrenList.size == z3Inf._2.size) - for ((child, (consFun, testFun)) <- childrenList zip (z3Inf._2 zip z3Inf._3)) { - adtTesters += (child -> testFun) - adtConstructors += (child -> consFun) - } - for ((child, fieldFuns) <- childrenList zip z3Inf._4) { - assert(child.fields.size == fieldFuns.size) - for ((fid, selFun) <- (child.fields.map(_.id) zip fieldFuns)) { - adtFieldSelectors += (fid -> selFun) - reverseADTFieldSelectors += (selFun -> (child, fid)) - } - } - } - - reverseADTTesters = adtTesters.map(_.swap) - reverseADTConstructors = adtConstructors.map(_.swap) - // ...and now everything should be in there... - } - def isKnownDef(funDef: FunDef) : Boolean = functionMap.isDefinedAt(funDef) def functionDefToDecl(funDef: FunDef) : Z3FuncDecl = @@ -389,92 +136,6 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S }) } - // assumes prepareSorts has been called.... - def typeToSort(tt: TypeTree): Z3Sort = tt match { - case Int32Type => intSort - case BooleanType => boolSort - case UnitType => unitSort - case AbstractClassType(cd) => adtSorts(cd) - case CaseClassType(cd) => { - if (cd.hasParent) { - adtSorts(cd.parent.get) - } else { - adtSorts(cd) - } - } - case SetType(base) => setSorts.get(base) match { - case Some(s) => s - case None => { - val newSetSort = z3.mkSetSort(typeToSort(base)) - setSorts = setSorts + (base -> newSetSort) - val newCardFun = z3.mkFreshFuncDecl("card", Seq(newSetSort), intSort) - setCardFuns = setCardFuns + (base -> newCardFun) - newSetSort - } - } - case mt @ MapType(fromType, toType) => mapSorts.get(mt) match { - case Some(s) => s - case None => { - val fromSort = typeToSort(fromType) - val toSort = mapRangeSort(toType) - val ms = z3.mkArraySort(fromSort, toSort) - mapSorts += ((mt, ms)) - ms - } - } - case at @ ArrayType(base) => arraySorts.get(at) match { - case Some(s) => s - case None => { - val intSort = typeToSort(Int32Type) - val toSort = typeToSort(base) - val as = z3.mkArraySort(intSort, toSort) - val tupleSortSymbol = z3.mkFreshStringSymbol("Array") - val (arrayTupleSort, arrayTupleCons_, Seq(arrayTupleSelectorArray_, arrayTupleSelectorLength_)) = z3.mkTupleSort(tupleSortSymbol, as, intSort) - arraySorts += (at -> arrayTupleSort) - arrayTupleCons += (at -> arrayTupleCons_) - arrayTupleSelectorArray += (at -> arrayTupleSelectorArray_) - arrayTupleSelectorLength += (at -> arrayTupleSelectorLength_) - arrayTupleSort - } - } - case ft @ FunctionType(fts, tt) => funSorts.get(ft) match { - case Some(s) => s - case None => { - val fss = fts map typeToSort - val ts = typeToSort(tt) - val (tupleSort, consFuncDecl, projFuncDecls) = z3.mkTupleSort(fts.map(_.toString).mkString("(",", ", ")"), fss: _*) - val funSort = z3.mkArraySort(tupleSort, ts) - funSorts += (ft -> funSort) - funDomainConstructors += (ft -> consFuncDecl) - funDomainSelectors += (ft -> projFuncDecls) - funSort - } - } - case tt @ TupleType(tpes) => tupleSorts.get(tt) match { - case Some(s) => s - case None => { - val tpesSorts = tpes.map(typeToSort) - val sortSymbol = z3.mkFreshStringSymbol("Tuple") - val (tupleSort, consTuple, projsTuple) = z3.mkTupleSort(sortSymbol, tpesSorts: _*) - tupleSorts += (tt -> tupleSort) - tupleConstructors += (tt -> consTuple) - reverseTupleConstructors += (consTuple -> tt) - tupleSelectors += (tt -> projsTuple) - projsTuple.zipWithIndex.foreach{ case (proj, i) => reverseTupleSelectors += (proj -> (tt, i)) } - tupleSort - } - } - case other => fallbackSorts.get(other) match { - case Some(s) => s - case None => { - reporter.warning("Resorting to uninterpreted type for : " + other) - val symbol = z3.mkIntSymbol(nextIntForSymbol()) - val newFBSort = z3.mkUninterpretedSort(symbol) - fallbackSorts = fallbackSorts + (other -> newFBSort) - newFBSort - } - } - } override def isUnsat(vc: Expr) = decide(vc, false) @@ -485,12 +146,6 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S decideWithModel(vc, true) } - def solveWithBounds(vc: Expr, fv: Boolean) : (Option[Boolean], Map[Identifier,Expr]) = { - restartZ3 - boundValues - decideWithModel(vc, fv) - } - def decide(vc: Expr, forValidity: Boolean):Option[Boolean] = { restartZ3 decideWithModel(vc, forValidity)._1 @@ -533,17 +188,6 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S initializationStopwatch.start foundDefinitiveAnswer = false - /* - def stopCallback() : Unit = { - if(!foundDefinitiveAnswer) { - reporter.error(" - Timeout reached.") - forceStop = true - z3.softCheckCancel - } - }*/ - - //val timer : Option[Timer] = Settings.solverTimeout.map(t => new Timer(stopCallback, t)) - //timer.foreach(_.start()) var definitiveAnswer : Option[Boolean] = None var definitiveModel : Map[Identifier,Expr] = Map.empty @@ -554,7 +198,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S //timer.foreach(t => t.halt) } - if (neverInitialized) { + if (program == null) { reporter.error("Z3 Solver was not initialized with a PureScala Program.") None } @@ -925,9 +569,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S (cleanedUp, newClauses.reverse, ite2Bools) } - protected[leon] var exprToZ3Id : Map[Expr,Z3AST] = Map.empty - protected[leon] var z3IdToExpr : Map[Z3AST,Expr] = Map.empty - protected[leon] def toZ3Formula(z3: Z3Context, expr: Expr, initialMap: Map[Identifier,Z3AST] = Map.empty) : Option[Z3AST] = { + protected[leon] override def toZ3Formula(z3: Z3Context, expr: Expr, initialMap: Map[Identifier,Z3AST] = Map.empty) : Option[Z3AST] = { class CantTranslateException extends Exception val varsInformula: Set[Identifier] = variablesOf(expr) @@ -1164,170 +806,6 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S } } - protected[leon] def fromZ3Formula(model: Z3Model, tree : Z3AST, expectedType: Option[TypeTree] = None) : Expr = { - def rec(t: Z3AST, expType: Option[TypeTree] = None) : Expr = expType match { - case Some(MapType(kt,vt)) => - model.getArrayValue(t) match { - case None => throw new CantTranslateException(t) - case Some((map, elseValue)) => - val singletons = map.map(e => (e, z3.getASTKind(e._2))).collect { - case ((index, value), Z3AppAST(someCons, arg :: Nil)) if someCons == mapRangeSomeConstructors(vt) => SingletonMap(rec(index, Some(kt)), rec(arg, Some(vt))) - } - (if (singletons.isEmpty) EmptyMap(kt, vt) else FiniteMap(singletons.toSeq)).setType(expType.get) - } - case funType @ Some(FunctionType(fts, tt)) => - model.getArrayValue(t) match { - case None => throw new CantTranslateException(t) - case Some((es, ev)) => - val entries: Seq[(Seq[Expr], Expr)] = es.toSeq.map(e => (e, z3.getASTKind(e._1))).collect { - case ((key, value), Z3AppAST(cons, args)) if cons == funDomainConstructors(funType.get) => ((args zip fts) map (p => rec(p._1, Some(p._2))), rec(value, Some(tt))) - } - val elseValue = rec(ev, Some(tt)) - AnonymousFunction(entries, elseValue).setType(expType.get) - } - case Some(SetType(dt)) => - model.getSetValue(t) match { - case None => throw new CantTranslateException(t) - case Some(set) => { - val elems = set.map(e => rec(e, Some(dt))) - (if (elems.isEmpty) EmptySet(dt) else FiniteSet(elems.toSeq)).setType(expType.get) - } - } - case Some(ArrayType(dt)) => { - val Z3AppAST(decl, args) = z3.getASTKind(t) - assert(args.size == 2) - val IntLiteral(length) = rec(args(1), Some(Int32Type)) - val array = model.getArrayValue(args(0)) match { - case None => throw new CantTranslateException(t) - case Some((map, elseValue)) => { - val exprs = map.foldLeft((1 to length).map(_ => rec(elseValue, Some(dt))).toSeq)((acc, p) => { - val IntLiteral(index) = rec(p._1, Some(Int32Type)) - if(index >= 0 && index < length) - acc.updated(index, rec(p._2, Some(dt))) - else acc - }) - FiniteArray(exprs) - } - } - array - } - case other => - if(t == unitValue) - UnitLiteral - else z3.getASTKind(t) match { - case Z3AppAST(decl, args) => { - val argsSize = args.size - if(argsSize == 0 && z3IdToExpr.isDefinedAt(t)) { - val toRet = z3IdToExpr(t) - // println("Map says I should replace " + t + " by " + toRet) - toRet - } else if(isKnownDecl(decl)) { - val fd = functionDeclToDef(decl) - assert(fd.args.size == argsSize) - FunctionInvocation(fd, (args zip fd.args).map(p => rec(p._1,Some(p._2.tpe)))) - } else if(argsSize == 1 && reverseADTTesters.isDefinedAt(decl)) { - CaseClassInstanceOf(reverseADTTesters(decl), rec(args(0))) - } else if(argsSize == 1 && reverseADTFieldSelectors.isDefinedAt(decl)) { - val (ccd, fid) = reverseADTFieldSelectors(decl) - CaseClassSelector(ccd, rec(args(0)), fid) - } else if(reverseADTConstructors.isDefinedAt(decl)) { - val ccd = reverseADTConstructors(decl) - assert(argsSize == ccd.fields.size) - CaseClass(ccd, (args zip ccd.fields).map(p => rec(p._1, Some(p._2.tpe)))) - } else if(reverseTupleConstructors.isDefinedAt(decl)) { - val TupleType(subTypes) = reverseTupleConstructors(decl) - val rargs = args.zip(subTypes).map(p => rec(p._1, Some(p._2))) - Tuple(rargs) - } else { - import Z3DeclKind._ - val rargs = args.map(rec(_)) - z3.getDeclKind(decl) match { - case OpTrue => BooleanLiteral(true) - case OpFalse => BooleanLiteral(false) - case OpEq => Equals(rargs(0), rargs(1)) - case OpITE => { - assert(argsSize == 3) - val r0 = rargs(0) - val r1 = rargs(1) - val r2 = rargs(2) - try { - IfExpr(r0, r1, r2).setType(leastUpperBound(r1.getType, r2.getType).get) - } catch { - case e => { - println("I was asking for lub because of this.") - println(t) - println("which was translated as") - println(IfExpr(r0,r1,r2)) - throw e - } - } - } - case OpAnd => And(rargs) - case OpOr => Or(rargs) - case OpIff => Iff(rargs(0), rargs(1)) - case OpXor => Not(Iff(rargs(0), rargs(1))) - case OpNot => Not(rargs(0)) - case OpImplies => Implies(rargs(0), rargs(1)) - case OpLE => LessEquals(rargs(0), rargs(1)) - case OpGE => GreaterEquals(rargs(0), rargs(1)) - case OpLT => LessThan(rargs(0), rargs(1)) - case OpGT => GreaterThan(rargs(0), rargs(1)) - case OpAdd => { - assert(argsSize == 2) - Plus(rargs(0), rargs(1)) - } - case OpSub => { - assert(argsSize == 2) - Minus(rargs(0), rargs(1)) - } - case OpUMinus => UMinus(rargs(0)) - case OpMul => { - assert(argsSize == 2) - Times(rargs(0), rargs(1)) - } - case OpDiv => { - assert(argsSize == 2) - Division(rargs(0), rargs(1)) - } - case OpIDiv => { - assert(argsSize == 2) - Division(rargs(0), rargs(1)) - } - case OpMod => { - assert(argsSize == 2) - Modulo(rargs(0), rargs(1)) - } - case OpAsArray => { - assert(argsSize == 0) - throw new Exception("encountered OpAsArray") - } - case other => { - System.err.println("Don't know what to do with this declKind : " + other) - System.err.println("The arguments are : " + args) - throw new CantTranslateException(t) - } - } - } - } - - case Z3NumeralAST(Some(v)) => IntLiteral(v) - case Z3NumeralAST(None) => { - reporter.info("Cannot read exact model from Z3: Integer does not fit in machine word") - reporter.info("Exiting procedure now") - sys.exit(0) - } - case other @ _ => { - System.err.println("Don't know what this is " + other) - System.err.println("REVERSE FUNCTION MAP:") - System.err.println(reverseFunctionMap.toSeq.mkString("\n")) - System.err.println("REVERSE CONS MAP:") - System.err.println(reverseADTConstructors.toSeq.mkString("\n")) - throw new CantTranslateException(t) - } - } - } - rec(tree, expectedType) - } class UnrollingBank { private val blockMap : MutableMap[(Identifier,Boolean),Set[FunctionInvocation]] = MutableMap.empty diff --git a/src/main/scala/leon/Z3ModelReconstruction.scala b/src/main/scala/leon/solvers/z3/Z3ModelReconstruction.scala similarity index 99% rename from src/main/scala/leon/Z3ModelReconstruction.scala rename to src/main/scala/leon/solvers/z3/Z3ModelReconstruction.scala index 87c75ddd5..5fc00acd0 100644 --- a/src/main/scala/leon/Z3ModelReconstruction.scala +++ b/src/main/scala/leon/solvers/z3/Z3ModelReconstruction.scala @@ -1,4 +1,5 @@ package leon +package solvers.z3 import z3.scala._ import purescala.Common._ diff --git a/src/main/scala/leon/synthesis/SynthesisPhase.scala b/src/main/scala/leon/synthesis/SynthesisPhase.scala index 898891307..91134fcbd 100644 --- a/src/main/scala/leon/synthesis/SynthesisPhase.scala +++ b/src/main/scala/leon/synthesis/SynthesisPhase.scala @@ -1,6 +1,9 @@ package leon package synthesis +import solvers.TrivialSolver +import solvers.z3.FairZ3Solver + import purescala.Definitions.Program object SynthesisPhase extends LeonPhase[Program, Program] { diff --git a/src/main/scala/leon/testgen/CallGraph.scala b/src/main/scala/leon/testgen/CallGraph.scala index afebd8bde..d7169bb17 100644 --- a/src/main/scala/leon/testgen/CallGraph.scala +++ b/src/main/scala/leon/testgen/CallGraph.scala @@ -6,7 +6,7 @@ import leon.purescala.TreeOps._ import leon.purescala.Extractors._ import leon.purescala.TypeTrees._ import leon.purescala.Common._ -import leon.FairZ3Solver +import leon.solvers.z3.FairZ3Solver class CallGraph(val program: Program) { diff --git a/src/main/scala/leon/testgen/TestGeneration.scala b/src/main/scala/leon/testgen/TestGeneration.scala index 8404294ee..5056ec0e8 100644 --- a/src/main/scala/leon/testgen/TestGeneration.scala +++ b/src/main/scala/leon/testgen/TestGeneration.scala @@ -7,7 +7,7 @@ import leon.purescala.TreeOps._ import leon.purescala.TypeTrees._ import leon.purescala.ScalaPrinter import leon.Extensions._ -import leon.FairZ3Solver +import leon.solvers.z3.FairZ3Solver import leon.Reporter import scala.collection.mutable.{Set => MutableSet} -- GitLab