From ed46c135f0b05fecbf61558140db3f4f3f47bf5b Mon Sep 17 00:00:00 2001 From: Etienne Kneuss <ekneuss@gmail.com> Date: Thu, 29 Nov 2012 22:36:14 +0100 Subject: [PATCH] Seems to work. Chances of success still under 9000 though --- src/main/scala/leon/FunctionTemplate.scala | 142 +++---- .../scala/leon/solvers/z3/FairZ3Solver.scala | 386 +++++++++++++----- 2 files changed, 359 insertions(+), 169 deletions(-) diff --git a/src/main/scala/leon/FunctionTemplate.scala b/src/main/scala/leon/FunctionTemplate.scala index 279bafef9..04a717151 100644 --- a/src/main/scala/leon/FunctionTemplate.scala +++ b/src/main/scala/leon/FunctionTemplate.scala @@ -11,23 +11,23 @@ import scala.collection.mutable.{Set=>MutableSet,Map=>MutableMap} // TODO: maybe a candidate for moving into purescala package? class FunctionTemplate private( - funDef : FunDef, + funDef : Option[FunDef], activatingBool : Identifier, condVars : Set[Identifier], exprVars : Set[Identifier], guardedExprs : Map[(Identifier,Boolean),Seq[Expr]]) { - private val asClauses : Seq[Expr] = { + val asClauses : Seq[Expr] = { (for(((b,p),es) <- guardedExprs; e <- es) yield { Implies(if(!p) Not(Variable(b)) else Variable(b), e) }).toSeq } - private val blockers : Map[(Identifier,Boolean),Set[FunctionInvocation]] = { - val idCall = FunctionInvocation(funDef, funDef.args.map(_.toVariable)) + val blockers : Map[(Identifier,Boolean),Set[FunctionInvocation]] = { + val idCall = funDef.map(fd => FunctionInvocation(fd, fd.args.map(_.toVariable))) Map((for((p, es) <- guardedExprs) yield { - val calls = es.foldLeft(Set.empty[FunctionInvocation])((s,e) => s ++ functionCallsOf(e)) - idCall + val calls = es.foldLeft(Set.empty[FunctionInvocation])((s,e) => s ++ functionCallsOf(e)) -- idCall if(calls.isEmpty) { None } else { @@ -35,11 +35,14 @@ class FunctionTemplate private( } }).flatten.toSeq : _*) } - + // Returns two things: // - a set of clauses representing the computation of the function/post // - a map indicating which boolean variables guard which (recursive) fun. invoc. def instantiate(aVar : Identifier, aPol : Boolean, args : Seq[Expr]) : (Seq[Expr],Map[(Identifier,Boolean),Set[FunctionInvocation]]) = { + assert(this.funDef.isDefined) + + val funDef = this.funDef.get assert(args.size == funDef.args.size) val idSubstMap : Map[Identifier,Identifier] = @@ -72,7 +75,11 @@ class FunctionTemplate private( } override def toString : String = { - "Template for def " + funDef.id + "(" + funDef.args.map(a => a.id + " : " + a.tpe).mkString(", ") + ") : " + funDef.returnType + " is :\n" + + if (funDef.isDefined) { + "Template for def " + funDef.get.id + "(" + funDef.get.args.map(a => a.id + " : " + a.tpe).mkString(", ") + ") : " + funDef.get.returnType + " is :\n" + } else { + "Template for expr is :\n" + } + " * Activating boolean : " + activatingBool + "\n" + " * Control booleans : " + condVars.toSeq.map(_.toString).mkString(", ") + "\n" + " * Expression vars : " + exprVars.toSeq.map(_.toString).mkString(", ") + "\n" + @@ -86,18 +93,18 @@ object FunctionTemplate { private val PREPENDPRECONDS : Boolean = true // always instantiate axioms guarded by the precond. private val KEEPLETS : Boolean = true // don't expand the lets, instantiate them with the rest - private val cache : MutableMap[FunDef,FunctionTemplate] = MutableMap.empty + private val cache : MutableMap[(Option[FunDef], Option[Expr]),FunctionTemplate] = MutableMap.empty + + def mkTemplate(funDef: FunDef): FunctionTemplate = + mkTemplate(Some(funDef), funDef.body) - def mkTemplate(funDef : FunDef /*, program : Program*/) : FunctionTemplate = if(cache.isDefinedAt(funDef)) { - cache(funDef) + def mkTemplate(body: Expr): FunctionTemplate = + mkTemplate(None, Some(body)) + + private def mkTemplate(funDef: Option[FunDef], body : Option[Expr]) : FunctionTemplate = if(cache.isDefinedAt((funDef, body))) { + cache((funDef, body)) } else { val result = { - /* - if(!funDef.hasImplementation) { - sys.error("Cannot create a FunctionTemplate out of a function with no body.") - } - */ - val condVars : MutableSet[Identifier] = MutableSet.empty val exprVars : MutableSet[Identifier] = MutableSet.empty @@ -163,76 +170,73 @@ object FunctionTemplate { // The precondition if it exists. val prec : Option[Expr] = if(KEEPLETS) { - funDef.precondition.map(p => matchToIfThenElse(p)) + funDef.flatMap(_.precondition.map(p => matchToIfThenElse(p))) } else { - funDef.precondition.map(p => matchToIfThenElse(expandLets(p))) + funDef.flatMap(_.precondition.map(p => matchToIfThenElse(expandLets(p)))) } - // Treating the body first. - /* - val body : Expr = if(KEEPLETS) { - matchToIfThenElse(funDef.getImplementation) + val newBody : Option[Expr] = if(KEEPLETS) { + body.map(b => matchToIfThenElse(b)) } else { - matchToIfThenElse(expandLets(funDef.getImplementation)) - } - */ - val body : Option[Expr] = if(KEEPLETS) { - funDef.body.map(b => matchToIfThenElse(b)) - } else { - funDef.body.map(b => matchToIfThenElse(expandLets(b))) + body.map(b => matchToIfThenElse(expandLets(b))) } - val invocation : Expr = FunctionInvocation(funDef, funDef.args.map(_.toVariable)) + val invocation : Option[Expr] = funDef.map(fd => FunctionInvocation(fd, fd.args.map(_.toVariable))) - /* - val invocationEqualsBody : Expr = { - val b : Expr = Equals(invocation, body) - if(PREPENDPRECONDS && funDef.hasPrecondition) { - Implies(prec.get, b) - } else { - b - } + val invocationEqualsBody : Option[Expr] = (invocation, newBody) match { + case (Some(inv), Some(body)) => + val b : Expr = Equals(inv, body) + + Some(if(PREPENDPRECONDS && prec.isDefined) { + Implies(prec.get, b) + } else { + b + }) + + case _ => + None } - */ - val invocationEqualsBody : Option[Expr] = body.map(body => { - val b : Expr = Equals(invocation, body) - if(PREPENDPRECONDS && funDef.hasPrecondition) { - Implies(prec.get, b) - } else { - b - } - }) val activatingBool : Identifier = FreshIdentifier("a", true).setType(BooleanType) - //val finalPred : Expr = rec(activatingBool, true, invocationEqualsBody) - val finalPred : Option[Expr] = invocationEqualsBody.map(expr => rec(activatingBool, true, expr)) - //storeGuarded(activatingBool, true, finalPred) - finalPred.foreach(p => storeGuarded(activatingBool, true, p)) + funDef match { + case Some(fd) => + val finalPred : Option[Expr] = invocationEqualsBody.map(expr => rec(activatingBool, true, expr)) + finalPred.foreach(p => storeGuarded(activatingBool, true, p)) + + case None => + storeGuarded(activatingBool, false, BooleanLiteral(false)) + val newFormula = rec(activatingBool, true, body.get) + storeGuarded(activatingBool, true, newFormula) + } // Now the postcondition. - if(funDef.hasPostcondition) { - val postHolds : Expr = { - val post0 : Expr = if(KEEPLETS) { - matchToIfThenElse(funDef.getPostcondition) - } else { - matchToIfThenElse(expandLets(funDef.getPostcondition)) - } - val post : Expr = replace(Map(ResultVariable() -> invocation), post0) - if(PREPENDPRECONDS && funDef.hasPrecondition) { - Implies(prec.get, post) - } else { - post + funDef match { + case Some(fd) if fd.hasPostcondition => + val postHolds : Expr = { + val post0 : Expr = if(KEEPLETS) { + matchToIfThenElse(fd.getPostcondition) + } else { + matchToIfThenElse(expandLets(fd.getPostcondition)) + } + val post : Expr = replace(Map(ResultVariable() -> invocation.get), post0) + if(PREPENDPRECONDS && fd.hasPrecondition) { + Implies(prec.get, post) + } else { + post + } } - } - val finalPred2 : Expr = rec(activatingBool, true, postHolds) - storeGuarded(activatingBool, true, postHolds) + val finalPred2 : Expr = rec(activatingBool, true, postHolds) + storeGuarded(activatingBool, true, postHolds) + case _ => + + } - val ft = new FunctionTemplate(funDef, activatingBool, Set(condVars.toSeq : _*), Set(exprVars.toSeq : _*), Map(guardedExprs.toSeq : _*)) - ft + new FunctionTemplate(funDef, activatingBool, Set(condVars.toSeq : _*), Set(exprVars.toSeq : _*), Map(guardedExprs.toSeq : _*)) } - cache(funDef) = result + + cache((funDef, body)) = result result } } diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala index 71e26b83f..401ebb6cb 100644 --- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala +++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala @@ -322,9 +322,8 @@ class FairZ3Solver(context : LeonContext) extends Solver(context) with AbstractZ // This branch is both for with and without unsat cores. The // distinction is made inside. case (Some(false), m) => { - if(!Settings.useCores) - solver.pop(1) - + solver.pop(1) + if (Settings.luckyTest && !forceStop) { // we need the model to perform the additional test reporter.info(" - Running search without blocked literals (w/ lucky test)") @@ -493,7 +492,7 @@ class FairZ3Solver(context : LeonContext) extends Solver(context) with AbstractZ } } - private def validateAndDeleteModel(model: Z3Model, formula: Expr, variables: Set[Identifier], evaluator: Option[(Map[Identifier,Expr])=>Boolean]) : (Boolean, Map[Identifier,Expr]) = { + private def validateAndDeleteModel(model: Z3Model, formula: Expr, variables: Set[Identifier], evaluator: Option[(Map[Identifier,Expr])=>Boolean] = None) : (Boolean, Map[Identifier,Expr]) = { import Evaluator._ if(!forceStop) { @@ -556,7 +555,7 @@ class FairZ3Solver(context : LeonContext) extends Solver(context) with AbstractZ } } - class UnrollingBank { + class UnrollingBank { private val blockMap : MutableMap[(Identifier,Boolean),Set[FunctionInvocation]] = MutableMap.empty private def registerBlocked(id: Identifier, pol: Boolean, fi: FunctionInvocation) : Boolean = registerBlocked(id,pol,Set(fi)) @@ -579,6 +578,10 @@ class FairZ3Solver(context : LeonContext) extends Solver(context) with AbstractZ } } + def scanForNewTemplates(expr: Expr): (Seq[Expr], Seq[(Identifier, Boolean)]) = { + (Seq(), Seq()) + } + private def treatFunctionInvocationSet(sVar : Identifier, pol : Boolean, fis : Set[FunctionInvocation]) : (Seq[Expr],Seq[(Identifier,Boolean)]) = { val allBlocks : MutableSet[(Identifier,Boolean)] = MutableSet.empty var allNewExprs : Seq[Expr] = Seq.empty @@ -597,11 +600,14 @@ class FairZ3Solver(context : LeonContext) extends Solver(context) with AbstractZ (allNewExprs, allBlocks.toSeq) } - // This is called just once, for the "initial unrolling". FIXME: TODO: - // Wouldn't it be better/more uniform to pretend the initial formula is a - // function and generate a template for it? def initialUnrolling(formula : Expr) : (Seq[Expr], Seq[(Identifier,Boolean)]) = { - initialUnrolling0(formula) + val tmp = FunctionTemplate.mkTemplate(formula) + + for (((p1, p2), calls) <- tmp.blockers) { + registerBlocked(p1, p2, calls) + } + + (tmp.asClauses, tmp.blockers.keySet.toSeq) } def unlock(id: Identifier, pol: Boolean) : (Seq[Expr], Seq[(Identifier,Boolean)]) = { @@ -613,123 +619,303 @@ class FairZ3Solver(context : LeonContext) extends Solver(context) with AbstractZ treatFunctionInvocationSet(id, pol, copy) } } - - //this is mostly copied from FunctionTemplate. This is sort of a quick hack to the problem - //of the initial unrolling - def initialUnrolling0(formula: Expr): (Seq[Expr], Seq[(Identifier,Boolean)]) = { - - var guardedExprs : Map[(Identifier,Boolean),Seq[Expr]] = Map.empty - def storeGuarded(guardVar : Identifier, guardPol : Boolean, expr : Expr) : Unit = { - assert(expr.getType == BooleanType) - val p : (Identifier,Boolean) = (guardVar,guardPol) - if(guardedExprs.isDefinedAt(p)) { - val prev : Seq[Expr] = guardedExprs(p) - guardedExprs += (p -> (expr +: prev)) - } else { - guardedExprs += (p -> Seq(expr)) - } - } - - def rec(pathVar : Identifier, pathPol : Boolean, expr : Expr) : Expr = { - expr match { - case l : Let => sys.error("Let's should have been eliminated.") - case m : MatchExpr => sys.error("MatchExpr's should have been eliminated.") - - case i @ IfExpr(cond, then, elze) => { - if(!containsFunctionCalls(cond) && !containsFunctionCalls(then) && !containsFunctionCalls(elze)) { - i - } else { - val newBool : Identifier = FreshIdentifier("b", true).setType(BooleanType) - val newExpr : Identifier = FreshIdentifier("e", true).setType(i.getType) - - val crec = rec(pathVar, pathPol, cond) - val trec = rec(newBool, true, then) - val erec = rec(newBool, false, elze) - - storeGuarded(pathVar, pathPol, Iff(Variable(newBool), crec)) - storeGuarded(newBool, true, Equals(Variable(newExpr), trec)) - storeGuarded(newBool, false, Equals(Variable(newExpr), erec)) - Variable(newExpr) - } - } - - case n @ NAryOperator(as, r) => r(as.map(a => rec(pathVar, pathPol, a))).setType(n.getType) - case b @ BinaryOperator(a1, a2, r) => r(rec(pathVar, pathPol, a1), rec(pathVar, pathPol, a2)).setType(b.getType) - case u @ UnaryOperator(a, r) => r(rec(pathVar, pathPol, a)).setType(u.getType) - case t : Terminal => t - case a : AnonymousFunction => { - Settings.reporter.warning("AnonymousFunction literal showed up in the construction of a FunctionTemplate.") - a - } - } - } - val startingVar : Identifier = FreshIdentifier("start", true).setType(BooleanType) - storeGuarded(startingVar, false, BooleanLiteral(false)) - val newFormula = rec(startingVar, true, formula) - storeGuarded(startingVar, true, newFormula) - - val asClauses : Seq[Expr] = { - (for(((b,p),es) <- guardedExprs; e <- es) yield { - Implies(if(!p) Not(Variable(b)) else Variable(b), e) - }).toSeq - } - - val blockers : Map[(Identifier,Boolean),Set[FunctionInvocation]] = { - Map((for((p, es) <- guardedExprs) yield { - val calls = es.foldLeft(Set.empty[FunctionInvocation])((s,e) => s ++ functionCallsOf(e)) - if(calls.isEmpty) { - None - } else { - registerBlocked(p._1, p._2, calls) - Some((p, calls)) - } - }).flatten.toSeq : _*) - } - - (asClauses, blockers.keys.toSeq) - - } } def getNewSolver = new solvers.IncrementalSolver { val solver = z3.mkSolver - private var varsInVC = Set[Identifier]() + private var ownStack = List[Set[Z3AST]](Set()) + private var assertionsStack = List[List[Expr]](Nil) + private var varsInVC = Set[Identifier]() + + def allClausePredicates = ownStack.flatten def push() { - solver.push + ownStack = Set[Z3AST]() :: ownStack + assertionsStack = Nil :: assertionsStack } def pop(lvl: Int = 1) { - solver.pop(lvl) - } + val frame = ownStack.head + ownStack = ownStack.tail - def assertCnstr(expression: Expr) { - varsInVC ++= variablesOf(expression) - solver.assertCnstr(toZ3Formula(expression).get) + assertionsStack = assertionsStack.tail + + frame.foreach { b => + solver.assertCnstr(z3.mkNot(b)) + } } def check: Option[Boolean] = { - solver.check + fairCheck(Set()) } def checkAssumptions(assumptions: Set[Expr]): Option[Boolean] = { - solver.checkAssumptions(assumptions.toSeq.map(toZ3Formula(_).get) : _*) + fairCheck(assumptions) + } + + val unrollingBank = new UnrollingBank() + var isBankInitialized = false + + var foundDefinitiveAnswer = false + var definitiveAnswer : Option[Boolean] = None + var definitiveModel : Map[Identifier,Expr] = Map.empty + var definitiveCore : Set[Expr] = Set.empty + + // Unrolling state + private var blockingSet: Set[Expr] = Set.empty + + def assertCnstr(expression: Expr) { + val b = z3.mkFreshConst("b", z3.mkBoolSort) + varsInVC ++= variablesOf(expression) + + ownStack = (ownStack.head + b) :: ownStack.tail + assertionsStack = (expression :: assertionsStack.head) :: assertionsStack.tail + + solver.assertCnstr(z3.mkImplies(b, toZ3Formula(expression).get)) + + if (isBankInitialized) { + val (newClauses, newGuards) = unrollingBank.scanForNewTemplates(expression) + for (cl <- newClauses) { + solver.assertCnstr(toZ3Formula(cl).get) + } + blockingSet ++= newGuards.map(p => if(p._2) Not(Variable(p._1)) else Variable(p._1)) + } } def getModel = { - modelToMap(solver.getModel, varsInVC) + definitiveModel } def getUnsatCore = { - solver.getUnsatCore.map(ast => fromZ3Formula(null, ast, None) match { - case n @ Not(Variable(_)) => n - case v @ Variable(_) => v - case x => scala.sys.error("Impossible element extracted from core: " + ast + " (as Leon tree : " + x + ")") - }).toSet + definitiveCore } + def fairCheck(assumptions: Set[Expr]): Option[Boolean] = { + foundDefinitiveAnswer = false + + def foundAnswer(answer : Option[Boolean], model : Map[Identifier,Expr] = Map.empty, core: Set[Expr] = Set.empty) : Unit = { + foundDefinitiveAnswer = true + definitiveAnswer = answer + definitiveModel = model + definitiveCore = core + } + + def z3CoreToCore(core: Seq[Z3AST]): Set[Expr] = { + val internalAssumptions = allClausePredicates.toSet + val userlandAssumptions = core.filterNot(internalAssumptions) + + userlandAssumptions.map(ast => fromZ3Formula(null, ast, None) match { + case n @ Not(Variable(_)) => n + case v @ Variable(_) => v + case x => scala.sys.error("Impossible element extracted from core: " + ast + " (as Leon tree : " + x + ")") + }).toSet + } + + if (!isBankInitialized) { + reporter.info(" - Initial unrolling...") + val (clauses, guards) = unrollingBank.initialUnrolling(And(assertionsStack.flatten)) + + solver.assertCnstr(toZ3Formula(And(clauses)).get) + blockingSet ++= guards.map(p => if(p._2) Not(Variable(p._1)) else Variable(p._1)) + } + + // these are the optional sequence of assumption literals + val assumptionsAsZ3: Seq[Z3AST] = allClausePredicates ++ assumptions.map(toZ3Formula(_).get) + + + var iterationsLeft : Int = if(Settings.unrollingLevel > 0) Settings.unrollingLevel else 16121984 + + while(!foundDefinitiveAnswer && !forceStop) { + iterationsLeft -= 1 + + val blockingSetAsZ3 : Seq[Z3AST] = blockingSet.toSeq.map(toZ3Formula(_).get) + // println("Blocking set : " + blockingSet) + + solver.push + if(!blockingSetAsZ3.isEmpty) + solver.assertCnstr(z3.mkAnd(blockingSetAsZ3 : _*)) + reporter.info(" - Running Z3 search...") + val answerModelCore : (Option[Boolean], Z3Model, Set[Expr]) = { + + val res = solver.checkAssumptions(assumptionsAsZ3 : _*) + + val z3model = res match { + case Some(true) => solver.getModel + case _ => null + } + + (res, z3model, z3CoreToCore(solver.getUnsatCore)) + } + + val (answer, model, core) = answerModelCore // to work around the stupid type inferer + + reporter.info(" - Finished search with blocked literals") + + val reinterpretedAnswer = if(!UNKNOWNASSAT) answer else (answer match { + case None | Some(true) => Some(true) + case Some(false) => Some(false) + }) + + (reinterpretedAnswer, model) match { + case (None, m) => { // UNKNOWN + // reporter.warning("Z3 doesn't know because: " + z3.getSearchFailure.message) + reporter.warning("Z3 doesn't know because ??") + foundAnswer(None) + } + case (Some(true), m) => { // SAT + val (trueModel, model) = if(Settings.verifyModel) + validateAndDeleteModel(m, toCheckAgainstModels, varsInVC) + else { + val res = (true, modelToMap(m, varsInVC)) + lazy val modelAsString = res._2.toList.map(p => p._1 + " -> " + p._2).mkString("\n") + reporter.info("- Found a model:") + reporter.info(modelAsString) + res + } + + if (trueModel) { + foundAnswer(Some(true), model) + } else { + reporter.error("Something went wrong. The model should have been valid, yet we got this : ") + reporter.error(model) + foundAnswer(None, model) + } + } + case (Some(false), m) if blockingSet.isEmpty => { + foundAnswer(Some(false), core = core) + solver.pop(1) + } + // This branch is both for with and without unsat cores. The + // distinction is made inside. + case (Some(false), m) => { + solver.pop(1) + + if (Settings.luckyTest && !forceStop) { + // we need the model to perform the additional test + reporter.info(" - Running search without blocked literals (w/ lucky test)") + + val res2 = solver.checkAssumptions(assumptionsAsZ3 : _*) + + val z3model2 = res2 match { + case Some(true) => solver.getModel + case _ => null + } + + reporter.info(" - Finished search without blocked literals") + + if (res2 == Some(false)) { + foundAnswer(Some(false), core = z3CoreToCore(solver.getUnsatCore)) + } else { + // we might have been lucky :D + val (wereWeLucky, cleanModel) = validateAndDeleteModel(z3model2, toCheckAgainstModels, varsInVC) + if(wereWeLucky) { + foundAnswer(Some(true), cleanModel) + } + } + } else { + // only checking will suffice + reporter.info(" - Running search without blocked literals (w/o lucky test)") + + val result2 = solver.checkAssumptions(assumptionsAsZ3 : _*) + + reporter.info(" - Finished search without blocked literals") + + if (result2 == Some(false)) { + foundAnswer(Some(false), core = z3CoreToCore(solver.getUnsatCore)) + } + } + + if(forceStop) { + foundAnswer(None) + } + + if(!foundDefinitiveAnswer) { + reporter.info("- We need to keep going.") + + val toRelease : Set[Expr] = blockingSet + + // reporter.info(" - toRelease : " + toRelease) + // reporter.info(" - blockingSet : " + blockingSet) + + var fixedForEver : Set[Expr] = Set.empty + + if(Settings.pruneBranches) { + for(ex <- blockingSet) ex match { + case Not(Variable(b)) => { + solver.push + solver.assertCnstr(toZ3Formula(Variable(b)).get) + solver.check match { + case Some(false) => { + //println("We had ~" + b + " in the blocking set. We now know it should stay there forever.") + solver.pop(1) + solver.assertCnstr(toZ3Formula(Not(Variable(b))).get) + fixedForEver = fixedForEver + ex + } + case _ => solver.pop(1) + } + } + case Variable(b) => { + solver.push + solver.assertCnstr(toZ3Formula(Not(Variable(b))).get) + solver.check match { + case Some(false) => { + //println("We had " + b + " in the blocking set. We now know it should stay there forever.") + solver.pop(1) + solver.assertCnstr(toZ3Formula(Variable(b)).get) + fixedForEver = fixedForEver + ex + } + case _ => solver.pop(1) + } + } + case _ => scala.sys.error("Should not have happened.") + } + if(fixedForEver.size > 0) { + reporter.info("- Pruned out " + fixedForEver.size + " branches.") + } + } + + + blockingSet = blockingSet -- toRelease + + val toReleaseAsPairs : Set[(Identifier,Boolean)] = (toRelease -- fixedForEver).map(b => b match { + case Variable(id) => (id, true) + case Not(Variable(id)) => (id, false) + case _ => scala.sys.error("Impossible value in release set: " + b) + }) + + reporter.info(" - more unrollings") + for((id,polarity) <- toReleaseAsPairs) { + val (newClauses,newBlockers) = unrollingBank.unlock(id, !polarity) + + for(ncl <- newClauses) { + solver.assertCnstr(toZ3Formula(ncl).get) + } + blockingSet = blockingSet ++ Set(newBlockers.map(p => if(p._2) Not(Variable(p._1)) else Variable(p._1)) : _*) + } + reporter.info(" - finished unrolling") + } + } + } + + if(iterationsLeft <= 0) { + reporter.error(" - Max. number of iterations reached.") + foundAnswer(None) + } + } + + if(forceStop) { + None + } else { + definitiveAnswer + } + } + + if (program == null) { + reporter.error("Z3 Solver was not initialized with a PureScala Program.") + None + } } } -- GitLab