diff --git a/src/main/scala/leon/synthesis/Heuristics.scala b/src/main/scala/leon/synthesis/Heuristics.scala index 95ac39a13d8d8d55d295ff7c1edd8655495226dc..cb18ef781aec214808b3d9275b03c992deef524b 100644 --- a/src/main/scala/leon/synthesis/Heuristics.scala +++ b/src/main/scala/leon/synthesis/Heuristics.scala @@ -7,7 +7,7 @@ import purescala.TypeTrees.TupleType import heuristics._ object Heuristics { - def all = Set[Rule]( + def all = List[Rule]( IntInduction, InnerCaseSplit, //new OptimisticInjection(_), diff --git a/src/main/scala/leon/synthesis/ParallelSearch.scala b/src/main/scala/leon/synthesis/ParallelSearch.scala index fb3f824c820c5b4f493d75ff85917feecf5d45e9..efe05182e1d329af67f7d744b7fa10348b941244 100644 --- a/src/main/scala/leon/synthesis/ParallelSearch.scala +++ b/src/main/scala/leon/synthesis/ParallelSearch.scala @@ -8,7 +8,7 @@ import solvers.TrivialSolver class ParallelSearch(synth: Synthesizer, problem: Problem, - rules: Set[Rule], + rules: Seq[Rule], costModel: CostModel, nWorkers: Int) extends AndOrGraphParallelSearch[SynthesisContext, TaskRunRule, TaskTryRules, Solution](new AndOrGraph(TaskTryRules(problem), SearchCostModel(costModel)), nWorkers) { @@ -69,14 +69,22 @@ class ParallelSearch(synth: Synthesizer, } def expandOrTask(ref: ActorRef, sctx: SynthesisContext)(t: TaskTryRules) = { - val sub = rules.flatMap { r => - r.instantiateOn(sctx, t.p).map(TaskRunRule(_)) - } + val (normRules, otherRules) = rules.partition(_.isInstanceOf[NormalizingRule]) + + val normApplications = normRules.flatMap(_.instantiateOn(sctx, t.p)) - if (!sub.isEmpty) { - Expanded(sub.toList) + if (!normApplications.isEmpty) { + Expanded(List(TaskRunRule(normApplications.head))) } else { - ExpandFailure() + val sub = otherRules.flatMap { r => + r.instantiateOn(sctx, t.p).map(TaskRunRule(_)) + } + + if (!sub.isEmpty) { + Expanded(sub.toList) + } else { + ExpandFailure() + } } } } diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala index 27eba7ac6fc8b78b22fc8b6bef17cbbb483118df..7926efd69ac916f6678ec00b6a97fbddb7171864 100644 --- a/src/main/scala/leon/synthesis/Rules.scala +++ b/src/main/scala/leon/synthesis/Rules.scala @@ -8,7 +8,7 @@ import purescala.TreeOps._ import rules._ object Rules { - def all = Set[Rule]( + def all = List[Rule]( Unification.DecompTrivialClash, Unification.OccursCheck, // probably useless Disunification.Decomp, @@ -89,3 +89,10 @@ abstract class Rule(val name: String) { override def toString = "R: "+name } + +// Note: Rules that extend NormalizingRule should all be commutative, The will +// be applied before others in a deterministic order and their application +// should never fail! +abstract class NormalizingRule(name: String) extends Rule(name) { + override def toString = "N: "+name +} diff --git a/src/main/scala/leon/synthesis/SimpleSearch.scala b/src/main/scala/leon/synthesis/SimpleSearch.scala index 2b329ef705977bda1f12b15da05ebf207976edce..32258cedda16cbb3da45c077b89f68d8e0cd074c 100644 --- a/src/main/scala/leon/synthesis/SimpleSearch.scala +++ b/src/main/scala/leon/synthesis/SimpleSearch.scala @@ -32,7 +32,7 @@ case class SearchCostModel(cm: CostModel) extends AOCostModel[TaskRunRule, TaskT class SimpleSearch(synth: Synthesizer, problem: Problem, - rules: Set[Rule], + rules: Seq[Rule], costModel: CostModel) extends AndOrGraphSearch[TaskRunRule, TaskTryRules, Solution](new AndOrGraph(TaskTryRules(problem), SearchCostModel(costModel))) { import synth.reporter._ @@ -64,12 +64,22 @@ class SimpleSearch(synth: Synthesizer, } def expandOrTask(t: TaskTryRules): ExpandResult[TaskRunRule] = { - val sub = rules.flatMap ( r => r.instantiateOn(sctx, t.p).map(TaskRunRule(_)) ) + val (normRules, otherRules) = rules.partition(_.isInstanceOf[NormalizingRule]) - if (!sub.isEmpty) { - Expanded(sub.toList) + val normApplications = normRules.flatMap(_.instantiateOn(sctx, t.p)) + + if (!normApplications.isEmpty) { + Expanded(List(TaskRunRule(normApplications.head))) } else { - ExpandFailure() + val sub = otherRules.flatMap { r => + r.instantiateOn(sctx, t.p).map(TaskRunRule(_)) + } + + if (!sub.isEmpty) { + Expanded(sub.toList) + } else { + ExpandFailure() + } } } diff --git a/src/main/scala/leon/synthesis/Synthesizer.scala b/src/main/scala/leon/synthesis/Synthesizer.scala index 0a402e5db9cbfce350bdd69302479f6aa9b636df..624b6a178e01c71090cb94823b56364900743676 100644 --- a/src/main/scala/leon/synthesis/Synthesizer.scala +++ b/src/main/scala/leon/synthesis/Synthesizer.scala @@ -22,7 +22,7 @@ class Synthesizer(val context : LeonContext, val solver: Solver, val program: Program, val problem: Problem, - val rules: Set[Rule], + val rules: Seq[Rule], val options: SynthesizerOptions) { protected[synthesis] val reporter = context.reporter diff --git a/src/main/scala/leon/synthesis/rules/Assert.scala b/src/main/scala/leon/synthesis/rules/Assert.scala index 898f1ea05fa8eb74f949dc6093bbce51df2e7147..cab8ea72c20094db0018dd2ad97f74c982a2c5a9 100644 --- a/src/main/scala/leon/synthesis/rules/Assert.scala +++ b/src/main/scala/leon/synthesis/rules/Assert.scala @@ -6,7 +6,7 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -case object Assert extends Rule("Assert") { +case object Assert extends NormalizingRule("Assert") { def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { p.phi match { case TopLevelAnds(exprs) => diff --git a/src/main/scala/leon/synthesis/rules/OnePoint.scala b/src/main/scala/leon/synthesis/rules/OnePoint.scala index 42c931f5996bbd8d31c40b6bcb0be4e82f6ad0c7..d245e7bb2ee45030442ff0bf41beae33c066a28e 100644 --- a/src/main/scala/leon/synthesis/rules/OnePoint.scala +++ b/src/main/scala/leon/synthesis/rules/OnePoint.scala @@ -6,7 +6,7 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -case object OnePoint extends Rule("One-point") { +case object OnePoint extends NormalizingRule("One-point") { def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val TopLevelAnds(exprs) = p.phi diff --git a/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala b/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala index c5ddd02ef6845ef46c2b60af41e4444b4fc2133c..2ae957da30dc98e0b5e5903c331a08a9ac089cd7 100644 --- a/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala +++ b/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala @@ -6,7 +6,7 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -case object UnconstrainedOutput extends Rule("Unconstr.Output") { +case object UnconstrainedOutput extends NormalizingRule("Unconstr.Output") { def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val unconstr = p.xs.toSet -- variablesOf(p.phi) diff --git a/src/main/scala/leon/synthesis/rules/UnusedInput.scala b/src/main/scala/leon/synthesis/rules/UnusedInput.scala index b44ad3411529237a12f1dc3acc53db19a5dd3954..b97ff9033b44c7e926c86362ace2fb6497399e65 100644 --- a/src/main/scala/leon/synthesis/rules/UnusedInput.scala +++ b/src/main/scala/leon/synthesis/rules/UnusedInput.scala @@ -6,7 +6,7 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -case object UnusedInput extends Rule("UnusedInput") { +case object UnusedInput extends NormalizingRule("UnusedInput") { def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { val unused = p.as.toSet -- variablesOf(p.phi) -- variablesOf(p.pc)