From 862613e1fc9b34da4ab5a5d5a9b31e64b5c0819f Mon Sep 17 00:00:00 2001
From: Etienne Kneuss <ekneuss@gmail.com>
Date: Fri, 2 Nov 2012 16:36:20 +0100
Subject: [PATCH] This tends to guarantee termination, better handling of
 giveups

---
 .../scala/leon/synthesis/Heuristics.scala     |  2 +-
 src/main/scala/leon/synthesis/Rules.scala     |  9 +------
 .../scala/leon/synthesis/Synthesizer.scala    | 18 ++++++++++---
 src/main/scala/leon/synthesis/Task.scala      | 27 +++++++++++++++++--
 4 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/src/main/scala/leon/synthesis/Heuristics.scala b/src/main/scala/leon/synthesis/Heuristics.scala
index c1ad89415..f96ecacbf 100644
--- a/src/main/scala/leon/synthesis/Heuristics.scala
+++ b/src/main/scala/leon/synthesis/Heuristics.scala
@@ -72,7 +72,7 @@ class OptimisticGround(synth: Synthesizer) extends Rule("Optimistic Ground", syn
 }
 
 
-class IntInduction(synth: Synthesizer) extends Rule("Int Induction", synth, 8, 50) {
+class IntInduction(synth: Synthesizer) extends Rule("Int Induction", synth, 8, 100) {
   def applyOn(task: Task): RuleResult = {
     val p = task.problem
 
diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala
index 7210ef271..51e1c02ea 100644
--- a/src/main/scala/leon/synthesis/Rules.scala
+++ b/src/main/scala/leon/synthesis/Rules.scala
@@ -17,8 +17,7 @@ object Rules {
     new CaseSplit(synth),
     new UnusedInput(synth),
     new UnconstrainedOutput(synth),
-    new Assert(synth),
-    new GiveUp(synth)
+    new Assert(synth)
   )
 }
 
@@ -276,9 +275,3 @@ class ADTDual(synth: Synthesizer) extends Rule("ADTDual", synth, 20, 0) {
   }
 }
 
-class GiveUp(synth: Synthesizer) extends Rule("GiveUp", synth, -100000, 100) {
-  def applyOn(task: Task): RuleResult = {
-    RuleSuccess(Solution.choose(task.problem))
-  }
-}
-
diff --git a/src/main/scala/leon/synthesis/Synthesizer.scala b/src/main/scala/leon/synthesis/Synthesizer.scala
index d18bd0cb1..0739733ea 100644
--- a/src/main/scala/leon/synthesis/Synthesizer.scala
+++ b/src/main/scala/leon/synthesis/Synthesizer.scala
@@ -28,16 +28,26 @@ class Synthesizer(val r: Reporter,
     val workList = new PriorityQueue[Task]()
     val rootTask = new RootTask(this, p)
 
+    val giveUpComplexity = new TaskComplexity(null) {
+      override def value = 100000
+    }
 
     workList += rootTask
 
     while (!workList.isEmpty && !(firstOnly && rootTask.solution.isDefined)) {
       val task = workList.dequeue()
 
-      val subProblems = task.run
-
-      for (p <- subProblems; r <- rules) yield {
-        workList += new Task(this, task, p, r)
+      if (task.complexity > giveUpComplexity) {
+        // This task is too complicated, we give up with a choose solution
+        val solution = Solution.choose(task.problem)
+        task.solution = Some(solution)
+        task.parent.partlySolvedBy(task, solution)
+      } else {
+        val subProblems = task.run
+
+        for (p <- subProblems; r <- rules) yield {
+          workList += new Task(this, task, p, r)
+        }
       }
     }
 
diff --git a/src/main/scala/leon/synthesis/Task.scala b/src/main/scala/leon/synthesis/Task.scala
index fd4e8a2c9..c1c5bdb69 100644
--- a/src/main/scala/leon/synthesis/Task.scala
+++ b/src/main/scala/leon/synthesis/Task.scala
@@ -2,7 +2,7 @@ package leon
 package synthesis
 
 class Task(synth: Synthesizer,
-           parent: Task,
+           val parent: Task,
            val problem: Problem,
            val rule: Rule) extends Ordered[Task] {
 
@@ -34,6 +34,17 @@ class Task(synth: Synthesizer,
     }
   }
 
+  var failures = Set[Rule]()
+  def unsolvedBy(t: Task) {
+    failures += t.rule
+
+    if (failures.size == synth.rules.size) {
+      // We might want to report unsolved instead of solvedByChoose, depending
+      // on the cases
+      parent.partlySolvedBy(this, Solution.choose(problem))
+    }
+  }
+
   def run: List[Problem] = {
     rule.applyOn(this) match {
       case RuleSuccess(solution) =>
@@ -48,6 +59,7 @@ class Task(synth: Synthesizer,
         subProblems
 
       case RuleInapplicable =>
+        parent.unsolvedBy(this)
         Nil
     }
   }
@@ -62,13 +74,24 @@ class RootTask(synth: Synthesizer, problem: Problem) extends Task(synth, null, p
 
   override lazy val minSolutionCost = 0
 
-  override def partlySolvedBy(t: Task, s: Solution) = {
+  override def partlySolvedBy(t: Task, s: Solution) {
     if (isBetterSolutionThan(s, solution)) {
       solution = Some(s)
       solver   = Some(t)
     }
   }
 
+  override def unsolvedBy(t: Task) {
+    failures += t.rule
+
+    if (failures.size == synth.rules.size) {
+      // We might want to report unsolved instead of solvedByChoose, depending
+      // on the cases
+      solution = Some(Solution.choose(problem))
+      solver   = None
+    }
+  }
+
   override def run: List[Problem] = {
     List(problem)
   }
-- 
GitLab