gapt.proofs.expansion.ExpansionProofToMG3i.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.Atom
import gapt.expr.formula.Bottom
import gapt.expr.formula.Ex
import gapt.expr.formula.Formula
import gapt.expr.formula.Top
import gapt.expr.formula.hol.instantiate
import gapt.expr.util.freeVariables
import gapt.expr.util.rename
import gapt.logic.Polarity
import gapt.proofs._
import gapt.proofs.context.Context
import gapt.proofs.context.mutable.MutableContext
import gapt.proofs.expansion.ExpansionProofToLK._
import gapt.proofs.lk._
import gapt.proofs.lk.rules.AndRightRule
import gapt.proofs.lk.rules.BottomAxiom
import gapt.proofs.lk.rules.CutRule
import gapt.proofs.lk.rules.ConversionRule
import gapt.proofs.lk.rules.ExistsLeftRule
import gapt.proofs.lk.rules.ExistsRightRule
import gapt.proofs.lk.rules.ForallLeftRule
import gapt.proofs.lk.rules.ForallRightRule
import gapt.proofs.lk.rules.ImpLeftRule
import gapt.proofs.lk.rules.ImpRightRule
import gapt.proofs.lk.rules.LogicalAxiom
import gapt.proofs.lk.rules.NegLeftRule
import gapt.proofs.lk.rules.NegRightRule
import gapt.proofs.lk.rules.OrLeftRule
import gapt.proofs.lk.rules.OrRightRule
import gapt.proofs.lk.rules.TopAxiom
import gapt.proofs.lk.rules.WeakeningLeftRule
import gapt.proofs.lk.rules.WeakeningRightRule
import gapt.proofs.lk.rules.macros.AndLeftMacroRule
import gapt.proofs.lk.rules.macros.ContractionMacroRule
import gapt.proofs.lk.rules.macros.ImpRightMacroRule
import gapt.proofs.lk.rules.macros.OrRightMacroRule
import gapt.proofs.lk.rules.macros.WeakeningMacroRule
import gapt.proofs.lk.transformations.eliminateDefinitions
import gapt.proofs.lk.util.SolveUtils
import gapt.provers.escargot.Escargot
import gapt.utils.quiet
import scala.collection.mutable
object ExpansionProofToMG3i {
def apply(expansionProof: ExpansionProof)(implicit ctx: Context = MutableContext.guess(expansionProof.deep)): Either[(Theory, ExpansionSequent), LKProof] =
new ExpansionProofToMG3i(Escargot.getAtomicLKProof)(ctx.newMutable).apply(expansionProof)
}
class ExpansionProofToMG3i(theorySolver: HOLClause => Option[LKProof])(implicit ctx: MutableContext) extends SolveUtils {
type Error = (Theory, ExpansionSequent)
def apply(expansionProof: ExpansionProof): UnprovableOrLKProof =
solve(Theory(expansionProof.cuts, expansionProof.inductions), expansionProof.nonTheoryPart).map(WeakeningMacroRule(_, expansionProof.nonTheoryPart.shallow)).map(eliminateDefinitions(newDefs.toMap)(_))
val newDefs = mutable.Map[Const, Expr]()
def mkAbbrAtom(f: Formula): Atom = {
val fvs = freeVariables(f).toSeq
val what = Abs(fvs, f)
val by = ctx.addDefinition(what)
newDefs(by) = what
by(fvs).asInstanceOf[Atom]
}
private def solve(theory: Theory, expSeq: ExpansionSequent): UnprovableOrLKProof = {
None.orElse(tryAxiom(theory, expSeq)).orElse(tryDef(theory, expSeq)).orElse(tryMerge(theory, expSeq)).orElse(tryWeakening(theory, expSeq)).orElse(tryNullary(theory, expSeq)).orElse(tryInvStrongQ(theory, expSeq)).orElse(tryWeakQ(theory, expSeq)).orElse(tryInvUnary(theory, expSeq)).orElse(tryInvBinary(theory, expSeq)).orElse(trySimpNegL(theory, expSeq)).orElse(trySimpImpL(theory, expSeq)).orElse(tryPropag(theory, expSeq)).orElse(tryNonInv(theory, expSeq)).orElse(tryCut(theory, expSeq)).orElse(tryTheory(theory, expSeq)).getOrElse(Left(theory -> expSeq)).map {
ContractionMacroRule(_).ensuring { _.conclusion isSubsetOf expSeq.shallow }
}
}
private def tryAxiom(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] = {
val shallowSequent = expSeq.shallow
if (shallowSequent.isTaut)
Some(Right(LogicalAxiom(shallowSequent.antecedent intersect shallowSequent.succedent head)))
else
None
}
private def tryTheory(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] =
quiet(theorySolver(expSeq collect { case ETAtom(atom: Atom, _) => atom })).map {
Right(_)
}
private def tryDef(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] =
expSeq.zipWithIndex.elements collectFirst {
case (ETDefinition(sh, ch), i) =>
mapIf(solve(theory, expSeq.updated(i, ch)), ch.shallow, i.polarity) {
ConversionRule(_, ch.shallow, sh, i.polarity)
}
}
private def tryMerge(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] =
expSeq.zipWithIndex.elements collectFirst {
case (ETMerge(a, b), i: Ant) => solve(theory, a +: b +: expSeq.delete(i))
case (ETMerge(a, b), i: Suc) => solve(theory, expSeq.delete(i) :+ a :+ b)
}
private def tryNullary(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] =
expSeq.zipWithIndex.elements collectFirst {
case (ETTop(_), _: Suc) => Right(TopAxiom)
case (ETBottom(_), _: Ant) => Right(BottomAxiom)
}
private def tryWeakening(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] =
expSeq.zipWithIndex.elements collectFirst {
case (ETWeakening(_, _), i) => solve(theory, expSeq delete i)
case (ETTop(_), i: Ant) => solve(theory, expSeq delete i)
case (ETBottom(_), i: Suc) => solve(theory, expSeq delete i)
}
private def tryInvUnary(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] =
expSeq.zipWithIndex.elements collectFirst {
case (ETAnd(f, g), i: Ant) =>
mapIf(solve(theory, f +: g +: expSeq.delete(i)), f.shallow, i.polarity, g.shallow, i.polarity) {
AndLeftMacroRule(_, f.shallow, g.shallow)
}
case (ETOr(f, g), i: Suc) =>
mapIf(solve(theory, expSeq.delete(i) :+ f :+ g), f.shallow, i.polarity, g.shallow, i.polarity) {
OrRightMacroRule(_, f.shallow, g.shallow)
}
}
private def isCopy(e: ExpansionTree): Boolean =
e match {
case ETTop(_) => true
case ETBottom(_) => true
case ETAtom(_, _) => true
case _ => false
}
private def trySimpNegL(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] =
expSeq.zipWithIndex.elements collectFirst {
case (ETNeg(ETTop(_)), _: Ant) => Right(NegLeftRule(TopAxiom, Top()))
case (ETNeg(ETBottom(_)), _: Suc) => Right(NegRightRule(BottomAxiom, Bottom()))
case (ETNeg(ETBottom(_)), i: Ant) => solve(theory, expSeq.delete(i))
case (ETNeg(ETTop(_)), i: Suc) => solve(theory, expSeq.delete(i))
case (ETNeg(ETNeg(f)), i: Ant) if expSeq.succedent.isEmpty =>
mapIf(solve(theory, expSeq.updated(i, f)), f.shallow, f.polarity) {
ProofBuilder.c(_).u(NegRightRule(_, f.shallow)).u(NegLeftRule(_, -f.shallow)).qed
}
case (ETNeg(ETAnd(f, g)), i: Ant) =>
val h = ETImp(f, ETNeg(g))
mapIf(solve(theory, ETImp(f, ETNeg(g)) +: expSeq.delete(i)), h.shallow, h.polarity) {
ProofBuilder.c(LogicalAxiom(f.shallow)).c(LogicalAxiom(g.shallow)).b(AndRightRule(_, _, f.shallow & g.shallow)).u(NegLeftRule(_, f.shallow & g.shallow)).u(NegRightRule(_, g.shallow)).u(ImpRightRule(_, h.shallow)).c(_).b(CutRule(_, _, h.shallow)).qed
}
case (ETNeg(ETOr(f, g)), i: Ant) =>
mapIf(
solve(theory, ETNeg(f) +: ETNeg(g) +: expSeq.delete(i)),
-f.shallow,
!f.polarity,
-g.shallow,
!g.polarity
) {
ProofBuilder.c(LogicalAxiom(f.shallow)).u(WeakeningRightRule(_, g.shallow)).u(OrRightRule(_, f.shallow, g.shallow)).u(NegLeftRule(_, f.shallow | g.shallow)).u(NegRightRule(_, f.shallow)).c(LogicalAxiom(g.shallow)).u(WeakeningRightRule(_, f.shallow)).u(OrRightRule(_, f.shallow, g.shallow)).u(NegLeftRule(_, f.shallow | g.shallow)).u(NegRightRule(_, g.shallow)).c(_).u(WeakeningMacroRule(_, -f.shallow +: -g.shallow +: Sequent(), strict = false)).b(CutRule(_, _, -g.shallow)).b(CutRule(_, _, -f.shallow)).qed
}
case (ETNeg(f @ (ETImp(_, _) | ETStrongQuantifier(_, _, _) | ETNeg(_))), i: Ant) =>
val h = ETImp(f, ETBottom(Polarity.InAntecedent))
mapIf(solve(theory, h +: expSeq.delete(i)), h.shallow, h.polarity) {
ProofBuilder.c(LogicalAxiom(f.shallow)).u(NegLeftRule(_, f.shallow)).u(WeakeningRightRule(_, Bottom())).u(ImpRightRule(_, h.shallow)).c(_).b(CutRule(_, _, h.shallow)).qed
}
case (ETNeg(ETWeakQuantifier(Ex(x, sh), insts)), i: Ant) =>
val h = ETWeakQuantifier(All(x, -sh), for ((i, f) <- insts) yield i -> ETNeg(f))
mapIf(solve(theory, expSeq.updated(i, h)), h.shallow, h.polarity) {
ProofBuilder.c(LogicalAxiom(sh)).u(ExistsRightRule(_, Ex(x, sh), x)).u(NegLeftRule(_, Ex(x, sh))).u(NegRightRule(_, sh)).u(ForallRightRule(_, All(x, -sh))).c(_).b(CutRule(_, _, h.shallow)).qed
}
}
private def trySimpImpL(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] =
expSeq.zipWithIndex.elements collectFirst {
case (ETImp(ETBottom(_), _), i: Ant) => solve(theory, expSeq.delete(i))
case (ETImp(ETTop(_), f), i: Ant) =>
mapIf(solve(theory, expSeq.updated(i, f)), f.shallow, f.polarity) {
ImpLeftRule(TopAxiom, _, Top() --> f.shallow)
}
case (ETImp(ETAnd(f, g), h), i: Ant) =>
val e = ETImp(f, ETImp(g, h))
mapIf(solve(theory, expSeq.updated(i, e)), e.shallow, e.polarity) {
ProofBuilder.c(LogicalAxiom(f.shallow)).c(LogicalAxiom(g.shallow)).b(AndRightRule(_, _, f.shallow & g.shallow)).c(LogicalAxiom(h.shallow)).b(ImpLeftRule(_, _, (f.shallow & g.shallow) --> h.shallow)).u(ImpRightRule(_, g.shallow --> h.shallow)).u(ImpRightRule(_, e.shallow)).c(_).b(CutRule(_, _, e.shallow)).qed
}
case (f0 @ ETImp(ETImp(f, g), h), i: Ant) if !isCopy(g) =>
val g_ = mkAbbrAtom(g.shallow)
val e1 = ETDefinition(f0.shallow, ETImp(ETImp(f, ETAtom(g_, Polarity.InSuccedent)), h))
val e2 = ETDefinition(g.shallow --> g.shallow, ETImp(g, ETAtom(g_, Polarity.InAntecedent)))
mapIf(solve(theory, e1 +: e2 +: expSeq.delete(i)), e2.shallow, e2.polarity) {
ProofBuilder.c(LogicalAxiom(g.shallow)).u(ImpRightRule(_, e2.shallow)).c(_).b(CutRule(_, _, e2.shallow)).qed
}
case (f @ ETImp(g @ (ETOr(_, _) | ETWeakQuantifier(_, _)), h), i: Ant) if !isCopy(h) =>
val h_ = mkAbbrAtom(h.shallow)
val e1 = ETDefinition(f.shallow, ETImp(g, ETAtom(h_, Polarity.InAntecedent)))
val e2 = ETDefinition(h.shallow --> h.shallow, ETImp(ETAtom(h_, Polarity.InSuccedent), h))
mapIf(solve(theory, e1 +: e2 +: expSeq.delete(i)), e2.shallow, e2.polarity) {
ProofBuilder.c(LogicalAxiom(h.shallow)).u(ImpRightRule(_, e2.shallow)).c(_).b(CutRule(_, _, e2.shallow)).qed
}
case (f0 @ ETImp(ETOr(f, g), h), i: Ant) if isCopy(h) =>
val e1 = ETImp(f, h)
val e2 = ETImp(g, h)
mapIf(solve(theory, e1 +: e2 +: expSeq.delete(i)), e1.shallow, e1.polarity, e2.shallow, e2.polarity) {
ProofBuilder.c(LogicalAxiom(f.shallow)).u(WeakeningRightRule(_, g.shallow)).u(OrRightRule(_, f.shallow, g.shallow)).c(LogicalAxiom(h.shallow)).b(ImpLeftRule(_, _, f0.shallow)).u(ImpRightRule(_, e1.shallow)).c(LogicalAxiom(g.shallow)).u(WeakeningRightRule(_, f.shallow)).u(OrRightRule(_, f.shallow, g.shallow)).c(LogicalAxiom(h.shallow)).b(ImpLeftRule(_, _, f0.shallow)).u(ImpRightRule(_, e2.shallow)).c(_).u(WeakeningMacroRule(_, e1.shallow +: e2.shallow +: Sequent(), strict = false)).b(CutRule(_, _, e2.shallow)).b(CutRule(_, _, e1.shallow)).qed
}
case (ETImp(ETWeakQuantifier(sh0 @ Ex(x0, _), insts), g), i: Ant) if isCopy(g) =>
val x = rename(x0, freeVariables(g.shallow))
val sh = instantiate(sh0, x)
val h = ETWeakQuantifier(All(x, sh --> g.shallow), for ((i, e) <- insts) yield i -> ETImp(e, g))
mapIf(solve(theory, expSeq.updated(i, h)), h.shallow, h.polarity) {
ProofBuilder.c(LogicalAxiom(sh)).u(ExistsRightRule(_, Ex(x, sh), x)).c(LogicalAxiom(g.shallow)).b(ImpLeftRule(_, _, Ex(x, sh) --> g.shallow)).u(ImpRightRule(_, sh, g.shallow)).u(ForallRightRule(_, All(x, sh --> g.shallow))).c(_).b(CutRule(_, _, h.shallow)).qed
}
case (f0 @ ETImp(ETNeg(f), g), i: Ant) =>
val h = ETImp(ETImp(f, ETBottom(Polarity.InSuccedent)), g)
mapIf(solve(theory, expSeq.updated(i, h)), h.shallow, h.polarity) {
ProofBuilder.c(LogicalAxiom(f.shallow)).c(BottomAxiom).b(ImpLeftRule(_, _, f.shallow --> Bottom())).u(NegRightRule(_, f.shallow)).c(LogicalAxiom(g.shallow)).b(ImpLeftRule(_, _, f0.shallow)).u(ImpRightRule(_, h.shallow)).c(_).b(CutRule(_, _, h.shallow)).qed
}
}
private def solveAtomic(clause: HOLClause): Option[LKProof] =
clause.antecedent.intersect(clause.succedent).headOption.map(LogicalAxiom.apply).orElse(theorySolver(clause))
private def tryPropag(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] = {
lazy val antClause = Sequent(expSeq.shallow.antecedent.collect { case a: Atom => a }, Vector())
expSeq.zipWithIndex.elements.view.flatMap {
case (ETImp(ETAtom(f: Atom, _), g), i: Ant) =>
solveAtomic(antClause :+ f).map { p1 =>
if (!p1.conclusion.succedent.contains(f)) Right(p1)
else mapIf(solve(theory, expSeq.updated(i, g)), g.shallow, g.polarity) { p2 =>
ImpLeftRule(p1, p2, f --> g.shallow)
}
}
case (ETNeg(ETAtom(f: Atom, _)), _: Ant) =>
solveAtomic(antClause :+ f).map { p1 =>
Right(if (!p1.conclusion.succedent.contains(f)) p1
else NegLeftRule(p1, f))
}
case _ => None
}.headOption
}
private def tryInvBinary(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] = {
def handle(i: SequentIndex, e: ExpansionTree, f: ExpansionTree, g: ExpansionTree, rule: (LKProof, LKProof, Formula) => LKProof) =
solve(theory, if (f.polarity.inSuc) expSeq.delete(i) :+ f else f +: expSeq.delete(i)) flatMap { p1 =>
if (!p1.conclusion.contains(f.shallow, f.polarity)) Right(p1)
else solve(theory, if (g.polarity.inSuc) expSeq.delete(i) :+ g else g +: expSeq.delete(i)) map { p2 =>
if (!p2.conclusion.contains(g.shallow, g.polarity)) p2
else rule(p1, p2, e.shallow)
}
}
expSeq.zipWithIndex.swapped.elements collectFirst {
case (e @ ETAnd(f, g), i: Suc) => handle(i, e, f, g, AndRightRule(_, _, _))
case (e @ ETOr(f, g), i: Ant) => handle(i, e, f, g, OrLeftRule(_, _, _))
}
}
private def tryNonInv(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] = {
def invIfSucc1(x: UnprovableOrLKProof): Option[UnprovableOrLKProof] =
if (expSeq.succedent.size <= 1) Some(x)
else x.toOption.map(Right(_))
expSeq.zipWithIndex.elements.view.flatMap {
case (ETNeg(f), _: Suc) =>
invIfSucc1(mapIf(solve(theory, f +: expSeq.antecedent ++: Sequent()), f.shallow, f.polarity) {
NegRightRule(_, f.shallow)
})
case (ETImp(f, g), _: Suc) =>
invIfSucc1(mapIf(solve(theory, f +: expSeq.antecedent ++: Sequent() :+ g), f.shallow, f.polarity, g.shallow, g.polarity) {
ImpRightMacroRule(_, f.shallow, g.shallow)
})
case (ETStrongQuantifier(sh, ev, f), i: Suc) =>
invIfSucc1(mapIf(solve(theory, expSeq.antecedent ++: Sequent() :+ f), f.shallow, i.polarity) {
ForallRightRule(_, sh, ev)
})
case (f0 @ ETImp(ETStrongQuantifier(All(x, sh), ev, f), g), i: Ant) =>
solve(theory, expSeq.delete(i).antecedent ++: Sequent() :+ f) match {
case Right(p1) if p1.endSequent.succedent.isEmpty => Some(Right(p1))
case Right(p1) =>
Some(mapIf(solve(theory, g +: expSeq.delete(i)), g.shallow, g.polarity) { p2 =>
ProofBuilder.c(p1).u(ForallRightRule(_, All(x, sh), ev)).c(p2).b(ImpLeftRule(_, _, f0.shallow)).qed
})
case Left(_) => None
}
case (ETImp(ETImp(f, g), h), i: Ant) if isCopy(g) =>
solve(theory, f +: ETImp(g, h) +: expSeq.delete(i).antecedent ++: Sequent() :+ g) match {
case Right(p1) if p1.endSequent isSubsetOf expSeq.shallow => Some(Right(p1))
case Right(p1) =>
Some(mapIf(solve(theory, h +: expSeq.delete(i)), h.shallow, h.polarity) { p2 =>
ProofBuilder.c(LogicalAxiom(g.shallow)).u(WeakeningLeftRule(_, f.shallow)).u(ImpRightRule(_, f.shallow --> g.shallow)).c(LogicalAxiom(h.shallow)).b(ImpLeftRule(_, _, (f.shallow --> g.shallow) --> h.shallow)).u(ImpRightRule(_, g.shallow --> h.shallow)).c(p1).u(WeakeningMacroRule(_, f.shallow +: (g.shallow --> h.shallow) +: Sequent() :+ g.shallow, strict = false)).b(CutRule(_, _, g.shallow --> h.shallow)).u(ImpRightRule(_, f.shallow --> g.shallow)).c(p2).b(ImpLeftRule(_, _, (f.shallow --> g.shallow) --> h.shallow)).qed
})
case Left(_) => None
}
case _ => None
}.headOption
}
private def tryInvStrongQ(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] =
expSeq.zipWithIndex.elements collectFirst {
case (ETStrongQuantifier(sh, ev, f), i: Ant) =>
mapIf(solve(theory, expSeq.updated(i, f)), f.shallow, i.polarity) {
ExistsLeftRule(_, sh, ev)
}
}
private def tryWeakQ(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] = scala.util.boundary {
lazy val upcomingEVs = (for {
et <- theory.getExpansionTrees ++ expSeq.elements
case ETStrongQuantifier(_, ev, _) <- et.subProofs
} yield ev).toSet
def possibleInsts(insts: Map[Expr, ExpansionTree]) =
Map() ++ insts.view.filterKeys(t => freeVariables(t) intersect upcomingEVs isEmpty).toMap
for (case (ETWeakQuantifier(sh, insts), i) <- expSeq.zipWithIndex.elements) {
val insts_ = possibleInsts(insts)
if (insts_.nonEmpty) {
var newExpSeq =
if (insts_ == insts) expSeq.delete(i)
else expSeq.updated(i, ETWeakQuantifier(sh, insts -- insts_.keys))
if (i isSuc) newExpSeq :++= insts_.values
else newExpSeq ++:= insts_.values
scala.util.boundary.break(Some(solve(theory, newExpSeq) map { p0 =>
insts_.foldLeft(p0) {
case (p, (t, child)) =>
if (!p.conclusion.contains(child.shallow, i.polarity))
p
else i match {
case Ant(_) => ForallLeftRule(p, sh, t)
case Suc(_) => ExistsRightRule(p, sh, t)
}
}
}))
}
}
None
}
private def tryCut(theory: Theory, expSeq: ExpansionSequent): Option[UnprovableOrLKProof] = {
lazy val upcomingEVs = (for {
et <- theory.getExpansionTrees ++ expSeq.elements
case ETStrongQuantifier(_, ev, _) <- et.subProofs
} yield ev).toSet
theory.cuts.zipWithIndex collectFirst {
case (ETCut.Cut(cut1, cut2), i) if freeVariables(cut1.shallow) intersect upcomingEVs isEmpty =>
val newCuts = theory.cuts.zipWithIndex.filter { _._2 != i }.map { _._1 }
solve(Theory(newCuts, theory.inductions), expSeq :+ cut1) flatMap { p1 =>
if (!p1.conclusion.contains(cut1.shallow, Polarity.InSuccedent)) Right(p1)
else solve(Theory(newCuts, theory.inductions), cut2 +: expSeq) map { p2 =>
if (!p2.conclusion.contains(cut2.shallow, Polarity.InAntecedent)) p2
else CutRule(p1, p2, cut1.shallow)
}
}
}
}
// TODO: induction
}