diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala index 8b24c2053de01c42becd5336dfce113d0043b75c..ce0656727dbca2499600a3b6ff84704aa9daa6b8 100644 --- a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala +++ b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala @@ -538,10 +538,8 @@ trait SMTLIBTarget extends Interruptible { * ===== Everything else ===== */ case ap @ Application(caller, args) => - FunctionApplication( - declareLambda(caller.getType.asInstanceOf[FunctionType]), - (caller +: args).map(toSMT) - ) + val dyn = declareLambda(caller.getType.asInstanceOf[FunctionType]) + FunctionApplication(dyn, (caller +: args).map(toSMT)) case Not(u) => Core.Not(toSMT(u)) case UMinus(u) => Ints.Neg(toSMT(u)) diff --git a/src/main/scala/leon/solvers/templates/LambdaManager.scala b/src/main/scala/leon/solvers/templates/LambdaManager.scala index 75d163815a17fbf31c56b684d58e3d26efe7feaa..d1aa0377a8f939830cb877c5aba78071d74c2de6 100644 --- a/src/main/scala/leon/solvers/templates/LambdaManager.scala +++ b/src/main/scala/leon/solvers/templates/LambdaManager.scala @@ -72,6 +72,36 @@ object LambdaTemplate { } } +trait KeyedTemplate[T, E <: Expr] { + val dependencies: Map[Identifier, T] + val structuralKey: E + + lazy val key: (E, Seq[T]) = { + def rec(e: Expr): Seq[Identifier] = e match { + case Variable(id) => + if (dependencies.isDefinedAt(id)) { + Seq(id) + } else { + Seq.empty + } + + case Operator(es, _) => es.flatMap(rec) + + case _ => Seq.empty + } + + structuralKey -> rec(structuralKey).distinct.map(dependencies) + } + + override def equals(that: Any): Boolean = that match { + case t: KeyedTemplate[T, E] => + key == t.key + case _ => false + } + + override def hashCode: Int = key.hashCode +} + class LambdaTemplate[T] private ( val ids: (Identifier, T), val encoder: TemplateEncoder[T], @@ -87,9 +117,9 @@ class LambdaTemplate[T] private ( val quantifications: Seq[QuantificationTemplate[T]], val matchers: Map[T, Set[Matcher[T]]], val lambdas: Seq[LambdaTemplate[T]], - private[templates] val dependencies: Map[Identifier, T], - private[templates] val structuralKey: Lambda, - stringRepr: () => String) extends Template[T] { + val dependencies: Map[Identifier, T], + val structuralKey: Lambda, + stringRepr: () => String) extends Template[T] with KeyedTemplate[T, Lambda] { val args = arguments.map(_._2) val tpe = ids._1.getType.asInstanceOf[FunctionType] @@ -139,43 +169,18 @@ class LambdaTemplate[T] private ( ) } - private lazy val str : String = stringRepr() - override def toString : String = str - - lazy val key: (Expr, Seq[T]) = { - def rec(e: Expr): Seq[Identifier] = e match { - case Variable(id) => - if (dependencies.isDefinedAt(id)) { - Seq(id) - } else { - Seq.empty - } - - case Operator(es, _) => es.flatMap(rec) - - case _ => Seq.empty - } - - structuralKey -> rec(structuralKey).distinct.map(dependencies) - } - - override def equals(that: Any): Boolean = that match { - case t: LambdaTemplate[T] => - val (lambda1, deps1) = key - val (lambda2, deps2) = t.key - (lambda1 == lambda2) && { - (deps1 zip deps2).forall { case (id1, id2) => - (manager.byID.get(id1), manager.byID.get(id2)) match { - case (Some(t1), Some(t2)) => t1 == t2 - case _ => id1 == id2 - } - } - } - - case _ => false + def withId(idT: T): LambdaTemplate[T] = { + val substituter = encoder.substitute(Map(ids._2 -> idT)) + new LambdaTemplate[T]( + ids._1 -> idT, encoder, manager, pathVar, arguments, condVars, exprVars, condTree, + clauses map substituter, // make sure the body-defining clause is inlined! + blockers, applications, quantifications, matchers, lambdas, + dependencies, structuralKey, stringRepr + ) } - override def hashCode: Int = key.hashCode + private lazy val str : String = stringRepr() + override def toString : String = str override def instantiate(substMap: Map[T, T]): Instantiation[T] = { super.instantiate(substMap) ++ manager.instantiateAxiom(this, substMap) @@ -186,7 +191,7 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) extends TemplateManager(enco private[templates] lazy val trueT = encoder.encodeExpr(Map.empty)(BooleanLiteral(true)) protected[templates] val byID = new IncrementalMap[T, LambdaTemplate[T]] - protected val byType = new IncrementalMap[FunctionType, Set[LambdaTemplate[T]]].withDefaultValue(Set.empty) + protected val byType = new IncrementalMap[FunctionType, Map[(Expr, Seq[T]), LambdaTemplate[T]]].withDefaultValue(Map.empty) protected val applications = new IncrementalMap[FunctionType, Set[(T, App[T])]].withDefaultValue(Set.empty) protected val freeLambdas = new IncrementalMap[FunctionType, Set[T]].withDefaultValue(Set.empty) @@ -203,27 +208,30 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) extends TemplateManager(enco } } - def instantiateLambda(template: LambdaTemplate[T]): Instantiation[T] = { - val idT = template.ids._2 - var clauses : Clauses[T] = equalityClauses(template) - var appBlockers : AppBlockers[T] = Map.empty.withDefaultValue(Set.empty) + def instantiateLambda(template: LambdaTemplate[T]): (T, Instantiation[T]) = { + byType(template.tpe).get(template.key) match { + case Some(template) => + (template.ids._2, Instantiation.empty) - // make sure the new lambda isn't equal to any free lambda var - clauses ++= freeLambdas(template.tpe).map(pIdT => encoder.mkNot(encoder.mkEquals(pIdT, idT))) + case None => + val idT = encoder.encodeId(template.ids._1) + val newTemplate = template.withId(idT) - byID += idT -> template + var clauses : Clauses[T] = equalityClauses(newTemplate) + var appBlockers : AppBlockers[T] = Map.empty.withDefaultValue(Set.empty) - if (byType(template.tpe)(template)) { - (clauses, Map.empty, Map.empty) - } else { - byType += template.tpe -> (byType(template.tpe) + template) + // make sure the new lambda isn't equal to any free lambda var + clauses ++= freeLambdas(newTemplate.tpe).map(pIdT => encoder.mkNot(encoder.mkEquals(pIdT, idT))) - for (blockedApp @ (_, App(caller, tpe, args)) <- applications(template.tpe)) { - val equals = encoder.mkEquals(idT, caller) - appBlockers += (blockedApp -> (appBlockers(blockedApp) + TemplateAppInfo(template, equals, args))) - } + byID += idT -> newTemplate + byType += newTemplate.tpe -> (byType(newTemplate.tpe) + (newTemplate.key -> newTemplate)) + + for (blockedApp @ (_, App(caller, tpe, args)) <- applications(newTemplate.tpe)) { + val equals = encoder.mkEquals(idT, caller) + appBlockers += (blockedApp -> (appBlockers(blockedApp) + TemplateAppInfo(newTemplate, equals, args))) + } - (clauses, Map.empty, appBlockers) + (idT, (clauses, Map.empty, appBlockers)) } } @@ -244,7 +252,7 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) extends TemplateManager(enco // make sure that even if byType(tpe) is empty, app is recorded in blockers // so that UnrollingBank will generate the initial block! val init = instantiation withApps Map(key -> Set.empty) - val inst = byType(tpe).foldLeft(init) { + val inst = byType(tpe).values.foldLeft(init) { case (instantiation, template) => val equals = encoder.mkEquals(template.ids._2, caller) instantiation withApp (key -> TemplateAppInfo(template, equals, args)) @@ -260,7 +268,7 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) extends TemplateManager(enco private def equalityClauses(template: LambdaTemplate[T]): Seq[T] = { val (s1, deps1) = template.key - byType(template.tpe).map { that => + byType(template.tpe).values.map { that => val (s2, deps2) = that.key val equals = encoder.mkEquals(template.ids._2, that.ids._2) if (s1 == s2) { diff --git a/src/main/scala/leon/solvers/templates/QuantificationManager.scala b/src/main/scala/leon/solvers/templates/QuantificationManager.scala index c7f715b5eefe573d88eeb94b45293ba7cde646bf..314c7549c0899488ba9e78c9739e4718e350b608 100644 --- a/src/main/scala/leon/solvers/templates/QuantificationManager.scala +++ b/src/main/scala/leon/solvers/templates/QuantificationManager.scala @@ -58,7 +58,9 @@ class QuantificationTemplate[T]( val blockers: Map[T, Set[TemplateCallInfo[T]]], val applications: Map[T, Set[App[T]]], val matchers: Map[T, Set[Matcher[T]]], - val lambdas: Seq[LambdaTemplate[T]]) { + val lambdas: Seq[LambdaTemplate[T]], + val dependencies: Map[Identifier, T], + val structuralKey: Forall) extends KeyedTemplate[T, Forall] { lazy val start = pathVar._2 @@ -84,7 +86,9 @@ class QuantificationTemplate[T]( matchers.map { case (b, ms) => substituter(b) -> ms.map(_.substitute(substituter)) }, - lambdas.map(_.substitute(substituter)) + lambdas.map(_.substitute(substituter)), + dependencies.map { case (id, value) => id -> substituter(value) }, + structuralKey ) } } @@ -104,7 +108,9 @@ object QuantificationTemplate { condTree: Map[Identifier, Set[Identifier]], guardedExprs: Map[Identifier, Seq[Expr]], lambdas: Seq[LambdaTemplate[T]], - subst: Map[Identifier, T] + baseSubstMap: Map[Identifier, T], + dependencies: Map[Identifier, T], + proposition: Forall ): QuantificationTemplate[T] = { val q2s: (Identifier, T) = q2 -> encoder.encodeId(q2) @@ -113,11 +119,15 @@ object QuantificationTemplate { val (clauses, blockers, applications, matchers, _) = Template.encode(encoder, pathVar, quantifiers, condVars, exprVars, guardedExprs, lambdas, - substMap = subst + q2s + insts + guards + qs) + substMap = baseSubstMap + q2s + insts + guards + qs) + + val (structuralQuant, structSubst) = normalizeStructure(proposition) + val keyDeps = dependencies.map { case (id, idT) => structSubst(id) -> idT } + val key = structuralQuant.asInstanceOf[Forall] new QuantificationTemplate[T](quantificationManager, - pathVar, qs, q2s, insts, guards._2, quantifiers, - condVars, exprVars, condTree, clauses, blockers, applications, matchers, lambdas) + pathVar, qs, q2s, insts, guards._2, quantifiers, condVars, exprVars, condTree, + clauses, blockers, applications, matchers, lambdas, keyDeps, key) } } @@ -130,9 +140,10 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage private val known = new IncrementalSet[T] private val lambdaAxioms = new IncrementalSet[(LambdaTemplate[T], Seq[(Identifier, T)])] + private val templates = new IncrementalMap[(Expr, Seq[T]), T] override protected def incrementals: List[IncrementalState] = - List(quantifications, instCtx, handled, ignored, known, lambdaAxioms) ++ super.incrementals + List(quantifications, instCtx, handled, ignored, known, lambdaAxioms, templates) ++ super.incrementals private sealed abstract class MatcherKey(val tpe: TypeTree) private case class CallerKey(caller: T, tt: TypeTree) extends MatcherKey(tt) @@ -441,12 +452,12 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage instantiation = instantiation withClause encoder.mkEquals(enabler, optEnabler.get) } - val baseSubstMap = exprVars.map { case (id, idT) => idT -> encoder.encodeId(id) } ++ - freshConds(pathVar._1 -> enabler, condVars, condTree) - val lambdaSubstMap = lambdas map (lambda => lambda.ids._2 -> encoder.encodeId(lambda.ids._1)) - val substMap = subst.mapValues(Matcher.argValue) ++ baseSubstMap ++ lambdaSubstMap ++ instanceSubst(enablers) + val baseSubst = subst.mapValues(Matcher.argValue) ++ instanceSubst(enablers) + val (substMap, inst) = Template.substitution(encoder, QuantificationManager.this, + exprVars, condVars, condTree, Seq.empty, lambdas, baseSubst, pathVar._1, enabler) if (!skip(substMap)) { + instantiation ++= inst instantiation ++= Template.instantiate(encoder, QuantificationManager.this, clauses, blockers, applications, Seq.empty, Map.empty[T, Set[Matcher[T]]], lambdas, substMap) @@ -671,66 +682,63 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage instantiation } - def instantiateQuantification(template: QuantificationTemplate[T], substMap: Map[T, T]): Instantiation[T] = { - val quantified = template.quantifiers.map(_._2).toSet - val matchQuorums = extractQuorums(quantified, template.matchers.flatMap(_._2).toSet, template.lambdas) - - var instantiation = Instantiation.empty[T] - - val qs = for (matchers <- matchQuorums) yield { - val newQ = encoder.encodeId(template.qs._1) - val subst = substMap + (template.qs._2 -> newQ) + def instantiateQuantification(template: QuantificationTemplate[T]): (T, Instantiation[T]) = { + templates.get(template.key) match { + case Some(idT) => + (idT, Instantiation.empty) - val substituter = encoder.substitute(subst) - val quantification = new Quantification( - template.pathVar._1 -> substituter(template.start), - template.qs._1 -> newQ, - template.q2s, template.insts, template.guardVar, - quantified, - matchers map (_.substitute(substituter)), - template.matchers map { case (b, ms) => substituter(b) -> ms.map(_.substitute(substituter)) }, - template.condVars, - template.exprVars, - template.condTree, - template.clauses map substituter, - template.blockers map { case (b, fis) => - substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(substituter))) - }, - template.applications map { case (b, fas) => - substituter(b) -> fas.map(fa => fa.copy(caller = substituter(fa.caller), args = fa.args.map(substituter))) - }, - template.lambdas map (_.substitute(substituter)) - ) + case None => + val qT = encoder.encodeId(template.qs._1) + val quantified = template.quantifiers.map(_._2).toSet + val matchQuorums = extractQuorums(quantified, template.matchers.flatMap(_._2).toSet, template.lambdas) - quantifications += quantification + var instantiation = Instantiation.empty[T] - val newCtx = new InstantiationContext() - for ((b,m) <- instCtx.instantiated) { - instantiation ++= newCtx.instantiate(b, m)(quantification) - } - instCtx.merge(newCtx) + val qs = for (matchers <- matchQuorums) yield { + val newQ = encoder.encodeId(template.qs._1) + val substituter = encoder.substitute(Map(template.qs._2 -> newQ)) + + val quantification = new Quantification( + template.pathVar, + template.qs._1 -> newQ, + template.q2s, template.insts, template.guardVar, + quantified, matchers, template.matchers, + template.condVars, template.exprVars, template.condTree, + template.clauses map substituter, // one clause depends on 'q' (and therefore 'newQ') + template.blockers, template.applications, template.lambdas + ) + + quantifications += quantification + + val newCtx = new InstantiationContext() + for ((b,m) <- instCtx.instantiated) { + instantiation ++= newCtx.instantiate(b, m)(quantification) + } + instCtx.merge(newCtx) - quantification.qs._2 - } + quantification.qs._2 + } - instantiation = instantiation withClause { - val newQs = - if (qs.isEmpty) trueT - else if (qs.size == 1) qs.head - else encoder.mkAnd(qs : _*) - encoder.mkImplies(substMap(template.start), encoder.mkEquals(substMap(template.qs._2), newQs)) - } + instantiation = instantiation withClause { + val newQs = + if (qs.isEmpty) trueT + else if (qs.size == 1) qs.head + else encoder.mkAnd(qs : _*) + encoder.mkImplies(template.start, encoder.mkEquals(qT, newQs)) + } - val quantifierSubst = uniformSubst(template.quantifiers) - val substituter = encoder.substitute(substMap ++ quantifierSubst) + val quantifierSubst = uniformSubst(template.quantifiers) + val substituter = encoder.substitute(quantifierSubst) - for { - (_, ms) <- template.matchers; m <- ms - sm = m.substitute(substituter) - if !instCtx.corresponding(sm).exists(_._2.args == sm.args) - } instantiation ++= instCtx.instantiate(Set.empty, sm)(quantifications.toSeq : _*) + for { + (_, ms) <- template.matchers; m <- ms + sm = m.substitute(substituter) + if !instCtx.corresponding(sm).exists(_._2.args == sm.args) + } instantiation ++= instCtx.instantiate(Set.empty, sm)(quantifications.toSeq : _*) - instantiation + templates += template.key -> qT + (qT, instantiation) + } } def instantiateMatcher(blocker: T, matcher: Matcher[T]): Instantiation[T] = { diff --git a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala index 60ddb145058eeb33b4bcb796307fba87d586d52f..fc570b83d85e5a4298ae52f01ead895f928a2061 100644 --- a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala +++ b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala @@ -453,8 +453,10 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T], Equals(Variable(q), And(Variable(q2), Variable(inst))) ) ++ qGuarded.getOrElse(pathVar, Seq.empty))) + val dependencies: Map[Identifier, T] = vars.filterNot(quantifiers).map(id => id -> localSubst(id)).toMap val template = QuantificationTemplate[T](encoder, manager, pathVar -> encodedCond(pathVar), - qs, q2, inst, guard, idQuantifiers zip trQuantifiers, qConds, qExprs, qTree, allGuarded, qTemplates, localSubst) + qs, q2, inst, guard, idQuantifiers zip trQuantifiers, qConds, qExprs, qTree, allGuarded, qTemplates, localSubst, + dependencies, Forall(quantifiers.toSeq.sortBy(_.uniqueName).map(ValDef(_)), flatConj)) registerQuantification(template) Variable(q) } diff --git a/src/main/scala/leon/solvers/templates/TemplateManager.scala b/src/main/scala/leon/solvers/templates/TemplateManager.scala index bb6629ec16988a79eb686259aea4fa32c6111dbb..32f07a271ce45cbb76e2444f425b593561ce3358 100644 --- a/src/main/scala/leon/solvers/templates/TemplateManager.scala +++ b/src/main/scala/leon/solvers/templates/TemplateManager.scala @@ -76,24 +76,11 @@ trait Template[T] { self => lazy val start = pathVar._2 - private var substCache : Map[Seq[T],Map[T,T]] = Map.empty - def instantiate(aVar: T, args: Seq[T]): Instantiation[T] = { - - val baseSubstMap : Map[T,T] = substCache.get(args) match { - case Some(subst) => subst - case None => - val subst = exprVars.map { case (id, idT) => idT -> encoder.encodeId(id) } ++ - manager.freshConds(pathVar._1 -> aVar, condVars, condTree) ++ - (this.args zip args) - substCache += args -> subst - subst - } - - val lambdaSubstMap = lambdas.map(lambda => lambda.ids._2 -> encoder.encodeId(lambda.ids._1)) - val quantificationSubstMap = quantifications.map(q => q.qs._2 -> encoder.encodeId(q.qs._1)) - val substMap : Map[T,T] = baseSubstMap ++ lambdaSubstMap ++ quantificationSubstMap + (start -> aVar) - instantiate(substMap) + val (substMap, instantiation) = Template.substitution(encoder, manager, + condVars, exprVars, condTree, quantifications, lambdas, + (this.args zip args).toMap + (start -> aVar), pathVar._1, aVar) + instantiation ++ instantiate(substMap) } protected def instantiate(substMap: Map[T, T]): Instantiation[T] = { @@ -231,6 +218,57 @@ object Template { (clauses, encodedBlockers, encodedApps, encodedMatchers, stringRepr) } + def substitution[T]( + encoder: TemplateEncoder[T], + manager: QuantificationManager[T], + condVars: Map[Identifier, T], + exprVars: Map[Identifier, T], + condTree: Map[Identifier, Set[Identifier]], + quantifications: Seq[QuantificationTemplate[T]], + lambdas: Seq[LambdaTemplate[T]], + baseSubst: Map[T, T], + pathVar: Identifier, + aVar: T + ): (Map[T, T], Instantiation[T]) = { + var subst = exprVars.map { case (id, idT) => idT -> encoder.encodeId(id) } ++ + manager.freshConds(pathVar -> aVar, condVars, condTree) ++ + baseSubst + + // /!\ CAREFUL /!\ + // We have to be wary while computing the lambda subst map since lambdas can + // depend on each other. However, these dependencies cannot be cyclic so it + // suffices to make sure the traversal order is correct. + var instantiation : Instantiation[T] = Instantiation.empty + var seen : Set[LambdaTemplate[T]] = Set.empty + + val lambdaKeys = lambdas.map(lambda => lambda.ids._1 -> lambda).toMap + def extractSubst(lambda: LambdaTemplate[T]): Unit = { + for { + dep <- lambda.dependencies.flatMap(p => lambdaKeys.get(p._1)) + if !seen(dep) + } extractSubst(dep) + + if (!seen(lambda)) { + val substLambda = lambda.substitute(encoder.substitute(subst)) + val (idT, inst) = manager.instantiateLambda(substLambda) + instantiation ++= inst + subst += lambda.ids._2 -> idT + seen += lambda + } + } + + for (l <- lambdas) extractSubst(l) + + for (q <- quantifications) { + val substQuant = q.substitute(encoder.substitute(subst)) + val (qT, inst) = manager.instantiateQuantification(substQuant) + instantiation ++= inst + subst += q.qs._2 -> qT + } + + (subst, instantiation) + } + def instantiate[T]( encoder: TemplateEncoder[T], manager: QuantificationManager[T], @@ -252,10 +290,6 @@ object Template { var instantiation: Instantiation[T] = (newClauses, newBlockers, Map.empty) - for (lambda <- lambdas) { - instantiation ++= manager.instantiateLambda(lambda.substitute(substituter)) - } - for ((b,apps) <- applications; bp = substituter(b); app <- apps) { val newApp = app.copy(caller = substituter(app.caller), args = app.args.map(substituter)) instantiation ++= manager.instantiateApp(bp, newApp) @@ -265,10 +299,6 @@ object Template { instantiation ++= manager.instantiateMatcher(bp, m.substitute(substituter)) } - for (q <- quantifications) { - instantiation ++= manager.instantiateQuantification(q, substMap) - } - instantiation } } diff --git a/src/main/scala/leon/solvers/templates/UnrollingBank.scala b/src/main/scala/leon/solvers/templates/UnrollingBank.scala index d1c4432a3c69f1882c9b4a1787a12dc8cf64f520..f96d44239eef30f2c9ef4d758924c322036591f9 100644 --- a/src/main/scala/leon/solvers/templates/UnrollingBank.scala +++ b/src/main/scala/leon/solvers/templates/UnrollingBank.scala @@ -240,16 +240,22 @@ class UnrollingBank[T <% Printable](ctx: LeonContext, templateGenerator: Templat callInfos --= ids val apps = ids.flatMap(id => blockerToApps.get(id)) - val thisAppInfos = apps.map(app => app -> appInfos(app)) + val thisAppInfos = apps.map(app => app -> { + val (gen, _, _, _, infos) = appInfos(app) + (gen, infos) + }) + blockerToApps --= ids appInfos --= apps - for ((app, (_, _, _, _, infos)) <- thisAppInfos if infos.nonEmpty) { + for ((app, (_, infos)) <- thisAppInfos if infos.nonEmpty) { val extension = extendAppBlock(app, infos) reporter.debug(" -> extending lambda blocker: " + extension) newClauses :+= extension } + var fastAppInfos : Map[(T, App[T]), (Int, Set[TemplateAppInfo[T]])] = Map.empty + for ((id, (gen, _, _, infos)) <- newCallInfos; info @ TemplateCallInfo(tfd, args) <- infos) { var newCls = Seq[T]() @@ -268,13 +274,24 @@ class UnrollingBank[T <% Printable](ctx: LeonContext, templateGenerator: Templat //reporter.debug(template) val (newExprs, callBlocks, appBlocks) = template.instantiate(defBlocker, args) - val blockExprs = freshAppBlocks(appBlocks.keys) + + // we handle obvious appBlocks in an immediate manner in order to increase + // performance for folds that just pass a lambda around to recursive calls + val (fastApps, nextApps) = appBlocks.partition(p => p._2.toSeq match { + case Seq(TemplateAppInfo(_, equals, _)) if equals == manager.trueT => true + case _ => false + }) + + fastAppInfos ++= fastApps.mapValues(gen -> _) + + val blockExprs = freshAppBlocks(nextApps.keys) for((b, newInfos) <- callBlocks) { registerCallBlocker(nextGeneration(gen), b, newInfos) } - for ((app, newInfos) <- appBlocks) { + for ((app, newInfos) <- nextApps) { + println(app -> newInfos) registerAppBlocker(nextGeneration(gen), app, newInfos) } @@ -296,7 +313,7 @@ class UnrollingBank[T <% Printable](ctx: LeonContext, templateGenerator: Templat newClauses ++= newCls } - for ((app @ (b, _), (gen, _, _, _, infos)) <- thisAppInfos; info @ TemplateAppInfo(template, equals, args) <- infos) { + for ((app @ (b, _), (gen, infos)) <- thisAppInfos ++ fastAppInfos; info @ TemplateAppInfo(template, equals, args) <- infos) { var newCls = Seq.empty[T] val lambdaBlocker = lambdaBlockers.get(info) match {