Skip to content
Snippets Groups Projects
Commit b542b300 authored by Philippe Suter's avatar Philippe Suter
Browse files

Passing flags to Z3...

parent be5a9987
No related branches found
No related tags found
No related merge requests found
...@@ -15,9 +15,12 @@ object Main { ...@@ -15,9 +15,12 @@ object Main {
} }
// Add whatever you need here. // Add whatever you need here.
lazy val allComponents : List[LeonComponent] = allPhases ++ Nil lazy val allComponents : Set[LeonComponent] = allPhases.toSet ++ Set(
// It's a little unfortunate that we need to build one...
new solvers.z3.FairZ3Solver(LeonContext())
)
lazy val allOptions = allPhases.flatMap(_.definedOptions) ++ Set( lazy val topLevelOptions : Set[LeonOptionDef] = Set(
LeonFlagOptionDef ("synthesis", "--synthesis", "Partial synthesis of choose() constructs"), LeonFlagOptionDef ("synthesis", "--synthesis", "Partial synthesis of choose() constructs"),
LeonFlagOptionDef ("xlang", "--xlang", "Support for extra program constructs (imperative,...)"), LeonFlagOptionDef ("xlang", "--xlang", "Support for extra program constructs (imperative,...)"),
LeonFlagOptionDef ("parse", "--parse", "Checks only whether the program is valid PureScala"), LeonFlagOptionDef ("parse", "--parse", "Checks only whether the program is valid PureScala"),
...@@ -27,31 +30,26 @@ object Main { ...@@ -27,31 +30,26 @@ object Main {
// Unimplemented Options: // Unimplemented Options:
// //
// LeonFlagOptionDef("uniqid", "--uniqid", "When pretty-printing purescala trees, show identifiers IDs"), // LeonFlagOptionDef("uniqid", "--uniqid", "When pretty-printing purescala trees, show identifiers IDs"),
// LeonValueOptionDef("extensions", "--extensions=ex1:...", "Specifies a list of qualified class names of extensions to be loaded"),
// LeonFlagOptionDef("nodefaults", "--nodefaults", "Runs only the analyses provided by the extensions"),
// LeonValueOptionDef("functions", "--functions=fun1:...", "Only generates verification conditions for the specified functions"),
// LeonFlagOptionDef("unrolling", "--unrolling=[0,1,2]", "Unrolling depth for recursive functions" ),
// LeonFlagOptionDef("axioms", "--axioms", "Generate simple forall axioms for recursive functions when possible" ),
// LeonFlagOptionDef("tolerant", "--tolerant", "Silently extracts non-pure function bodies as ''unknown''"), // LeonFlagOptionDef("tolerant", "--tolerant", "Silently extracts non-pure function bodies as ''unknown''"),
// LeonFlagOptionDef("bapa", "--bapa", "Use BAPA Z3 extension (incompatible with many other things)"), // LeonFlagOptionDef("bapa", "--bapa", "Use BAPA Z3 extension (incompatible with many other things)"),
// LeonFlagOptionDef("impure", "--impure", "Generate testcases only for impure functions"), // LeonFlagOptionDef("impure", "--impure", "Generate testcases only for impure functions"),
// LeonValueOptionDef("testcases", "--testcases=[1,2]", "Number of testcases to generate per function"), // LeonValueOptionDef("testcases", "--testcases=[1,2]", "Number of testcases to generate per function"),
// LeonValueOptionDef("testbounds", "--testbounds=l:u", "Lower and upper bounds for integers in recursive datatypes"), // LeonValueOptionDef("testbounds", "--testbounds=l:u", "Lower and upper bounds for integers in recursive datatypes"),
// LeonValueOptionDef("timeout", "--timeout=N", "Sets a timeout of N seconds"), // LeonValueOptionDef("timeout", "--timeout=N", "Sets a timeout of N seconds"),
// LeonFlagOptionDef("XP", "--XP", "Enable weird transformations and other bug-producing features"),
// LeonFlagOptionDef("BV", "--BV", "Use bit-vectors for integers"), // LeonFlagOptionDef("BV", "--BV", "Use bit-vectors for integers"),
// LeonFlagOptionDef("prune", "--prune", "Use additional SMT queries to rule out some unrollings"),
// LeonFlagOptionDef("cores", "--cores", "Use UNSAT cores in the unrolling/refinement step"),
// LeonFlagOptionDef("quickcheck", "--quickcheck", "Use QuickCheck-like random search"), // LeonFlagOptionDef("quickcheck", "--quickcheck", "Use QuickCheck-like random search"),
// LeonFlagOptionDef("parallel", "--parallel", "Run all solvers in parallel"), // LeonFlagOptionDef("parallel", "--parallel", "Run all solvers in parallel"),
// LeonFlagOptionDef("noLuckyTests", "--noLuckyTests", "Do not perform additional tests to potentially find models early"),
// LeonFlagOptionDef("noverifymodel", "--noverifymodel", "Do not verify the correctness of models returned by Z3"),
// LeonValueOptionDef("tags", "--tags=t1:...", "Filter out debug information that are not of one of the given tags"), // LeonValueOptionDef("tags", "--tags=t1:...", "Filter out debug information that are not of one of the given tags"),
) )
lazy val allOptions = allComponents.flatMap(_.definedOptions) ++ topLevelOptions
def displayHelp(reporter: Reporter) { def displayHelp(reporter: Reporter) {
reporter.info("usage: leon [--xlang] [--synthesis] [--help] [--debug=<N>] [..] <files>") reporter.info("usage: leon [--xlang] [--synthesis] [--help] [--debug=<N>] [..] <files>")
reporter.info("") reporter.info("")
for (opt <- topLevelOptions.toSeq.sortBy(_.name)) {
reporter.info("%-20s %s".format(opt.usageOption, opt.usageDesc))
}
reporter.info("(By default, Leon verifies PureScala programs.)") reporter.info("(By default, Leon verifies PureScala programs.)")
reporter.info("") reporter.info("")
reporter.info("Additional options, by component:") reporter.info("Additional options, by component:")
...@@ -96,7 +94,7 @@ object Main { ...@@ -96,7 +94,7 @@ object Main {
case (false, LeonValueOption(name, value)) => case (false, LeonValueOption(name, value)) =>
Some(leonOpt) Some(leonOpt)
case _ => case _ =>
reporter.error("Invalid option usage: "+opt) reporter.error("Invalid option usage: " + opt)
displayHelp(reporter) displayHelp(reporter)
None None
} }
......
...@@ -5,17 +5,11 @@ package leon ...@@ -5,17 +5,11 @@ package leon
object Settings { object Settings {
var showIDs: Boolean = false var showIDs: Boolean = false
lazy val reporter: Reporter = new DefaultReporter lazy val reporter: Reporter = new DefaultReporter
var noForallAxioms: Boolean = true
var unrollingLevel: Int = 0
var useBAPA: Boolean = false var useBAPA: Boolean = false
var impureTestcases: Boolean = false var impureTestcases: Boolean = false
var nbTestcases: Int = 1 var nbTestcases: Int = 1
var testBounds: (Int, Int) = (0, 3) var testBounds: (Int, Int) = (0, 3)
var useCores : Boolean = false
var pruneBranches : Boolean = false
var solverTimeout : Option[Int] = None var solverTimeout : Option[Int] = None
var luckyTest : Boolean = true
var verifyModel : Boolean = true
var useQuickCheck : Boolean = false var useQuickCheck : Boolean = false
var useParallel : Boolean = false var useParallel : Boolean = false
// When this is None, use real integers // When this is None, use real integers
......
...@@ -18,7 +18,6 @@ class LeonPlugin(val global: PluginRunner) extends Plugin { ...@@ -18,7 +18,6 @@ class LeonPlugin(val global: PluginRunner) extends Plugin {
" --uniqid When pretty-printing purescala trees, show identifiers IDs" + "\n" + " --uniqid When pretty-printing purescala trees, show identifiers IDs" + "\n" +
" --with-code Allows the compiler to keep running after the static analysis" + "\n" + " --with-code Allows the compiler to keep running after the static analysis" + "\n" +
" --parse Checks only whether the program is valid PureScala" + "\n" + " --parse Checks only whether the program is valid PureScala" + "\n" +
" --unrolling=[0,1,2] Unrolling depth for recursive functions" + "\n" +
" --axioms Generate simple forall axioms for recursive functions when possible" + "\n" + " --axioms Generate simple forall axioms for recursive functions when possible" + "\n" +
" --tolerant Silently extracts non-pure function bodies as ''unknown''" + "\n" + " --tolerant Silently extracts non-pure function bodies as ''unknown''" + "\n" +
" --bapa Use BAPA Z3 extension (incompatible with many other things)" + "\n" + " --bapa Use BAPA Z3 extension (incompatible with many other things)" + "\n" +
...@@ -27,11 +26,8 @@ class LeonPlugin(val global: PluginRunner) extends Plugin { ...@@ -27,11 +26,8 @@ class LeonPlugin(val global: PluginRunner) extends Plugin {
" --testbounds=l:u Lower and upper bounds for integers in recursive datatypes" + "\n" + " --testbounds=l:u Lower and upper bounds for integers in recursive datatypes" + "\n" +
" --timeout=N Sets a timeout of N seconds" + "\n" + " --timeout=N Sets a timeout of N seconds" + "\n" +
" --BV Use bit-vectors for integers" + "\n" + " --BV Use bit-vectors for integers" + "\n" +
" --prune Use additional SMT queries to rule out some unrollings" + "\n" +
" --cores Use UNSAT cores in the unrolling/refinement step" + "\n" +
" --quickcheck Use QuickCheck-like random search" + "\n" + " --quickcheck Use QuickCheck-like random search" + "\n" +
" --parallel Run all solvers in parallel" + "\n" + " --parallel Run all solvers in parallel" + "\n" +
" --noverifymodel Do not verify the correctness of models returned by Z3" + "\n" +
" --debug=[1-5] Debug level" + "\n" + " --debug=[1-5] Debug level" + "\n" +
" --imperative Preprocessing and transformation from imperative programs" + "\n" + " --imperative Preprocessing and transformation from imperative programs" + "\n" +
" --synthesis Magic!" " --synthesis Magic!"
...@@ -46,15 +42,11 @@ class LeonPlugin(val global: PluginRunner) extends Plugin { ...@@ -46,15 +42,11 @@ class LeonPlugin(val global: PluginRunner) extends Plugin {
case "uniqid" => leon.Settings.showIDs = true case "uniqid" => leon.Settings.showIDs = true
case "parse" => leon.Settings.stopAfterExtraction = true case "parse" => leon.Settings.stopAfterExtraction = true
case "tolerant" => leon.Settings.silentlyTolerateNonPureBodies = true case "tolerant" => leon.Settings.silentlyTolerateNonPureBodies = true
case "axioms" => leon.Settings.noForallAxioms = false
case "bapa" => leon.Settings.useBAPA = true case "bapa" => leon.Settings.useBAPA = true
case "impure" => leon.Settings.impureTestcases = true case "impure" => leon.Settings.impureTestcases = true
case "BV" => leon.Settings.bitvectorBitwidth = Some(32) case "BV" => leon.Settings.bitvectorBitwidth = Some(32)
case "prune" => leon.Settings.pruneBranches = true
case "cores" => leon.Settings.useCores = true
case "quickcheck" => leon.Settings.useQuickCheck = true case "quickcheck" => leon.Settings.useQuickCheck = true
case "parallel" => leon.Settings.useParallel = true case "parallel" => leon.Settings.useParallel = true
case "noverifymodel" => leon.Settings.verifyModel = false
case "imperative" => leon.Settings.synthesis = false; case "imperative" => leon.Settings.synthesis = false;
leon.Settings.transformProgram = true; leon.Settings.transformProgram = true;
case "synthesis" => leon.Settings.synthesis = true; case "synthesis" => leon.Settings.synthesis = true;
...@@ -62,7 +54,6 @@ class LeonPlugin(val global: PluginRunner) extends Plugin { ...@@ -62,7 +54,6 @@ class LeonPlugin(val global: PluginRunner) extends Plugin {
leon.Settings.stopAfterTransformation = true; leon.Settings.stopAfterTransformation = true;
case s if s.startsWith("debug=") => leon.Settings.debugLevel = try { s.substring("debug=".length, s.length).toInt } catch { case _ => 0 } case s if s.startsWith("debug=") => leon.Settings.debugLevel = try { s.substring("debug=".length, s.length).toInt } catch { case _ => 0 }
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("testbounds=") => leon.Settings.testBounds = try { val l = splitList(s.substring("testBounds=".length, s.length)).map(_.toInt); if (l.size != 2) (0, 3) else (l(0), l(1)) } catch { case _ => (0, 3) } case s if s.startsWith("testbounds=") => leon.Settings.testBounds = try { val l = splitList(s.substring("testBounds=".length, s.length)).map(_.toInt); if (l.size != 2) (0, 3) else (l(0), l(1)) } catch { case _ => (0, 3) }
case s if s.startsWith("timeout=") => leon.Settings.solverTimeout = try { Some(s.substring("timeout=".length, s.length).toInt) } catch { case _ => None } case s if s.startsWith("timeout=") => leon.Settings.solverTimeout = try { Some(s.substring("timeout=".length, s.length).toInt) } catch { case _ => None }
case s if s.startsWith("testcases=") => leon.Settings.nbTestcases = try { s.substring("testcases=".length, s.length).toInt } catch { case _ => 1 } case s if s.startsWith("testcases=") => leon.Settings.nbTestcases = try { s.substring("testcases=".length, s.length).toInt } catch { case _ => 1 }
......
...@@ -21,9 +21,29 @@ class FairZ3Solver(context : LeonContext) ...@@ -21,9 +21,29 @@ class FairZ3Solver(context : LeonContext)
with Z3ModelReconstruction with Z3ModelReconstruction
with LeonComponent { with LeonComponent {
enclosing =>
val name = "Z3-f" val name = "Z3-f"
val description = "Fair Z3 Solver" val description = "Fair Z3 Solver"
override val definedOptions : Set[LeonOptionDef] = Set(
LeonFlagOptionDef("checkmodels", "--checkmodels", "Double-check counter-examples"),
LeonFlagOptionDef("feelinglucky", "--feelinglucky", "Use evaluator to find counter-examples early")
)
val (feelingLucky, checkModels) = locally {
var lucky = false
var check = false
for(opt <- context.options) opt match {
case LeonFlagOption("checkmodels") => check = true
case LeonFlagOption("feelinglucky") => lucky = true
case _ =>
}
(lucky,check)
}
// this is fixed // this is fixed
protected[leon] val z3cfg = new Z3Config( protected[leon] val z3cfg = new Z3Config(
"MODEL" -> true, "MODEL" -> true,
...@@ -60,59 +80,6 @@ class FairZ3Solver(context : LeonContext) ...@@ -60,59 +80,6 @@ class FairZ3Solver(context : LeonContext)
} }
} }
private def prepareAxioms(solver: Z3Solver): Unit = {
assert(!Settings.noForallAxioms)
program.definedFunctions.foreach(_ match {
case fd @ Catamorphism(acd, cases) => {
assert(!fd.hasPrecondition && fd.hasImplementation)
reporter.info("Will attempt to axiomatize the function definition:")
reporter.info(fd)
for(cse <- cases) {
val (cc @ CaseClass(ccd, args), expr) = cse
assert(args.forall(_.isInstanceOf[Variable]))
val argsAsIDs = args.map(_.asInstanceOf[Variable].id)
assert(variablesOf(expr) -- argsAsIDs.toSet == Set.empty)
val axiom : Z3AST = if(args.isEmpty) {
val eq = Equals(FunctionInvocation(fd, Seq(cc)), expr)
toZ3Formula(eq).get
} else {
val z3ArgSorts = argsAsIDs.map(i => typeToSort(i.getType))
val boundVars = z3ArgSorts.zipWithIndex.map(p => z3.mkBound(p._2, p._1))
val map : Map[Identifier,Z3AST] = (argsAsIDs zip boundVars).toMap
val eq = Equals(FunctionInvocation(fd, Seq(cc)), expr)
val z3IzedEq = toZ3Formula(eq, map).get
val z3IzedCC = toZ3Formula(cc, map).get
val pattern = z3.mkPattern(functionDefToDecl(fd)(z3IzedCC))
val nameTypePairs = z3ArgSorts.map(s => (z3.mkFreshIntSymbol, s))
z3.mkForAll(0, List(pattern), nameTypePairs, z3IzedEq)
}
// println("I'll assert now an axiom: " + axiom)
// println("Case axiom:")
// println(axiom)
solver.assertCnstr(axiom)
}
if(fd.hasPostcondition) {
// we know it doesn't contain any function invocation
val cleaned = matchToIfThenElse(expandLets(fd.postcondition.get))
val argSort = typeToSort(fd.args(0).getType)
val bound = z3.mkBound(0, argSort)
val subst = replace(Map(ResultVariable() -> FunctionInvocation(fd, Seq(fd.args(0).toVariable))), cleaned)
val z3IzedPost = toZ3Formula(subst, Map(fd.args(0).id -> bound)).get
val pattern = z3.mkPattern(functionDefToDecl(fd)(bound))
val nameTypePairs = Seq((z3.mkFreshIntSymbol, argSort))
val postAxiom = z3.mkForAll(0, List(pattern), nameTypePairs, z3IzedPost)
//println("Post axiom:")
//println(postAxiom)
solver.assertCnstr(postAxiom)
}
axiomatizedFunctions += fd
}
case _ => ;
})
}
override def solve(vc: Expr) = { override def solve(vc: Expr) = {
val solver = getNewSolver val solver = getNewSolver
solver.assertCnstr(Not(vc)) solver.assertCnstr(Not(vc))
...@@ -271,17 +238,12 @@ class FairZ3Solver(context : LeonContext) ...@@ -271,17 +238,12 @@ class FairZ3Solver(context : LeonContext)
val solver = z3.mkSolver val solver = z3.mkSolver
if(!Settings.noForallAxioms) {
prepareAxioms(solver)
}
for(funDef <- program.definedFunctions) { for(funDef <- program.definedFunctions) {
if (funDef.annotations.contains("axiomatize") && !axiomatizedFunctions(funDef)) { if (funDef.annotations.contains("axiomatize") && !axiomatizedFunctions(funDef)) {
reporter.warning("Function " + funDef.id + " was marked for axiomatization but could not be handled.") reporter.warning("Function " + funDef.id + " was marked for axiomatization but could not be handled.")
} }
} }
private var frameGuards = List[Z3AST](z3.mkFreshConst("frame", z3.mkBoolSort)) private var frameGuards = List[Z3AST](z3.mkFreshConst("frame", z3.mkBoolSort))
private var frameExpressions = List[List[Expr]](Nil) private var frameExpressions = List[List[Expr]](Nil)
private var varsInVC = Set[Identifier]() private var varsInVC = Set[Identifier]()
...@@ -368,10 +330,7 @@ class FairZ3Solver(context : LeonContext) ...@@ -368,10 +330,7 @@ class FairZ3Solver(context : LeonContext)
// these are the optional sequence of assumption literals // these are the optional sequence of assumption literals
val assumptionsAsZ3: Seq[Z3AST] = frameGuards ++ assumptions.map(toZ3Formula(_).get) val assumptionsAsZ3: Seq[Z3AST] = frameGuards ++ assumptions.map(toZ3Formula(_).get)
var iterationsLeft : Int = if(Settings.unrollingLevel > 0) Settings.unrollingLevel else 16121984
while(!foundDefinitiveAnswer && !forceStop) { while(!foundDefinitiveAnswer && !forceStop) {
iterationsLeft -= 1
//val blockingSetAsZ3 : Seq[Z3AST] = blockingSet.toSeq.map(toZ3Formula(_).get) //val blockingSetAsZ3 : Seq[Z3AST] = blockingSet.toSeq.map(toZ3Formula(_).get)
// println("Blocking set : " + blockingSet) // println("Blocking set : " + blockingSet)
...@@ -398,7 +357,7 @@ class FairZ3Solver(context : LeonContext) ...@@ -398,7 +357,7 @@ class FairZ3Solver(context : LeonContext)
val z3model = solver.getModel val z3model = solver.getModel
if (Settings.verifyModel && false) { if (enclosing.checkModels) {
val (isValid, model) = validateAndDeleteModel(z3model, entireFormula, varsInVC) val (isValid, model) = validateAndDeleteModel(z3model, entireFormula, varsInVC)
if (isValid) { if (isValid) {
...@@ -432,7 +391,7 @@ class FairZ3Solver(context : LeonContext) ...@@ -432,7 +391,7 @@ class FairZ3Solver(context : LeonContext)
reporter.info("UNSAT BECAUSE: "+core.mkString(" AND ")) reporter.info("UNSAT BECAUSE: "+core.mkString(" AND "))
if (!forceStop) { if (!forceStop) {
if (Settings.luckyTest && false) { //TODO: something with false if (enclosing.feelingLucky) {
// we need the model to perform the additional test // we need the model to perform the additional test
reporter.info(" - Running search without blocked literals (w/ lucky test)") reporter.info(" - Running search without blocked literals (w/ lucky test)")
} else { } else {
...@@ -449,7 +408,7 @@ class FairZ3Solver(context : LeonContext) ...@@ -449,7 +408,7 @@ class FairZ3Solver(context : LeonContext)
foundAnswer(Some(false), core = z3CoreToCore(solver.getUnsatCore)) foundAnswer(Some(false), core = z3CoreToCore(solver.getUnsatCore))
case Some(true) => case Some(true) =>
//reporter.info("SAT WITHOUT Blockers") //reporter.info("SAT WITHOUT Blockers")
if (Settings.luckyTest && !forceStop) { //TODO: still with the above "false" if (enclosing.feelingLucky) {
// we might have been lucky :D // we might have been lucky :D
luckyTime.start luckyTime.start
val (wereWeLucky, cleanModel) = validateAndDeleteModel(solver.getModel, entireFormula, varsInVC) val (wereWeLucky, cleanModel) = validateAndDeleteModel(solver.getModel, entireFormula, varsInVC)
...@@ -470,52 +429,6 @@ class FairZ3Solver(context : LeonContext) ...@@ -470,52 +429,6 @@ class FairZ3Solver(context : LeonContext)
if(!foundDefinitiveAnswer) { if(!foundDefinitiveAnswer) {
reporter.info("- We need to keep going.") reporter.info("- We need to keep going.")
// reporter.info(" - toRelease : " + toRelease)
// reporter.info(" - blockingSet : " + blockingSet)
//var fixedForEver : Set[Expr] = Set.empty
//if(Settings.pruneBranches) {
// z3Time.start
// 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.")
// }
// z3Time.stop
//}
val toReleaseAsPairs = unrollingBank.getBlockersToUnlock val toReleaseAsPairs = unrollingBank.getBlockersToUnlock
reporter.info(" - more unrollings") reporter.info(" - more unrollings")
...@@ -533,11 +446,6 @@ class FairZ3Solver(context : LeonContext) ...@@ -533,11 +446,6 @@ class FairZ3Solver(context : LeonContext)
reporter.info(" - finished unrolling") reporter.info(" - finished unrolling")
} }
} }
if(iterationsLeft <= 0) {
reporter.error(" - Max. number of iterations reached.")
foundAnswer(None)
}
} }
totalTime.stop totalTime.stop
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment