gapt.proofs.expansion.termExtraction.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gapt_3 Show documentation
Show all versions of gapt_3 Show documentation
General Architecture for Proof Theory
The newest version!
package gapt.proofs.expansion
import gapt.expr._
import gapt.expr.formula.All
import gapt.expr.formula.And
import gapt.expr.formula.Atom
import gapt.expr.formula.Bottom
import gapt.expr.formula.Ex
import gapt.expr.formula.Formula
import gapt.expr.formula.Imp
import gapt.expr.formula.Neg
import gapt.expr.formula.Or
import gapt.expr.formula.Top
import gapt.expr.formula.fol.FOLTerm
import gapt.expr.formula.hol._
import gapt.expr.subst.Substitution
import gapt.expr.ty.FunctionType
import gapt.expr.ty.TBase
import gapt.expr.ty.To
import gapt.expr.ty.Ty
import gapt.expr.util.constants
import gapt.expr.util.freeVariables
import gapt.expr.util.isInVNF
import gapt.expr.util.rename
import gapt.expr.util.syntacticMatching
import gapt.expr.util.toVNF
import gapt.grammars.{RecursionScheme, Rule}
import gapt.logic.Polarity
import gapt.proofs._
import gapt.proofs.lk.LKProof
import gapt.proofs.lk.transformations.LKToExpansionProof
/**
* Extracts the instances used in a prenex FOL Pi_1 expansion tree / Sigma_1 expansion sequent.
*
* Each expansion tree is transformed into a list of instances of its shallow formula.
*
* In contrast to [[ExpansionProof.deep]], this function doesn't produce conjunctions of instances,
* but instead increases the number of formulas in the antecedent/succedent.
*/
object extractInstances {
def apply(expansionTree: ExpansionTree): Set[Formula] =
if (!containsQuantifier(expansionTree.shallow))
Set(expansionTree.shallow)
else (expansionTree: @unchecked) match {
case ETMerge(t, s) => extractInstances(t) ++ extractInstances(s)
case ETWeakening(_, _) => Set()
case ETWeakQuantifier(_, instances) =>
instances flatMap { i => extractInstances(i._2) } toSet
case ETStrongQuantifier(_, _, t) => extractInstances(t)
case ETSkolemQuantifier(_, _, t) => extractInstances(t)
case ETAnd(t, s) => for ((ti, si) <- apply(t, s)) yield ti & si
case ETOr(t, s) => for ((ti, si) <- apply(t, s)) yield ti | si
case ETImp(t, s) => for ((ti, si) <- apply(t, s)) yield ti --> si
case ETNeg(t) => for (ti <- extractInstances(t)) yield -ti
case ETDefinition(_, t) => extractInstances(t)
case ETAtom(_, _) | ETBottom(_) | ETTop(_) => throw new Exception("Inconceivable!")
}
private def apply(a: ExpansionTree, b: ExpansionTree): Set[(Formula, Formula)] = {
val ais = extractInstances(a)
val bis = extractInstances(b)
if (ais.isEmpty && bis.isEmpty) {
Set()
} else if (ais.isEmpty) {
val dummy = removeAllQuantifiers(a.shallow)
for (bi <- bis) yield (dummy, bi)
} else if (bis.isEmpty) {
val dummy = removeAllQuantifiers(b.shallow)
for (ai <- ais) yield (ai, dummy)
} else {
for (ai <- ais; bi <- bis) yield (ai, bi)
}
}
def apply(expansionSequent: ExpansionSequent): HOLSequent =
expansionSequent flatMap apply
def apply(expansionProof: ExpansionProof): HOLSequent =
apply(expansionProof.expansionSequent)
}
object groundTerms {
def apply(term: Expr): Expr =
Substitution(freeVariables(term) map { case v @ Var(name, ty) => v -> Const(name, ty) })(term)
def apply(lang: Set[Expr]): Set[Expr] = lang map apply
def apply(term: FOLTerm): FOLTerm = apply(term.asInstanceOf[Expr]).asInstanceOf[FOLTerm]
def apply(lang: Set[FOLTerm])(implicit dummyImplicit: DummyImplicit): Set[FOLTerm] = lang map apply
}
/**
* Encodes instances of an end-sequent as terms.
*
* Only instances of weak quantifiers are recorded, instances of strong quantifiers or free variables are ignored.
*
* The end-sequent will be internally transformed into one which is in variable normal form.
*
* In the case of cut-introduction, the end-sequent has no free variables and no strong quantifiers
* and we're encoding a Herbrand sequent as a
* set of terms. A term r_i(t_1,...,t_n) encodes an instance of the formula "forall x_1 ... x_n, phi(x_1,...,x_n)"
* using the instances (t_1,...,t_n).
*
* In the case of inductive proofs, the end-sequent contains strong quantifiers variable (alpha). Here, we consider
* proofs of instance sequents, which are obtained by e.g. substituting a numeral for alpha.
* Hence the formulas occurring in the end-sequents of instance proofs are substitution instances of [[endSequent]];
* the encoded terms still only
* capture the instances used in the instance proofs--i.e. not alpha.
*/
class InstanceTermEncoding private (val endSequent: HOLSequent, val instanceTermType: Ty) {
private val nameGen = rename.awayFrom(constants.nonLogical(endSequent))
endSequent.elements foreach { formula =>
require(isInVNF(formula), s"$formula is not in variable normal form")
}
/**
* The propositional matrices phi of the end-sequent.
*/
val matrices = endSequent map { removeAllQuantifiers(_) }
/**
* The propositional matrices of the end-sequent, where the formulas in the succedent are negated.
*/
val signedMatrices = matrices.map(identity, -_)
private def getWeakQuantVars(esFormula: Formula, pol: Polarity): Seq[Var] = esFormula match {
case All(x, t) if pol.inAnt => x +: getWeakQuantVars(t, pol)
case Ex(x, t) if pol.inSuc => x +: getWeakQuantVars(t, pol)
case All(x, t) if pol.inSuc => getWeakQuantVars(t, pol)
case Ex(x, t) if pol.inAnt => getWeakQuantVars(t, pol)
case And(t, s) => getWeakQuantVars(t, pol) ++ getWeakQuantVars(s, pol)
case Or(t, s) => getWeakQuantVars(t, pol) ++ getWeakQuantVars(s, pol)
case Imp(t, s) => getWeakQuantVars(t, !pol) ++ getWeakQuantVars(s, pol)
case Neg(t) => getWeakQuantVars(t, !pol)
case Top() | Bottom() | Atom(_, _) =>
Seq()
}
/**
* The quantified variables of each formula in the end-sequent.
*/
val quantVars = endSequent.map(
getWeakQuantVars(_, Polarity.InAntecedent),
getWeakQuantVars(_, Polarity.InSuccedent)
)
/**
* Assigns each formula in the end-sequent a fresh function symbol name used to encode its instances.
*/
protected def mkSym(idx: SequentIndex) = {
val idxPart = idx match {
case Ant(i) => s"a$i"
case Suc(i) => s"s$i"
}
nameGen fresh s"$idxPart:${matrices(idx).toUntypedAsciiString.replaceAll("\\s", "").take(30)}"
}
/**
* The function symbols used to encode the instances of each formula in the end-sequent.
*/
val symbols = for ((vars, idx) <- quantVars.zipWithIndex)
yield Const(mkSym(idx), FunctionType(instanceTermType, vars map { _.ty }))
private def instanceTerms(signedInstance: Formula, esFormula: SequentIndex) =
syntacticMatching(signedMatrices(esFormula), signedInstance) map { subst =>
esFormula -> subst(quantVars(esFormula))
}
private def findInstance(signedInstance: Formula): Option[(SequentIndex, Seq[Expr])] =
endSequent.indices.flatMap { instanceTerms(signedInstance, _) }.headOption
def encodeOption(signedInstance: Formula): Option[Expr] =
findInstance(signedInstance) map {
case (esFormula, terms) => symbols(esFormula)(terms: _*)
}
def encode(signedInstance: Formula): Expr = encodeOption(signedInstance).getOrElse {
throw new IllegalArgumentException(s"Cannot find $signedInstance in $endSequent")
}
/**
* Encodes a sequent consisting of instances of an instance sequent.
*/
def encode(instance: HOLSequent): Set[Expr] =
instance.map(identity, -_).elements map encode toSet
/**
* Encodes an expansion sequent (of an instance proof).
*
* The shallow formulas of the expansion sequents should be subsumed by formulas in the end-sequent.
*/
def encode(instance: ExpansionSequent)(implicit dummyImplicit: DummyImplicit): Set[Expr] =
encode(extractInstances(instance))
/**
* Encodes an expansion proof (of an instance proof).
*
* The shallow formulas of the expansion sequents should be subsumed by formulas in the end-sequent.
*/
def encode(instance: ExpansionProof): Set[Expr] = encode(extractInstances(instance))
/**
* Maps a function symbol to the index of its corresponding formula in the end-sequent.
*/
def findESIndex(sym: Const): Option[SequentIndex] = symbols indexOfOption sym
/**
* Maps a function symbol to its corresponding formula in the end-sequent.
*/
def findESFormula(sym: Const): Option[Formula] = findESIndex(sym) map { endSequent(_) }
def decodeOption(term: Expr): Option[(SequentIndex, Substitution)] = term match {
case Apps(f: Const, args) =>
findESIndex(f) map { idx => idx -> Substitution(quantVars(idx) zip args) }
case _ => None
}
/**
* Decodes a term into its corresponding instance.
*
* The resulting instance can contain alpha in the inductive case.
*/
def decodeToPolarizedFormula(term: Expr): (Formula, Polarity) =
decodeOption(term) map { case (idx, subst) => subst(matrices(idx)) -> idx.polarity } get
def decodeToSignedFormula(term: Expr): Formula =
decodeOption(term) map { case (idx, subst) => subst(signedMatrices(idx)) } get
def decodeToInstanceSequent(terms: Iterable[Expr]): HOLSequent =
Sequent(terms map decodeToPolarizedFormula toSeq)
def decodeToExpansionSequent(terms: Iterable[Expr]): ExpansionSequent =
Sequent(terms flatMap decodeOption groupBy { _._1 } map {
case (idx, instances) =>
formulaToExpansionTree(endSequent(idx), instances map { _._2 } toList, idx.polarity) -> idx.polarity
} toSeq)
def decodeToExpansionProof(terms: Iterable[Expr]): ExpansionProof =
ExpansionProof(decodeToExpansionSequent(terms))
def encode(recursionScheme: RecursionScheme): RecursionScheme = {
val encodedNTs = recursionScheme.nonTerminals.map {
case c @ Const(name, FunctionType(To, argTypes), ps) =>
c -> Const(name, FunctionType(instanceTermType, argTypes), ps)
}.toMap
RecursionScheme(
encodedNTs(recursionScheme.startSymbol),
encodedNTs.values.toSet,
recursionScheme.rules map { r =>
(r: @unchecked) match {
case Rule(Apps(lhsNT: Const, lhsArgs), Apps(rhsNT: Const, rhsArgs)) if encodedNTs contains rhsNT =>
Rule(encodedNTs(lhsNT)(lhsArgs: _*), encodedNTs(rhsNT)(rhsArgs: _*))
case Rule(Apps(lhsNT: Const, lhsArgs), instance: Formula) =>
Rule(encodedNTs(lhsNT)(lhsArgs: _*), encode(instance))
}
}
)
}
def decode(recursionScheme: RecursionScheme): RecursionScheme = {
val decodedNTs = recursionScheme.nonTerminals.map {
case c @ Const(name, FunctionType(`instanceTermType`, argTypes), ps) =>
c -> Const(name, FunctionType(To, argTypes), ps)
}.toMap
RecursionScheme(
decodedNTs(recursionScheme.startSymbol),
decodedNTs.values.toSet,
recursionScheme.rules map { r =>
(r: @unchecked) match {
case Rule(Apps(lhsNT: Const, lhsArgs), Apps(rhsNT: Const, rhsArgs)) if decodedNTs contains rhsNT =>
Rule(decodedNTs(lhsNT)(lhsArgs: _*), decodedNTs(rhsNT)(rhsArgs: _*))
case Rule(Apps(lhsNT: Const, lhsArgs), term) =>
Rule(decodedNTs(lhsNT)(lhsArgs: _*), decodeToSignedFormula(term))
}
}
)
}
}
object InstanceTermEncoding {
def defaultType = TBase("_Inst", Nil)
def apply(endSequent: HOLSequent, instanceTermType: Ty = defaultType): InstanceTermEncoding =
new InstanceTermEncoding(endSequent map { toVNF(_) }, instanceTermType)
def apply(expansionSequent: ExpansionSequent): (Set[Expr], InstanceTermEncoding) = {
val encoding = InstanceTermEncoding(expansionSequent.shallow)
encoding.encode(expansionSequent) -> encoding
}
def apply(expansionProof: ExpansionProof): (Set[Expr], InstanceTermEncoding) =
apply(expansionProof.expansionSequent)
def apply(lkProof: LKProof): (Set[Expr], InstanceTermEncoding) = {
val encoding = InstanceTermEncoding(lkProof.endSequent)
encoding.encode(eliminateCutsET(LKToExpansionProof(lkProof))) -> encoding
}
}