diff --git a/src/main/scala/leon/purescala/TreeOps.scala b/src/main/scala/leon/purescala/TreeOps.scala index f3554752238134baa03b92572a750663d0396237..f69f3846e9d880aa73caa57606659a4cf1fe80c2 100644 --- a/src/main/scala/leon/purescala/TreeOps.scala +++ b/src/main/scala/leon/purescala/TreeOps.scala @@ -336,6 +336,14 @@ object TreeOps { postMap(substs.lift)(expr) } + def replaceSeq(substs: Seq[(Expr, Expr)], expr: Expr): Expr = { + var res = expr + for (s <- substs) { + res = replace(Map(s), res) + } + res + } + def replaceFromIDs(substs: Map[Identifier, Expr], expr: Expr) : Expr = { postMap( { diff --git a/src/main/scala/leon/repair/Repairman.scala b/src/main/scala/leon/repair/Repairman.scala index f216eb33d6fd413c49af61fbe4d1a279a3c5f7bb..8afe7d70a23da52f70acd6b089e02b9ab5b9d146 100644 --- a/src/main/scala/leon/repair/Repairman.scala +++ b/src/main/scala/leon/repair/Repairman.scala @@ -58,9 +58,10 @@ class Repairman(ctx: LeonContext, initProgram: Program, fd: FunDef, verifTimeout val soptions = soptions0.copy( costModel = RepairCostModel(soptions0.costModel), rules = (soptions0.rules ++ Seq( - GuidedDecomp, - GuidedCloser, - CEGLESS + //GuidedDecomp, + //GuidedCloser, + CEGLESS, + TEGLESS )) diff Seq(ADTInduction) ); @@ -149,23 +150,15 @@ class Repairman(ctx: LeonContext, initProgram: Program, fd: FunDef, verifTimeout var res: Option[(Expr, Expr)] = None // in case scrut is an non-variable expr, we simplify to a variable + inject in env - val (sid, nenv) = scrut match { - case Variable(id) => - (id, env) - case expr => - val id = FreshIdentifier("scrut", true).copiedFrom(scrut) - (id, env + (id -> scrut)) - } - for (c <- cases if res.isEmpty) { - val cond = and(conditionForPattern(sid.toVariable, c.pattern, includeBinders = false), + val cond = and(conditionForPattern(scrut, c.pattern, includeBinders = false), c.optGuard.getOrElse(BooleanLiteral(true))) - val map = mapForPattern(sid.toVariable, c.pattern) + val map = mapForPattern(scrut, c.pattern) - forAllTests(cond, nenv ++ map) match { + forAllTests(cond, env ++ map) match { case Some(true) => - val (b, r) = focus(c.rhs, nenv ++ map) + val (b, r) = focus(c.rhs, env ++ map) res = Some((MatchExpr(scrut, cases.map { c2 => if (c2 eq c) { c2.copy(rhs = b) diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala index b36573bc719f4740e4b4127e5d02b2b9e0f2590b..330ba38c0c89ba20dee64b6824677d0052851444 100644 --- a/src/main/scala/leon/synthesis/Rules.scala +++ b/src/main/scala/leon/synthesis/Rules.scala @@ -20,6 +20,7 @@ object Rules { CaseSplit, IfSplit, UnusedInput, + EquivalentInputs, UnconstrainedOutput, OptimisticGround, EqualitySplit, diff --git a/src/main/scala/leon/synthesis/rules/CegisLike.scala b/src/main/scala/leon/synthesis/rules/CegisLike.scala index cec945313f378e5401fc62463c3e73bddf1fe872..da431e8c0c14bca7346be58d523395f6dbb30fde 100644 --- a/src/main/scala/leon/synthesis/rules/CegisLike.scala +++ b/src/main/scala/leon/synthesis/rules/CegisLike.scala @@ -600,6 +600,7 @@ abstract class CEGISLike[T <% Typed](name: String) extends Rule(name) { val e = examples.next() if (!ndProgram.testForProgram(bs)(e)) { failedTestsStats(e) += 1 + //sctx.reporter.debug(" Program: "+ndProgram.determinize(bs)+" failed on "+e) wrongPrograms += bs prunedPrograms -= bs diff --git a/src/main/scala/leon/synthesis/rules/Cegless.scala b/src/main/scala/leon/synthesis/rules/Cegless.scala index b2c35de16c6fe3a822ecef487d55266743288972..9c36964a24f028f49da927370ddf214a0ed14f76 100644 --- a/src/main/scala/leon/synthesis/rules/Cegless.scala +++ b/src/main/scala/leon/synthesis/rules/Cegless.scala @@ -26,6 +26,13 @@ case object CEGLESS extends CEGISLike[Label[String]]("CEGLESS") { val inputs = p.as.map(_.toVariable) + sctx.reporter.ifDebug { printer => + printer("Guides available:") + for (g <- guides) { + printer(" - "+g) + } + } + val guidedGrammar = guides.map(SimilarTo(_, inputs.toSet, sctx, p)).foldLeft[ExpressionGrammar[Label[String]]](Empty())(_ || _) CegisParams( diff --git a/src/main/scala/leon/synthesis/rules/EquivalentInputs.scala b/src/main/scala/leon/synthesis/rules/EquivalentInputs.scala new file mode 100644 index 0000000000000000000000000000000000000000..99057db0cf2f8934450f2f46a609037264f04535 --- /dev/null +++ b/src/main/scala/leon/synthesis/rules/EquivalentInputs.scala @@ -0,0 +1,66 @@ +/* Copyright 2009-2014 EPFL, Lausanne */ + +package leon +package synthesis +package rules + +import leon.utils._ +import purescala.Trees._ +import purescala.TreeOps._ +import purescala.Extractors._ + +case object EquivalentInputs extends NormalizingRule("EquivalentInputs") { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { + val TopLevelAnds(clauses) = p.pc + + def discoverEquivalences(allClauses: Seq[Expr]): Seq[(Expr, Expr)] = { + val instanceOfs = allClauses.collect { + case ccio @ CaseClassInstanceOf(cct, s) => ccio + } + + var clauses = allClauses.filterNot(instanceOfs.toSet) + + val ccSubsts = for (CaseClassInstanceOf(cct, s) <- instanceOfs) yield { + + val fieldsVals = (for (f <- cct.fields) yield { + val id = f.id + + clauses.find { + case Equals(e, CaseClassSelector(`cct`, `s`, `id`)) => true + case _ => false + } match { + case Some(Equals(e, _)) => + Some(e) + case _ => + None + } + + }).flatten + + + if (fieldsVals.size == cct.fields.size) { + Some((s, CaseClass(cct, fieldsVals))) + } else { + None + } + } + + ccSubsts.flatten + } + + + val substs = discoverEquivalences(clauses) + + if (substs.nonEmpty) { + val simplifier = Simplifiers.bestEffort(sctx.context, sctx.program) _ + + val sub = p.copy(ws = replaceSeq(substs, p.ws), + pc = simplifier(replaceSeq(substs, p.pc)), + phi = simplifier(replaceSeq(substs, p.phi))) + + List(RuleInstantiation.immediateDecomp(p, this, List(sub), forward, this.name)) + } else { + Nil + } + } +} diff --git a/src/main/scala/leon/synthesis/rules/GuidedDecomp.scala b/src/main/scala/leon/synthesis/rules/GuidedDecomp.scala index a5a7418c218a87fa9e08acccedee547ebf5f4d9a..77ee3c002a01de67407837e90c2a33ff923f48a8 100644 --- a/src/main/scala/leon/synthesis/rules/GuidedDecomp.scala +++ b/src/main/scala/leon/synthesis/rules/GuidedDecomp.scala @@ -28,14 +28,6 @@ case object GuidedDecomp extends Rule("Guided Decomp") { val simplify = Simplifiers.bestEffort(sctx.context, sctx.program)_ - def doSubstitute(substs: Seq[(Expr, Expr)], e: Expr): Expr = { - var res = e - for (s <- substs) { - res = postMap(Map(s).lift)(res) - } - res - } - val alts = guides.collect { case g @ IfExpr(c, thn, els) => val sub1 = p.copy(ws = replace(Map(g -> thn), p.ws), pc = and(c, replace(Map(g -> thn), p.pc))) @@ -66,11 +58,11 @@ case object GuidedDecomp extends Rule("Guided Decomp") { val pc = simplify(and( scrutCond, - replace(Map(scrut0 -> scrut), doSubstitute(substs,scrutConstraint)), + replace(Map(scrut0 -> scrut), replaceSeq(substs,scrutConstraint)), replace(Map(scrut0 -> scrut), replace(Map(m -> c.rhs), andJoin(cond))) )) val ws = replace(Map(m -> c.rhs), p.ws) - val phi = doSubstitute(substs, p.phi) + val phi = replaceSeq(substs, p.phi) val free = variablesOf(and(pc, phi)) -- p.xs val asPrefix = p.as.filter(free) diff --git a/src/main/scala/leon/synthesis/rules/Tegis.scala b/src/main/scala/leon/synthesis/rules/Tegis.scala index 736b7035380dda4bbd718a257278b7dcbbb9dcae..273e170ecbf8c30aeb84bbfe63bca216e916f37f 100644 --- a/src/main/scala/leon/synthesis/rules/Tegis.scala +++ b/src/main/scala/leon/synthesis/rules/Tegis.scala @@ -16,9 +16,10 @@ import datagen._ import utils._ case object TEGIS extends TEGISLike[TypeTree]("TEGIS") { - def getGrammar(sctx: SynthesisContext, p: Problem) = { - ExpressionGrammars.default(sctx, p) + def getParams(sctx: SynthesisContext, p: Problem) = { + TegisParams( + grammar = ExpressionGrammars.default(sctx, p), + rootLabel = {(tpe: TypeTree) => tpe } + ) } - - def getRootLabel(tpe: TypeTree): TypeTree = tpe } diff --git a/src/main/scala/leon/synthesis/rules/TegisLike.scala b/src/main/scala/leon/synthesis/rules/TegisLike.scala index ed5003d47a27f4d9bb600496dd6ec4b6c14c19f3..3f55650e38646c654d788932cfcfbfae647744d3 100644 --- a/src/main/scala/leon/synthesis/rules/TegisLike.scala +++ b/src/main/scala/leon/synthesis/rules/TegisLike.scala @@ -21,19 +21,22 @@ import bonsai._ import bonsai.enumerators._ abstract class TEGISLike[T <% Typed](name: String) extends Rule(name) { - def getGrammar(sctx: SynthesisContext, p: Problem): ExpressionGrammar[T] + case class TegisParams( + grammar: ExpressionGrammar[T], + rootLabel: TypeTree => T, + enumLimit: Int = 10000, + reorderInterval: Int = 50 + ); - def getRootLabel(tpe: TypeTree): T - - val enumLimit = 10000; - val testsReorderInterval = 50; // Every X test filterings, we reorder tests with most filtering first. + def getParams(sctx: SynthesisContext, p: Problem): TegisParams def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { List(new RuleInstantiation(p, this, SolutionBuilder.none, this.name, this.priority) { def apply(sctx: SynthesisContext): RuleApplication = { - val grammar = getGrammar(sctx, p) + val params = getParams(sctx, p) + val grammar = params.grammar var tests = p.getTests(sctx).map(_.ins).distinct if (tests.nonEmpty) { @@ -53,7 +56,7 @@ abstract class TEGISLike[T <% Typed](name: String) extends Rule(name) { val timers = sctx.context.timers.synthesis.rules.tegis; - val allExprs = enum.iterator(getRootLabel(targetType)) + val allExprs = enum.iterator(params.rootLabel(targetType)) var failStat = Map[Seq[Expr], Int]().withDefaultValue(0) @@ -63,7 +66,7 @@ abstract class TEGISLike[T <% Typed](name: String) extends Rule(name) { def findNext(): Option[Expr] = { candidate = None timers.generating.start() - allExprs.take(enumLimit).takeWhile(e => candidate.isEmpty).foreach { e => + allExprs.take(params.enumLimit).takeWhile(e => candidate.isEmpty).foreach { e => val exprToTest = if (!isWrapped) { Let(p.xs.head, e, p.phi) } else { @@ -93,7 +96,7 @@ abstract class TEGISLike[T <% Typed](name: String) extends Rule(name) { } timers.testing.stop() - if (n % testsReorderInterval == 0) { + if (n % params.reorderInterval == 0) { tests = tests.sortBy(t => -failStat(t)) } n += 1 @@ -114,6 +117,7 @@ abstract class TEGISLike[T <% Typed](name: String) extends Rule(name) { RuleClosed(toStream()) } else { + sctx.reporter.debug("No test available") RuleFailed() } } diff --git a/src/main/scala/leon/synthesis/rules/Tegless.scala b/src/main/scala/leon/synthesis/rules/Tegless.scala new file mode 100644 index 0000000000000000000000000000000000000000..cdef20a9bbcd3ae89aeee0b34c76bdadf41dda49 --- /dev/null +++ b/src/main/scala/leon/synthesis/rules/Tegless.scala @@ -0,0 +1,46 @@ +/* Copyright 2009-2014 EPFL, Lausanne */ + +package leon +package synthesis +package rules + +import purescala.Trees._ +import purescala.TreeOps._ +import purescala.TypeTrees._ +import purescala.Common._ +import purescala.Definitions._ +import purescala.Extractors._ +import utils._ +import utils.ExpressionGrammars._ + +case object TEGLESS extends TEGISLike[Label[String]]("TEGLESS") { + def getParams(sctx: SynthesisContext, p: Problem) = { + + val TopLevelAnds(clauses) = p.ws + + val guide = sctx.program.library.guide.get + + val guides = clauses.collect { + case FunctionInvocation(TypedFunDef(`guide`, _), Seq(expr)) => expr + } + + val inputs = p.as.map(_.toVariable) + + sctx.reporter.ifDebug { printer => + printer("Guides available:") + for (g <- guides) { + printer(" - "+g) + } + } + + val guidedGrammar = guides.map(SimilarTo(_, inputs.toSet, sctx, p)).foldLeft[ExpressionGrammar[Label[String]]](Empty())(_ || _) + + TegisParams( + grammar = guidedGrammar, + rootLabel = { (tpe: TypeTree) => Label(tpe, "G0") } + ) + } +} + + + diff --git a/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala b/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala index f87d9e6b58bfdfa4982bb411a625d81bb10c2227..565a6c2bc6856e3dfee5430c74fde3da1afef0d7 100644 --- a/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala +++ b/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala @@ -222,7 +222,7 @@ object ExpressionGrammars { gl -> Generator(subEls.updated(i, sgl), builder) } - val swaps = if (subs.size > 1 || isCommutative(e)) { + val swaps = if (subs.size > 1 && !isCommutative(e)) { (for (i <- 0 until subs.size; j <- i+1 until subs.size) yield {