From 3914a9a09592aa30f30c0d26978d872721def35c Mon Sep 17 00:00:00 2001 From: Manos Koukoutos <emmanouil.koukoutos@epfl.ch> Date: Tue, 9 Feb 2016 11:49:30 +0100 Subject: [PATCH] CEGIS: Skip CE search if all programs have been excluded. Also some fixes --- .../leon/synthesis/rules/CEGISLike.scala | 92 +++++-------------- 1 file changed, 21 insertions(+), 71 deletions(-) diff --git a/src/main/scala/leon/synthesis/rules/CEGISLike.scala b/src/main/scala/leon/synthesis/rules/CEGISLike.scala index 4a0a315d7..a5fceaad8 100644 --- a/src/main/scala/leon/synthesis/rules/CEGISLike.scala +++ b/src/main/scala/leon/synthesis/rules/CEGISLike.scala @@ -102,11 +102,11 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { * b3 => c6 == H(c4, c5) * * c1 -> Seq( - * (b1, F(c2, c3), Set(c2, c3)) - * (b2, G(c4, c5), Set(c4, c5)) + * (b1, F(_, _), Seq(c2, c3)) + * (b2, G(_, _), Seq(c4, c5)) * ) * c6 -> Seq( - * (b3, H(c7, c8), Set(c7, c8)) + * (b3, H(_, _), Seq(c7, c8)) * ) */ private var cTree: Map[Identifier, Seq[(Identifier, Seq[Expr] => Expr, Seq[Identifier])]] = Map() @@ -198,6 +198,7 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { } bsOrdered = bs.toSeq.sorted + excludedPrograms = ArrayBuffer() setCExpr(computeCExpr()) ctx.timers.synthesis.cegis.updateCTree.stop() @@ -250,44 +251,7 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { SeqUtils.cartesianProduct(seqs).map(_.flatten.toSet) } - def redundant(e: Expr): Boolean = { - val (op1, op2) = e match { - case Minus(o1, o2) => (o1, o2) - case Modulo(o1, o2) => (o1, o2) - case Division(o1, o2) => (o1, o2) - case BVMinus(o1, o2) => (o1, o2) - case BVRemainder(o1, o2) => (o1, o2) - case BVDivision(o1, o2) => (o1, o2) - - case And(Seq(Not(o1), Not(o2))) => (o1, o2) - case And(Seq(Not(o1), o2)) => (o1, o2) - case And(Seq(o1, Not(o2))) => (o1, o2) - case And(Seq(o1, o2)) => (o1, o2) - - case Or(Seq(Not(o1), Not(o2))) => (o1, o2) - case Or(Seq(Not(o1), o2)) => (o1, o2) - case Or(Seq(o1, Not(o2))) => (o1, o2) - case Or(Seq(o1, o2)) => (o1, o2) - - case SetUnion(o1, o2) => (o1, o2) - case SetIntersection(o1, o2) => (o1, o2) - case SetDifference(o1, o2) => (o1, o2) - - case Equals(Not(o1), Not(o2)) => (o1, o2) - case Equals(Not(o1), o2) => (o1, o2) - case Equals(o1, Not(o2)) => (o1, o2) - case Equals(o1, o2) => (o1, o2) - case _ => return false - } - - op1 == op2 - } - - allProgramsFor(Seq(rootC))/* filterNot { bs => - val res = params.optimizations && exists(redundant)(getExpr(bs)) - if (!res) excludeProgram(bs, false) - res - }*/ + allProgramsFor(Seq(rootC)) } private def debugCTree(cTree: Map[Identifier, Seq[(Identifier, Seq[Expr] => Expr, Seq[Identifier])]], @@ -377,8 +341,7 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { Lambda(p.xs.map(ValDef), p.phi) ) - - phiFd.body = Some( + phiFd.body = Some( letTuple(p.xs, FunctionInvocation(cTreeFd.typed, p.as.map(_.toVariable)), p.phi) @@ -566,6 +529,8 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { var excludedPrograms = ArrayBuffer[Set[Identifier]]() + def allProgramsClosed = allProgramsCount() <= excludedPrograms.size + // Explicitly remove program computed by bValues from the search space // // If the bValues comes from models, we make sure the bValues we exclude @@ -825,18 +790,12 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { if (hasInputExamples) { timers.filter.start() for (bs <- prunedPrograms if !interruptManager.isInterrupted) { - var valid = true val examples = allInputExamples() - while(valid && examples.hasNext) { - val e = examples.next() - if (!ndProgram.testForProgram(bs)(e)) { - failedTestsStats(e) += 1 - sctx.reporter.debug(f" Program: ${ndProgram.getExpr(bs).asString}%-80s failed on: ${e.asString}") - wrongPrograms += bs - prunedPrograms -= bs - - valid = false - } + examples.find(e => !ndProgram.testForProgram(bs)(e)).foreach { e => + failedTestsStats(e) += 1 + sctx.reporter.debug(f" Program: ${ndProgram.getExpr(bs).asString}%-80s failed on: ${e.asString}") + wrongPrograms += bs + prunedPrograms -= bs } if (wrongPrograms.size+1 % 1000 == 0) { @@ -850,14 +809,6 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { val nTotal = ndProgram.allProgramsCount() //println(s"Iotal: $nTotal, passing: $nPassing") - /*locally { - val progs = ndProgram.allPrograms() map ndProgram.getExpr - val ground = progs count isGround - println("Programs") - progs take 100 foreach println - println(s"$ground ground out of $nTotal") - }*/ - sctx.reporter.debug(s"#Programs passing tests: $nPassing out of $nTotal") sctx.reporter.ifDebug{ printer => for (p <- prunedPrograms.take(100)) { @@ -898,14 +849,11 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { val newCexs = cexs.map(InExample) baseExampleInputs ++= newCexs // Retest whether the newly found C-E invalidates some programs - for (p <- otherPrograms) { - // Exclude any programs that fail the new cex's - var valid = true - newCexs.takeWhile(_ => valid).foreach { cex => - if (!ndProgram.testForProgram(p)(cex)) { - ndProgram.excludeProgram(p, true) - valid = false - } + for (p <- otherPrograms if !interruptManager.isInterrupted) { + // Exclude any programs that fail at least one new cex + newCexs.find { cex => !ndProgram.testForProgram(p)(cex) }.foreach { cex => + failedTestsStats(cex) += 1 + ndProgram.excludeProgram(p, true) } } // If we excluded all programs, we can skip CE search @@ -921,7 +869,7 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { } // CEGIS Loop at a given unfolding level - while (result.isEmpty && !skipCESearch && !interruptManager.isInterrupted) { + while (result.isEmpty && !skipCESearch && !interruptManager.isInterrupted && !ndProgram.allProgramsClosed) { timers.loop.start() ndProgram.solveForTentativeProgram() match { case Some(Some(bs)) => @@ -968,12 +916,14 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) { case None => result = Some(RuleFailed()) } + timers.loop.stop() } unfolding += 1 } while(unfolding <= maxSize && result.isEmpty && !interruptManager.isInterrupted) + if (interruptManager.isInterrupted) interruptManager.recoverInterrupt() result.getOrElse(RuleFailed()) } catch { -- GitLab