From 1ba68eab543958a376fa969cb1c2b7718a0510f3 Mon Sep 17 00:00:00 2001
From: Nicolas Voirol <voirol.nicolas@gmail.com>
Date: Thu, 3 Nov 2016 10:41:43 +0100
Subject: [PATCH] Better separation between lambda templates and their
 structure key

---
 .../solvers/unrolling/LambdaTemplates.scala   | 27 ++++++++++++-------
 .../unrolling/QuantificationTemplates.scala   |  1 +
 .../solvers/unrolling/TemplateGenerator.scala | 23 +++++++++-------
 3 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/src/main/scala/inox/solvers/unrolling/LambdaTemplates.scala b/src/main/scala/inox/solvers/unrolling/LambdaTemplates.scala
index 14fdc53e3..ad9640ddc 100644
--- a/src/main/scala/inox/solvers/unrolling/LambdaTemplates.scala
+++ b/src/main/scala/inox/solvers/unrolling/LambdaTemplates.scala
@@ -54,6 +54,7 @@ trait LambdaTemplates { self: Templates =>
       ids: (Variable, Encoded),
       pathVar: (Variable, Encoded),
       arguments: Seq[(Variable, Encoded)],
+      closures: Seq[(Variable, Encoded)],
       condVars: Map[Variable, Encoded],
       exprVars: Map[Variable, Encoded],
       condTree: Map[Variable, Set[Variable]],
@@ -70,14 +71,14 @@ trait LambdaTemplates { self: Templates =>
       val tpe = ids._1.getType.asInstanceOf[FunctionType]
       val (clauses, blockers, applications, matchers, templateString) =
         Template.encode(pathVar, arguments, condVars, exprVars, guardedExprs, equations,
-          lambdas, quantifications, substMap = baseSubstMap + ids, optApp = Some(id -> tpe))
+          lambdas, quantifications, substMap = baseSubstMap + ids ++ closures, optApp = Some(id -> tpe))
 
       val lambdaString : () => String = () => {
         "Template for lambda " + ids._1 + ": " + lambda + " is :\n" + templateString()
       }
 
       new LambdaTemplate(
-        ids, pathVar, arguments,
+        ids, pathVar, arguments, closures,
         condVars, exprVars, condTree,
         clauses, blockers, applications, matchers,
         lambdas, quantifications,
@@ -195,6 +196,7 @@ trait LambdaTemplates { self: Templates =>
     val ids: (Variable, Encoded),
     val pathVar: (Variable, Encoded),
     val arguments: Seq[(Variable, Encoded)],
+    val closures: Seq[(Variable, Encoded)],
     val condVars: Map[Variable, Encoded],
     val exprVars: Map[Variable, Encoded],
     val condTree: Map[Variable, Set[Variable]],
@@ -214,7 +216,7 @@ trait LambdaTemplates { self: Templates =>
     def substitute(substituter: Encoded => Encoded, msubst: Map[Encoded, Matcher]): LambdaTemplate = new LambdaTemplate(
       ids._1 -> substituter(ids._2),
       pathVar._1 -> substituter(pathVar._2),
-      arguments, condVars, exprVars, condTree,
+      arguments, closures, condVars, exprVars, condTree,
       clauses.map(substituter),
       blockers.map { case (b, fis) => substituter(b) -> fis.map(_.substitute(substituter, msubst)) },
       applications.map { case (b, apps) => substituter(b) -> apps.map(_.substitute(substituter, msubst)) },
@@ -224,12 +226,18 @@ trait LambdaTemplates { self: Templates =>
       structure.substitute(substituter, msubst),
       lambda, stringRepr)
 
-    def withId(idT: Encoded): LambdaTemplate = {
-      val substituter = mkSubstituter(Map(ids._2 -> idT))
+    /** This must be called right before returning the clauses in [[structure.instantiation]]! */
+    def concretize(idT: Encoded): LambdaTemplate = {
+      val substituter = mkSubstituter(Map(ids._2 -> idT) ++ (closures.map(_._2) zip structure.locals.map(_._2)))
       new LambdaTemplate(
-        ids._1 -> idT, pathVar, arguments, condVars, exprVars, condTree,
-        clauses map substituter, // make sure the body-defining clause is inlined!
-        blockers, applications, matchers, lambdas, quantifications,
+        ids._1 -> idT,
+        pathVar, arguments, closures, condVars, exprVars, condTree,
+        clauses map substituter,
+        blockers.map { case (b, fis) => b -> fis.map(_.substitute(substituter, Map.empty)) },
+        applications.map { case (b, apps) => b -> apps.map(_.substitute(substituter, Map.empty)) },
+        matchers.map { case (b, ms) => b -> ms.map(_.substitute(substituter, Map.empty)) },
+        lambdas.map(_.substitute(substituter, Map.empty)),
+        quantifications.map(_.substitute(substituter, Map.empty)),
         structure, lambda, stringRepr)
     }
 
@@ -294,7 +302,7 @@ trait LambdaTemplates { self: Templates =>
 
       case None =>
         val idT = encodeSymbol(template.ids._1)
-        val newTemplate = template.withId(idT)
+        val newTemplate = template.concretize(idT)
 
         val orderingClauses = newTemplate.structure.locals.flatMap {
           case (v, dep) => registerClosure(newTemplate.start, idT -> newTemplate.tpe, dep -> v.tpe)
@@ -320,7 +328,6 @@ trait LambdaTemplates { self: Templates =>
           extClauses ++
           arglessEqClauses
 
-
         byID += idT -> newTemplate
         byType += newTemplate.tpe -> (byType(newTemplate.tpe) + (newTemplate.structure -> newTemplate))
 
diff --git a/src/main/scala/inox/solvers/unrolling/QuantificationTemplates.scala b/src/main/scala/inox/solvers/unrolling/QuantificationTemplates.scala
index 0cce88476..46d591a37 100644
--- a/src/main/scala/inox/solvers/unrolling/QuantificationTemplates.scala
+++ b/src/main/scala/inox/solvers/unrolling/QuantificationTemplates.scala
@@ -308,6 +308,7 @@ trait QuantificationTemplates { self: Templates =>
     if (handledMatchers(relevantBlockers -> matcher)) {
       Seq.empty
     } else {
+      ctx.reporter.debug(" -> instantiating matcher " + blockers.mkString("{",",","}") + " ==> " + matcher)
       handledMatchers += relevantBlockers -> matcher
       quantifications.flatMap(_.instantiate(relevantBlockers, matcher, defer))
     }
diff --git a/src/main/scala/inox/solvers/unrolling/TemplateGenerator.scala b/src/main/scala/inox/solvers/unrolling/TemplateGenerator.scala
index 9d4f63a07..96cdd6408 100644
--- a/src/main/scala/inox/solvers/unrolling/TemplateGenerator.scala
+++ b/src/main/scala/inox/solvers/unrolling/TemplateGenerator.scala
@@ -276,24 +276,25 @@ trait TemplateGenerator { self: Templates =>
         val idArgs : Seq[Variable] = lambdaArgs(l)
         val trArgs : Seq[Encoded] = idArgs.map(id => substMap.getOrElse(id, encodeSymbol(id)))
 
+        val (struct, deps) = normalizeStructure(l)
+        val sortedDeps = deps.toSeq.sortBy(_._1.id.uniqueName)
+        val idDeps = sortedDeps.map(_._1)
+        val trDeps = idDeps.map(id => encodeSymbol(id))
+
         val lid = Variable(FreshIdentifier("lambda", true), bestRealType(l.getType))
-        val clauses = liftedEquals(lid, l, idArgs, inlineFirst = true)
+        val clauses = liftedEquals(lid, struct, idArgs, inlineFirst = true)
 
         val localSubst: Map[Variable, Encoded] = substMap ++ condVars ++ exprVars ++ lambdaVars
-        val clauseSubst: Map[Variable, Encoded] = localSubst ++ (idArgs zip trArgs)
+        val clauseSubst: Map[Variable, Encoded] = localSubst ++ (idArgs zip trArgs) ++ (idDeps zip trDeps)
         val (lambdaConds, lambdaExprs, lambdaTree, lambdaGuarded, lambdaEqs, lambdaTemplates, lambdaQuants) =
           clauses.foldLeft(emptyClauses)((clsSet, cls) => clsSet ++ mkClauses(pathVar, cls, clauseSubst))
 
         val ids: (Variable, Encoded) = lid -> storeLambda(lid)
 
-        val (struct, deps) = normalizeStructure(l)
-        val sortedDeps = deps.toSeq.sortBy(_._1.id.uniqueName)
-
         val (dependencies, (depConds, depExprs, depTree, depGuarded, depEqs, depLambdas, depQuants)) =
           sortedDeps.foldLeft[(Seq[Encoded], TemplateClauses)](Seq.empty -> emptyClauses) {
-            case ((dependencies, clsSet), (id, expr)) =>
+            case ((dependencies, clsSet), (_, expr)) =>
               if (!exprOps.isSimple(expr)) {
-                val encoded = encodeSymbol(id)
                 val (e, cls @ (_, _, _, _, _, lmbds, quants)) = mkExprClauses(pathVar, expr, localSubst)
                 val clauseSubst = localSubst ++ lmbds.map(_.ids) ++ quants.flatMap(_.mapping)
                 (dependencies :+ mkEncoder(clauseSubst)(e), clsSet ++ cls)
@@ -307,9 +308,11 @@ trait TemplateGenerator { self: Templates =>
           depConds, depExprs, depGuarded, depEqs, depLambdas, depQuants, localSubst)
 
         val depClosures: Seq[Encoded] = {
-          val vars = exprOps.variablesOf(l)
           var cls: Seq[Variable] = Seq.empty
-          exprOps.preTraversal { case v: Variable if vars(v) => cls :+= v case _ => } (l)
+          for ((_, e) <- sortedDeps) {
+            val vars = exprOps.variablesOf(e).toSet
+            exprOps.preTraversal { case v: Variable if vars(v) => cls :+= v case _ => } (e)
+          }
           cls.distinct.map(localSubst)
         }
 
@@ -318,7 +321,7 @@ trait TemplateGenerator { self: Templates =>
           depConds, depExprs, depTree, depClauses, depCalls, depApps, depMatchers, depLambdas, depQuants)
 
         val template = LambdaTemplate(ids, pathVar -> encodedCond(pathVar),
-          idArgs zip trArgs, lambdaConds, lambdaExprs, lambdaTree,
+          idArgs zip trArgs, idDeps zip trDeps, lambdaConds, lambdaExprs, lambdaTree,
           lambdaGuarded, lambdaEqs, lambdaTemplates, lambdaQuants, structure, localSubst, l)
         registerLambda(template)
         lid
-- 
GitLab