From dd55c7f2699bf1aa6d9f04ed2db331f7370dbd62 Mon Sep 17 00:00:00 2001 From: SimonGuilloud <simon.guilloud@bluewin.ch> Date: Thu, 27 Oct 2022 12:02:24 +0200 Subject: [PATCH] Substitutions (#84) * Simple tactic for substitution of equals for equals and equivalent for equivalents. * Some corrections in the EquivalenceChecker * Moved InstantiateBinder to helpers. * Some more changes regarding tactics and proof steps. --- lisa-examples/src/main/scala/Example.scala | 1 + .../lisa/kernel/fol/EquivalenceChecker.scala | 124 ++++++----- .../scala/lisa/kernel/fol/Substitutions.scala | 3 - .../main/scala/lisa/utils/KernelHelpers.scala | 10 + .../lisa/utils/tactics/BasicStepTactic.scala | 1 + .../lisa/utils/tactics/ProofsHelpers.scala | 8 + .../utils/tactics/SimpleDeducedSteps.scala | 11 +- .../automation/kernel/SimpleSimplifier.scala | 208 ++++++++++++++++++ 8 files changed, 301 insertions(+), 65 deletions(-) create mode 100644 src/main/scala/lisa/automation/kernel/SimpleSimplifier.scala diff --git a/lisa-examples/src/main/scala/Example.scala b/lisa-examples/src/main/scala/Example.scala index 00a566cf..3737c53e 100644 --- a/lisa-examples/src/main/scala/Example.scala +++ b/lisa-examples/src/main/scala/Example.scala @@ -1,5 +1,6 @@ import lisa.Main import lisa.automation.kernel.SimplePropositionalSolver.* +import lisa.automation.kernel.SimpleSimplifier.* import lisa.kernel.fol.FOL.* import lisa.kernel.proof.SCProof import lisa.kernel.proof.SCProofChecker diff --git a/lisa-kernel/src/main/scala/lisa/kernel/fol/EquivalenceChecker.scala b/lisa-kernel/src/main/scala/lisa/kernel/fol/EquivalenceChecker.scala index b81d1244..e7a0fe25 100644 --- a/lisa-kernel/src/main/scala/lisa/kernel/fol/EquivalenceChecker.scala +++ b/lisa-kernel/src/main/scala/lisa/kernel/fol/EquivalenceChecker.scala @@ -58,62 +58,71 @@ private[fol] trait EquivalenceChecker extends FormulaDefinitions { * A class that encapsulate "runtime" information of the equivalence checker. It performs memoization for efficiency. */ class LocalEquivalenceChecker { - private val unsugaredVersion = scala.collection.mutable.HashMap[Formula, SimpleFormula]() + private val unsugaredVersion = scala.collection.mutable.HashMap[Formula, SimpleFormula]() // transform a LISA formula into a simpler, desugarised version with less symbols. Conjunction, implication, iff, existsOne are treated as alliases and translated. - def removeSugar(phi: Formula): SimpleFormula = unsugaredVersion.getOrElseUpdate( - phi, { - phi match { - case PredicateFormula(label, args) => SimplePredicate(label, args.toList) - case ConnectorFormula(label, args) => - label match { - case Neg => SNeg(removeSugar(args(0))) - case Implies => - val l = removeSugar(args(0)) - val r = removeSugar(args(1)) - SOr(List(SNeg(l), r)) - case Iff => - val l = removeSugar(args(0)) - val r = removeSugar(args(1)) - val c1 = SNeg(SOr(List(SNeg(l), r))) - val c2 = SNeg(SOr(List(SNeg(r), l))) - SNeg(SOr(List(c1, c2))) - case And => - SNeg(SOr(args.map(c => SNeg(removeSugar(c))).toList)) - case Or => SOr((args map removeSugar).toList) - case _ => SimpleConnector(label, args.toList.map(removeSugar)) - } - case BinderFormula(label, bound, inner) => - label match { - case Forall => SForall(bound.id, removeSugar(inner)) - case Exists => SExists(bound.id, removeSugar(inner)) - case ExistsOne => - val y = VariableLabel(freshId(inner.freeVariables.map(_.id), bound.id)) - val c1 = SimplePredicate(equality, List(VariableTerm(bound), VariableTerm(y))) - val c2 = removeSugar(inner) - val c1_c2 = SOr(List(SNeg(c1), c2)) - val c2_c1 = SOr(List(SNeg(c2), c1)) - SExists(y.id, SForall(bound.id, SNeg(SOr(List(SNeg(c1_c2), SNeg(c2_c1)))))) - } - } + def removeSugar1(phi: Formula): SimpleFormula = { + phi match { + case PredicateFormula(label, args) => + if (label == top) SLiteral(true) + else if (label == bot) SLiteral(false) + else SimplePredicate(label, args.toList) + case ConnectorFormula(label, args) => + label match { + case Neg => SNeg(removeSugar1(args(0))) + case Implies => + val l = removeSugar1(args(0)) + val r = removeSugar1(args(1)) + SOr(List(SNeg(l), r)) + case Iff => + val l = removeSugar1(args(0)) + val r = removeSugar1(args(1)) + val c1 = SNeg(SOr(List(SNeg(l), r))) + val c2 = SNeg(SOr(List(SNeg(r), l))) + SNeg(SOr(List(c1, c2))) + case And => + SNeg(SOr(args.map(c => SNeg(removeSugar1(c))).toList)) + case Or => SOr((args map removeSugar1).toList) + case _ => SimpleConnector(label, args.toList.map(removeSugar1)) + } + case BinderFormula(label, bound, inner) => + label match { + case Forall => SForall(bound.id, removeSugar1(inner)) + case Exists => SExists(bound.id, removeSugar1(inner)) + case ExistsOne => + val y = VariableLabel(freshId(inner.freeVariables.map(_.id), bound.id)) + val c1 = SimplePredicate(equality, List(VariableTerm(bound), VariableTerm(y))) + val c2 = removeSugar1(inner) + val c1_c2 = SOr(List(SNeg(c1), c2)) + val c2_c1 = SOr(List(SNeg(c2), c1)) + SExists(y.id, SForall(bound.id, SNeg(SOr(List(SNeg(c1_c2), SNeg(c2_c1)))))) + } } - ) + } + + def toLocallyNameless(t: Term, subst: Map[VariableLabel, Int], i: Int): Term = { + t match { + case Term(label: VariableLabel, _) => + if (subst.contains(label)) VariableTerm(VariableLabel("x" + (i - subst(label)))) + else VariableTerm(VariableLabel("_" + label.id)) + case Term(label, args) => Term(label, args.map(c => toLocallyNameless(c, subst, i))) + } + } - def toLocallyNameless(t: Term, subst: Map[VariableLabel, Int], i: Int): Term = t match { - case Term(label: VariableLabel, _) => - if (subst.contains(label)) VariableTerm(VariableLabel("x" + (i - subst(label)))) - else VariableTerm(VariableLabel("_" + label)) - case Term(label, args) => Term(label, args.map(c => toLocallyNameless(c, subst, i))) + def toLocallyNameless(phi: SimpleFormula, subst: Map[VariableLabel, Int], i: Int): SimpleFormula = { + phi match { + case SimplePredicate(id, args) => SimplePredicate(id, args.map(c => toLocallyNameless(c, subst, i))) + case SimpleConnector(id, args) => SimpleConnector(id, args.map(f => toLocallyNameless(f, subst, i))) + case SNeg(child) => SNeg(toLocallyNameless(child, subst, i)) + case SOr(children) => SOr(children.map(toLocallyNameless(_, subst, i))) + case SForall(x, inner) => SForall("", toLocallyNameless(inner, subst + (VariableLabel(x) -> i), i + 1)) + case SExists(x, inner) => SExists("", toLocallyNameless(inner, subst + (VariableLabel(x) -> i), i + 1)) + case SLiteral(b) => phi + } } - def toLocallyNameless(phi: SimpleFormula, subst: Map[VariableLabel, Int], i: Int): SimpleFormula = phi match { - case SimplePredicate(id, args) => SimplePredicate(id, args.map(c => toLocallyNameless(c, subst, i))) - case SimpleConnector(id, args) => SimpleConnector(id, args.map(f => toLocallyNameless(f, subst, i))) - case SNeg(child) => SNeg(toLocallyNameless(child, subst, i)) - case SOr(children) => SOr(children.map(toLocallyNameless(_, subst, i))) - case SForall(x, inner) => SForall("", toLocallyNameless(inner, subst + (VariableLabel(x) -> i), i + 1)) - case SExists(x, inner) => SExists("", toLocallyNameless(inner, subst + (VariableLabel(x) -> i), i + 1)) - case SLiteral(b) => phi + def removeSugar(phi: Formula): SimpleFormula = { + unsugaredVersion.getOrElseUpdate(phi, toLocallyNameless(removeSugar1(phi), Map.empty, 0)) } private val codesSig: mutable.HashMap[(String, Seq[Int]), Int] = mutable.HashMap() @@ -130,7 +139,6 @@ private[fol] trait EquivalenceChecker extends FormulaDefinitions { codesSigTerms.getOrElseUpdate((label, Nil), codesSigTerms.size) case Term(label, args) => val c = args map codesOfTerm - codesSigTerms.getOrElseUpdate((label, c), codesSigTerms.size) } ) @@ -274,10 +282,7 @@ private[fol] trait EquivalenceChecker extends FormulaDefinitions { } parent.normalForm.get :: acc case SimpleConnector(id, args) => - val lab = id match { - case _: ConstantConnectorLabel => "cons_conn_" + id.id + "_" + id.arity - case _: SchematicConnectorLabel => "schem_conn_" + id.id + "_" + id.arity - } + val lab = "conn_" + id.id + "_" + id.arity phi.normalForm = Some(NormalConnector(id, args.map(_.normalForm.get), updateCodesSig((lab, args map OCBSLCode)))) parent.normalForm = Some(NNeg(phi.normalForm.get, updateCodesSig(("neg", List(phi.normalForm.get.code))))) parent.normalForm.get :: acc @@ -343,7 +348,7 @@ private[fol] trait EquivalenceChecker extends FormulaDefinitions { def check(formula1: Formula, formula2: Formula): Boolean = { getCode(formula1) == getCode(formula2) } - def getCode(formula: Formula): Int = OCBSLCode(toLocallyNameless(removeSugar(formula), Map.empty, 0)) + def getCode(formula: Formula): Int = OCBSLCode(removeSugar(formula)) def isSame(term1: Term, term2: Term): Boolean = codesOfTerm(term1) == codesOfTerm(term2) @@ -359,13 +364,17 @@ private[fol] trait EquivalenceChecker extends FormulaDefinitions { val codesSet1 = s1.map(this.getCode) val codesSet2 = s2.map(this.getCode) codesSet1.subsetOf(codesSet2) - } + def contains(s: Set[Formula], f: Formula): Boolean = { val codesSet = s.map(this.getCode) val codesFormula = this.getCode(f) codesSet.contains(codesFormula) } + def normalForm(phi: Formula): NormalFormula = { + getCode(phi) + removeSugar(phi).normalForm.get + } } def isSame(term1: Term, term2: Term): Boolean = (new LocalEquivalenceChecker).isSame(term1, term2) @@ -377,4 +386,5 @@ private[fol] trait EquivalenceChecker extends FormulaDefinitions { def isSubset(s1: Set[Formula], s2: Set[Formula]): Boolean = (new LocalEquivalenceChecker).isSubset(s1, s2) def contains(s: Set[Formula], f: Formula): Boolean = (new LocalEquivalenceChecker).contains(s, f) + } diff --git a/lisa-kernel/src/main/scala/lisa/kernel/fol/Substitutions.scala b/lisa-kernel/src/main/scala/lisa/kernel/fol/Substitutions.scala index cd8bdc3d..2e743aa0 100644 --- a/lisa-kernel/src/main/scala/lisa/kernel/fol/Substitutions.scala +++ b/lisa-kernel/src/main/scala/lisa/kernel/fol/Substitutions.scala @@ -195,7 +195,4 @@ trait Substitutions extends FormulaDefinitions { } } - @deprecated - def instantiateBinder(f: BinderFormula, t: Term): Formula = substituteVariables(f.inner, Map(f.bound -> t)) - } diff --git a/lisa-utils/src/main/scala/lisa/utils/KernelHelpers.scala b/lisa-utils/src/main/scala/lisa/utils/KernelHelpers.scala index 16af6f19..c8f42e39 100644 --- a/lisa-utils/src/main/scala/lisa/utils/KernelHelpers.scala +++ b/lisa-utils/src/main/scala/lisa/utils/KernelHelpers.scala @@ -199,4 +199,14 @@ trait KernelHelpers { given Conversion[String, Term] = parseTerm(_) given Conversion[String, VariableLabel] = s => VariableLabel(if (s.head == '?') s.tail else s) + def lambda(x: VariableLabel, t: Term) = LambdaTermTerm(Seq(x), t) + def lambda(xs: Seq[VariableLabel], t: Term) = LambdaTermTerm(xs, t) + + def lambda(x: VariableLabel, phi: Formula) = LambdaTermFormula(Seq(x), phi) + def lambda(xs: Seq[VariableLabel], phi: Formula) = LambdaTermFormula(xs, phi) + + def lambda(X: VariableFormulaLabel, phi: Formula) = LambdaFormulaFormula(Seq(X), phi) + def lambda(Xs: Seq[VariableFormulaLabel], phi: Formula) = LambdaFormulaFormula(Xs, phi) + + def instantiateBinder(f: BinderFormula, t: Term): Formula = substituteVariables(f.inner, Map(f.bound -> t)) } diff --git a/lisa-utils/src/main/scala/lisa/utils/tactics/BasicStepTactic.scala b/lisa-utils/src/main/scala/lisa/utils/tactics/BasicStepTactic.scala index 4f2651e8..9c02f590 100644 --- a/lisa-utils/src/main/scala/lisa/utils/tactics/BasicStepTactic.scala +++ b/lisa-utils/src/main/scala/lisa/utils/tactics/BasicStepTactic.scala @@ -5,6 +5,7 @@ import lisa.kernel.proof.SCProof import lisa.kernel.proof.SequentCalculus.SCProofStep import lisa.kernel.proof.SequentCalculus.Sequent import lisa.kernel.proof.{SequentCalculus => SC} +import lisa.utils.Helpers.* import lisa.utils.Library import lisa.utils.tactics.ProofStepLib.{_, given} diff --git a/lisa-utils/src/main/scala/lisa/utils/tactics/ProofsHelpers.scala b/lisa-utils/src/main/scala/lisa/utils/tactics/ProofsHelpers.scala index 2fa04fdd..3471a8b4 100644 --- a/lisa-utils/src/main/scala/lisa/utils/tactics/ProofsHelpers.scala +++ b/lisa-utils/src/main/scala/lisa/utils/tactics/ProofsHelpers.scala @@ -87,6 +87,10 @@ trait ProofsHelpers { proofStack.head.newImportedFact(just) } + def andThen(pswp: ProofStepWithoutPrem)(using String => Unit)(using Throwable => Nothing): library.Proof#DoubleStep = { + val r = pswp.asProofStep(Seq(proof.mostRecentStep._2)) + r.validate(library) + } /** * Assume the given formula in all future left hand-side of claimed sequents. @@ -107,6 +111,10 @@ trait ProofsHelpers { } } + extension (pswp: ProofStepWithoutPrem) { + def by(premises: Seq[Library#Proof#Fact])(using String => Unit)(using Throwable => Nothing) = pswp.asProofStep(premises).validate(library) + } + given Conversion[ProofStepWithoutBotNorPrem[0], ProofStepWithoutBot] = _.asProofStepWithoutBot(Seq()) // case class InstantiatedJustification(just:theory.Justification, instsPred: Map[SchematicVarOrPredLabel, LambdaTermFormula], instsTerm: Map[SchematicTermLabel, LambdaTermTerm], instForall:Seq[Term]) diff --git a/lisa-utils/src/main/scala/lisa/utils/tactics/SimpleDeducedSteps.scala b/lisa-utils/src/main/scala/lisa/utils/tactics/SimpleDeducedSteps.scala index 5bb30600..0575b554 100644 --- a/lisa-utils/src/main/scala/lisa/utils/tactics/SimpleDeducedSteps.scala +++ b/lisa-utils/src/main/scala/lisa/utils/tactics/SimpleDeducedSteps.scala @@ -7,6 +7,7 @@ import lisa.kernel.proof.SequentCalculus.RewriteTrue import lisa.kernel.proof.SequentCalculus.SCProofStep import lisa.kernel.proof.SequentCalculus.Sequent import lisa.kernel.proof.{SequentCalculus => SC} +import lisa.utils.Helpers.* import lisa.utils.Helpers.{_, given} import lisa.utils.Library import lisa.utils.tactics.BasicStepTactic.SCSubproof @@ -90,7 +91,7 @@ object SimpleDeducedSteps { phi match { case psi @ FOL.BinderFormula(FOL.Forall, _, _) => { - val in = FOL.instantiateBinder(psi, t) + val in = instantiateBinder(psi, t) this.asSCProof(currentProof.getSequent(premises(0)) -> phi +> in, premises, currentProof) } @@ -112,11 +113,11 @@ object SimpleDeducedSteps { val tempVar = FOL.VariableLabel(FOL.freshId(psi.freeVariables.map(_.id), "x")) // instantiate the formula with input - val in = FOL.instantiateBinder(psi, t) + val in = instantiateBinder(psi, t) // construct proof val p0 = SC.Hypothesis(in |- in, in) - val p1 = SC.LeftForall(phi |- in, 0, FOL.instantiateBinder(psi, tempVar), tempVar, t) + val p1 = SC.LeftForall(phi |- in, 0, instantiateBinder(psi, tempVar), tempVar, t) val p2 = SC.Cut(bot, -1, 1, phi) /** @@ -226,12 +227,12 @@ object SimpleDeducedSteps { val tempVar = FOL.VariableLabel(FOL.freshId(psi.freeVariables.map(_.id), "x")) // instantiate the formula with input - val in = FOL.instantiateBinder(psi, t) + val in = instantiateBinder(psi, t) val bot = p.conclusion -> f +> in // construct proof val p0 = SC.Hypothesis(in |- in, in) - val p1 = SC.LeftForall(f |- in, 0, FOL.instantiateBinder(psi, tempVar), tempVar, t) + val p1 = SC.LeftForall(f |- in, 0, instantiateBinder(psi, tempVar), tempVar, t) val p2 = SC.Cut(bot, -1, 1, f) /** diff --git a/src/main/scala/lisa/automation/kernel/SimpleSimplifier.scala b/src/main/scala/lisa/automation/kernel/SimpleSimplifier.scala new file mode 100644 index 00000000..c87d1b88 --- /dev/null +++ b/src/main/scala/lisa/automation/kernel/SimpleSimplifier.scala @@ -0,0 +1,208 @@ +package lisa.automation.kernel + +import lisa.kernel.fol.FOL.* +import lisa.kernel.proof.SCProof +import lisa.kernel.proof.SequentCalculus.* +import lisa.utils.Helpers.* +import lisa.utils.Printer +import lisa.utils.tactics.ProofStepJudgement +import lisa.utils.tactics.ProofStepLib.* + +import scala.collection + +object SimpleSimplifier { + + private def condflat[T](s: Seq[(T, Boolean)]): (Seq[T], Boolean) = (s.map(_._1), s.exists(_._2)) + + def nFreshId(froms: Iterable[String], n: Int): IndexedSeq[String] = { + val max = if (froms.isEmpty) 0 else froms.map(c => ("0" + c.filter(_.isDigit)).toInt).max + Range(0, n).map(i => "_" + (max + i)) + } + + private def findSubterm2(t: Term, subs: Seq[(VariableLabel, Term)]): (Term, Boolean) = { + val eq = subs.find(s => isSame(t, s._2)) + if (eq.nonEmpty) (eq.get._1(), true) + else { + val induct = condflat(t.args.map(te => findSubterm2(te, subs))) + if (!induct._2) (t, false) + else (Term(t.label, induct._1), true) + + } + + } + + private def findSubterm2(f: Formula, subs: Seq[(VariableLabel, Term)]): (Formula, Boolean) = { + f match { + case PredicateFormula(label, args) => + val induct = condflat(args.map(findSubterm2(_, subs))) + if (!induct._2) (f, false) + else (PredicateFormula(label, induct._1), true) + case ConnectorFormula(label, args) => + val induct = condflat(args.map(findSubterm2(_, subs))) + if (!induct._2) (f, false) + else (ConnectorFormula(label, induct._1), true) + case BinderFormula(label, bound, inner) => + val fv_in_f = subs.flatMap(e => e._2.freeVariables + e._1) + if (!fv_in_f.contains(bound)) { + val induct = findSubterm2(inner, subs) + if (!induct._2) (f, false) + else (BinderFormula(label, bound, induct._1), true) + } else { + val newv = VariableLabel(freshId((f.freeVariables ++ fv_in_f).map(_.id), bound.id)) + val newInner = substituteVariables(inner, Map(bound -> newv())) + val induct = findSubterm2(newInner, subs) + if (!induct._2) (f, false) + else (BinderFormula(label, newv, induct._1), true) + } + } + } + + private def findSubformula2(f: Formula, subs: Seq[(VariableFormulaLabel, Formula)]): (Formula, Boolean) = { + val eq = subs.find(s => isSame(f, s._2)) + if (eq.nonEmpty) (eq.get._1(), true) + else + f match { + case PredicateFormula(label, args) => + (f, false) + case ConnectorFormula(label, args) => + val induct = condflat(args.map(findSubformula2(_, subs))) + if (!induct._2) (f, false) + else (ConnectorFormula(label, induct._1), true) + case BinderFormula(label, bound, inner) => + val fv_in_f = subs.flatMap(_._2.freeVariables) + if (!fv_in_f.contains(bound)) { + val induct = findSubformula2(inner, subs) + if (!induct._2) (f, false) + else (BinderFormula(label, bound, induct._1), true) + } else { + val newv = VariableLabel(freshId((f.freeVariables ++ fv_in_f).map(_.id), bound.id)) + val newInner = substituteVariables(inner, Map(bound -> newv())) + val induct = findSubformula2(newInner, subs) + if (!induct._2) (f, false) + else (BinderFormula(label, newv, induct._1), true) + } + } + } + def findSubterm(t: Term, subs: Seq[(VariableLabel, Term)]): Option[LambdaTermTerm] = { + val vars = subs.map(_._1) + val r = findSubterm2(t, subs) + if (r._2) Some(LambdaTermTerm(vars, r._1)) + else None + } + + def findSubterm(f: Formula, subs: Seq[(VariableLabel, Term)]): Option[LambdaTermFormula] = { + val vars = subs.map(_._1) + val r = findSubterm2(f, subs) + if (r._2) Some(LambdaTermFormula(vars, r._1)) + else None + } + + def findSubformula(f: Formula, subs: Seq[(VariableFormulaLabel, Formula)]): Option[LambdaFormulaFormula] = { + val vars = subs.map(_._1) + val r = findSubformula2(f, subs) + if (r._2) Some(LambdaFormulaFormula(vars, r._1)) + else None + } + + case class applySubst(phi: Formula) extends ProofStepWithoutPrem { + override def asSCProof(premises: Seq[Int], currentProof: lisa.utils.Library#Proof): ProofStepJudgement = { + val originSequent = currentProof.getSequent(premises.head) + val leftOrigin = ConnectorFormula(And, originSequent.left.toSeq) + val rightOrigin = ConnectorFormula(Or, originSequent.right.toSeq) + + phi match { + case PredicateFormula(label, args) if label == equality => + val left = args(0) + val right = args(1) + val fv_in_phi = (originSequent.left ++ originSequent.right).flatMap(_.freeVariables).map(_.id) + val v = VariableLabel(nFreshId(fv_in_phi, 1).head) + val isolatedLeft = originSequent.left.filterNot(f => isSame(f, phi)).map(f => (f, findSubterm(f, IndexedSeq(v -> left)))) + val isolatedRight = originSequent.right.map(f => (f, findSubterm(f, IndexedSeq(v -> left)))) + if (isolatedLeft.forall(_._2.isEmpty) && isolatedRight.forall(_._2.isEmpty)) + return ProofStepJudgement.InvalidProofStep(this.asProofStep(premises), s"There is no instance of ${Printer.prettyTerm(left)} to replace.") + + val leftForm = ConnectorFormula(And, isolatedLeft.map((f, ltf) => if (ltf.isEmpty) f else ltf.get.body).toSeq) + val rightForm = ConnectorFormula(Or, isolatedRight.map((f, ltf) => if (ltf.isEmpty) f else ltf.get.body).toSeq) + val newleft = isolatedLeft.map((f, ltf) => if (ltf.isEmpty) f else ltf.get(Seq(right))) + phi + val newright = isolatedRight.map((f, ltf) => if (ltf.isEmpty) f else ltf.get(Seq(right))) + val result1: Sequent = (ConnectorFormula(And, newleft.toSeq), phi) |- rightOrigin + val result2: Sequent = result1.left |- ConnectorFormula(And, newright.toSeq) + + val proof: SCProof = SCProof( + IndexedSeq( + Rewrite(leftOrigin |- rightOrigin, -1), + LeftSubstEq(result1, 0, List(left -> right), LambdaTermFormula(Seq(v), leftForm)), + RightSubstEq(result2, 1, List(left -> right), LambdaTermFormula(Seq(v), rightForm)), + Rewrite(newleft |- newright, 2) + ), + IndexedSeq(originSequent) + ) + val subproof: SCSubproof = SCSubproof( + proof, + Seq(premises.head) + ) + ProofStepJudgement.ValidProofStep(subproof) + case ConnectorFormula(label, args) if label == Iff => + val left = args(0) + val right = args(1) + val fv_in_phi = (originSequent.left ++ originSequent.right).flatMap(_.schematicFormulaLabels).map(_.id) + val H = VariableFormulaLabel(nFreshId(fv_in_phi, 1).head) + val isolatedLeft = originSequent.left.filterNot(f => isSame(f, phi)).map(f => (f, findSubformula(f, IndexedSeq(H -> left)))) + val isolatedRight = originSequent.right.map(f => (f, findSubformula(f, IndexedSeq(H -> left)))) + if (isolatedLeft.forall(_._2.isEmpty) && isolatedRight.forall(_._2.isEmpty)) + return ProofStepJudgement.InvalidProofStep(this.asProofStep(premises), s"There is no instance of ${Printer.prettyFormula(left)} to replace.") + + val leftForm = ConnectorFormula(And, isolatedLeft.map((f, ltf) => if (ltf.isEmpty) f else ltf.get.body).toSeq) + val rightForm = ConnectorFormula(Or, isolatedRight.map((f, ltf) => if (ltf.isEmpty) f else ltf.get.body).toSeq) + val newleft = isolatedLeft.map((f, ltf) => if (ltf.isEmpty) f else ltf.get(Seq(right))) + phi + val newright = isolatedRight.map((f, ltf) => if (ltf.isEmpty) f else ltf.get(Seq(right))) + val result1: Sequent = (ConnectorFormula(And, newleft.toSeq), phi) |- rightOrigin + val result2: Sequent = result1.left |- ConnectorFormula(Or, newright.toSeq) + + val proof: SCProof = SCProof( + IndexedSeq( + Rewrite(leftOrigin |- rightOrigin, -1), + LeftSubstIff(result1, 0, List(left -> right), LambdaFormulaFormula(Seq(H), leftForm)), + RightSubstIff(result2, 1, List(left -> right), LambdaFormulaFormula(Seq(H), rightForm)), + Rewrite(newleft |- newright, 2) + ), + IndexedSeq(originSequent) + ) + val subproof: SCSubproof = SCSubproof( + proof, + Seq(premises.head) + ) + ProofStepJudgement.ValidProofStep(subproof) + case _ => ProofStepJudgement.InvalidProofStep(this.asProofStep(premises), s"Formula in applySingleSimp need to be of the form a=b or q<=>p and not ${phi.label}") + } + + } + } + + def simplifySeq(seq: Sequent, ruleseq: IndexedSeq[PredicateFormula], rulesiff: IndexedSeq[ConnectorFormula]): SCProof = { + /* + val takenVarsIff = (seq.left.flatMap(_.schematicPredicateLabels) ++ seq.right.flatMap(_.schematicPredicateLabels) ++ ruleseq.flatMap(_.schematicPredicateLabels) ++ rulesiff.flatMap(_.schematicPredicateLabels)).map(_.id) + val varsIff = nFreshId(takenVarsIff, rulesiff.length).map(VariableFormulaLabel) + val subsIff = varsIff.zip(rulesiff.map(_.args(0))) + + val substs: Set[(Formula, LambdaFormulaFormula)] = seq.left.map(f => (f, findSubformula(f, subsIff)) ) + val newseq = substs.map(_._2(rulesiff.map(_.args(1)))) |- seq.right + val step1 = ??? // LeftSubstIff(newseq, prev.length-1, ) + */ + ??? + } + + def simplifySequent(seq: Sequent): SCProof = { + val (ruleseq, rulesiff, rem): (List[PredicateFormula], List[ConnectorFormula], List[Formula]) = + seq.left.foldLeft((List[PredicateFormula](), List[ConnectorFormula](), List[Formula]()))((prev, f) => { + f match { + case f @ PredicateFormula(label, _) if label == equality => (f :: prev._1, prev._2, prev._3) + case f @ ConnectorFormula(label, _) if label == iff => (prev._1, f :: prev._2, prev._3) + case _ => prev + } + }) + + ??? + } + +} -- GitLab