diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala index e835637a49d32d5c2035e3925186134c15c4673f..c1b392774c2f61bd88a7d395691c1c44fdf8deed 100644 --- a/src/main/scala/leon/synthesis/Rules.scala +++ b/src/main/scala/leon/synthesis/Rules.scala @@ -17,7 +17,7 @@ object Rules { abstract class Rule(val name: String, val synth: Synthesizer) { - def isApplicable(p: Problem, parent: Task): List[Task] + def isApplicable(task: Task): List[DecomposedTask] def subst(what: Tuple2[Identifier, Expr], in: Expr): Expr = replace(Map(Variable(what._1) -> what._2), in) @@ -25,7 +25,9 @@ abstract class Rule(val name: String, val synth: Synthesizer) { } class OnePoint(synth: Synthesizer) extends Rule("One-point", synth) { - def isApplicable(p: Problem, parent: Task): List[Task] = { + def isApplicable(task: Task): List[DecomposedTask] = { + + val p = task.problem p.phi match { case TopLevelAnds(exprs) => @@ -54,7 +56,7 @@ class OnePoint(synth: Synthesizer) extends Rule("One-point", synth) { case _ => Solution.none } - List(new Task(synth, parent, this, p, List(newProblem), onSuccess, 100)) + List(new DecomposedTask(synth, task.parent, p, 100, this, List(newProblem), onSuccess)) } else { Nil } @@ -67,7 +69,9 @@ class OnePoint(synth: Synthesizer) extends Rule("One-point", synth) { } class Ground(synth: Synthesizer) extends Rule("Ground", synth) { - def isApplicable(p: Problem, parent: Task): List[Task] = { + def isApplicable(task: Task): List[DecomposedTask] = { + val p = task.problem + if (p.as.isEmpty) { val tpe = TupleType(p.xs.map(_.getType)) @@ -78,13 +82,13 @@ class Ground(synth: Synthesizer) extends Rule("Ground", synth) { case Nil => Solution(BooleanLiteral(true), Tuple(p.xs.map(model)).setType(tpe), 200) } - List(new Task(synth, parent, this, p, Nil, onSuccess, 200)) + List(new DecomposedTask(synth, task.parent, p, 200, this, Nil, onSuccess)) case (Some(false), model) => val onSuccess: List[Solution] => Solution = { case Nil => Solution(BooleanLiteral(false), Error(p.phi+" is UNSAT!").setType(tpe), 200) } - List(new Task(synth, parent, this, p, Nil, onSuccess, 200)) + List(new DecomposedTask(synth, task.parent, p, 200, this, Nil, onSuccess)) case _ => Nil } @@ -95,7 +99,8 @@ class Ground(synth: Synthesizer) extends Rule("Ground", synth) { } class CaseSplit(synth: Synthesizer) extends Rule("Case-Split", synth) { - def isApplicable(p: Problem, parent: Task): List[Task] = { + def isApplicable(task: Task): List[DecomposedTask] = { + val p = task.problem p.phi match { case Or(Seq(o1, o2)) => val sub1 = Problem(p.as, o1, p.xs) @@ -106,7 +111,7 @@ class CaseSplit(synth: Synthesizer) extends Rule("Case-Split", synth) { case _ => Solution.none } - List(new Task(synth, parent, this, p, List(sub1, sub2), onSuccess, 100)) + List(new DecomposedTask(synth, task.parent, p, 100, this, List(sub1, sub2), onSuccess)) case _ => Nil } @@ -114,7 +119,9 @@ class CaseSplit(synth: Synthesizer) extends Rule("Case-Split", synth) { } class Assert(synth: Synthesizer) extends Rule("Assert", synth) { - def isApplicable(p: Problem, parent: Task): List[Task] = { + def isApplicable(task: Task): List[DecomposedTask] = { + val p = task.problem + p.phi match { case TopLevelAnds(exprs) => val xsSet = p.xs.toSet @@ -128,14 +135,16 @@ class Assert(synth: Synthesizer) extends Rule("Assert", synth) { case _ => Solution.none } - List(new Task(synth, parent, this, p, Nil, onSuccess, 150)) + List(new DecomposedTask(synth, task.parent, p, 150, this, Nil, onSuccess)) } else { val onSuccess: List[Solution] => Solution = { case List(s) => Solution(And(s.pre +: exprsA), s.term, 150) case _ => Solution.none } - List(new Task(synth, parent, this, p, List(p.copy(phi = And(others))), onSuccess, 150)) + val sub = p.copy(phi = And(others)) + + List(new DecomposedTask(synth, task.parent, p, 150, this, List(sub), onSuccess)) } } else { Nil @@ -147,7 +156,8 @@ class Assert(synth: Synthesizer) extends Rule("Assert", synth) { } class UnusedInput(synth: Synthesizer) extends Rule("UnusedInput", synth) { - def isApplicable(p: Problem, parent: Task): List[Task] = { + def isApplicable(task: Task): List[DecomposedTask] = { + val p = task.problem val unused = p.as.toSet -- variablesOf(p.phi) if (!unused.isEmpty) { @@ -158,7 +168,7 @@ class UnusedInput(synth: Synthesizer) extends Rule("UnusedInput", synth) { case _ => Solution.none } - List(new Task(synth, parent, this, p, List(sub), onSuccess, 300)) + List(new DecomposedTask(synth, task.parent, p, 300, this, List(sub), onSuccess)) } else { Nil } diff --git a/src/main/scala/leon/synthesis/Synthesizer.scala b/src/main/scala/leon/synthesis/Synthesizer.scala index e17b34683ebf446ba17f2d1dbd71eed2566e1609..754c740f079f648724e5bb0af4720644ba345d9e 100644 --- a/src/main/scala/leon/synthesis/Synthesizer.scala +++ b/src/main/scala/leon/synthesis/Synthesizer.scala @@ -17,49 +17,34 @@ class Synthesizer(val r: Reporter, val solvers: List[Solver]) { def synthesize(p: Problem, rules: List[Rule]): Solution = { - def applyRules(p: Problem, parent: Task): List[Task] = { - rules.flatMap(_.isApplicable(p, parent)) - } - val workList = new PriorityQueue[Task]() - val rootTask = new RootTask(this, p) workList += rootTask - solution = None while (!workList.isEmpty && solution.isEmpty) { val task = workList.dequeue() - task.subProblems match { - case Nil => - throw new Exception("Such tasks shouldbe handled immediately") - case subProblems => - for (sp <- subProblems) { - info("Now handling: "+sp) - - val alternatives = applyRules(sp, task) - - alternatives.find(_.isSuccess) match { - case Some(ss) => - ss.succeeded() - case None => - info(" => Possible Next Steps:") - alternatives.foreach(t => info(" - "+t.description)) - workList ++= alternatives - } - - // We are stuck - if (alternatives.isEmpty) { - // I give up - val sol = Solution.choose(sp) - warning(" => Solved (by choose): "+sp+" ⊢ "+sol) - task.subSucceeded(sp, sol) - } - } + info("Now handling: "+task.problem) + + val alternatives = rules.flatMap(_.isApplicable(task)) + + alternatives.find(_.isSuccess) match { + case Some(ss) => + ss.succeeded() + case None => + info(" => Possible Next Steps:") + alternatives.foreach(t => info(" - "+t.description)) + workList ++= alternatives.flatMap(_.subTasks) } + // We are stuck + if (alternatives.isEmpty) { + val sol = Solution.choose(task.problem) + warning(" => I give up: "+task+" ⊢ "+sol) + onTaskSucceeded(task, sol) + } } solution.getOrElse(Solution.none) @@ -79,13 +64,12 @@ class Synthesizer(val r: Reporter, val solvers: List[Solver]) { } def onTaskSucceeded(task: Task, solution: Solution) { - task match { - case rt: RootTask => - info(" SUCCESS!") - this.solution = Some(solution) - case t: Task => - info(" => Solved "+task.problem+" ⊢ "+solution) - t.parent.subSucceeded(t.problem, solution) + if (task.parent eq null) { + info(" SUCCESS!") + this.solution = Some(solution) + } else { + info(" => Solved "+task.problem+" ⊢ "+solution) + task.parent.subSucceeded(task.problem, solution) } } diff --git a/src/main/scala/leon/synthesis/Task.scala b/src/main/scala/leon/synthesis/Task.scala index fd6702c812e695882e77e2609da77ae6aaa9dbc5..71e0f4f18bc72cb464e4e85593ae366772e06aaa 100644 --- a/src/main/scala/leon/synthesis/Task.scala +++ b/src/main/scala/leon/synthesis/Task.scala @@ -1,20 +1,28 @@ package leon package synthesis -class Task( - val synth: Synthesizer, - val parent: Task, - val rule: Rule, - val problem: Problem, - val subProblems: List[Problem], - val onSuccess: List[Solution] => Solution, - val score: Score - ) extends Ordered[Task] { - - var subSolutions = Map[Problem, Solution]() +class Task(val synth: Synthesizer, + val parent: DecomposedTask, + val problem: Problem, + val score: Score) extends Ordered[Task] { def compare(that: Task) = this.score - that.score + override def toString = "("+score+") " +problem +} + +class DecomposedTask(synth: Synthesizer, + parent: DecomposedTask, + problem: Problem, + score: Score, + val rule: Rule, + val subProblems: List[Problem], + val onSuccess: List[Solution] => Solution) extends Task(synth, parent, problem, score) { + + def subTasks = subProblems.map(new Task(synth, this, _, score)) + + var subSolutions = Map[Problem, Solution]() + def isSuccess = subProblems.isEmpty def succeeded() { @@ -40,9 +48,7 @@ class Task( } } - override def toString = description - def description = "by "+rule.name+"("+score+"): "+problem +" ⟿ "+subProblems.mkString(" ; ") } -class RootTask(synth: Synthesizer, p: Problem) extends Task(synth, null, null, p, List(p), xs => xs.head, 0) +class RootTask(synth: Synthesizer, p: Problem) extends Task(synth, null, p, 0)