Skip to content
Snippets Groups Projects
Commit b7d0f616 authored by Nicolas Voirol's avatar Nicolas Voirol
Browse files

Better quantifier instantiation optimizations

parent 3877a916
No related branches found
No related tags found
No related merge requests found
...@@ -248,7 +248,7 @@ trait QuantificationTemplates { self: Templates => ...@@ -248,7 +248,7 @@ trait QuantificationTemplates { self: Templates =>
def unroll: Clauses = { def unroll: Clauses = {
val imClauses = new scala.collection.mutable.ListBuffer[Encoded] val imClauses = new scala.collection.mutable.ListBuffer[Encoded]
for (e @ (gen, bs, m) <- ignoredMatchers.toSeq if gen <= currentGeneration) { for (e @ (gen, bs, m) <- ignoredMatchers.toSeq if gen <= currentGeneration) {
imClauses ++= instantiateMatcher(bs, m) imClauses ++= instantiateMatcher(bs, m, defer = true)
ignoredMatchers -= e ignoredMatchers -= e
} }
...@@ -263,7 +263,7 @@ trait QuantificationTemplates { self: Templates => ...@@ -263,7 +263,7 @@ trait QuantificationTemplates { self: Templates =>
ignoredSubsts += q -> keep ignoredSubsts += q -> keep
for ((_, bs, subst) <- release) { for ((_, bs, subst) <- release) {
suClauses ++= q.instantiateSubst(bs, subst) suClauses ++= q.instantiateSubst(bs, subst, defer = true)
} }
} }
...@@ -293,18 +293,18 @@ trait QuantificationTemplates { self: Templates => ...@@ -293,18 +293,18 @@ trait QuantificationTemplates { self: Templates =>
} }
def instantiateMatcher(blocker: Encoded, matcher: Matcher): Clauses = { def instantiateMatcher(blocker: Encoded, matcher: Matcher): Clauses = {
instantiateMatcher(Set(blocker), matcher) instantiateMatcher(Set(blocker), matcher, false)
} }
@inline @inline
private def instantiateMatcher(blockers: Set[Encoded], matcher: Matcher): Clauses = { private def instantiateMatcher(blockers: Set[Encoded], matcher: Matcher, defer: Boolean = false): Clauses = {
val relevantBlockers = blockerPath(blockers) val relevantBlockers = blockerPath(blockers)
if (handledMatchers(relevantBlockers -> matcher)) { if (handledMatchers(relevantBlockers -> matcher)) {
Seq.empty Seq.empty
} else { } else {
handledMatchers += relevantBlockers -> matcher handledMatchers += relevantBlockers -> matcher
quantifications.flatMap(_.instantiate(relevantBlockers, matcher)) quantifications.flatMap(_.instantiate(relevantBlockers, matcher, defer))
} }
} }
...@@ -509,7 +509,29 @@ trait QuantificationTemplates { self: Templates => ...@@ -509,7 +509,29 @@ trait QuantificationTemplates { self: Templates =>
def clear(): Unit = for (gs <- grounds.values) gs.clear() def clear(): Unit = for (gs <- grounds.values) gs.clear()
def reset(): Unit = for (gs <- grounds.values) gs.reset() def reset(): Unit = for (gs <- grounds.values) gs.reset()
def instantiate(bs: Set[Encoded], m: Matcher): Clauses = { private val optimizationQuorums: Seq[Set[Matcher]] = {
def matchersOf(m: Matcher): Set[Matcher] = m.args.flatMap {
case Right(m) => matchersOf(m) + m
case _ => Set.empty[Matcher]
}.toSet
def quantifiersOf(m: Matcher): Set[Encoded] =
(matchersOf(m) + m).flatMap(_.args.collect { case Left(q) if quantified(q) => q })
val allMatchers = matchers.flatMap(_._2).toList
val allQuorums = allMatchers.toSet.subsets
.filter(ms => ms.flatMap(quantifiersOf) == quantified)
.filterNot(ms => allMatchers.exists { m =>
!ms(m) && {
val common = ms & matchersOf(m)
common.nonEmpty &&
(quantifiersOf(m) -- common.flatMap(quantifiersOf)).nonEmpty
}
})
allQuorums.foldLeft(Seq[Set[Matcher]]())((qs,q) => if (qs.exists(_ subsetOf q)) qs else qs :+ q)
}
def instantiate(bs: Set[Encoded], m: Matcher, defer: Boolean = false): Clauses = {
generationCounter += 1 generationCounter += 1
val gen = generationCounter val gen = generationCounter
...@@ -531,7 +553,7 @@ trait QuantificationTemplates { self: Templates => ...@@ -531,7 +553,7 @@ trait QuantificationTemplates { self: Templates =>
(key, i) <- constraints; (key, i) <- constraints;
perfect <- correspond(matcherKey(m), key) perfect <- correspond(matcherKey(m), key)
if !grounds(q)(bs, m.args(i))) { if !grounds(q)(bs, m.args(i))) {
val initGens: Set[Int] = if (perfect) Set.empty else Set(gen) val initGens: Set[Int] = if (perfect && !defer) Set.empty else Set(gen)
val newMappings = (quantified - q).foldLeft(Seq((bs, Map(q -> m.args(i)), initGens, 0))) { val newMappings = (quantified - q).foldLeft(Seq((bs, Map(q -> m.args(i)), initGens, 0))) {
case (maps, oq) => for { case (maps, oq) => for {
(bs, map, gens, c) <- maps (bs, map, gens, c) <- maps
...@@ -546,7 +568,21 @@ trait QuantificationTemplates { self: Templates => ...@@ -546,7 +568,21 @@ trait QuantificationTemplates { self: Templates =>
/* @nv: I tried some smarter cost computations here but it turns out that the /* @nv: I tried some smarter cost computations here but it turns out that the
* overhead needed to determine when to optimize exceeds the benefits */ * overhead needed to determine when to optimize exceeds the benefits */
mappings ++= newMappings.map { case (bs, map, gens, c) => mappings ++= newMappings.map { case (bs, map, gens, c) =>
(bs, map, c + (3 * map.values.collect { case Right(m) => totalDepth(m) }.sum)) val substituter = mkSubstituter(map.mapValues(_.encoded))
val msubst = map.collect { case (q, Right(m)) => q -> m }
val isOpt = optimizationQuorums.exists { ms =>
ms.forall(m => handledMatchers.contains(m.substitute(substituter, msubst)))
}
val cost = if (initGens.nonEmpty) {
1 + 3 * map.values.collect { case Right(m) => totalDepth(m) }.sum
} else if (!isOpt) {
3
} else {
0
}
(bs, map, c + cost)
} }
// register ground instantiation for future instantiations // register ground instantiation for future instantiations
...@@ -600,14 +636,14 @@ trait QuantificationTemplates { self: Templates => ...@@ -600,14 +636,14 @@ trait QuantificationTemplates { self: Templates =>
val gen = currentGeneration + delay + (if (getPolarity.isEmpty) 2 else 0) val gen = currentGeneration + delay + (if (getPolarity.isEmpty) 2 else 0)
ignoredSubsts += this -> (ignoredSubsts.getOrElse(this, Set.empty) + ((gen, bs, subst))) ignoredSubsts += this -> (ignoredSubsts.getOrElse(this, Set.empty) + ((gen, bs, subst)))
} else { } else {
instantiation ++= instantiateSubst(bs, subst) instantiation ++= instantiateSubst(bs, subst, defer = false)
} }
} }
instantiation.toSeq instantiation.toSeq
} }
def instantiateSubst(bs: Set[Encoded], subst: Map[Encoded, Arg]): Clauses = { def instantiateSubst(bs: Set[Encoded], subst: Map[Encoded, Arg], defer: Boolean = false): Clauses = {
handledSubsts += this -> (handledSubsts.getOrElse(this, Set.empty) + (bs -> subst)) handledSubsts += this -> (handledSubsts.getOrElse(this, Set.empty) + (bs -> subst))
val instantiation = new scala.collection.mutable.ListBuffer[Encoded] val instantiation = new scala.collection.mutable.ListBuffer[Encoded]
...@@ -630,14 +666,11 @@ trait QuantificationTemplates { self: Templates => ...@@ -630,14 +666,11 @@ trait QuantificationTemplates { self: Templates =>
val sb = bs ++ (if (b == guard) Set.empty else Set(substituter(b))) val sb = bs ++ (if (b == guard) Set.empty else Set(substituter(b)))
val sm = m.substitute(substituter, msubst) val sm = m.substitute(substituter, msubst)
def abs(i: Int): Int = if (i < 0) -i else i if (b != guard) {
val totalDelay = 2 * (abs(totalDepth(sm) - totalDepth(m)) + (if (b == guard) 0 else 1)) val gen = currentGeneration + 1
if (totalDelay > 0) {
val gen = currentGeneration + totalDelay
ignoredMatchers += ((gen, sb, sm)) ignoredMatchers += ((gen, sb, sm))
} else { } else {
instantiation ++= instantiateMatcher(sb, sm) instantiation ++= instantiateMatcher(sb, sm, defer = defer)
} }
} }
...@@ -883,7 +916,7 @@ trait QuantificationTemplates { self: Templates => ...@@ -883,7 +916,7 @@ trait QuantificationTemplates { self: Templates =>
val freshSubst = mkSubstituter(template.quantifiers.map(p => p._2 -> encodeSymbol(p._1)).toMap) val freshSubst = mkSubstituter(template.quantifiers.map(p => p._2 -> encodeSymbol(p._1)).toMap)
for ((b,ms) <- template.matchers; m <- ms) { for ((b,ms) <- template.matchers; m <- ms) {
clauses ++= instantiateMatcher(Set.empty[Encoded], m) clauses ++= instantiateMatcher(Set.empty[Encoded], m, false)
// it is very rare that such instantiations are actually required, so we defer them // it is very rare that such instantiations are actually required, so we defer them
val gen = currentGeneration + 20 val gen = currentGeneration + 20
ignoredMatchers += ((gen, Set(b), m.substitute(freshSubst, Map.empty))) ignoredMatchers += ((gen, Set(b), m.substitute(freshSubst, Map.empty)))
...@@ -996,7 +1029,7 @@ trait QuantificationTemplates { self: Templates => ...@@ -996,7 +1029,7 @@ trait QuantificationTemplates { self: Templates =>
val valuesP = values.map(v => v -> encodeSymbol(v)) val valuesP = values.map(v => v -> encodeSymbol(v))
val exprT = mkEncoder(elemsP.toMap ++ valuesP + guardP)(expr) val exprT = mkEncoder(elemsP.toMap ++ valuesP + guardP)(expr)
val disjunction = handledSubsts(q) match { val disjunction = handledSubsts.getOrElse(q, Set.empty) match {
case set if set.isEmpty => mkEncoder(Map.empty)(BooleanLiteral(false)) case set if set.isEmpty => mkEncoder(Map.empty)(BooleanLiteral(false))
case set => mkOr(set.toSeq.map { case (enablers, subst) => case set => mkOr(set.toSeq.map { case (enablers, subst) =>
val b = if (enablers.isEmpty) trueT else mkAnd(enablers.toSeq : _*) val b = if (enablers.isEmpty) trueT else mkAnd(enablers.toSeq : _*)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment