gapt.provers.viper.grammars.solveBupViaInterpolationBoundedDepth.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.provers.viper.grammars
import gapt.expr._
import gapt.expr.formula.fol.folTermSize
import gapt.expr.formula.hol.instantiate
import gapt.proofs._
import gapt.provers.{Prover, Session}
import gapt.provers.smtlib.{SmtInterpol, Z3}
import gapt.utils.Tree
import cats.implicits._
import gapt.logic.bdt.BDT
import gapt.expr.formula.And
import gapt.expr.formula.Eq
import gapt.expr.formula.Formula
import gapt.expr.formula.Or
import gapt.expr.formula.Top
import gapt.expr.subst.Substitution
import gapt.expr.util.freeVariables
import gapt.expr.util.rename
import gapt.logic.hol.CNFp
import gapt.logic.hol.simplifyPropositional
import gapt.logic.hol.skolemize
import gapt.proofs.resolution.{forgetfulPropParam, forgetfulPropResolve}
import scala.collection.mutable
object solveBupViaInterpolationBoundedDepth {
type PredVars = (Var, Seq[Var])
def boundedUnfolding(bup: InductionBUP, i: Int): Tree[(PredVars, Formula)] = {
val nameGen = rename.awayFrom(containedNames(bup.formula))
def u(nu: Var, gam: Seq[Var], i: Int): Tree[(PredVars, Formula)] = {
val bgth = mutable.Buffer[Formula]()
val caseEqs = mutable.Buffer[Formula]()
val children = mutable.Buffer[Tree[(PredVars, Formula)]]()
for {
cas <- bup.indCases
if i > 0 || cas.indHyps.isEmpty
nus = cas.nu.map(nameGen.fresh(_))
} {
val subst = Substitution((cas.nu zip nus) ++ (bup.grammar.gamma zip gam))
bgth += subst(cas.theoryFormulas.toNegConjunction)
for {
gamTerm <- cas.gammas
gam_ = bup.grammar.gamma.map(nameGen.fresh(_))
} {
for ((g, t) <- gam_.zip(subst(gamTerm)))
bgth += Eq(g, t)
for (nu_ <- nus if nu_.ty == bup.grammar.indTy)
children += u(nu_, gam_, i - 1)
}
caseEqs += Eq(nu, cas.constructor(nus))
}
Tree(((nu, gam), And(Or(caseEqs) +: bgth)), children.toVector)
}
{
val bgth = mutable.Buffer[Formula]()
val children = mutable.Buffer[Tree[(PredVars, Formula)]]()
val nu_ = nameGen.fresh(bup.grammar.alpha)
bgth += Eq(nu_, bup.grammar.alpha)
bgth += bup.endCut.theoryFormulas.toNegConjunction
bgth += -bup.goal
for {
gamTerm <- bup.endCut.gammas
gam_ = bup.grammar.gamma.map(nameGen.fresh(_))
} {
for ((g, t) <- gam_.zip(gamTerm))
bgth += Eq(g, t)
children += u(nu_, gam_, i)
}
Tree(((nu_, bup.grammar.gamma), And(bgth)), children.toVector)
}
}
def apply(bup: InductionBUP, i: Int = 0): Expr = {
val tree = boundedUnfolding(bup, i)
val Some(interpolants) = SmtInterpol.getInterpolant(tree.map(_._2)): @unchecked
val nu = rename(
(bup.grammar.nus.values.toSeq.flatten :+ bup.grammar.alpha).find(_.ty == bup.grammar.indTy).head,
bup.grammar.gamma.toSet + bup.grammar.alpha
)
val generalized =
tree.zip(interpolants).map {
case (((nu_, gam), _), interp) =>
TermReplacement(simplifyPropositional(interp), Map[Expr, Expr](nu_ -> nu) ++ gam.zip(bup.grammar.gamma)): Formula
}
val solution = simplifyPropositional(Or(
generalized.zipWithDepth.postOrder.groupBy(_._2).values.map(_.map(_._1)).map(And(_)).filterNot(_ == Top())
))
TreeGrammarProver.logger.info(s"candidate solution: ${solution.toUntypedString}")
val sol = Abs.Block(bup.grammar.alpha +: nu +: bup.grammar.gamma, solution)
val cond = skolemize(BetaReduction.betaNormalize(instantiate(bup.formula, sol)))
if (SmtInterpol.isValid(cond))
sol
else
apply(bup, i + 1)
}
}
object solveBupViaInterpolationConcreteTerms {
def norm(t: Expr): Expr =
Substitution(for (x <- freeVariables(t)) yield x -> Var("x", x.ty))(t)
type PredVars = (Expr, Var, Seq[Var])
def boundedUnfolding(bup: InductionBUP, t: Expr): Tree[(PredVars, Formula)] = {
val nameGen = rename.awayFrom(containedNames(bup.formula))
def u(nu: Var, gam: Seq[Var], t: Expr): Tree[(PredVars, Formula)] = {
val bgth = mutable.Buffer[Formula]()
val caseEqs = mutable.Buffer[Formula]()
val children = mutable.Buffer[Tree[(PredVars, Formula)]]()
val Apps(ctr, args) = t
val Some(cas) = bup.indCases.find(_.constructor == ctr): @unchecked
val nus = cas.nu.map(nameGen.fresh(_))
val subst = Substitution((cas.nu zip nus) ++ (bup.grammar.gamma zip gam))
bgth += subst(cas.theoryFormulas.toNegConjunction)
for {
gamTerm <- cas.gammas
gam_ = bup.grammar.gamma.map(nameGen.fresh(_))
} {
for ((g, t) <- gam_.zip(subst(gamTerm)))
bgth += Eq(g, t)
for ((nu_, a) <- nus zip args if nu_.ty == bup.grammar.indTy)
children += u(nu_, gam_, a)
}
caseEqs += Eq(nu, cas.constructor(nus))
Tree(((norm(t), nu, gam), And(Or(caseEqs) +: bgth)), children.toVector)
}
{
val bgth = mutable.Buffer[Formula]()
val children = mutable.Buffer[Tree[(PredVars, Formula)]]()
val nu_ = nameGen.fresh(
(bup.grammar.nus.values.toSeq.flatten :+ bup.grammar.alpha).find(_.ty == bup.grammar.indTy).head
)
bgth += Eq(nu_, bup.grammar.alpha)
bgth += bup.endCut.theoryFormulas.toNegConjunction
bgth += -bup.goal
for {
gamTerm <- bup.endCut.gammas
gam_ = bup.grammar.gamma.map(nameGen.fresh(_))
} {
for ((g, t) <- gam_.zip(gamTerm))
bgth += Eq(g, t)
children += u(nu_, gam_, t)
}
Tree(((norm(t), nu_, bup.grammar.gamma), And(bgth)), children.toVector)
}
}
def improve(context: Formula, start: Formula, instances: Set[Substitution], prover: Prover, hasEquality: Boolean, forgetOne: Boolean): Formula = {
import gapt.provers.Session._
val names = containedNames(instances) ++ containedNames(start) ++ containedNames(context)
val nameGen = rename.awayFrom(names)
val grounding = Substitution(for (v <- freeVariables(start & context) ++ instances.flatMap(_.range))
yield v -> Const(nameGen.fresh(v.name), v.ty))
val groundInstances = instances.map(grounding.compose)
def checkSolution(cnf: Set[HOLClause]): Session[Option[Formula]] = {
val clauses = for (inst <- groundInstances; clause <- cnf) yield inst(clause.toDisjunction)
withScope(assert(clauses.toList) *> checkUnsat).flatMap { isSolOrUnknown =>
val isSol = isSolOrUnknown.getOrElse(false)
if (isSol) {
val next =
(if (forgetOne) cnf.toList.map(cnf - _) else Nil) ++
forgetfulPropResolve(cnf).toList ++
(if (hasEquality) forgetfulPropParam(cnf).toList else Nil)
def findFirst(next: List[Set[HOLClause]]): Session[Option[Formula]] =
next match {
case n :: ns =>
checkSolution(n).flatMap {
case Some(sol) => Session.pure(Some(sol))
case None =>
findFirst(ns)
}
case Nil =>
Session.pure(Some(And(cnf.map(_.toFormula))))
}
findFirst(next)
} else {
Session.pure(None)
}
}
}
prover.runSession {
declareSymbolsIn(names ++ containedNames(grounding)) *>
assert(grounding(-context)) *>
checkSolution(CNFp(start).map { _.distinct.sortBy { _.hashCode } })
}.get
}
def improveAt(interps: Map[Expr, Formula], t: Expr, bup: InductionBUP, nu: Var): Formula = {
val nameGen = rename.awayFrom(containedNames(bup.formula) ++ containedNames(interps.values.toSeq) + nu)
val insts = mutable.Buffer[List[Var]]()
val contexts = mutable.Buffer[Formula]()
def getInsts(args: Seq[List[Expr]]): Formula = {
while (insts.size < args.size)
insts += (nu +: bup.grammar.gamma).map(nameGen.fresh(_))
And(for ((is, as) <- insts zip args; (i, a) <- is zip as) yield i === a)
}
contexts +=
(getInsts(bup.endCut.gammas.map(bup.grammar.alpha +: _)) &
bup.endCut.theoryFormulas.toNegConjunction) --> bup.goal
for {
case (par @ Apps(ctr: Const, parArgs), f) <- interps
if parArgs contains t
cas <- bup.indCases if cas.constructor == ctr
} contexts +=
(cas.theoryFormulas.toNegConjunction & And(
for ((nui, t_) <- cas.nu zip parArgs if nui.ty == bup.grammar.indTy)
yield
if (t_ == t)
getInsts(cas.gammas.map(nui +: _))
else
And(for (gam <- cas.gammas)
yield Substitution((nu -> nui) +: (bup.grammar.gamma zip gam))(interps(t_)))
)) -->
Substitution(nu -> ctr(cas.nu))(f)
improve(And(contexts), interps(t), Set() ++ (for (is <- insts) yield Substitution((nu +: bup.grammar.gamma) zip is)), Z3, hasEquality = true, forgetOne = true)
}
def improve(interps: Map[Expr, Formula], bup: InductionBUP, nu: Var): Map[Expr, Formula] =
interps.keys.toSeq.sortBy(-folTermSize(_)).foldLeft(interps)((interps, t) =>
interps.updated(t, improveAt(interps, t, bup, nu))
)
def apply(bup: InductionBUP, ts: LazyList[Expr]): Expr =
apply(
bup,
ts,
Map(),
rename(
(bup.grammar.nus.values.toSeq.flatten :+ bup.grammar.alpha).find(_.ty == bup.grammar.indTy).head,
bup.grammar.gamma.toSet + bup.grammar.alpha
)
)
def apply(bup: InductionBUP, ts: LazyList[Expr], prev: Map[Expr, Formula], nu: Var): Expr = {
val tree = boundedUnfolding(bup, ts.head)
val Some(interpolants) = SmtInterpol.getInterpolant(tree.map(_._2)).map(_.map(simplifyPropositional(_))): @unchecked
val generalized =
tree.zip(interpolants).map {
case (((t, nu_, gam), _), interp) =>
t -> (TermReplacement(simplifyPropositional(interp), Map[Expr, Expr](nu_ -> nu) ++ gam.zip(bup.grammar.gamma)): Formula)
}
val grouped = Map() ++
generalized.postOrder.dropRight(1).groupBy(_._1).view.mapValues(fs => And(fs.map(_._2))).toMap
val groupedAndPrev =
(grouped.keySet ++ prev.keySet).map(k => k -> simplifyPropositional(grouped.getOrElse(k, Top()) & prev.getOrElse(k, Top()))).toMap
// val improved = groupedAndPrev
// val improved = improve( groupedAndPrev, bup, nu )
val improved = groupedAndPrev.map { case (k, f) => k -> BDT(f).simpEq.toFormula }
val solution = simplifyPropositional(BDT(Or(improved.values.filterNot(_ == Top()))).simpEq.toFormula)
TreeGrammarProver.logger.info(s"candidate solution: ${solution.toUntypedString}")
val sol = Abs.Block(bup.grammar.alpha +: nu +: bup.grammar.gamma, solution)
val cond = skolemize(BetaReduction.betaNormalize(instantiate(bup.formula, sol)))
if (SmtInterpol.isValid(cond))
sol
else
apply(bup, ts.tail, improved, nu)
}
}