diff --git a/src/main/scala/leon/Analysis.scala b/src/main/scala/leon/Analysis.scala index 9849330cedf1a3d48c0eabd8cff0508a4a01b8b3..40468a4bef174cd93278452a038cc2b711710328 100644 --- a/src/main/scala/leon/Analysis.scala +++ b/src/main/scala/leon/Analysis.scala @@ -28,12 +28,10 @@ class Analysis(val program: Program, val reporter: Reporter = Settings.reporter) // conditions are generated and passed to all solvers. Otherwise, only the // Analysis extensions are run on the program. def analyse : Unit = { - // to save some time... - if(Settings.useTemplates) { - for(funDef <- program.definedFunctions if funDef.hasImplementation) { - // this gets cached :D - FunctionTemplate.mkTemplate(funDef) - } + // We generate all function templates in advance. + for(funDef <- program.definedFunctions if funDef.hasImplementation) { + // this gets cached :D + FunctionTemplate.mkTemplate(funDef) } if(solverExtensions.size > 1) { diff --git a/src/main/scala/leon/FairZ3Solver.scala b/src/main/scala/leon/FairZ3Solver.scala index 549f18f97860e46198bd7283ad455c28cbd45d0d..7e5b8625602383541de4d52770fe5ea4f9192933 100644 --- a/src/main/scala/leon/FairZ3Solver.scala +++ b/src/main/scala/leon/FairZ3Solver.scala @@ -74,11 +74,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S prepareSorts prepareFunctions - unrollingBank = if(Settings.useTemplates) { - new NewUnrollingBank - } else { - new UnrollingBank - } + unrollingBank = new UnrollingBank blockingSet = Set.empty toCheckAgainstModels = BooleanLiteral(true) varsInVC = Set.empty @@ -1144,193 +1140,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S rec(tree, expectedType) } - // This remembers everything that was unrolled, which literal is blocking - // which calls, etc. - class UnrollingBank { - private val everythingEverUnrolled : MutableSet[FunctionInvocation] = MutableSet.empty - - // stores the invocations that boolean literals are guarding. - private val blocked : MutableMap[(Identifier,Boolean),Set[FunctionInvocation]] = MutableMap.empty - - // Returns whether some invocations were actually blocked in the end. - private def registerBlocked(blockingAtom : Identifier, polarity : Boolean, invocations : Set[FunctionInvocation]) : Boolean = { - val filtered = invocations.filter(i => { - val FunctionInvocation(fd, _) = i - if(axiomatizedFunctions(fd)) { - reporter.info("I'm not registering " + i + " as blocked because it's axiomatized.") - false - } else { - true - } - }) - - val pair = (blockingAtom, polarity) - val alreadyBlocked = blocked.get(pair) - alreadyBlocked match { - case None => blocked(pair) = filtered - case Some(prev) => blocked(pair) = prev ++ filtered - } - - !filtered.isEmpty - } - - private def wasUnrolledBefore(functionInvocation : FunctionInvocation) : Boolean = { - everythingEverUnrolled(functionInvocation) - } - - private def registerAsUnrolled(functionInvocation : FunctionInvocation) : Unit = { - everythingEverUnrolled += functionInvocation - } - - def initialUnrolling(formula : Expr) : (Seq[Expr], Seq[(Identifier,Boolean)]) = { - val (e,s,ss) = closeUnrollings(formula) - (e +: s, ss) - } - - private def closeUnrollings(formula : Expr) : (Expr, Seq[Expr], Seq[(Identifier,Boolean)]) = { - var (basis, clauses, ite2Bools) = clausifyITE(formula) - - var unrolledNow : Set[FunctionInvocation] = Set.empty - var stillToUnroll : Set[FunctionInvocation] = Set.empty - var treatedClauses : List[Expr] = Nil - var blockers : List[(Identifier,Boolean)] = Nil - - stillToUnroll = stillToUnroll ++ topLevelFunctionCallsOf(basis, axiomatizedFunctions) - do { - // We go through each clause and figure out what must be enrolled and - // what must be blocked. We register everything. - for(clause <- clauses) { - clause match { - case Iff(Variable(_), cond) => { - stillToUnroll = stillToUnroll ++ topLevelFunctionCallsOf(cond, axiomatizedFunctions) - } - case Implies(v @ Variable(id), then) => { - val calls = topLevelFunctionCallsOf(then, axiomatizedFunctions) - if(!calls.isEmpty) { - assert(!blocked.isDefinedAt((id,true))) - if(registerBlocked(id, true, calls)) //blocked((id,true)) = calls - blockers = (id,true) :: blockers - } - } - case Implies(Not(v @ Variable(id)), elze) => { - val calls = topLevelFunctionCallsOf(elze, axiomatizedFunctions) - if(!calls.isEmpty) { - assert(!blocked.isDefinedAt((id,false))) - if(registerBlocked(id, false, calls)) //blocked((id,false)) = calls - blockers = (id,false) :: blockers - } - } - case _ => scala.sys.error("Who added this as a clause? " + clause) - } - treatedClauses = clause :: treatedClauses - } - - clauses = Nil - - while(!stillToUnroll.isEmpty) { - val copy = stillToUnroll - stillToUnroll = Set.empty - - for(stu <- (copy -- unrolledNow) if !wasUnrolledBefore(stu)) { - // println("unrolling " + stu) - val unrolled : Seq[Expr] = unroll(stu) // that's between 0 and two formulas - registerAsUnrolled(stu) - unrolledNow = unrolledNow + stu - - for(formula <- unrolled) { - val (basis2, clauses2, _) = clausifyITE(formula) - stillToUnroll = stillToUnroll ++ topLevelFunctionCallsOf(basis2, axiomatizedFunctions) - clauses = clauses2 ::: clauses - treatedClauses = basis2 :: treatedClauses - } - } - } - - } while(!clauses.isEmpty) - - (basis, treatedClauses.reverse, blockers.reverse) - } - - // takes in a conjunction and returns a new conjunction, where all - // non-recursive function calls are "defined" and "contracted" - // NEVER USED !!! - /* - def expandAllNonRecursive(exprs: List[Expr]) : List[Expr] = { - val todo : MutableSet[FunctionInvocation] = MutableSet.empty - val todo2 : MutableSet[FunctionInvocation] = MutableSet.empty - var resulting : List[Expr] = Nil - - for(expr <- exprs) { - todo ++= allNonRecursiveFunctionCallsOf(expr, program) - resulting = expr :: resulting - } - - while(!todo.isEmpty) { - todo2.clear - for(fi <- todo) if(!wasUnrolledBefore(fi)) { - registerAsUnrolled(fi) - val ur = unroll(fi) - resulting = ur ::: resulting - for(u <- ur) { - todo2 ++= allNonRecursiveFunctionCallsOf(u, program) - } - } - todo.clear - todo ++= todo2 - } - - resulting - }*/ - - // Returns between 0 and 2 tautologies with respect to the interpretation of - // the function and its postcondition. - private def unroll(functionInvocation: FunctionInvocation) : List[Expr] = { - val FunctionInvocation(fd, args) = functionInvocation - val postExpr = if(fd.hasPostcondition) { - val post = expandLets(matchToIfThenElse(fd.postcondition.get)) - val substMap = Map[Expr,Expr]((fd.args.map(_.toVariable) zip args) : _*) + (ResultVariable() -> functionInvocation) - val newBody = replace(substMap, post) - List(newBody) - } else Nil - - val bodyExpr = if(fd.hasBody) { - val body = expandLets(matchToIfThenElse(fd.body.get)) - val substMap = Map[Expr,Expr]((fd.args.map(_.toVariable) zip args) : _*) - val newBody = replace(substMap, body) - List(Equals(functionInvocation, newBody)) - } else Nil - - postExpr ::: bodyExpr - } - - // if polarity == true, means that we used to have !id in the blocking set, - // and that now it's gone. As a result, we need to unroll everything that - // id is guarding. Similarly for polarity == false - def unlock(id: Identifier, polarity: Boolean) : (Seq[Expr], Seq[(Identifier,Boolean)]) = { - if(!blocked.isDefinedAt((id,polarity))) { - (Seq.empty,Seq.empty) - } else { - var newBlockers : Set[(Identifier,Boolean)] = Set.empty - var newClauses : List[Expr] = Nil - - val blockedSet = blocked((id,polarity)) - - for(functionInvocation <- blockedSet) { - // TODO this is probably where the unrolling of the recursive call - // should actually occur, rather than delegating that to - // closeUnrollings. - // reporter.info("Unlocking : " + functionInvocation) - val (_, clauses, blockers) = closeUnrollings(functionInvocation) - newClauses = newClauses ++ clauses - newBlockers = newBlockers ++ blockers - } - - (newClauses, newBlockers.toSeq) - } - } - } - - class NewUnrollingBank extends 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)) @@ -1374,7 +1184,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S // 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? - override def initialUnrolling(formula : Expr) : (Seq[Expr], Seq[(Identifier,Boolean)]) = { + def initialUnrolling(formula : Expr) : (Seq[Expr], Seq[(Identifier,Boolean)]) = { val fi = functionCallsOf(formula) if(fi.isEmpty) { (Seq(formula), Seq.empty) @@ -1387,7 +1197,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S } } - override def unlock(id: Identifier, pol: Boolean) : (Seq[Expr], Seq[(Identifier,Boolean)]) = { + def unlock(id: Identifier, pol: Boolean) : (Seq[Expr], Seq[(Identifier,Boolean)]) = { if(!blockMap.isDefinedAt((id,pol))) { (Seq.empty,Seq.empty) } else { diff --git a/src/main/scala/leon/Settings.scala b/src/main/scala/leon/Settings.scala index d62dd80d241e1dbdded051234169f8ab06f91c01..6593e418c28a4f49f5b8a798b527b468e9f3040c 100644 --- a/src/main/scala/leon/Settings.scala +++ b/src/main/scala/leon/Settings.scala @@ -23,5 +23,4 @@ object Settings { var useParallel : Boolean = false // When this is None, use real integers var bitvectorBitwidth : Option[Int] = None - var useTemplates : Boolean = false } diff --git a/src/main/scala/leon/plugin/LeonPlugin.scala b/src/main/scala/leon/plugin/LeonPlugin.scala index 39356927db6f25774de59f175ef2d8167f4a60ae..7919cbcd5717c25c9120db29e063ccfeb2343492 100644 --- a/src/main/scala/leon/plugin/LeonPlugin.scala +++ b/src/main/scala/leon/plugin/LeonPlugin.scala @@ -39,7 +39,6 @@ class LeonPlugin(val global: Global, val actionAfterExtraction : Option[Program= " -P:leon:cores Use UNSAT cores in the unrolling/refinement step" + "\n" + " -P:leon:quickcheck Use QuickCheck-like random search" + "\n" + " -P:leon:parallel Run all solvers in parallel" + "\n" + - " -P:leon:templates Use new ``FunctionTemplate'' technique" + "\n" + " -P:leon:noLuckyTests Do not perform additional tests to potentially find models early" ) @@ -62,7 +61,6 @@ class LeonPlugin(val global: Global, val actionAfterExtraction : Option[Program= case "cores" => leon.Settings.useCores = true case "quickcheck" => leon.Settings.useQuickCheck = true case "parallel" => leon.Settings.useParallel = true - case "templates" => leon.Settings.useTemplates = true case "noLuckyTests" => leon.Settings.luckyTest = false case s if s.startsWith("unrolling=") => leon.Settings.unrollingLevel = try { s.substring("unrolling=".length, s.length).toInt } catch { case _ => 0 } case s if s.startsWith("functions=") => leon.Settings.functionsToAnalyse = Set(splitList(s.substring("functions=".length, s.length)): _*)