From b081084b82053544b860ebf729857f15b10486e3 Mon Sep 17 00:00:00 2001
From: Etienne Kneuss <ekneuss@gmail.com>
Date: Tue, 23 Oct 2012 01:52:53 +0200
Subject: [PATCH] Implement Assert, score solutions to order them

---
 src/main/scala/leon/synthesis/Rules.scala     | 49 ++++++++++++++++---
 src/main/scala/leon/synthesis/Solution.scala  |  4 +-
 .../scala/leon/synthesis/Synthesizer.scala    |  1 -
 src/main/scala/leon/synthesis/Task.scala      | 11 +++--
 4 files changed, 50 insertions(+), 15 deletions(-)

diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala
index 13129acdf..00c8af3a2 100644
--- a/src/main/scala/leon/synthesis/Rules.scala
+++ b/src/main/scala/leon/synthesis/Rules.scala
@@ -9,7 +9,8 @@ object Rules {
   def all(synth: Synthesizer) = List(
     new OnePoint(synth),
     new Ground(synth),
-    new CaseSplit(synth)
+    new CaseSplit(synth),
+    new Assert(synth)
   )
 }
 
@@ -43,11 +44,11 @@ class OnePoint(synth: Synthesizer) extends Rule("One-point", synth) {
           val newProblem = Problem(p.as, subst(x -> e, And(others)), oxs)
 
           val onSuccess: List[Solution] => Solution = { 
-            case List(Solution(pre, term)) =>
+            case List(Solution(pre, term, sc)) =>
               if (oxs.isEmpty) {
-                Solution(pre, e) 
+                Solution(pre, e, sc) 
               } else {
-                Solution(pre, LetTuple(oxs, term, subst(x -> e, Tuple(p.xs.map(Variable(_))))) ) 
+                Solution(pre, LetTuple(oxs, term, subst(x -> e, Tuple(p.xs.map(Variable(_))))), sc) 
               }
             case _ => Solution.none
           }
@@ -73,13 +74,13 @@ class Ground(synth: Synthesizer) extends Rule("Ground", synth) {
       synth.solveSAT(p.phi) match {
         case (Some(true), model) =>
           val onSuccess: List[Solution] => Solution = { 
-            case Nil => Solution(BooleanLiteral(true), Tuple(p.xs.map(model)).setType(tpe))
+            case Nil => Solution(BooleanLiteral(true), Tuple(p.xs.map(model)).setType(tpe), 200)
           }
 
           List(new Task(synth, parent, this, p, Nil, onSuccess, 200))
         case (Some(false), model) =>
           val onSuccess: List[Solution] => Solution = { 
-            case Nil => Solution(BooleanLiteral(false), Error(p.phi+" is UNSAT!").setType(tpe))
+            case Nil => Solution(BooleanLiteral(false), Error(p.phi+" is UNSAT!").setType(tpe), 200)
           }
 
           List(new Task(synth, parent, this, p, Nil, onSuccess, 200))
@@ -100,7 +101,8 @@ class CaseSplit(synth: Synthesizer) extends Rule("Case-Split", synth) {
         val sub2 = Problem(p.as, o2, p.xs)
 
         val onSuccess: List[Solution] => Solution = { 
-          case List(s1, s2) => Solution(Or(s1.pre, s2.pre), IfExpr(s1.pre, s1.term, s2.term))
+          case List(s1, s2) => Solution(Or(s1.pre, s2.pre), IfExpr(s1.pre, s1.term, s2.term), 100)
+          case _ => Solution.none
         }
 
         List(new Task(synth, parent, this, p, List(sub1, sub2), onSuccess, 100))
@@ -109,3 +111,36 @@ 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] = {
+    p.phi match {
+      case TopLevelAnds(exprs) =>
+        val xsSet = p.xs.toSet
+
+        val (exprsA, others) = exprs.partition(e => (variablesOf(e) & xsSet).isEmpty)
+
+        if (!exprsA.isEmpty) {
+          if (others.isEmpty) {
+            val onSuccess: List[Solution] => Solution = { 
+              case Nil => Solution(And(exprsA), BooleanLiteral(true), 150)
+              case _ => Solution.none
+            }
+
+            List(new Task(synth, parent, this, p, Nil, onSuccess, 150))
+          } 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))
+          }
+        } else {
+          Nil
+        }
+      case _ =>
+        Nil
+    }
+  }
+}
diff --git a/src/main/scala/leon/synthesis/Solution.scala b/src/main/scala/leon/synthesis/Solution.scala
index 8346a9a60..f9e9f28c3 100644
--- a/src/main/scala/leon/synthesis/Solution.scala
+++ b/src/main/scala/leon/synthesis/Solution.scala
@@ -5,12 +5,12 @@ import leon.purescala.Trees._
 
 // Defines a synthesis solution of the form:
 // ⟨ P | T ⟩
-case class Solution(pre: Expr, term: Expr) {
+case class Solution(pre: Expr, term: Expr, score: Score = 0) {
   override def toString = "⟨ "+pre+" | "+term+" ⟩" 
 }
 
 object Solution {
-  def choose(p: Problem): Solution = Solution(BooleanLiteral(true), Choose(p.xs, p.phi))
+  def choose(p: Problem): Solution = Solution(BooleanLiteral(true), Choose(p.xs, p.phi), 0)
 
   def none: Solution = throw new Exception("Unexpected failure to construct solution")
 }
diff --git a/src/main/scala/leon/synthesis/Synthesizer.scala b/src/main/scala/leon/synthesis/Synthesizer.scala
index 437556701..12da7a5e3 100644
--- a/src/main/scala/leon/synthesis/Synthesizer.scala
+++ b/src/main/scala/leon/synthesis/Synthesizer.scala
@@ -40,7 +40,6 @@ class Synthesizer(val r: Reporter, val solvers: List[Solver]) {
 
             alternatives.find(_.isSuccess) match {
               case Some(ss) =>
-                info(" => Success!")
                 ss.succeeded()
               case None =>
                 info(" => Possible Next Steps:")
diff --git a/src/main/scala/leon/synthesis/Task.scala b/src/main/scala/leon/synthesis/Task.scala
index 7941afea6..fd6702c81 100644
--- a/src/main/scala/leon/synthesis/Task.scala
+++ b/src/main/scala/leon/synthesis/Task.scala
@@ -27,15 +27,16 @@ class Task(
 
   def subSucceeded(p: Problem, s: Solution) {
     assert(subProblems contains p, "Problem "+p+" is unknown to me ?!?")
-    assert(!(subSolutions contains p), "I already have a solution for "+p+" ?!?")
 
-    subSolutions += p -> s
+    if (subSolutions.get(p).map(_.score).getOrElse(-1) < s.score) {
+      subSolutions += p -> s
 
-    if (subSolutions.size == subProblems.size) {
+      if (subSolutions.size == subProblems.size) {
 
-      val solution = onSuccess(subProblems map subSolutions) 
+        val solution = onSuccess(subProblems map subSolutions) 
 
-      synth.onTaskSucceeded(this, solution)
+        synth.onTaskSucceeded(this, solution)
+      }
     }
   }
 
-- 
GitLab