diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala index e22367b8e5dd11887e59b1a0cc5babc51fe94d52..a6993de88fc9193492e88f09953eec777e938d88 100644 --- a/src/main/scala/leon/synthesis/Rules.scala +++ b/src/main/scala/leon/synthesis/Rules.scala @@ -52,11 +52,11 @@ object Rules { //IntegerEquation, //IntegerInequalities, IntInduction, - InnerCaseSplit, + InnerCaseSplit //new OptimisticInjection(_), //new SelectiveInlining(_), //ADTLongInduction, - ADTInduction + //ADTInduction //AngelicHoles // @EK: Disabled now as it is explicit with withOracle { .. } ) diff --git a/src/main/scala/leon/synthesis/rules/CEGISLike.scala b/src/main/scala/leon/synthesis/rules/CEGISLike.scala index f178f6297d31d34e9cc352222d1b330cf7cd4db1..d6dd877201ac88f635c1e5acbd8cdfcb9b109d5f 100644 --- a/src/main/scala/leon/synthesis/rules/CEGISLike.scala +++ b/src/main/scala/leon/synthesis/rules/CEGISLike.scala @@ -227,7 +227,7 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { * the current unfolding level */ private val outerSolution = { - val part = new PartialSolution(hctx.search.g) + val part = new PartialSolution(hctx.search.g, true) e : Expr => part.solutionAround(hctx.currentNode)(e).getOrElse { sctx.reporter.fatalError("Unable to create outer solution") } @@ -439,7 +439,9 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { // Explicitly remove program computed by bValues from the search space def excludeProgram(bValues: Set[Identifier]): Unit = { - excludedPrograms += bValues + val bvs = bValues.filter(isBActive) + //println(f" (-) ${bvs.mkString(", ")}%-40s ("+getExpr(bvs)+")") + excludedPrograms += bvs } /** @@ -525,6 +527,8 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { bs = cTree.map(_._2.map(_._1)).flatten.toSet bsOrdered = bs.toSeq.sortBy(_.id) + excludedPrograms = excludedPrograms.filter(_.forall(bs)) + //debugCExpr(cTree) updateCTree() } @@ -572,6 +576,9 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { closedBs = Map[Identifier, Set[Identifier]]() + // Set of Cs that still have no active alternatives after unfolding + var postClosedCs = Set[Identifier]() + for (c <- unfoldBehind) { var alts = grammar.getProductions(labels(c)) @@ -628,6 +635,26 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { bs = bs ++ newBs bsOrdered = bs.toSeq.sortBy(_.id) + /** + * Close dead-ends + * + * Find 'c' that have no active alternatives, then close all 'b's that + * depend on such "dead" 'c's + */ + var deadCs = Set[Identifier]() + + for ((c, alts) <- cTree) { + if (alts.forall{ case (b, _, _) => !isBActive(b) }) { + deadCs += c + } + } + + for ((_, alts) <- cTree; (b, _, cs) <- alts) { + if ((cs & deadCs).nonEmpty) { + closedBs += (b -> closedBs.getOrElse(b, Set())) + } + } + //debugCExpr(cTree) updateCTree() @@ -635,8 +662,12 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { } def solveForTentativeProgram(): Option[Option[Set[Identifier]]] = { - val solver = (new FairZ3Solver(ctx, programCTree) with TimeoutSolver).setTimeout(exSolverTo) + val solver = (new FairZ3Solver(ctx, programCTree) with TimeoutSolver).setTimeout(exSolverTo) val cnstr = FunctionInvocation(phiFd.typed, phiFd.params.map(_.id.toVariable)) + //debugCExpr(cTree) + + //println(" --- PhiFD ---") + //println(phiFd.fullBody.asString(ctx)) val fixedBs = finiteArray(bsOrdered.map(_.toVariable), None, BooleanType) val cnstrFixed = replaceFromIDs(Map(bArrayId -> fixedBs), cnstr) @@ -647,19 +678,40 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { solver.assertCnstr(toFind) // oneOfBs + //println(" -- OneOf:") for ((c, alts) <- cTree) { val activeBs = alts.map(_._1).filter(isBActive) + val either = for (a1 <- activeBs; a2 <- activeBs if a1.globalId < a2.globalId) yield { + Or(Not(a1.toVariable), Not(a2.toVariable)) + } + if (activeBs.nonEmpty) { + //println(" - "+andJoin(either)) + solver.assertCnstr(andJoin(either)) + val oneOf = orJoin(activeBs.map(_.toVariable)) //println(" - "+oneOf) solver.assertCnstr(oneOf) } } + //println(" -- Excluded:") + //println(" -- Active:") + val isActive = andJoin(bsOrdered.filterNot(isBActive).map(id => Not(id.toVariable))) + //println(" - "+isActive) + solver.assertCnstr(isActive) + + + for (b <- bs.filterNot(isBActive)) { + + } + + //println(" -- Excluded:") for (ex <- excludedPrograms) { val notThisProgram = Not(andJoin(ex.map(_.toVariable).toSeq)) - //println(" - "+notThisProgram) + + //println(f" - $notThisProgram%-40s ("+getExpr(ex)+")") solver.assertCnstr(notThisProgram) } @@ -670,16 +722,21 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { val bModel = bs.filter(b => model.get(b).contains(BooleanLiteral(true))) - //println("Found potential expr: "+getExpr(bModel)+" under inputs: "+model) + //println("Tentative expr: "+getExpr(bModel)) Some(Some(bModel)) case Some(false) => - println("No Model!") + //println("UNSAT!") Some(None) case None => - println("Timeout!") - None + /** + * If the remaining tentative programs are all infeasible, it + * might timeout instead of returning Some(false). We might still + * benefit from unfolding further + */ + ctx.reporter.debug("Timeout while getting tentative program!") + Some(None) } } finally { solver.free() @@ -884,6 +941,8 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { doFilter = false result = Some(RuleClosed(sols)) case Right(cexs) => + baseExampleInputs ++= cexs + if (nPassing <= validateUpTo) { // All programs failed verification, we filter everything out and unfold //ndProgram.shrinkTo(Set(), unfolding == maxUnfoldings) @@ -929,7 +988,7 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { true } - if (true || validateWithZ3) { + if (validateWithZ3) { ndProgram.solveForCounterExample(bs) match { case Some(Some(inputsCE)) => // Found counter example! @@ -938,6 +997,8 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { // Retest whether the newly found C-E invalidates all programs if (prunedPrograms.forall(p => !ndProgram.testForProgram(p)(inputsCE))) { skipCESearch = true + } else { + ndProgram.excludeProgram(bs) } case Some(None) =>