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

Handling universal quantification in post

parent 2afbeb4e
Branches
Tags
No related merge requests found
...@@ -12,21 +12,32 @@ import Instantiation._ ...@@ -12,21 +12,32 @@ import Instantiation._
trait QuantificationManager[T] { self : LambdaManager[T] => trait QuantificationManager[T] { self : LambdaManager[T] =>
lazy val startId = FreshIdentifier("q", BooleanType)
lazy val start = encoder.encodeId(startId)
private class QuantificationScope( private class QuantificationScope(
val quantifiedApps: List[(T, App[T])], val quantifiedApps: List[App[T]],
val quantifiedID: Map[Identifier, T], val quantifiers: Map[Identifier, T],
val condVars: Map[Identifier, T], val condVars: Map[Identifier, T],
val exprVars: Map[Identifier, T], val exprVars: Map[Identifier, T],
val clauses: Seq[T], val clauses: Seq[T],
val blockers: Map[T, Set[TemplateCallInfo[T]]], val blockers: Map[T, Set[TemplateCallInfo[T]]],
val applications: Map[T, Set[App[T]]], val applications: Map[T, Set[App[T]]],
val lambdas: Map[T, LambdaTemplate[T]] val lambdas: Map[T, LambdaTemplate[T]],
val res: Set[T]
) { ) {
def this() = this(Nil, Map.empty, Map.empty, Map.empty, Seq.empty, Map.empty, Map.empty, Map.empty) def this() = this(Nil, Map.empty, Map.empty, Map.empty, Seq.empty, Map.empty, Map.empty, Map.empty, Set.empty)
lazy val quantified: Set[T] = quantifiedID.values.toSet def this(scope: QuantificationScope) = this(
scope.quantifiedApps,
scope.quantifiers,
scope.condVars,
scope.exprVars,
scope.clauses,
scope.blockers,
scope.applications,
scope.lambdas,
scope.res
)
lazy val quantified: Set[T] = quantifiers.values.toSet
def free(tpe: FunctionType, idT: T): Boolean = res(idT) || freeLambdas(tpe)(idT)
} }
private var scopes: List[QuantificationScope] = List(new QuantificationScope) private var scopes: List[QuantificationScope] = List(new QuantificationScope)
...@@ -36,16 +47,7 @@ trait QuantificationManager[T] { self : LambdaManager[T] => ...@@ -36,16 +47,7 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
self.push() self.push()
val currentScope = scope val currentScope = scope
scopes = new QuantificationScope( scopes = new QuantificationScope(currentScope) :: scopes.tail
currentScope.quantifiedApps,
currentScope.quantifiedID,
currentScope.condVars,
currentScope.exprVars,
currentScope.clauses,
currentScope.blockers,
currentScope.applications,
currentScope.lambdas
) :: scopes.tail
} }
override def pop(lvl: Int): Unit = { override def pop(lvl: Int): Unit = {
...@@ -53,16 +55,36 @@ trait QuantificationManager[T] { self : LambdaManager[T] => ...@@ -53,16 +55,36 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
scopes = scopes.drop(lvl) scopes = scopes.drop(lvl)
} }
def registerQuantified(start: T, condVars: Map[Identifier, T], exprVars: Map[Identifier, T], clauses: Seq[T], blockers: Map[T, Set[TemplateCallInfo[T]]], apps: Set[(T, App[T])], quantified: Set[T]): Unit = { def registerQuantified(
startVar: Identifier,
quantifierVars: Seq[Identifier],
condVars: Map[Identifier, T],
exprVars: Map[Identifier, T],
guardedExprs: Map[Identifier, Seq[Expr]],
lambdas: Map[T, LambdaTemplate[T]],
subst: Map[Identifier, T],
res: Option[T]
): Unit = {
val currentScope = scope
def free(tpe: FunctionType, idT: T): Boolean = currentScope.free(tpe, idT) || res.exists(_ == idT)
val quantifiers: Seq[(Identifier, T)] = quantifierVars.map(id => id -> encoder.encodeId(id))
val quantified: Set[T] = quantifiers.map(_._2).toSet
val pathVar = startVar -> encoder.encodeId(startVar)
val (clauses, blockers, apps, _) = Template.encode(encoder, pathVar, quantifiers, condVars, exprVars, guardedExprs, lambdas, subst)
val bindingCalls: Set[App[T]] = apps.collect { val bindingApps: Set[App[T]] = {
case (b, app @ App(caller, tpe, args)) if args exists quantified => app def rec(templates: Map[T, LambdaTemplate[T]]): Set[App[T]] = templates.flatMap {
case (_, template) => template.applications.flatMap(_._2).toSet ++ rec(template.lambdas)
}.toSet
val allApps = apps.flatMap(_._2).toSet
for (app @ App(caller, tpe, args) <- (allApps ++ rec(lambdas)) if args exists quantified) yield app
} }
// TODO: postcondition res ?? val argumentBindings: Set[(Option[T], FunctionType, Int, T)] = bindingApps.flatMap {
val argumentBindings: Set[(Option[T], FunctionType, Int, T)] = bindingCalls.flatMap {
case App(caller, tpe, args) => args.zipWithIndex.collect { case App(caller, tpe, args) => args.zipWithIndex.collect {
case (qid, idx) if quantified(qid) => (if (freeLambdas(tpe)(caller)) Some(caller) else None, tpe, idx, qid) case (qid, idx) if quantified(qid) => (if (free(tpe, caller)) Some(caller) else None, tpe, idx, qid)
} }
} }
...@@ -103,12 +125,48 @@ trait QuantificationManager[T] { self : LambdaManager[T] => ...@@ -103,12 +125,48 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
case (mappings, (_, pairs)) => pairs.toList.flatMap(p => mappings.map(mapping => mapping + p)) case (mappings, (_, pairs)) => pairs.toList.flatMap(p => mappings.map(mapping => mapping + p))
} }
val expandedClauses = mappings.flatMap { mapping => val (allClauses, allBlockers, allApps) = {
val substituter = encoder.substitute(mapping) var allClauses : Seq[T] = Seq.empty
clauses map substituter var allBlockers : Map[T, Set[TemplateCallInfo[T]]] = Map.empty.withDefaultValue(Set.empty)
var allApps : Map[T, Set[App[T]]] = Map.empty.withDefaultValue(Set.empty)
for (mapping <- mappings) {
val substituter = encoder.substitute(mapping)
allClauses ++= clauses.map(substituter)
blockers.foreach { case (b, fis) =>
val bp = substituter(b)
val fisp = fis.map(fi => fi.copy(args = fi.args.map(substituter)))
allBlockers += bp -> (allBlockers(bp) ++ fisp)
}
apps.foreach { case (b, fas) =>
val bp = substituter(b)
val fasp = fas.map(fa => fa.copy(caller = substituter(fa.caller), args = fa.args.map(substituter)))
allApps += bp -> (allApps(bp) ++ fasp)
}
}
(allClauses, allBlockers, allApps)
} }
val quantifiedApps: Set[(T, App[T])] = for {
(b, bApps) <- allApps.toSet
app @ App(caller, tpe, args) <- bApps
if args exists quantified
} yield (b, app)
scopes = new QuantificationScope(
currentScope.quantifiedApps ++ quantifiedApps,
currentScope.quantifiers ++ quantifiers,
currentScope.condVars ++ condVars,
currentScope.exprVars ++ exprVars,
currentScope.clauses ++ allClauses,
currentScope.blockers merge allBlockers,
currentScope.applications merge allApps,
currentScope.lambdas ++ lambdas,
currentScope.res ++ res
) :: scopes.tail
} }
override def instantiateApp(blocker: T, app: App[T]): Instantiation[T] = { override def instantiateApp(blocker: T, app: App[T]): Instantiation[T] = {
...@@ -120,24 +178,24 @@ trait QuantificationManager[T] { self : LambdaManager[T] => ...@@ -120,24 +178,24 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
// applications previously encountered. Also make sure the current `app` is in the mapping // applications previously encountered. Also make sure the current `app` is in the mapping
// as other instantiations have been performed previously when the associated applications // as other instantiations have been performed previously when the associated applications
// were first encountered. // were first encountered.
val appMappings: List[List[((T, App[T]), (T, App[T]))]] = quantifiedApps val appMappings: List[List[(App[T], App[T])]] = quantifiedApps
// 1. select an application in the quantified proposition for which the current app can // 1. select an application in the quantified proposition for which the current app can
// be bound when generating the new constraints // be bound when generating the new constraints
.filter { case (qb, qapp) => .filter(qapp => qapp.caller == caller || (qapp.tpe == tpe && !free(qapp.tpe, qapp.caller)))
qapp.caller == caller || (qapp.tpe == tpe && !freeLambdas(qapp.tpe)(qapp.caller))
}
// 2. build the instantiation mapping associated to the chosen current application binding // 2. build the instantiation mapping associated to the chosen current application binding
.flatMap { bindingApp => quantifiedApps .flatMap { bindingApp => quantifiedApps
// 2.1. select all potential matches for each quantified application // 2.1. select all potential matches for each quantified application
.map { case qapp @ (qb, App(qcaller, qtpe, qargs)) => .map { case qapp @ App(qcaller, qtpe, qargs) =>
if (qapp == bindingApp) { if (qapp == bindingApp) {
bindingApp -> Set(blocker -> app) bindingApp -> Set(app)
} else { } else {
val instances = self.applications(qtpe).filter(p => qcaller == p._2.caller || !freeLambdas(qtpe)(p._2.caller)) val instances = self.applications(qtpe).collect {
case (_, app @ App(caller, _, _)) if qcaller == caller || !free(qtpe, caller) => app
}
// concrete applications can appear multiple times in the constraint, and this is also the case // concrete applications can appear multiple times in the constraint, and this is also the case
// for the current application for which we are generating the constraints // for the current application for which we are generating the constraints
val withApp = if (qcaller == caller || !freeLambdas(tpe)(caller)) instances + (blocker -> app) else instances val withApp = if (qcaller == caller || !free(tpe, caller)) instances + app else instances
// add quantified application to instances for constraints that depend on free variables // add quantified application to instances for constraints that depend on free variables
// this also make sure that constraints that don't depend on all variables will also be instantiated // this also make sure that constraints that don't depend on all variables will also be instantiated
...@@ -148,7 +206,7 @@ trait QuantificationManager[T] { self : LambdaManager[T] => ...@@ -148,7 +206,7 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
} }
// 2.2. based on the possible bindings for each quantified application, build a set of // 2.2. based on the possible bindings for each quantified application, build a set of
// instantiation mappings that can be used to instantiate all necessary constraints // instantiation mappings that can be used to instantiate all necessary constraints
.foldLeft[List[List[((T, App[T]), (T, App[T]))]]] (List(Nil)) { .foldLeft[List[List[(App[T], App[T])]]] (List(Nil)) {
case (mappings, (qapp, instances)) => case (mappings, (qapp, instances)) =>
instances.toList.flatMap(app => mappings.map(mapping => mapping :+ (app -> qapp))) instances.toList.flatMap(app => mappings.map(mapping => mapping :+ (app -> qapp)))
} }
...@@ -161,8 +219,7 @@ trait QuantificationManager[T] { self : LambdaManager[T] => ...@@ -161,8 +219,7 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
var subst: Map[T, T] = Map.empty var subst: Map[T, T] = Map.empty
for { for {
((qb, App(qcaller, _, qargs)), (b, App(caller, _, args))) <- mapping (App(qcaller, _, qargs), App(caller, _, args)) <- mapping
_ = constraints ++= Seq(qb, b)
_ = if (qcaller != caller) constraints :+= encoder.mkEquals(qcaller, caller) _ = if (qcaller != caller) constraints :+= encoder.mkEquals(qcaller, caller)
(qarg, arg) <- (qargs zip args) (qarg, arg) <- (qargs zip args)
} if (subst.isDefinedAt(qarg) || !quantified(qarg)) { } if (subst.isDefinedAt(qarg) || !quantified(qarg)) {
...@@ -172,7 +229,7 @@ trait QuantificationManager[T] { self : LambdaManager[T] => ...@@ -172,7 +229,7 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
} }
// make sure we freshen quantified variables that haven't been bound by concrete calls // make sure we freshen quantified variables that haven't been bound by concrete calls
subst ++= quantifiedID.collect { subst ++= quantifiers.collect {
case (id, idT) if !subst.isDefinedAt(idT) => idT -> encoder.encodeId(id) case (id, idT) if !subst.isDefinedAt(idT) => idT -> encoder.encodeId(id)
} }
......
...@@ -25,16 +25,18 @@ object Instantiation { ...@@ -25,16 +25,18 @@ object Instantiation {
def empty[T] = (Seq.empty[T], Map.empty[T, Set[TemplateCallInfo[T]]], Map.empty[(T, App[T]), Set[TemplateAppInfo[T]]]) def empty[T] = (Seq.empty[T], Map.empty[T, Set[TemplateCallInfo[T]]], Map.empty[(T, App[T]), Set[TemplateAppInfo[T]]])
implicit class MapWrapper[A,B](map: Map[A,Set[B]]) {
def merge(that: Map[A,Set[B]]): Map[A,Set[B]] = (map.keys ++ that.keys).map { k =>
k -> (map.getOrElse(k, Set.empty) ++ that.getOrElse(k, Set.empty))
}.toMap
}
implicit class InstantiationWrapper[T](i: Instantiation[T]) { implicit class InstantiationWrapper[T](i: Instantiation[T]) {
def ++(that: Instantiation[T]): Instantiation[T] = { def ++(that: Instantiation[T]): Instantiation[T] = {
val (thisClauses, thisBlockers, thisApps) = i val (thisClauses, thisBlockers, thisApps) = i
val (thatClauses, thatBlockers, thatApps) = that val (thatClauses, thatBlockers, thatApps) = that
( (thisClauses ++ thatClauses, thisBlockers merge thatBlockers, thisApps merge thatApps)
thisClauses ++ thatClauses,
(thisBlockers.keys ++ thatBlockers.keys).map(k => k -> (thisBlockers.getOrElse(k, Set.empty) ++ thatBlockers.getOrElse(k, Set.empty))).toMap,
(thisApps.keys ++ thatApps.keys).map(k => k -> (thisApps.getOrElse(k, Set.empty) ++ thatApps.getOrElse(k, Set.empty))).toMap
)
} }
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment