From dd8b19484dd2944628e4183178f41c3d13f9b8a7 Mon Sep 17 00:00:00 2001 From: Etienne Kneuss <etienne.kneuss@epfl.ch> Date: Mon, 15 Dec 2014 19:12:07 +0100 Subject: [PATCH] Fix forAllTests, improve tests printing --- src/main/scala/leon/repair/Repairman.scala | 45 +++++++------------ .../scala/leon/synthesis/InOutExample.scala | 23 ++++++++++ src/main/scala/leon/utils/GraphOps.scala | 6 +-- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/main/scala/leon/repair/Repairman.scala b/src/main/scala/leon/repair/Repairman.scala index 10c94e7cc..c88913162 100644 --- a/src/main/scala/leon/repair/Repairman.scala +++ b/src/main/scala/leon/repair/Repairman.scala @@ -141,18 +141,9 @@ class Repairman(ctx: LeonContext, initProgram: Program, fd: FunDef, verifTimeout private def focusRepair(program: Program, fd: FunDef, passingTests: List[Example], failingTests: List[Example]): (Expr, Expr) = { reporter.ifDebug { printer => - printer(title("Tests failing are: ")) - failingTests.foreach { ex => - printer(ex.ins.mkString(", ")) - } - } - reporter.ifDebug { printer => - printer(title("Tests passing are: ")) - passingTests.foreach { ex => - printer(ex.ins.mkString(", ")) - } + printer(new ExamplesTable("Tests failing:", failingTests).toString) + printer(new ExamplesTable("Tests passing:", passingTests).toString) } - val pre = fd.precondition.getOrElse(BooleanLiteral(true)) val args = fd.params.map(_.id) @@ -168,6 +159,7 @@ class Repairman(ctx: LeonContext, initProgram: Program, fd: FunDef, verifTimeout val evaluator = new DefaultEvaluator(ctx, program) + // We exclude redundant failing tests, and only select the minimal tests val minimalFailingTests = { // We don't want tests whose invocation will call other failing tests. // This is because they will appear erroneous, @@ -179,24 +171,24 @@ class Repairman(ctx: LeonContext, initProgram: Program, fd: FunDef, verifTimeout case _ => None } } - + val passingTs = for (test <- passingTests) yield InExample(test.ins) val failingTs = for (test <- failingTests) yield InExample(test.ins) - + val test2Tests : Map[InExample, Set[InExample]] = (failingTs ++ passingTs).map{ ts => testEval.eval(body, args.zip(ts.ins).toMap) (ts, testEval.collected map (InExample(_))) }.toMap - + val recursiveTests : Set[InExample] = test2Tests.values.toSet.flatten -- (failingTs ++ passingTs) - + val testsTransitive : Map[InExample,Set[InExample]] = leon.utils.GraphOps.transitiveClosure[InExample]( test2Tests ++ recursiveTests.map ((_,Set[InExample]())) ) - + val knownWithResults : Map[InExample, Boolean] = (failingTs.map((_, false)).toMap) ++ (passingTs.map((_,true))) - + val recWithResults : Map[InExample, Boolean] = recursiveTests.map { ex => (ex, evaluator.eval(spec, (args zip ex.ins).toMap + (out -> body)) match { case EvaluationResults.Successful(BooleanLiteral(true)) => true @@ -205,19 +197,16 @@ class Repairman(ctx: LeonContext, initProgram: Program, fd: FunDef, verifTimeout }.toMap val allWithResults = knownWithResults ++ recWithResults - - - testsTransitive.collect { + + + testsTransitive.collect { case (rest, called) if !allWithResults(rest) && (called forall allWithResults) => rest - }.toSet + }.toSeq } - + reporter.ifDebug { printer => - printer(title("MinimalTests are: ")) - minimalFailingTests.foreach { ex => - printer(ex.ins.mkString(", ")) - } + printer(new ExamplesTable("Minimal failing:", minimalFailingTests).toString) } // Check how an expression behaves on tests @@ -230,9 +219,9 @@ class Repairman(ctx: LeonContext, initProgram: Program, fd: FunDef, verifTimeout evaluator.eval(e, env ++ (args zip ins)) match { case EvaluationResults.Successful(BooleanLiteral(true)) => Some(true) case EvaluationResults.Successful(BooleanLiteral(false)) => Some(false) - case _ => None + case e => None } - } + }.distinct if (results.size == 1) { results.head diff --git a/src/main/scala/leon/synthesis/InOutExample.scala b/src/main/scala/leon/synthesis/InOutExample.scala index 932801c89..c68590fbd 100644 --- a/src/main/scala/leon/synthesis/InOutExample.scala +++ b/src/main/scala/leon/synthesis/InOutExample.scala @@ -4,8 +4,31 @@ package leon package synthesis import purescala.Trees._ +import leon.utils.ASCIIHelpers._ class Example(val ins: Seq[Expr]) case class InOutExample(is: Seq[Expr], val outs: Seq[Expr]) extends Example(is) case class InExample(is: Seq[Expr]) extends Example(is) +class ExamplesTable(title: String, ts: Seq[Example]) { + override def toString = { + var tt = new Table(title) + + for (t <- ts) { + val os = t match { + case InOutExample(_, outs) => + outs.map(Cell(_)) + case _ => + Seq(Cell("?")) + } + + tt += Row( + t.ins.map(Cell(_)) ++ Seq(Cell("->")) ++ os + ) + } + + tt.render + } + +} + diff --git a/src/main/scala/leon/utils/GraphOps.scala b/src/main/scala/leon/utils/GraphOps.scala index 505829e57..33fcb73f2 100644 --- a/src/main/scala/leon/utils/GraphOps.scala +++ b/src/main/scala/leon/utils/GraphOps.scala @@ -22,7 +22,8 @@ object GraphOps { } tSort(toPreds, Seq()) } - + + def transitiveClosure[A](graph: Map[A,Set[A]]) : Map[A,Set[A]] = { def step(graph : Map[A, Set[A]]) : Map[A,Set[A]] = graph map { case (k, vs) => (k, vs ++ (vs flatMap { v => @@ -39,7 +40,6 @@ object GraphOps { def sinks[A](graph : Map[A,Set[A]]) = graph.collect{ case (v, out) if out.isEmpty => v }.toSet - /** * Returns the set of reachable nodes from a given node, * not including the node itself (unless it is member of a cycle) @@ -73,4 +73,4 @@ object GraphOps { rec(source) } -} \ No newline at end of file +} -- GitLab