diff --git a/src/test/scala/leon/test/synthesis/RuleApplicationSuite.scala b/src/test/scala/leon/test/synthesis/RuleApplicationSuite.scala index 827accc66a500dd487aaa740c3d9de8dfb005fef..fa1305579b78742c870cdf41f4fd3a773f1c4633 100644 --- a/src/test/scala/leon/test/synthesis/RuleApplicationSuite.scala +++ b/src/test/scala/leon/test/synthesis/RuleApplicationSuite.scala @@ -5,105 +5,47 @@ import leon.purescala.Definitions._ import leon.purescala.Trees._ import leon.purescala.TreeOps._ import leon.solvers.z3._ +import leon.solvers.Solver import leon.synthesis._ import org.scalatest.FunSuite +import org.scalatest.matchers.ShouldMatchers._ import java.io.{BufferedWriter, FileWriter, File} -class SynthesisTestPhase(val options: SynthesizerOptions, - val rules: Set[Rule]) extends LeonPhase[Program, Map[Choose, (Solution, Boolean)]] { - val name = "Synthesis-test" - val description = "Synthesis-test" +object ExtractProblemsPhase extends LeonPhase[Program, (Map[FunDef, Seq[Problem]], Solver)] { + val name = "Synthesis Problem Extraction" + val description = "Synthesis Problem Extraction" - def run(ctx: LeonContext)(p: Program): Map[Choose, (Solution, Boolean)] = { - val silentContext : LeonContext = ctx.copy(reporter = new SilentReporter) + def run(ctx: LeonContext)(p: Program): (Map[FunDef, Seq[Problem]], Solver) = { - val mainSolver = new FairZ3Solver(silentContext) - mainSolver.setProgram(p) + val silentContext : LeonContext = ctx.copy(reporter = new SilentReporter) + val mainSolver = new FairZ3Solver(silentContext) + mainSolver.setProgram(p) - val uninterpretedZ3 = new UninterpretedZ3Solver(silentContext) - uninterpretedZ3.setProgram(p) + var results = Map[FunDef, Seq[Problem]]() + def noop(u:Expr, u2: Expr) = u - def synthesizeAll(program: Program): Map[Choose, (Solution, Boolean)] = { - def noop(u:Expr, u2: Expr) = u - var solutions = Map[Choose, (Solution, Boolean)]() + def actOnChoose(f: FunDef)(e: Expr, a: Expr): Expr = e match { + case ch @ Choose(vars, pred) => + val problem = Problem.fromChoose(ch) - def actOnChoose(f: FunDef)(e: Expr, a: Expr): Expr = e match { - case ch @ Choose(vars, pred) => - val problem = Problem.fromChoose(ch) - val synth = new Synthesizer(ctx, - mainSolver, - p, - problem, - rules, - options) - val (sol, isComplete) = synth.synthesize() + results += f -> (results.getOrElse(f, Seq()) :+ problem) - solutions += ch -> (sol, isComplete) - - a - case _ => - a - } - - // Look for choose() - for (f <- program.definedFunctions.sortBy(_.id.toString) if f.body.isDefined) { - if (options.filterFuns.isEmpty || options.filterFuns.get.contains(f.id.toString)) { - treeCatamorphism(x => x, noop, actOnChoose(f), f.body.get) - } - } - - solutions + a + case _ => + a } - synthesizeAll(p) - } -} - -class SynthesisRuleTestPhase(val options: SynthesizerOptions, - val rule: Rule) extends LeonPhase[Program, Map[Choose, RuleResult]] { - val name = "Synthesis-test" - val description = "Synthesis-test" - - def run(ctx: LeonContext)(p: Program): Map[Choose, RuleResult] = { - - val silentContext : LeonContext = ctx.copy(reporter = new SilentReporter) - val mainSolver = new FairZ3Solver(silentContext) - mainSolver.setProgram(p) - - def synthesizeAll(program: Program): Map[Choose, RuleResult] = { - def noop(u:Expr, u2: Expr) = u - - var results = Map[Choose, RuleResult]() - - - def actOnChoose(f: FunDef)(e: Expr, a: Expr): Expr = e match { - case ch @ Choose(vars, pred) => - val problem = Problem.fromChoose(ch) - - val sctx = SynthesisContext(mainSolver, silentContext.reporter) - - results += ch -> rule.attemptToApplyOn(sctx, problem) - - a - case _ => - a - } - - // Look for choose() - for (f <- program.definedFunctions.sortBy(_.id.toString) if f.body.isDefined) { - if (options.filterFuns.isEmpty || options.filterFuns.get.contains(f.id.toString)) { - treeCatamorphism(x => x, noop, actOnChoose(f), f.body.get) - } - } - - results + // Look for choose() + for (f <- p.definedFunctions.sortBy(_.id.toString) if f.body.isDefined) { + treeCatamorphism(x => x, noop, actOnChoose(f), f.body.get) } - synthesizeAll(p) + (results, mainSolver) } + } class SynthesisSuite extends FunSuite { @@ -113,39 +55,19 @@ class SynthesisSuite extends FunSuite { counter } - def synthesisSearch(file: File, rules: Set[Rule])(block: Map[Choose, (Solution, Boolean)] => Unit) { - val fullName = file.getPath() - val start = fullName.indexOf("synthesis") - - val displayName = if(start != -1) { - fullName.substring(start, fullName.length) - } else { - fullName - } - - test("Synthesizing %3d: [%s]".format(nextInt(), displayName)) { - assert(file.exists && file.isFile && file.canRead, - "Benchmark [%s] is not a readable file".format(displayName)) - - val ctx = LeonContext( - settings = Settings( - synthesis = true, - xlang = false, - verify = false - ), - files = List(file), - reporter = new SilentReporter - ) - - val opts = SynthesizerOptions() - val pipeline = leon.plugin.ExtractionPhase andThen new SynthesisTestPhase(opts, rules) + def testFile(file: String): (((Solver, FunDef, Problem) => Unit) => Unit) = testFile{ + val res = this.getClass.getClassLoader.getResource(file) - block(pipeline.run(ctx)("--synthesize" :: file.getPath :: Nil)) + if(res == null || res.getProtocol != "file") { + assert(false, "Tests have to be run from within `sbt`, for otherwise " + + "the test files will be harder to access (and we dislike that).") } + + new File(res.toURI) } - def synthesisStep(file: File, rule: Rule)(block: Map[Choose, RuleResult] => Unit) { + def testFile(file: File)(block: (Solver, FunDef, Problem) => Unit) { val fullName = file.getPath() val start = fullName.indexOf("synthesis") @@ -159,6 +81,7 @@ class SynthesisSuite extends FunSuite { assert(file.exists && file.isFile && file.canRead, "Benchmark [%s] is not a readable file".format(displayName)) + val ctx = LeonContext( settings = Settings( synthesis = true, @@ -171,35 +94,43 @@ class SynthesisSuite extends FunSuite { val opts = SynthesizerOptions() - val pipeline = leon.plugin.ExtractionPhase andThen new SynthesisRuleTestPhase(opts, rule) + val pipeline = leon.plugin.ExtractionPhase andThen ExtractProblemsPhase - block(pipeline.run(ctx)("--synthesize" :: file.getPath :: Nil)) + val (results, solver) = pipeline.run(ctx)(file.getPath :: Nil) + + for ((f, ps) <- results; p <- ps) { + block(solver, f, p) + } } } - def assertInnaplicable(rr: RuleResult) { - assert(rr.alternatives.forall(alt => alt.apply() == RuleApplicationImpossible) === true, "Rule was applicable") + def synthesisStep(s: Solver, r: Rule, p: Problem): RuleResult = { + val sctx = SynthesisContext(s, new SilentReporter) + r.attemptToApplyOn(sctx, p) } - def assertSuccess(rr: RuleResult) { + def assertRuleSuccess(rr: RuleResult) { assert(rr.alternatives.isEmpty === false, "No rule alternative while the rule should have succeeded") assert(rr.alternatives.exists(alt => alt.apply().isInstanceOf[RuleSuccess]) === true, "Rule did not succeed") } - def fileFor(name: String): File = { - val res = this.getClass.getClassLoader.getResource(name) - if(res == null || res.getProtocol != "file") { - assert(false, "Tests have to be run from within `sbt`, for otherwise " + - "the test files will be harder to access (and we dislike that).") - } + def assertFastEnough(rr: RuleResult, timeoutMs: Long) { + for (alt <- rr.alternatives) { + val ts = System.currentTimeMillis - new File(res.toURI) - } + val res = alt.apply() - synthesisStep(fileFor("synthesis/Cegis1.scala"), rules.CEGIS) { res => - for ((ch, rr) <- res) { - assertSuccess(rr) + val t = System.currentTimeMillis - ts + + t should be <= timeoutMs } } + + + testFile("synthesis/Cegis1.scala") { + case (solver, fd, p) => + assertRuleSuccess(synthesisStep(solver, rules.CEGIS, p)) + assertFastEnough(synthesisStep(solver, rules.CEGIS, p), 100) + } }