From 76c761d22fb6626133ddec5c3e86a71ba0eda9af Mon Sep 17 00:00:00 2001
From: "Emmanouil (Manos) Koukoutos" <emmanouil.koukoutos@epfl.ch>
Date: Wed, 17 Dec 2014 17:13:24 +0100
Subject: [PATCH] Introduce Witness, and Guide and Terminating as implementing
 classes

---
 library/annotation/package.scala              |  2 --
 library/lang/synthesis/package.scala          |  7 ------
 .../scala/leon/purescala/PrettyPrinter.scala  |  8 ++++++
 src/main/scala/leon/purescala/TreeOps.scala   | 25 +++++++++++++++++--
 .../scala/leon/repair/RepairCostModel.scala   |  1 +
 src/main/scala/leon/repair/Repairman.scala    | 10 +++-----
 .../leon/repair/rules/GuidedCloser.scala      |  6 ++---
 .../leon/repair/rules/GuidedDecomp.scala      |  6 ++---
 .../scala/leon/synthesis/ChooseInfo.scala     |  5 ++--
 src/main/scala/leon/synthesis/Problem.scala   |  4 ++-
 src/main/scala/leon/synthesis/Witnesses.scala | 24 ++++++++++++++++++
 .../scala/leon/synthesis/rules/Cegless.scala  |  5 ++--
 .../scala/leon/synthesis/rules/Tegless.scala  |  5 ++--
 .../scala/leon/synthesis/utils/Helpers.scala  |  8 +++---
 src/main/scala/leon/utils/Library.scala       |  8 ------
 15 files changed, 78 insertions(+), 46 deletions(-)
 create mode 100644 src/main/scala/leon/synthesis/Witnesses.scala

diff --git a/library/annotation/package.scala b/library/annotation/package.scala
index 2db992498..f6e084cda 100644
--- a/library/annotation/package.scala
+++ b/library/annotation/package.scala
@@ -11,8 +11,6 @@ package object annotation {
   class verified   extends StaticAnnotation
   @ignore
   class repair     extends StaticAnnotation
-  @ignore
-  class witness    extends StaticAnnotation
 
   @ignore
   class induct     extends StaticAnnotation
diff --git a/library/lang/synthesis/package.scala b/library/lang/synthesis/package.scala
index 1f5f749b6..e4f50b403 100644
--- a/library/lang/synthesis/package.scala
+++ b/library/lang/synthesis/package.scala
@@ -38,11 +38,4 @@ package object synthesis {
   @ignore
   def withOracle[A, R](body: Oracle[A] => R): R = noImpl
 
-  @library
-  @witness
-  def terminating[T](t: T): Boolean = true
-
-  @library
-  @witness
-  def guide[T](e: T): Boolean = true
 }
diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala
index 899605eb1..cda5084b9 100644
--- a/src/main/scala/leon/purescala/PrettyPrinter.scala
+++ b/src/main/scala/leon/purescala/PrettyPrinter.scala
@@ -16,6 +16,8 @@ import PrinterHelpers._
 import TreeOps.{isStringLiteral, isListLiteral}
 import TypeTreeOps.leastUpperBound
 
+import synthesis.Witnesses._
+
 case class PrinterContext(
   current: Tree,
   parent: Option[Tree],
@@ -389,6 +391,12 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe
               |} else $ie"""
         }
 
+      case Terminating(tfd, args) =>
+        p"↓ ${tfd.id}($args)"
+
+      case Guide(e) =>
+        p"⊙ {$e}"
+
       case IfExpr(c, t, e) =>
         optP {
           p"""|if ($c) {
diff --git a/src/main/scala/leon/purescala/TreeOps.scala b/src/main/scala/leon/purescala/TreeOps.scala
index db98554b6..e493ecbb3 100644
--- a/src/main/scala/leon/purescala/TreeOps.scala
+++ b/src/main/scala/leon/purescala/TreeOps.scala
@@ -1331,6 +1331,8 @@ object TreeOps {
         newFD
     }
 
+    import synthesis.Witnesses.Terminating
+    
     def pre(e : Expr) : Expr = e match {
       case Tuple(Seq()) => UnitLiteral()
       case Variable(id) if idMap contains id => Variable(idMap(id))
@@ -1351,6 +1353,9 @@ object TreeOps {
 
       case FunctionInvocation(tfd, args) =>
         FunctionInvocation(fd2fd(tfd.fd).typed(tfd.tps), args)
+      
+      case Terminating(tfd, args) =>
+        Terminating(fd2fd(tfd.fd).typed(tfd.tps), args)
 
       case _ => e
     }
@@ -1626,6 +1631,8 @@ object TreeOps {
         
       }
 
+      import synthesis.Witnesses.Terminating
+      
       val res = (t1, t2) match {
         case (Variable(i1), Variable(i2)) =>
           idHomo(i1, i2)
@@ -1659,7 +1666,12 @@ object TreeOps {
           // TODO: Check type params
           fdHomo(tfd1.fd, tfd2.fd) &&
           (args1 zip args2).forall{ case (a1, a2) => isHomo(a1, a2) }
-
+          
+        case (Terminating(tfd1, args1), Terminating(tfd2, args2)) =>
+          // TODO: Check type params
+          fdHomo(tfd1.fd, tfd2.fd) &&
+          (args1 zip args2).forall{ case (a1, a2) => isHomo(a1, a2) }
+        
         case Same(UnaryOperator(e1, _), UnaryOperator(e2, _)) =>
           isHomo(e1, e2)
 
@@ -2041,6 +2053,8 @@ object TreeOps {
    */
   def liftClosures(e: Expr): (Set[FunDef], Expr) = {
     var fds: Map[FunDef, FunDef] = Map()
+    
+    import synthesis.Witnesses.Terminating
     val res1 = preMap({
       case LetDef(fd, b) =>
         val nfd = new FunDef(fd.id.freshen, fd.tparams, fd.returnType, fd.params, fd.defType)
@@ -2051,12 +2065,19 @@ object TreeOps {
 
         Some(LetDef(nfd, b))
 
-      case fi @ FunctionInvocation(tfd, args) =>
+      case FunctionInvocation(tfd, args) =>
         if (fds contains tfd.fd) {
           Some(FunctionInvocation(fds(tfd.fd).typed(tfd.tps), args))
         } else {
           None
         }
+        
+      case Terminating(tfd, args) =>
+        if (fds contains tfd.fd) {
+          Some(Terminating(fds(tfd.fd).typed(tfd.tps), args))
+        } else {
+          None
+        }
 
       case _ =>
         None
diff --git a/src/main/scala/leon/repair/RepairCostModel.scala b/src/main/scala/leon/repair/RepairCostModel.scala
index 8de1a98f5..8525db32f 100644
--- a/src/main/scala/leon/repair/RepairCostModel.scala
+++ b/src/main/scala/leon/repair/RepairCostModel.scala
@@ -3,6 +3,7 @@
 package leon
 package repair
 import synthesis._
+import Witnesses._
 
 import synthesis.rules._
 import repair.rules._
diff --git a/src/main/scala/leon/repair/Repairman.scala b/src/main/scala/leon/repair/Repairman.scala
index 65aa3f9b8..1c34786ad 100644
--- a/src/main/scala/leon/repair/Repairman.scala
+++ b/src/main/scala/leon/repair/Repairman.scala
@@ -20,6 +20,7 @@ import verification._
 import synthesis._
 import synthesis.rules._
 import synthesis.heuristics._
+import synthesis.Witnesses._
 import graph.DotGenerator
 import leon.utils.ASCIIHelpers.title
 
@@ -100,7 +101,7 @@ class Repairman(ctx: LeonContext, initProgram: Program, fd: FunDef, verifTimeout
     val (newBody, replacedExpr) = focusRepair(program, fd, passingTests, failingTests)
     fd.body = Some(newBody)
 
-    val guide = guideOf(replacedExpr)
+    val guide = Guide(replacedExpr)
 
     // Return synthesizer for this choose
     val soptions0 = SynthesisPhase.processOptions(ctx);
@@ -119,18 +120,13 @@ class Repairman(ctx: LeonContext, initProgram: Program, fd: FunDef, verifTimeout
     // extract chooses from nfd
     val Seq(ci) = ChooseInfo.extractFromFunction(ctx, program, fd, soptions)
 
-    val nci = ci.copy(pc = and(ci.pc, guideOf(replacedExpr)))
+    val nci = ci.copy(pc = and(ci.pc, guide))
 
     val p = nci.problem
 
     new Synthesizer(ctx, fd, program, p, soptions)
   }
 
-  private def guideOf(expr: Expr): Expr = {
-    val gfd = program.library.guide.get.typed(Seq(expr.getType))
-    FunctionInvocation(gfd, Seq(expr))
-  }
-
   private def focusRepair(program: Program, fd: FunDef, passingTests: List[Example], failingTests: List[Example]): (Expr, Expr) = {
 
     reporter.ifDebug { printer =>
diff --git a/src/main/scala/leon/repair/rules/GuidedCloser.scala b/src/main/scala/leon/repair/rules/GuidedCloser.scala
index 30062477c..0b74f529a 100644
--- a/src/main/scala/leon/repair/rules/GuidedCloser.scala
+++ b/src/main/scala/leon/repair/rules/GuidedCloser.scala
@@ -15,16 +15,16 @@ import purescala.TreeOps._
 import purescala.Extractors._
 import purescala.Constructors._
 
+import Witnesses._
+
 import solvers._
 
 case object GuidedCloser extends NormalizingRule("Guided Closer") {
   def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = {
     val TopLevelAnds(clauses) = p.ws
 
-    val guide = sctx.program.library.guide.get
-
     val guides = clauses.collect {
-      case FunctionInvocation(TypedFunDef(`guide`, _), Seq(expr)) => expr
+      case Guide(expr) => expr
     }
 
     val alts = guides.filter(isDeterministic).flatMap { e =>
diff --git a/src/main/scala/leon/repair/rules/GuidedDecomp.scala b/src/main/scala/leon/repair/rules/GuidedDecomp.scala
index f200f6909..b07af84b9 100644
--- a/src/main/scala/leon/repair/rules/GuidedDecomp.scala
+++ b/src/main/scala/leon/repair/rules/GuidedDecomp.scala
@@ -16,16 +16,16 @@ import purescala.TreeOps._
 import purescala.Extractors._
 import purescala.Constructors._
 
+import Witnesses._
+
 import solvers._
 
 case object GuidedDecomp extends Rule("Guided Decomp") {
   def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = {
     val TopLevelAnds(clauses) = p.ws
 
-    val guide = sctx.program.library.guide.get
-
     val guides = clauses.collect {
-      case FunctionInvocation(TypedFunDef(`guide`, _), Seq(expr)) => expr
+      case Guide(expr) => expr
     }
 
     val simplify = Simplifiers.bestEffort(sctx.context, sctx.program)_
diff --git a/src/main/scala/leon/synthesis/ChooseInfo.scala b/src/main/scala/leon/synthesis/ChooseInfo.scala
index 1cf50638d..142498c59 100644
--- a/src/main/scala/leon/synthesis/ChooseInfo.scala
+++ b/src/main/scala/leon/synthesis/ChooseInfo.scala
@@ -9,6 +9,7 @@ import purescala.Constructors._
 import purescala.Trees._
 import purescala.TreeOps._
 import purescala.DefOps._
+import Witnesses._
 
 case class ChooseInfo(ctx: LeonContext,
                       prog: Program,
@@ -35,11 +36,9 @@ object ChooseInfo {
   }
 
   def extractFromFunction(ctx: LeonContext, prog: Program, fd: FunDef, options: SynthesisSettings): Seq[ChooseInfo] = {
-    val fterm = prog.library.terminating.getOrElse(ctx.reporter.fatalError("No library ?!?"))
 
     val actualBody = and(fd.precondition.getOrElse(BooleanLiteral(true)), fd.body.get)
-    val withinCall = FunctionInvocation(fd.typedWithDef, fd.params.map(_.id.toVariable))
-    val term = FunctionInvocation(fterm.typed(Seq(fd.returnType)), Seq(withinCall))
+    val term = Terminating(fd.typedWithDef, fd.params.map(_.id.toVariable))
 
     for ((ch, path) <- new ChooseCollectorWithPaths().traverse(actualBody)) yield {
       ChooseInfo(ctx, prog, fd, and(path, term), ch, ch, options)
diff --git a/src/main/scala/leon/synthesis/Problem.scala b/src/main/scala/leon/synthesis/Problem.scala
index 468754c7c..24d95f577 100644
--- a/src/main/scala/leon/synthesis/Problem.scala
+++ b/src/main/scala/leon/synthesis/Problem.scala
@@ -10,6 +10,7 @@ import leon.purescala.TypeTrees.TypeTree
 import leon.purescala.Common._
 import leon.purescala.Constructors._
 import leon.purescala.Extractors._
+import Witnesses._
 
 // Defines a synthesis triple of the form:
 // ⟦ as ⟨ ws && pc | phi ⟩ xs ⟧
@@ -28,10 +29,11 @@ object Problem {
     val phi = simplifyLets(ch.pred)
     val as = (variablesOf(And(pc, phi))--xs).toList
 
+    // FIXME do we need this at all?
     val TopLevelAnds(clauses) = pc
 
     val (pcs, wss) = clauses.partition {
-      case FunctionInvocation(TypedFunDef(fd, _), _) if fd.annotations("witness") => false
+      case w : Witness => false
       case _ => true
     }
 
diff --git a/src/main/scala/leon/synthesis/Witnesses.scala b/src/main/scala/leon/synthesis/Witnesses.scala
new file mode 100644
index 000000000..cfb8e00d2
--- /dev/null
+++ b/src/main/scala/leon/synthesis/Witnesses.scala
@@ -0,0 +1,24 @@
+package leon.synthesis
+
+import leon.purescala._
+import TypeTrees._
+import Definitions.TypedFunDef
+import Extractors._
+import Trees.Expr
+
+
+object Witnesses {
+  
+  class Witness extends Expr {
+    def getType = BooleanType
+  }
+  
+  case class Guide(e : Expr) extends Witness with UnaryExtractable {
+    def extract: Option[(Expr, Expr => Expr)] = Some((e, Guide))
+  }
+  
+  case class Terminating(tfd: TypedFunDef, args: Seq[Expr]) extends Witness with NAryExtractable {    
+    def extract: Option[(Seq[Expr], Seq[Expr] => Expr)] = Some((args, Terminating(tfd, _)))
+  }
+  
+}
\ No newline at end of file
diff --git a/src/main/scala/leon/synthesis/rules/Cegless.scala b/src/main/scala/leon/synthesis/rules/Cegless.scala
index 9c36964a2..914003fec 100644
--- a/src/main/scala/leon/synthesis/rules/Cegless.scala
+++ b/src/main/scala/leon/synthesis/rules/Cegless.scala
@@ -12,16 +12,15 @@ import purescala.Definitions._
 import purescala.Extractors._
 import utils._
 import utils.ExpressionGrammars._
+import Witnesses._
 
 case object CEGLESS extends CEGISLike[Label[String]]("CEGLESS") {
   def getParams(sctx: SynthesisContext, p: Problem) = {
 
     val TopLevelAnds(clauses) = p.ws
 
-    val guide = sctx.program.library.guide.get
-
     val guides = clauses.collect {
-      case FunctionInvocation(TypedFunDef(`guide`, _), Seq(expr)) => expr
+      case Guide(e) => e
     }
 
     val inputs = p.as.map(_.toVariable)
diff --git a/src/main/scala/leon/synthesis/rules/Tegless.scala b/src/main/scala/leon/synthesis/rules/Tegless.scala
index cdef20a9b..e1880752a 100644
--- a/src/main/scala/leon/synthesis/rules/Tegless.scala
+++ b/src/main/scala/leon/synthesis/rules/Tegless.scala
@@ -12,16 +12,15 @@ import purescala.Definitions._
 import purescala.Extractors._
 import utils._
 import utils.ExpressionGrammars._
+import Witnesses._
 
 case object TEGLESS extends TEGISLike[Label[String]]("TEGLESS") {
   def getParams(sctx: SynthesisContext, p: Problem) = {
 
     val TopLevelAnds(clauses) = p.ws
 
-    val guide = sctx.program.library.guide.get
-
     val guides = clauses.collect {
-      case FunctionInvocation(TypedFunDef(`guide`, _), Seq(expr)) => expr
+      case Guide(expr) => expr
     }
 
     val inputs = p.as.map(_.toVariable)
diff --git a/src/main/scala/leon/synthesis/utils/Helpers.scala b/src/main/scala/leon/synthesis/utils/Helpers.scala
index e30571d6d..790711ba7 100644
--- a/src/main/scala/leon/synthesis/utils/Helpers.scala
+++ b/src/main/scala/leon/synthesis/utils/Helpers.scala
@@ -12,6 +12,7 @@ import purescala.Trees._
 import purescala.TreeOps._
 import purescala.DefOps._
 import purescala.Common._
+import Witnesses._
 
 object Helpers {
   /**
@@ -35,13 +36,12 @@ object Helpers {
   }
 
   def terminatingCalls(prog: Program, tpe: TypeTree, ws: Expr, pc: Expr): List[(Expr, Set[Identifier])] = {
-    val terminating = prog.library.terminating.get
 
     val TopLevelAnds(wss) = ws
     val TopLevelAnds(clauses) = pc
 
-    val gs: List[FunctionInvocation] = wss.toList.collect {
-      case FunctionInvocation(TypedFunDef(`terminating`, _), Seq(fi: FunctionInvocation)) => fi
+    val gs: List[Terminating] = wss.toList.collect {
+      case t : Terminating => t
     }
 
     def subExprsOf(expr: Expr, v: Variable): Option[(Variable, Expr)] = expr match {
@@ -68,7 +68,7 @@ object Helpers {
     }
 
     val res = gs.flatMap {
-      case FunctionInvocation(tfd, args) if isSubtypeOf(tfd.returnType, tpe) =>
+      case Terminating(tfd, args) if isSubtypeOf(tfd.returnType, tpe) =>
         val ids = tfd.params.map(vd => FreshIdentifier("<hole>", true).setType(vd.tpe)).toList
 
         for (((a, i), tpe) <- args.zipWithIndex zip tfd.params.map(_.tpe);
diff --git a/src/main/scala/leon/utils/Library.scala b/src/main/scala/leon/utils/Library.scala
index 2a254a861..d80fd76a0 100644
--- a/src/main/scala/leon/utils/Library.scala
+++ b/src/main/scala/leon/utils/Library.scala
@@ -13,14 +13,6 @@ case class Library(pgm: Program) {
 
   lazy val String = lookup("leon.lang.string.String")
 
-  lazy val terminating: Option[FunDef] = lookup("leon.lang.synthesis.terminating").collect {
-    case fd: FunDef => fd
-  }
-
-  lazy val guide = lookup("leon.lang.synthesis.guide") collect {
-    case (fd: FunDef) => fd
-  }
-
   def lookup(name: String): Option[Definition] = {
     searchByFullName(name, pgm)
   }
-- 
GitLab