diff --git a/src/main/scala/leon/synthesis/CostModel.scala b/src/main/scala/leon/synthesis/CostModel.scala index 447da1fb9358f476c8f4bbb378b9c84d19f90ac7..e997d99761cc89862731de51c29194d4a452e365 100644 --- a/src/main/scala/leon/synthesis/CostModel.scala +++ b/src/main/scala/leon/synthesis/CostModel.scala @@ -10,11 +10,11 @@ abstract class CostModel(val name: String) { def solutionCost(s: Solution): Cost def problemCost(p: Problem): Cost - def ruleAppCost(r: Rule, app: RuleApplication): Cost = new Cost { - val subSols = (1 to app.subProblemsCount).map {i => Solution.simplest }.toList + def ruleAppCost(r: Rule, app: RuleInstantiation): Cost = new Cost { + val subSols = (1 to app.onSuccess.arity).map {i => Solution.simplest }.toList val simpleSol = app.onSuccess(subSols) - val value = solutionCost(simpleSol).value + val value = simpleSol.map(solutionCost(_).value).getOrElse(0) } } diff --git a/src/main/scala/leon/synthesis/Heuristics.scala b/src/main/scala/leon/synthesis/Heuristics.scala index f8dc04423a566e55dd38205131d4c089c79fb394..706ed0f6cd979adffcbfef8567265badbb387201 100644 --- a/src/main/scala/leon/synthesis/Heuristics.scala +++ b/src/main/scala/leon/synthesis/Heuristics.scala @@ -21,34 +21,31 @@ trait Heuristic { } -object HeuristicStep { - def verifyPre(sctx: SynthesisContext, problem: Problem)(s: Solution): Solution = { - //sctx here is unsafe to use in parallel. onSuccess should take a sctx for - //this to be possible - +object HeuristicInstantiation { + def verifyPre(sctx: SynthesisContext, problem: Problem)(s: Solution): Option[Solution] = { //sctx.solver.solveSAT(And(Not(s.pre), problem.phi)) match { // case (Some(true), model) => // sctx.reporter.warning("Heuristic failed to produce weakest precondition:") // sctx.reporter.warning(" - problem: "+problem) // sctx.reporter.warning(" - precondition: "+s.pre) - // s + // None // case _ => - // s + // Some(s) //} - s + + Some(s) } - def apply(sctx: SynthesisContext, problem: Problem, subProblems: List[Problem], onSuccess: List[Solution] => Solution) = { - new RuleApplication(subProblems.size, onSuccess.andThen(verifyPre(sctx, problem))) { - def apply(sctx: SynthesisContext) = RuleDecomposed(subProblems, onSuccess) + def apply(problem: Problem, subProblems: List[Problem], onSuccess: List[Solution] => Solution) = { + val builder = new SolutionBuilder(subProblems.size) { + def apply(sols: List[Solution]) = { + Some(onSuccess(sols)) + } } - } -} + new RuleInstantiation(builder) { + def apply(sctx: SynthesisContext) = RuleDecomposed(subProblems) -object HeuristicFastStep { - def apply(sctx: SynthesisContext, problem: Problem, subProblems: List[Problem], onSuccess: List[Solution] => Solution) = { - RuleResult(List(HeuristicStep(sctx, problem, subProblems, onSuccess))) + } } } - diff --git a/src/main/scala/leon/synthesis/ParallelSearch.scala b/src/main/scala/leon/synthesis/ParallelSearch.scala index 31ddf1fbbc7cc3be351e249392726d4ee954fa0b..0c48bd42a1cb331b4c4ceabee03e50d149f7fe90 100644 --- a/src/main/scala/leon/synthesis/ParallelSearch.scala +++ b/src/main/scala/leon/synthesis/ParallelSearch.scala @@ -34,7 +34,7 @@ class ParallelSearch(synth: Synthesizer, } ExpandSuccess(sol) - case RuleDecomposed(sub, onSuccess) => + case RuleDecomposed(sub) => synth.synchronized { info(prefix+"Got: "+t.problem) info(prefix+"Decomposed into:") @@ -52,7 +52,7 @@ class ParallelSearch(synth: Synthesizer, def expandOrTask(ref: ActorRef, sctx: SynthesisContext)(t: TaskTryRules) = { val sub = rules.flatMap { r => - r.attemptToApplyOn(sctx, t.p).alternatives.map(TaskRunRule(t.p, r, _)) + r.instantiateOn(sctx, t.p).map(TaskRunRule(t.p, r, _)) } if (!sub.isEmpty) { diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala index 3d2836c896ea52da7547cb04be6a24aa1350ef58..af348baf8edc03ba210a9e0b66d96f7dad78439d 100644 --- a/src/main/scala/leon/synthesis/Rules.scala +++ b/src/main/scala/leon/synthesis/Rules.scala @@ -27,54 +27,56 @@ object Rules { ) } -case class RuleResult(alternatives: Traversable[RuleApplication]) -object RuleInapplicable extends RuleResult(List()) +abstract class SolutionBuilder(val arity: Int) { + def apply(sols: List[Solution]): Option[Solution] +} -abstract class RuleApplication(val subProblemsCount: Int, - val onSuccess: List[Solution] => Solution) { +class SolutionCombiner(arity: Int, f: List[Solution] => Solution) extends SolutionBuilder(arity) { + def apply(sols: List[Solution]) = { + assert(sols.size == arity) + Some(f(sols)) + } +} +object SolutionBuilder { + val none = new SolutionBuilder(0) { + def apply(sols: List[Solution]) = None + } +} + +abstract class RuleInstantiation(val onSuccess: SolutionBuilder) { def apply(sctx: SynthesisContext): RuleApplicationResult } -abstract class RuleImmediateApplication extends RuleApplication(0, s => Solution.simplest) +//abstract class RuleApplication(val subProblemsCount: Int, +// val onSuccess: List[Solution] => Solution) { +// +// def apply(sctx: SynthesisContext): RuleApplicationResult +//} +// +//abstract class RuleImmediateApplication extends RuleApplication(0, s => Solution.simplest) sealed abstract class RuleApplicationResult -case class RuleSuccess(solution: Solution) extends RuleApplicationResult -case class RuleDecomposed(sub: List[Problem], onSuccess: List[Solution] => Solution) extends RuleApplicationResult -case object RuleApplicationImpossible extends RuleApplicationResult +case class RuleSuccess(solution: Solution) extends RuleApplicationResult +case class RuleDecomposed(sub: List[Problem]) extends RuleApplicationResult +case object RuleApplicationImpossible extends RuleApplicationResult -object RuleFastApplication { - def apply(sub: List[Problem], onSuccess: List[Solution] => Solution) = { - new RuleApplication(sub.size, onSuccess) { - def apply(sctx: SynthesisContext) = RuleDecomposed(sub, onSuccess) +object RuleInstantiation { + def immediateDecomp(sub: List[Problem], onSuccess: List[Solution] => Solution) = { + new RuleInstantiation(new SolutionCombiner(sub.size, onSuccess)) { + def apply(sctx: SynthesisContext) = RuleDecomposed(sub) } } -} - -object RuleFastInapplicable { - def apply() = { - RuleResult(List(new RuleApplication(0, ls => Solution.simplest) { - def apply(sctx: SynthesisContext) = RuleApplicationImpossible - })) - } -} -object RuleFastStep { - def apply(sub: List[Problem], onSuccess: List[Solution] => Solution) = { - RuleResult(List(RuleFastApplication(sub, onSuccess))) - } -} - -object RuleFastSuccess { - def apply(solution: Solution) = { - RuleResult(List(new RuleApplication(0, ls => solution) { + def immediateSuccess(solution: Solution) = { + new RuleInstantiation(new SolutionCombiner(0, ls => solution)) { def apply(sctx: SynthesisContext) = RuleSuccess(solution) - })) + } } } abstract class Rule(val name: String, val priority: Priority) { - def attemptToApplyOn(sctx: SynthesisContext, problem: Problem): RuleResult + def instantiateOn(scrx: SynthesisContext, problem: Problem): Traversable[RuleInstantiation] def subst(what: Tuple2[Identifier, Expr], in: Expr): Expr = replace(Map(Variable(what._1) -> what._2), in) def substAll(what: Map[Identifier, Expr], in: Expr): Expr = replace(what.map(w => Variable(w._1) -> w._2), in) diff --git a/src/main/scala/leon/synthesis/SimpleSearch.scala b/src/main/scala/leon/synthesis/SimpleSearch.scala index d92de1d1e8601fdc932368fe0ac20e9d71107807..bc254e2fa594e5e7a51d38c846e8000c95d444d0 100644 --- a/src/main/scala/leon/synthesis/SimpleSearch.scala +++ b/src/main/scala/leon/synthesis/SimpleSearch.scala @@ -3,8 +3,8 @@ package synthesis import synthesis.search._ -case class TaskRunRule(problem: Problem, rule: Rule, app: RuleApplication) extends AOAndTask[Solution] { - def composeSolution(sols: List[Solution]): Solution = { +case class TaskRunRule(problem: Problem, rule: Rule, app: RuleInstantiation) extends AOAndTask[Solution] { + def composeSolution(sols: List[Solution]): Option[Solution] = { app.onSuccess(sols) } @@ -44,7 +44,7 @@ class SimpleSearch(synth: Synthesizer, info(prefix+"Solved with: "+sol) ExpandSuccess(sol) - case RuleDecomposed(sub, onSuccess) => + case RuleDecomposed(sub) => info(prefix+"Got: "+t.problem) info(prefix+"Decomposed into:") for(p <- sub) { @@ -59,7 +59,7 @@ class SimpleSearch(synth: Synthesizer, } def expandOrTask(t: TaskTryRules): ExpandResult[TaskRunRule] = { - val sub = rules.flatMap ( r => r.attemptToApplyOn(sctx, t.p).alternatives.map(TaskRunRule(t.p, r, _)) ) + val sub = rules.flatMap ( r => r.instantiateOn(sctx, t.p).map(TaskRunRule(t.p, r, _)) ) if (!sub.isEmpty) { Expanded(sub.toList) diff --git a/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala b/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala index aec4b610b7ceb6e0eb68be1f5ed69a8ace8db502..02bff49b479589a98371e383eb6c2d6c706cf23b 100644 --- a/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala +++ b/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala @@ -10,7 +10,7 @@ import purescala.TypeTrees._ import purescala.Definitions._ case object ADTInduction extends Rule("ADT Induction", 80) with Heuristic { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val candidates = p.as.collect { case IsTyped(origId, AbstractClassType(cd)) => (origId, cd) } @@ -97,12 +97,12 @@ case object ADTInduction extends Rule("ADT Induction", 80) with Heuristic { Solution(Or(globalPre), sols.flatMap(_.defs).toSet+newFun, FunctionInvocation(newFun, p.as.map(Variable(_)))) } - Some(HeuristicStep(sctx, p, subProblemsInfo.map(_._1).toList, onSuccess)) + Some(HeuristicInstantiation(p, subProblemsInfo.map(_._1).toList, onSuccess)) } else { None } } - RuleResult(steps.flatten) + steps.flatten } } diff --git a/src/main/scala/leon/synthesis/heuristics/IntInduction.scala b/src/main/scala/leon/synthesis/heuristics/IntInduction.scala index 9d708689a8941e14e4dc400e9e0afb3c2e6136f4..a4c7f9cf2eb6704df288b0300c994f7f40557200 100644 --- a/src/main/scala/leon/synthesis/heuristics/IntInduction.scala +++ b/src/main/scala/leon/synthesis/heuristics/IntInduction.scala @@ -10,7 +10,7 @@ import purescala.TypeTrees._ import purescala.Definitions._ case object IntInduction extends Rule("Int Induction", 50) with Heuristic { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { p.as match { case List(IsTyped(origId, Int32Type)) => val tpe = TupleType(p.xs.map(_.getType)) @@ -54,9 +54,9 @@ case object IntInduction extends Rule("Int Induction", 50) with Heuristic { Solution.none } - HeuristicFastStep(sctx, p, List(subBase, subGT, subLT), onSuccess) + Some(HeuristicInstantiation(p, List(subBase, subGT, subLT), onSuccess)) case _ => - RuleInapplicable + None } } } diff --git a/src/main/scala/leon/synthesis/heuristics/OptimisticInjection.scala b/src/main/scala/leon/synthesis/heuristics/OptimisticInjection.scala index 1378649d435385c792865a78f8adea5ee887177a..494e0979af3fe28303c93160c83d91df3b373413 100644 --- a/src/main/scala/leon/synthesis/heuristics/OptimisticInjection.scala +++ b/src/main/scala/leon/synthesis/heuristics/OptimisticInjection.scala @@ -10,7 +10,7 @@ import purescala.TypeTrees._ import purescala.Definitions._ case object OptimisticInjection extends Rule("Opt. Injection", 50) with Heuristic { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val TopLevelAnds(exprs) = p.phi val eqfuncalls = exprs.collect{ @@ -36,9 +36,9 @@ case object OptimisticInjection extends Rule("Opt. Injection", 50) with Heuristi val sub = p.copy(phi = And(newExprs)) - HeuristicFastStep(sctx, p, List(sub), forward) + Some(HeuristicInstantiation(p, List(sub), forward)) } else { - RuleInapplicable + None } } } diff --git a/src/main/scala/leon/synthesis/heuristics/SelectiveInlining.scala b/src/main/scala/leon/synthesis/heuristics/SelectiveInlining.scala index 5961d6777a37237e6e05aed48e1f7a96c2cdc713..44ceb787964d3de4097217474b68129d524dd5d7 100644 --- a/src/main/scala/leon/synthesis/heuristics/SelectiveInlining.scala +++ b/src/main/scala/leon/synthesis/heuristics/SelectiveInlining.scala @@ -10,7 +10,7 @@ import purescala.TypeTrees._ import purescala.Definitions._ case object SelectiveInlining extends Rule("Sel. Inlining", 20) with Heuristic { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val TopLevelAnds(exprs) = p.phi val eqfuncalls = exprs.collect{ @@ -36,9 +36,9 @@ case object SelectiveInlining extends Rule("Sel. Inlining", 20) with Heuristic { val sub = p.copy(phi = And(newExprs)) - HeuristicFastStep(sctx, p, List(sub), forward) + Some(HeuristicInstantiation(p, List(sub), forward)) } else { - RuleInapplicable + None } } } diff --git a/src/main/scala/leon/synthesis/rules/ADTDual.scala b/src/main/scala/leon/synthesis/rules/ADTDual.scala index 0660f87a8819b9130cf9f419278b88c21988b874..78573c819d24fa57d36c10dc641c7951f365a054 100644 --- a/src/main/scala/leon/synthesis/rules/ADTDual.scala +++ b/src/main/scala/leon/synthesis/rules/ADTDual.scala @@ -7,7 +7,7 @@ import purescala.TreeOps._ import purescala.Extractors._ case object ADTDual extends Rule("ADTDual", 200) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val xs = p.xs.toSet val as = p.as.toSet @@ -24,9 +24,9 @@ case object ADTDual extends Rule("ADTDual", 200) { if (!toRemove.isEmpty) { val sub = p.copy(phi = And((exprs.toSet -- toRemove ++ toAdd.flatten).toSeq)) - RuleFastStep(List(sub), forward) + List(RuleInstantiation.immediateDecomp(List(sub), forward)) } else { - RuleInapplicable + Nil } } } diff --git a/src/main/scala/leon/synthesis/rules/ADTSplit.scala b/src/main/scala/leon/synthesis/rules/ADTSplit.scala index 6a4d88c7a28f471d48d7508c6d94719de4885290..631fe979a6be3c9934ded19e3898b16542764fbc 100644 --- a/src/main/scala/leon/synthesis/rules/ADTSplit.scala +++ b/src/main/scala/leon/synthesis/rules/ADTSplit.scala @@ -10,7 +10,7 @@ import purescala.Extractors._ import purescala.Definitions._ case object ADTSplit extends Rule("ADT Split.", 70) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation]= { val candidates = p.as.collect { case IsTyped(id, AbstractClassType(cd)) => @@ -42,7 +42,7 @@ case object ADTSplit extends Rule("ADT Split.", 70) { } - val steps = candidates.collect{ _ match { + candidates.collect{ _ match { case Some((id, cases)) => val oas = p.as.filter(_ != id) @@ -70,11 +70,9 @@ case object ADTSplit extends Rule("ADT Split.", 70) { Solution(Or(globalPre), sols.flatMap(_.defs).toSet, MatchExpr(Variable(id), cases)) } - Some(RuleFastApplication(subInfo.map(_._2).toList, onSuccess)) + Some(RuleInstantiation.immediateDecomp(subInfo.map(_._2).toList, onSuccess)) case _ => None }}.flatten - - RuleResult(steps) } } diff --git a/src/main/scala/leon/synthesis/rules/Assert.scala b/src/main/scala/leon/synthesis/rules/Assert.scala index 04459435e5f505f1ceca76fca4319dd66cf54050..962e090ae850695e9e4c1beae4e2cfb9dd9fda3b 100644 --- a/src/main/scala/leon/synthesis/rules/Assert.scala +++ b/src/main/scala/leon/synthesis/rules/Assert.scala @@ -7,7 +7,7 @@ import purescala.TreeOps._ import purescala.Extractors._ case object Assert extends Rule("Assert", 200) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { p.phi match { case TopLevelAnds(exprs) => val xsSet = p.xs.toSet @@ -16,20 +16,20 @@ case object Assert extends Rule("Assert", 200) { if (!exprsA.isEmpty) { if (others.isEmpty) { - RuleFastSuccess(Solution(And(exprsA), Set(), Tuple(p.xs.map(id => simplestValue(Variable(id)))))) + List(RuleInstantiation.immediateSuccess(Solution(And(exprsA), Set(), Tuple(p.xs.map(id => simplestValue(Variable(id))))))) } else { val sub = p.copy(pc = And(p.pc +: exprsA), phi = And(others)) - RuleFastStep(List(sub), { + List(RuleInstantiation.immediateDecomp(List(sub), { case Solution(pre, defs, term) :: Nil => Solution(And(exprsA :+ pre), defs, term) case _ => Solution.none - }) + })) } } else { - RuleInapplicable + Nil } case _ => - RuleInapplicable + Nil } } } diff --git a/src/main/scala/leon/synthesis/rules/CaseSplit.scala b/src/main/scala/leon/synthesis/rules/CaseSplit.scala index 50b769c704e592eafcb16e0f665c6aef5619adcb..a2627256be13884d8343b865022304cfc74c3e4e 100644 --- a/src/main/scala/leon/synthesis/rules/CaseSplit.scala +++ b/src/main/scala/leon/synthesis/rules/CaseSplit.scala @@ -7,7 +7,7 @@ import purescala.TreeOps._ import purescala.Extractors._ case object CaseSplit extends Rule("Case-Split", 200) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { p.phi match { case Or(o1 :: o2 :: _) => val sub1 = Problem(p.as, p.pc, o1, p.xs) @@ -18,9 +18,9 @@ case object CaseSplit extends Rule("Case-Split", 200) { case _ => Solution.none } - RuleFastStep(List(sub1, sub2), onSuccess) + List(RuleInstantiation.immediateDecomp(List(sub1, sub2), onSuccess)) case _ => - RuleInapplicable + Nil } } } diff --git a/src/main/scala/leon/synthesis/rules/Cegis.scala b/src/main/scala/leon/synthesis/rules/Cegis.scala index d3665ef42c83213babd233203f5b301721c2e5b7..c1029c5db50fa6de129b958276421972c1338597 100644 --- a/src/main/scala/leon/synthesis/rules/Cegis.scala +++ b/src/main/scala/leon/synthesis/rules/Cegis.scala @@ -12,7 +12,7 @@ import purescala.Extractors._ import solvers.z3.FairZ3Solver case object CEGIS extends Rule("CEGIS", 150) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { case class Generator(tpe: TypeTree, altBuilder: () => List[(Expr, Set[Identifier])]); var generators = Map[TypeTree, Generator]() @@ -122,7 +122,7 @@ case object CEGIS extends Rule("CEGIS", 150) { val (exprsA, others) = ands.partition(e => (variablesOf(e) & xsSet).isEmpty) if (exprsA.isEmpty) { - val res = new RuleImmediateApplication { + val res = new RuleInstantiation(SolutionBuilder.none) { def apply(sctx: SynthesisContext) = { var result: Option[RuleApplicationResult] = None @@ -272,12 +272,11 @@ case object CEGIS extends Rule("CEGIS", 150) { e.printStackTrace RuleApplicationImpossible } - } } - RuleResult(List(res)) + List(res) } else { - RuleInapplicable + Nil } } } diff --git a/src/main/scala/leon/synthesis/rules/Disunification.scala b/src/main/scala/leon/synthesis/rules/Disunification.scala index 7bce9d3782ebdcb076fe6462175a309753883e1e..53963b5024792c4a5a1e393bc2ad0b865008343b 100644 --- a/src/main/scala/leon/synthesis/rules/Disunification.scala +++ b/src/main/scala/leon/synthesis/rules/Disunification.scala @@ -9,7 +9,7 @@ import purescala.Extractors._ object Disunification { case object Decomp extends Rule("Disunif. Decomp.", 200) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val TopLevelAnds(exprs) = p.phi val (toRemove, toAdd) = exprs.collect { @@ -26,9 +26,9 @@ object Disunification { if (!toRemove.isEmpty) { val sub = p.copy(phi = Or((exprs.toSet -- toRemove ++ toAdd.flatten).toSeq)) - RuleFastStep(List(sub), forward) + List(RuleInstantiation.immediateDecomp(List(sub), forward)) } else { - RuleInapplicable + Nil } } } diff --git a/src/main/scala/leon/synthesis/rules/EqualitySplit.scala b/src/main/scala/leon/synthesis/rules/EqualitySplit.scala index f74c9fc55dbf817e642b1f51ccd9c2a7000392b8..eebab17e91365a444cb322bc433ce5cc163eec25 100644 --- a/src/main/scala/leon/synthesis/rules/EqualitySplit.scala +++ b/src/main/scala/leon/synthesis/rules/EqualitySplit.scala @@ -9,7 +9,7 @@ import purescala.TreeOps._ import purescala.Extractors._ case object EqualitySplit extends Rule("Eq. Split.", 90) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val candidates = p.as.groupBy(_.getType).map(_._2.toList).filter { case List(a1, a2) => val toValEQ = Implies(p.pc, Equals(Variable(a1), Variable(a2))) @@ -35,7 +35,7 @@ case object EqualitySplit extends Rule("Eq. Split.", 90) { } - val steps = candidates.map(_ match { + candidates.map(_ match { case List(a1, a2) => val sub1 = p.copy(pc = And(Equals(Variable(a1), Variable(a2)), p.pc)) @@ -48,11 +48,9 @@ case object EqualitySplit extends Rule("Eq. Split.", 90) { Solution.none } - Some(RuleFastApplication(List(sub1, sub2), onSuccess)) + Some(RuleInstantiation.immediateDecomp(List(sub1, sub2), onSuccess)) case _ => None }).flatten - - RuleResult(steps) } } diff --git a/src/main/scala/leon/synthesis/rules/Ground.scala b/src/main/scala/leon/synthesis/rules/Ground.scala index f79af5afb90c97b85b452ada4cc74163798ea057..97c0c836604cfc80a6dbd3fd2db205a4c58cedec 100644 --- a/src/main/scala/leon/synthesis/rules/Ground.scala +++ b/src/main/scala/leon/synthesis/rules/Ground.scala @@ -8,21 +8,23 @@ import purescala.TreeOps._ import purescala.Extractors._ case object Ground extends Rule("Ground", 500) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { if (p.as.isEmpty) { val tpe = TupleType(p.xs.map(_.getType)) sctx.solver.solveSAT(p.phi) match { case (Some(true), model) => - RuleFastSuccess(Solution(BooleanLiteral(true), Set(), Tuple(p.xs.map(valuateWithModel(model))).setType(tpe))) + val sol = Solution(BooleanLiteral(true), Set(), Tuple(p.xs.map(valuateWithModel(model))).setType(tpe)) + Some(RuleInstantiation.immediateSuccess(sol)) case (Some(false), model) => - RuleFastSuccess(Solution(BooleanLiteral(false), Set(), Error(p.phi+" is UNSAT!").setType(tpe))) + val sol = Solution(BooleanLiteral(false), Set(), Error(p.phi+" is UNSAT!").setType(tpe)) + Some(RuleInstantiation.immediateSuccess(sol)) case _ => - RuleInapplicable + None } } else { - RuleInapplicable + None } } } diff --git a/src/main/scala/leon/synthesis/rules/IntegerEquation.scala b/src/main/scala/leon/synthesis/rules/IntegerEquation.scala index 9fc9be76cd489c960e1dd8534cc24caa589d8739..00d21c6040579704cec09ad16cacb883f7e58bca 100644 --- a/src/main/scala/leon/synthesis/rules/IntegerEquation.scala +++ b/src/main/scala/leon/synthesis/rules/IntegerEquation.scala @@ -12,7 +12,7 @@ import purescala.Definitions._ import LinearEquations.elimVariable case object IntegerEquation extends Rule("Integer Equation", 600) { - def attemptToApplyOn(sctx: SynthesisContext, problem: Problem): RuleResult = if(!problem.xs.exists(_.getType == Int32Type)) RuleInapplicable else { + def instantiateOn(sctx: SynthesisContext, problem: Problem): Traversable[RuleInstantiation] = if(!problem.xs.exists(_.getType == Int32Type)) Nil else { val TopLevelAnds(exprs) = problem.phi @@ -41,7 +41,7 @@ case object IntegerEquation extends Rule("Integer Equation", 600) { allOthers = allOthers ++ candidates optionNormalizedEq match { - case None => RuleInapplicable + case None => Nil case Some(normalizedEq0) => { val eqas = problem.as.toSet.intersect(vars) @@ -60,7 +60,7 @@ case object IntegerEquation extends Rule("Integer Equation", 600) { case _ => Solution.none } - RuleFastStep(List(newProblem), onSuccess) + List(RuleInstantiation.immediateDecomp(List(newProblem), onSuccess)) } else { val (eqPre0, eqWitness, freshxs) = elimVariable(eqas, normalizedEq) @@ -103,10 +103,8 @@ case object IntegerEquation extends Rule("Integer Equation", 600) { case _ => Solution.none } - RuleFastStep(List(newProblem), onSuccess) + List(RuleInstantiation.immediateDecomp(List(newProblem), onSuccess)) } - - } } diff --git a/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala b/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala index 6d29637b2965822f38ee93e7c59554357cd01f64..7cb6b28cb374f0480c316fa0329b02374f0ed12d 100644 --- a/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala +++ b/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala @@ -13,7 +13,7 @@ import LinearEquations.elimVariable import leon.synthesis.Algebra.lcm case object IntegerInequalities extends Rule("Integer Inequalities", 600) { - def attemptToApplyOn(sctx: SynthesisContext, problem: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, problem: Problem): Traversable[RuleInstantiation] = { val TopLevelAnds(exprs) = problem.phi //assume that we only have inequalities @@ -32,7 +32,9 @@ case object IntegerInequalities extends Rule("Integer Inequalities", 600) { val nonIneqVars = exprNotUsed.foldLeft(Set[Identifier]())((acc, x) => acc ++ variablesOf(x)) val candidateVars = ineqVars.intersect(problem.xs.toSet).filterNot(nonIneqVars.contains(_)) - if(candidateVars.isEmpty) RuleInapplicable else { + if (candidateVars.isEmpty) { + Nil + } else { val processedVar: Identifier = candidateVars.map(v => { val normalizedLhs: List[List[Expr]] = lhsSides.map(linearArithmeticForm(_, Array(v)).toList) if(normalizedLhs.isEmpty) @@ -129,7 +131,7 @@ case object IntegerInequalities extends Rule("Integer Inequalities", 600) { val constraints: List[Expr] = for((ub, uc) <- upperBounds; (lb, lc) <- lowerBounds) yield LessEquals(ceilingDiv(lb, IntLiteral(lc)), floorDiv(ub, IntLiteral(uc))) val pre = And(exprNotUsed ++ constraints) - RuleFastSuccess(Solution(pre, Set(), witness)) + List(RuleInstantiation.immediateSuccess(Solution(pre, Set(), witness))) } else { val involvedVariables = (upperBounds++lowerBounds).foldLeft(Set[Identifier]())((acc, t) => { @@ -198,7 +200,7 @@ case object IntegerInequalities extends Rule("Integer Inequalities", 600) { case _ => Solution.none } - RuleFastStep(List(subProblem), onSuccess) + List(RuleInstantiation.immediateDecomp(List(subProblem), onSuccess)) } } } diff --git a/src/main/scala/leon/synthesis/rules/OnePoint.scala b/src/main/scala/leon/synthesis/rules/OnePoint.scala index 412796a98ce1697e80ecb15a6c461d4fe7dc073c..76aedbdc5216c5a84f735bf705950f1caa24b4da 100644 --- a/src/main/scala/leon/synthesis/rules/OnePoint.scala +++ b/src/main/scala/leon/synthesis/rules/OnePoint.scala @@ -7,7 +7,7 @@ import purescala.TreeOps._ import purescala.Extractors._ case object OnePoint extends Rule("One-point", 300) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val TopLevelAnds(exprs) = p.phi val candidates = exprs.collect { @@ -35,9 +35,9 @@ case object OnePoint extends Rule("One-point", 300) { case _ => Solution.none } - RuleFastStep(List(newProblem), onSuccess) + List(RuleInstantiation.immediateDecomp(List(newProblem), onSuccess)) } else { - RuleInapplicable + Nil } } } diff --git a/src/main/scala/leon/synthesis/rules/OptimisticGround.scala b/src/main/scala/leon/synthesis/rules/OptimisticGround.scala index 57e179ef33937586c5e0cddbd687655c3b408391..0ddce7824f8c403a2504ae866dfcc4927b89663d 100644 --- a/src/main/scala/leon/synthesis/rules/OptimisticGround.scala +++ b/src/main/scala/leon/synthesis/rules/OptimisticGround.scala @@ -8,7 +8,7 @@ import purescala.TreeOps._ import purescala.Extractors._ case object OptimisticGround extends Rule("Optimistic Ground", 150) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { if (!p.as.isEmpty && !p.xs.isEmpty) { val xss = p.xs.toSet val ass = p.as.toSet @@ -18,10 +18,11 @@ case object OptimisticGround extends Rule("Optimistic Ground", 150) { var i = 0; var maxTries = 3; - var result: Option[RuleResult] = None - var predicates: Seq[Expr] = Seq() + var result: Option[RuleInstantiation] = None + var continue = true + var predicates: Seq[Expr] = Seq() - while (result.isEmpty && i < maxTries) { + while (result.isEmpty && i < maxTries && continue) { val phi = And(p.pc +: p.phi +: predicates) //println("SOLVING " + phi + " ...") sctx.solver.solveSAT(phi) match { @@ -37,28 +38,31 @@ case object OptimisticGround extends Rule("Optimistic Ground", 150) { predicates = valuateWithModelIn(phi, ass, invalidModel) +: predicates case (Some(false), _) => - result = Some(RuleFastSuccess(Solution(BooleanLiteral(true), Set(), Tuple(p.xs.map(valuateWithModel(satModel))).setType(tpe)))) + result = Some(RuleInstantiation.immediateSuccess(Solution(BooleanLiteral(true), Set(), Tuple(p.xs.map(valuateWithModel(satModel))).setType(tpe)))) case _ => - result = Some(RuleFastInapplicable()) + continue = false + result = None } case (Some(false), _) => if (predicates.isEmpty) { - result = Some(RuleFastSuccess(Solution(BooleanLiteral(false), Set(), Error(p.phi+" is UNSAT!").setType(tpe)))) + result = Some(RuleInstantiation.immediateSuccess(Solution(BooleanLiteral(false), Set(), Error(p.phi+" is UNSAT!").setType(tpe)))) } else { - result = Some(RuleFastInapplicable()) + continue = false + result = None } case _ => - result = Some(RuleFastInapplicable()) + continue = false + result = None } i += 1 } - result.getOrElse(RuleFastInapplicable()) + result } else { - RuleInapplicable + Nil } } } diff --git a/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala b/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala index 8adc96ba116cb806a31579e25b177a2c1079a75f..808a76dd841cafb89444e94012c383b8437c2f87 100644 --- a/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala +++ b/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala @@ -7,7 +7,7 @@ import purescala.TreeOps._ import purescala.Extractors._ case object UnconstrainedOutput extends Rule("Unconstr.Output", 100) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val unconstr = p.xs.toSet -- variablesOf(p.phi) if (!unconstr.isEmpty) { @@ -20,11 +20,10 @@ case object UnconstrainedOutput extends Rule("Unconstr.Output", 100) { Solution.none } - RuleFastStep(List(sub), onSuccess) + List(RuleInstantiation.immediateDecomp(List(sub), onSuccess)) } else { - RuleInapplicable + Nil } - } } diff --git a/src/main/scala/leon/synthesis/rules/Unification.scala b/src/main/scala/leon/synthesis/rules/Unification.scala index c5ee4c320912c039b1fc9bf9d4652691fc553bc2..fd278ff24b40852d6e6101419cd99a65360d83ee 100644 --- a/src/main/scala/leon/synthesis/rules/Unification.scala +++ b/src/main/scala/leon/synthesis/rules/Unification.scala @@ -9,7 +9,7 @@ import purescala.Extractors._ object Unification { case object DecompTrivialClash extends Rule("Unif Dec./Clash/Triv.", 200) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val TopLevelAnds(exprs) = p.phi val (toRemove, toAdd) = exprs.collect { @@ -27,9 +27,9 @@ object Unification { val sub = p.copy(phi = And((exprs.toSet -- toRemove ++ toAdd.flatten).toSeq)) - RuleFastStep(List(sub), forward) + List(RuleInstantiation.immediateDecomp(List(sub), forward)) } else { - RuleInapplicable + Nil } } } @@ -37,7 +37,7 @@ object Unification { // This rule is probably useless; it never happens except in crafted // examples, and will be found by OptimisticGround anyway. case object OccursCheck extends Rule("Unif OccursCheck", 200) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val TopLevelAnds(exprs) = p.phi val isImpossible = exprs.exists { @@ -52,9 +52,9 @@ object Unification { if (isImpossible) { val tpe = TupleType(p.xs.map(_.getType)) - RuleFastSuccess(Solution(BooleanLiteral(false), Set(), Error(p.phi+" is UNSAT!").setType(tpe))) + List(RuleInstantiation.immediateSuccess(Solution(BooleanLiteral(false), Set(), Error(p.phi+" is UNSAT!").setType(tpe)))) } else { - RuleInapplicable + Nil } } } diff --git a/src/main/scala/leon/synthesis/rules/UnusedInput.scala b/src/main/scala/leon/synthesis/rules/UnusedInput.scala index 03f8aeef86a3e2968c3ff7a68d0de14f7d5cb1cc..d9b26efed9783b6c95f49d1477c7129ce1fe455e 100644 --- a/src/main/scala/leon/synthesis/rules/UnusedInput.scala +++ b/src/main/scala/leon/synthesis/rules/UnusedInput.scala @@ -7,15 +7,15 @@ import purescala.TreeOps._ import purescala.Extractors._ case object UnusedInput extends Rule("UnusedInput", 100) { - def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val unused = p.as.toSet -- variablesOf(p.phi) -- variablesOf(p.pc) if (!unused.isEmpty) { val sub = p.copy(as = p.as.filterNot(unused)) - RuleFastStep(List(sub), forward) + List(RuleInstantiation.immediateDecomp(List(sub), forward)) } else { - RuleInapplicable + Nil } } } diff --git a/src/main/scala/leon/synthesis/search/AndOrGraph.scala b/src/main/scala/leon/synthesis/search/AndOrGraph.scala index 2ac6881a2bc0ed52e2787e27eb4e7e7dcf078cf2..5a61217a0db7614fb272964263f159fd0bd6ab34 100644 --- a/src/main/scala/leon/synthesis/search/AndOrGraph.scala +++ b/src/main/scala/leon/synthesis/search/AndOrGraph.scala @@ -4,7 +4,7 @@ trait AOTask[S] { } trait AOAndTask[S] extends AOTask[S] { - def composeSolution(sols: List[S]): S + def composeSolution(sols: List[S]): Option[S] } trait AOOrTask[S] extends AOTask[S] { @@ -88,7 +88,7 @@ class AndOrGraph[AT <: AOAndTask[S], OT <: AOOrTask[S], S](val root: OT, val cos subSolutions += sub.task -> sol if (subSolutions.size == subProblems.size) { - solution = Some(task.composeSolution(subTasks.map(subSolutions))) + solution = task.composeSolution(subTasks.map(subSolutions)) updateMin() notifyParent(solution.get) diff --git a/src/main/scala/leon/synthesis/search/AndOrGraphPartialSolution.scala b/src/main/scala/leon/synthesis/search/AndOrGraphPartialSolution.scala index 2406bc1ca721b3bb9a1f0f1128ae062554efde1d..d4d38dd77605cf8a8fadbcada2bc581b39c9767f 100644 --- a/src/main/scala/leon/synthesis/search/AndOrGraphPartialSolution.scala +++ b/src/main/scala/leon/synthesis/search/AndOrGraphPartialSolution.scala @@ -17,7 +17,7 @@ class AndOrGraphPartialSolution[AT <: AOAndTask[S], case l: g.AndLeaf => missing(t.task) case n: g.AndNode => - n.task.composeSolution(n.subProblems.values.map(solveOr(_)).toList) + n.task.composeSolution(n.subProblems.values.map(solveOr(_)).toList).getOrElse(missing(t.task)) } } }