From 2daefa844dd2200d25b5b80354ffd53ca47dabdb Mon Sep 17 00:00:00 2001
From: "Emmanouil (Manos) Koukoutos" <emmanouil.koukoutos@epfl.ch>
Date: Tue, 4 Nov 2014 16:11:58 +0100
Subject: [PATCH] Generators from subexpressions with placeholders

---
 .../synthesis/utils/ExpressionGrammar.scala   | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala b/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala
index fe63e4ce5..84c6487ae 100644
--- a/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala
+++ b/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala
@@ -170,6 +170,99 @@ class ExpressionGrammar(ctx: LeonContext, prog: Program, inputs: Seq[Expr], curr
     }
   }
 
+  def computeSubexpressionGenerators(canPlacehold : Expr => Boolean)(e : Expr) : Seq[Gen] = {
+
+    /** A simple Generator API **/
+
+    def gen(tps : Seq[TypeTree], f : Seq[Expr] => Expr) : Gen = 
+      Generator[TypeTree, Expr](tps,f)
+
+    // A generator that accepts a single type, and always regenerates its input
+    // (simple placeholder of 1 position)
+    def wildcardGen(tp : TypeTree) = gen(Seq(tp), { case Seq(x) => x })
+
+    // A generator that always regenerates its input
+    def const(e: Expr) : Gen = gen(Seq(), _ => e)
+ 
+    // Creates a new generator by applying f on the result of g.builder
+    def map(f : Expr => Expr)(g : Gen) : Gen = {
+      gen(g.subTrees, es => f(g.builder(es)) )
+    }
+
+    // Concatenate a sequence of generators into a generator.
+    // The arity of the resulting generator is the total arity of the constituting generators.
+    // builder is the function combining the results of the partial generators
+    def concat(gens : Seq[Gen], builder : Seq[Expr] => Expr ) : Gen = {
+      val types = gens flatMap { _.subTrees }
+      gen(
+        types,
+        exprs => {
+          assert(exprs.length == types.length) // Total arity is arity of subgenerators
+          var remaining = exprs
+          val fromSubGens = for (gen <- gens) yield {
+            val (current, rem) = remaining splitAt gen.arity
+            remaining = rem
+            gen.builder(current)
+          }
+          builder(fromSubGens)
+        }
+      )
+          
+    }
+
+    
+    def rec(e : Expr) : Seq[Gen] = {
+      
+      // Add an additional wildcard generator, if current expression passes the filter
+      def optWild(gens : Seq[Gen]) : Seq[Gen] = 
+        if (canPlacehold(e)) {
+           wildcardGen(e.getType) +: gens
+        }
+        else gens
+
+
+      e match {
+
+        case t : Terminal => 
+          // In case of Terminal, we either return the terminal itself, or the input expression
+          optWild(Seq(const(t)))
+          
+        case UnaryOperator(sub, builder) =>
+          val fromSub = for (subGen <- rec(sub)) yield map(builder)(subGen) 
+          optWild(fromSub)
+
+        case BinaryOperator(e1,e2,builder) =>
+          val fromSub = for {
+            subGen1 <- rec(e1)
+            subGen2 <- rec(e2)
+          } yield concat(Seq(subGen1, subGen2), { case Seq(e1,e2) => builder(e1,e2) })
+
+          optWild(fromSub)
+
+        case NAryOperator(subExpressions, builder) =>
+
+          def combinations[A](seqs : Seq[Seq[A]]) : Seq[Seq[A]] = {
+            if (seqs.isEmpty) Seq(Seq())
+            else for {
+              hd <- seqs.head
+              tl <- combinations(seqs.tail)
+            } yield hd +: tl
+          }
+
+          val combos = combinations(subExpressions map rec) 
+          val fromSub = combos map { concat(_, builder) }
+     
+          optWild(fromSub)
+      }
+    }
+    
+    rec(e)
+
+  }
+
+  def computeCompleteSubexpressionGenerators = inputs flatMap computeSubexpressionGenerators{ _ => true}
+
+
   def printGrammar(printer: String => Unit) {
     for ((t, gs) <- cache; g <- gs) {
       val subs = g.subTrees.map { tpe => FreshIdentifier(tpe.toString).setType(tpe).toVariable }
-- 
GitLab