From 2d5ee19ed356d1f0902664a2a7eaf334555ca6e0 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:20 +0100 Subject: [PATCH 01/24] Add first draft for kernel2tactic transformation --- .gitignore | 5 +- build.sbt | 34 ++++--- ml-extract/src/main/scala/main.scala | 144 +++++++++++++++++++++++++++ 3 files changed, 168 insertions(+), 15 deletions(-) create mode 100644 ml-extract/src/main/scala/main.scala diff --git a/.gitignore b/.gitignore index b05d0969a..1727a24e8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .idea .metals .vscode -project/metals.sbt +*/metals.sbt # build-related .bsp @@ -22,3 +22,6 @@ cache # emacs backup files *~ + +# data extracted +data_extract diff --git a/build.sbt b/build.sbt index 8178b5599..09a613beb 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -ThisBuild / version := "0.6" +ThisBuild / version := "0.6" ThisBuild / homepage := Some(url("https://github.com/epfl-lara/lisa")) ThisBuild / startYear := Some(2021) ThisBuild / organization := "ch.epfl.lara" @@ -7,10 +7,10 @@ ThisBuild / organizationHomepage := Some(url("https://lara.epfl.ch")) ThisBuild / licenses := Seq("Apache-2.0" -> url("https://www.apache.org/licenses/LICENSE-2.0.html")) ThisBuild / versionScheme := Some("semver-spec") ThisBuild / scalacOptions ++= Seq( - "-feature", - "-deprecation", - "-unchecked", - ) + "-feature", + "-deprecation", + "-unchecked" +) ThisBuild / javacOptions ++= Seq("-encoding", "UTF-8") ThisBuild / semanticdbEnabled := true ThisBuild / semanticdbVersion := scalafixSemanticdb.revision @@ -24,7 +24,6 @@ val commonSettings = Seq( run / fork := true ) - val scala2 = "2.13.8" val scala3 = "3.3.1" @@ -35,14 +34,14 @@ val commonSettings2 = commonSettings ++ Seq( val commonSettings3 = commonSettings ++ Seq( scalaVersion := scala3, scalacOptions ++= Seq( - "-language:implicitConversions", + "-language:implicitConversions" // "-source:future", re-enable when liancheng/scalafix-organize-imports#221 is fixed ), libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.10" % "test", libraryDependencies += "com.lihaoyi" %% "sourcecode" % "0.3.0", - //libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1", + // libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1", libraryDependencies += ("io.github.uuverifiers" %% "princess" % "2023-06-19").cross(CrossVersion.for3Use2_13), Test / parallelExecution := false ) @@ -56,13 +55,13 @@ lazy val scallion = githubProject("https://github.com/sankalpgambhir/scallion.gi lazy val silex = githubProject("https://github.com/epfl-lara/silex.git", "fc07a8670a5fa8ea2dd5649a00424710274a5d18") -scallion/scalacOptions ~= (_.filterNot(Set("-Wvalue-discard"))) -silex/scalacOptions ~= (_.filterNot(Set("-Wvalue-discard"))) +scallion / scalacOptions ~= (_.filterNot(Set("-Wvalue-discard"))) +silex / scalacOptions ~= (_.filterNot(Set("-Wvalue-discard"))) lazy val root = Project( - id = "lisa", - base = file(".") - ) + id = "lisa", + base = file(".") +) .settings(commonSettings3) .dependsOn(kernel, withTests(utils), withTests(sets)) // Everything but `examples` .aggregate(utils) // To run tests on all modules @@ -87,7 +86,6 @@ lazy val utils = Project( id = "lisa-utils", base = file("lisa-utils") ) - .settings(commonSettings3) .dependsOn(kernel) .dependsOn(silex) @@ -112,3 +110,11 @@ lazy val examples = Project( .settings(commonSettings) .settings(commonSettings3) .dependsOn(root) + +lazy val mlextract = Project( + id = "ml-extract", + base = file("ml-extract") +) + .settings(commonSettings) + .settings(commonSettings3) + .dependsOn(root) diff --git a/ml-extract/src/main/scala/main.scala b/ml-extract/src/main/scala/main.scala new file mode 100644 index 000000000..720b3fcaa --- /dev/null +++ b/ml-extract/src/main/scala/main.scala @@ -0,0 +1,144 @@ +import lisa.utils.parsing.ProofPrinter._ +import lisa.utils.FOLPrinter.* + +import lisa.kernel.proof.SequentCalculus.* +import lisa.utils.K +import lisa.prooflib.ProofTacticLib.* + +// def sequent2code(sq: Sequent): String = prettySequent(sq).replace("⊢", "|-").replace("'", "") +def sequent2code(sq: Sequent): String = toFront(sq).toString + +def scproof2code(p: K.SCProof): String = { + p.steps.map(scproofstep2line).mkString("\n") +} +def scproofstep2line(ps: SCProofStep): String = { + ps match { + case Restate(bot, t1) => "have(" + sequent2code(bot) + ") by Restate" + case RestateTrue(bot) => "have(" + sequent2code(bot) + ") by Restate" + case Hypothesis(bot, phi) => "have(" + sequent2code(bot) + ") by Hypothesis" + case Cut(bot, t1, t2, phi) => "have(" + sequent2code(bot) + ") by Cut" + case LeftAnd(bot, t1, t2, phi) => "have(" + sequent2code(bot) + ") by LeftAnd" + case LeftOr(bot, t1, disjuncts) => "have(" + sequent2code(bot) + ") by LeftOr" + case LeftImplies(bot, t1, t2, phi, psi) => "have(" + sequent2code(bot) + ") by LeftImplies" + case LeftIff(bot, t1, phi, psi) => "have(" + sequent2code(bot) + ") by LeftIff" + case LeftNot(bot, t1, phi) => "have(" + sequent2code(bot) + ") by LeftNot" + case LeftForall(bot, t1, phi, x, t) => "have(" + sequent2code(bot) + ") by LeftForall" + case LeftExists(bot, t1, phi, x) => "have(" + sequent2code(bot) + ") by LeftExists" + case LeftExistsOne(bot, t1, phi, x) => "have(" + sequent2code(bot) + ") by LeftExistsOne" + case RightAnd(bot, t, conjuncts) => "have(" + sequent2code(bot) + ") by RightAnd" + case RightOr(bot, t1, phi, psi) => "have(" + sequent2code(bot) + ") by RightOr" + case RightImplies(bot, t1, phi, psi) => "have(" + sequent2code(bot) + ") by RightImplies" + case RightIff(bot, t1, t2, phi, psi) => "have(" + sequent2code(bot) + ") by RightIff" + case RightNot(bot, t1, phi) => "have(" + sequent2code(bot) + ") by RightNot" + case RightForall(bot, t1, phi, x) => "have(" + sequent2code(bot) + ") by RightForall" + case RightExists(bot, t1, phi, x, t) => "have(" + sequent2code(bot) + ") by RightExists" + case RightExistsOne(bot, t1, phi, x) => "have(" + sequent2code(bot) + ") by RightExistsOne" + case Weakening(bot, t1) => "have(" + sequent2code(bot) + ") by Weakening" + case LeftRefl(bot, t1, phi) => "have(" + sequent2code(bot) + ") by LeftRefl" + case RightRefl(bot, phi) => "have(" + sequent2code(bot) + ") by RightRefl" + case LeftSubstEq(bot, t1, equals, lambdaPhi) => "have(" + sequent2code(bot) + ") by LeftSubstEq" + case RightSubstEq(bot, t1, equals, lambdaPhi) => "have(" + sequent2code(bot) + ") by RightSubstEq" + case LeftSubstIff(bot, t1, equals, lambdaPhi) => "have(" + sequent2code(bot) + ") by LeftSubstIff" + case RightSubstIff(bot, t1, equals, lambdaPhi) => "have(" + sequent2code(bot) + ") by RightSubstIff" + case InstSchema(bot, t1, mCon, mPred, mTerm) => "have(" + sequent2code(bot) + ") by InstSchema" + case sp @ SCSubproof(_, _) => + if sp.sp.length == 1 then scproofstep2line(sp.sp.steps(0)) + else "have(" + sequent2code(sp.bot) + ") subproof {\n" + scproof2code(sp.sp) + "\n}" + case Sorry(bot) => "have(" + sequent2code(bot) + ") by Sorry" + } +} + +object MLExtract extends lisa.Main { + + /* + You may use the following tactics: + - Restate | "Trivially" true Sequent. Deals with alpha equivalence and most propositional rules but not distributivity + - Weakening | "Trivially" weaker sequent (than the previous one). + - Tautology.from | Anything that can be solved by propositional reasoning alone + + - LeftForall | To introduce a ∀ quantifier in an assumption + - LeftExists | To introduce a ∃ quantifier in an assumption (the variable must not be free somewhere else) + - RightForall | To introduce a ∀ quantifier in the conclusion (the variable must not be free somewhere else) + - RightExists | To introduce a ∃ quantifier in the conclusion + - InstantiateForall | To obtain a formula of the form P(t) from a quantified assumption ∀(x, P(x)) + + + + thm1 and thm2 illustrate how those tactics can be used, as well as the usage of "assume", "have", "thenHave", "by", "thesis", "of" and "subproof". + */ + + val x = variable + val y = variable + val z = variable + val f = function[1] + val P = formulaVariable + val Q = predicate[1] + val R = predicate[1] + val S = predicate[2] + + // A standard theorem about reordering quantifiers. Does the converse hold? + val thm1 = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + have(S(x, y) |- S(x, y)) by Restate + thenHave(∀(y, S(x, y)) |- S(x, y)) by LeftForall + thenHave(∀(y, S(x, y)) |- ∃(x, S(x, y))) by RightExists + thenHave(∃(x, ∀(y, S(x, y))) |- ∃(x, S(x, y))) by LeftExists + thenHave(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall + } + + println(prettyProof(thm1.proof)) + println(prettySCProof(thm1.proof.toSCProof)) + println(scproof2code(thm1.proof.toSCProof)) + + // // A standard theorem about reordering quantifiers. Does the converse hold? + // val thm11 = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + // have(S(x, y) |- S(x, y)) by Restate + // have(∀(y, S(x, y)) |- S(x, y)) by LeftForall + // have(∀(y, S(x, y)) |- ∃(x, S(x, y))) by RightExists + // have(∃(x, ∀(y, S(x, y))) |- ∃(x, S(x, y))) by LeftExists + // have(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall + // } + + // A standard and important property of ∀: It distributes over conjunction. This is useful to justify prenex normal form. + val thm2 = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { + + // Here we prove the two directions of <=> separately and then combine them. + val forward = have((∀(x, Q(x)), ∀(x, R(x))) |- ∀(x, Q(x) /\ R(x))) subproof { + have((Q(x), R(x)) |- Q(x) /\ R(x)) by Restate + thenHave((∀(x, Q(x)), R(x)) |- Q(x) /\ R(x)) by LeftForall + thenHave((∀(x, Q(x)), ∀(x, R(x))) |- Q(x) /\ R(x)) by LeftForall + thenHave(thesis) by RightForall + } + + // The second direction + val backward = have(∀(x, Q(x) /\ R(x)) |- ∀(x, Q(x)) /\ ∀(x, R(x))) subproof { + assume(∀(x, Q(x) /\ R(x))) + val assump = have(Q(x) /\ R(x)) by InstantiateForall + have(Q(x)) by Weakening(assump) + val conj1 = thenHave(∀(x, Q(x))) by RightForall + have(R(x)) by Weakening(assump) + val conj2 = thenHave(∀(x, R(x))) by RightForall + have(thesis) by Tautology.from(conj1, conj2) + } + + have(thesis) by Tautology.from(forward, backward) + } + + // println(prettyProof(thm2.proof)) + // println(prettySCProof(thm2.proof.toSCProof)) + // println(scproof2code(thm2.proof.toSCProof)) + + // This theorem requires instantiating the assumption twice, once with x and once with f(x), and then combine the two. + // Since x is free is the sequent step1, then step 1 is true with anything substituted for x. + // We can do such substitution with the "of" keyword. + // Specifically, `step1 of (x := f(x))` proves the formula P(f(x)) ==> P(f(f(x))) + val thm3 = Theorem(∀(x, Q(x) ==> Q(f(x))) |- Q(x) ==> Q(f(f(x)))) { + assume(∀(x, Q(x) ==> Q(f(x)))) + val step1 = have(Q(x) ==> Q(f(x))) by InstantiateForall + have(thesis) by Tautology.from(step1, step1 of (x := f(x))) + } + + // println(prettyProof(thm3.proof)) + // println(prettySCProof(thm3.proof.toSCProof)) + // println(scproof2code(thm3.proof.toSCProof)) + +} From 1ff80d925f68c1c2dc1fd13f3a70f7e2310f23c9 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:21 +0100 Subject: [PATCH 02/24] Add proofsteps reference --- ml-extract/src/main/scala/main.scala | 94 +++++++++++++++------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/ml-extract/src/main/scala/main.scala b/ml-extract/src/main/scala/main.scala index 720b3fcaa..d4c3c79d0 100644 --- a/ml-extract/src/main/scala/main.scala +++ b/ml-extract/src/main/scala/main.scala @@ -4,48 +4,53 @@ import lisa.utils.FOLPrinter.* import lisa.kernel.proof.SequentCalculus.* import lisa.utils.K import lisa.prooflib.ProofTacticLib.* +import lisa.fol.FOLHelpers.* -// def sequent2code(sq: Sequent): String = prettySequent(sq).replace("⊢", "|-").replace("'", "") -def sequent2code(sq: Sequent): String = toFront(sq).toString +def sequent2code(sq: Sequent): String = prettySequent(sq).replace("⊢", "|-").replace("'", "") +// def sequent2code(sq: Sequent): String = asFront(sq).toString def scproof2code(p: K.SCProof): String = { - p.steps.map(scproofstep2line).mkString("\n") + p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i)).mkString("\n") } -def scproofstep2line(ps: SCProofStep): String = { - ps match { - case Restate(bot, t1) => "have(" + sequent2code(bot) + ") by Restate" - case RestateTrue(bot) => "have(" + sequent2code(bot) + ") by Restate" - case Hypothesis(bot, phi) => "have(" + sequent2code(bot) + ") by Hypothesis" - case Cut(bot, t1, t2, phi) => "have(" + sequent2code(bot) + ") by Cut" - case LeftAnd(bot, t1, t2, phi) => "have(" + sequent2code(bot) + ") by LeftAnd" - case LeftOr(bot, t1, disjuncts) => "have(" + sequent2code(bot) + ") by LeftOr" - case LeftImplies(bot, t1, t2, phi, psi) => "have(" + sequent2code(bot) + ") by LeftImplies" - case LeftIff(bot, t1, phi, psi) => "have(" + sequent2code(bot) + ") by LeftIff" - case LeftNot(bot, t1, phi) => "have(" + sequent2code(bot) + ") by LeftNot" - case LeftForall(bot, t1, phi, x, t) => "have(" + sequent2code(bot) + ") by LeftForall" - case LeftExists(bot, t1, phi, x) => "have(" + sequent2code(bot) + ") by LeftExists" - case LeftExistsOne(bot, t1, phi, x) => "have(" + sequent2code(bot) + ") by LeftExistsOne" - case RightAnd(bot, t, conjuncts) => "have(" + sequent2code(bot) + ") by RightAnd" - case RightOr(bot, t1, phi, psi) => "have(" + sequent2code(bot) + ") by RightOr" - case RightImplies(bot, t1, phi, psi) => "have(" + sequent2code(bot) + ") by RightImplies" - case RightIff(bot, t1, t2, phi, psi) => "have(" + sequent2code(bot) + ") by RightIff" - case RightNot(bot, t1, phi) => "have(" + sequent2code(bot) + ") by RightNot" - case RightForall(bot, t1, phi, x) => "have(" + sequent2code(bot) + ") by RightForall" - case RightExists(bot, t1, phi, x, t) => "have(" + sequent2code(bot) + ") by RightExists" - case RightExistsOne(bot, t1, phi, x) => "have(" + sequent2code(bot) + ") by RightExistsOne" - case Weakening(bot, t1) => "have(" + sequent2code(bot) + ") by Weakening" - case LeftRefl(bot, t1, phi) => "have(" + sequent2code(bot) + ") by LeftRefl" - case RightRefl(bot, phi) => "have(" + sequent2code(bot) + ") by RightRefl" - case LeftSubstEq(bot, t1, equals, lambdaPhi) => "have(" + sequent2code(bot) + ") by LeftSubstEq" - case RightSubstEq(bot, t1, equals, lambdaPhi) => "have(" + sequent2code(bot) + ") by RightSubstEq" - case LeftSubstIff(bot, t1, equals, lambdaPhi) => "have(" + sequent2code(bot) + ") by LeftSubstIff" - case RightSubstIff(bot, t1, equals, lambdaPhi) => "have(" + sequent2code(bot) + ") by RightSubstIff" - case InstSchema(bot, t1, mCon, mPred, mTerm) => "have(" + sequent2code(bot) + ") by InstSchema" + +def scproofstep2line(ps: SCProofStep, stepNum: Int): String = { + def index2stepvar(i: Int): String = + if i < 0 then s"s${stepNum + i}" + else s"s$i" + + ps match + case Restate(bot, t1) => s"val s$stepNum = have(${sequent2code(bot)}) by Restate(${index2stepvar(t1)})" + case RestateTrue(bot) => s"val s$stepNum = have(${sequent2code(bot)}) by Restate" + case Hypothesis(bot, phi) => s"val s$stepNum = assume(${sequent2code(bot)}) by Hypothesis" + case Cut(bot, t1, t2, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by Cut(${index2stepvar(t1)}, ${index2stepvar(t2)})" + case LeftAnd(bot, t1, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftAnd(${index2stepvar(t1)})" + case LeftOr(bot, t, disjuncts) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftOr(${t.map(index2stepvar).mkString(", ")})" + case LeftImplies(bot, t1, t2, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftImplies(${index2stepvar(t1)}, ${index2stepvar(t2)})" + case LeftIff(bot, t1, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftIff(${index2stepvar(t1)})" + case LeftNot(bot, t1, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftNot(${index2stepvar(t1)})" + case LeftForall(bot, t1, phi, x, t) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftForall(${index2stepvar(t1)})" + case LeftExists(bot, t1, phi, x) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftExists(${index2stepvar(t1)})" + case LeftExistsOne(bot, t1, phi, x) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftExistsOne(${index2stepvar(t1)})" + case RightAnd(bot, t, conjuncts) => s"val s$stepNum = have(${sequent2code(bot)}) by RightAnd(${t.mkString(", ")})" + case RightOr(bot, t1, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightOr(${index2stepvar(t1)})" + case RightImplies(bot, t1, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightImplies(${index2stepvar(t1)})" + case RightIff(bot, t1, t2, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightIff(${index2stepvar(t1)}, ${index2stepvar(t2)})" + case RightNot(bot, t1, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightNot(${index2stepvar(t1)})" + case RightForall(bot, t1, phi, x) => s"val s$stepNum = have(${sequent2code(bot)}) by RightForall(${index2stepvar(t1)})" + case RightExists(bot, t1, phi, x, t) => s"val s$stepNum = have(${sequent2code(bot)}) by RightExists(${index2stepvar(t1)})" + case RightExistsOne(bot, t1, phi, x) => s"val s$stepNum = have(${sequent2code(bot)}) by RightExistsOne(${index2stepvar(t1)})" + case Weakening(bot, t1) => s"val s$stepNum = have(${sequent2code(bot)}) by Weakening(${index2stepvar(t1)})" + case LeftRefl(bot, t1, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftRefl(${index2stepvar(t1)})" + case RightRefl(bot, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightRefl" + case LeftSubstEq(bot, t1, equals, lambdaPhi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftSubstEq(${index2stepvar(t1)})" + case RightSubstEq(bot, t1, equals, lambdaPhi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightSubstEq(${index2stepvar(t1)})" + case LeftSubstIff(bot, t1, equals, lambdaPhi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftSubstIff(${index2stepvar(t1)})" + case RightSubstIff(bot, t1, equals, lambdaPhi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightSubstIff(${index2stepvar(t1)})" + case InstSchema(bot, t1, mCon, mPred, mTerm) => s"val s$stepNum = have(${sequent2code(bot)}) by InstSchema(${index2stepvar(t1)})" case sp @ SCSubproof(_, _) => - if sp.sp.length == 1 then scproofstep2line(sp.sp.steps(0)) - else "have(" + sequent2code(sp.bot) + ") subproof {\n" + scproof2code(sp.sp) + "\n}" - case Sorry(bot) => "have(" + sequent2code(bot) + ") by Sorry" - } + if sp.sp.length == 1 then scproofstep2line(sp.sp.steps(0), stepNum) + else s"have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp) + "\n}" + case Sorry(bot) => s"val s$stepNum = have(${sequent2code(bot)}) by Sorry" } object MLExtract extends lisa.Main { @@ -89,14 +94,13 @@ object MLExtract extends lisa.Main { println(prettySCProof(thm1.proof.toSCProof)) println(scproof2code(thm1.proof.toSCProof)) - // // A standard theorem about reordering quantifiers. Does the converse hold? - // val thm11 = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { - // have(S(x, y) |- S(x, y)) by Restate - // have(∀(y, S(x, y)) |- S(x, y)) by LeftForall - // have(∀(y, S(x, y)) |- ∃(x, S(x, y))) by RightExists - // have(∃(x, ∀(y, S(x, y))) |- ∃(x, S(x, y))) by LeftExists - // have(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall - // } + val thm11 = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + val s0 = have(S(x, y) |- S(x, y)) by Restate + val s1 = thenHave(∀(y, S(x, y)) |- S(x, y)) by LeftForall + val s2 = have(∀(y, S(x, y)) |- ∃(x, S(x, y))) by RightExists(s1) + val s3 = have(∃(x, ∀(y, S(x, y))) |- ∃(x, S(x, y))) by LeftExists(s2) + val s4 = have(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall(s3) + } // A standard and important property of ∀: It distributes over conjunction. This is useful to justify prenex normal form. val thm2 = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { From 94f9a6b190bd1bb521398bfda83477f174d5023a Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:21 +0100 Subject: [PATCH 03/24] Fix some kernel2code issues when refering to previous steps --- .../src/main/scala/lisa/fol/FOLHelpers.scala | 4 +- ml-extract/src/main/scala/main.scala | 272 ++++++++++++++---- 2 files changed, 222 insertions(+), 54 deletions(-) diff --git a/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala b/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala index 576a279c3..7a85439ef 100644 --- a/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala +++ b/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala @@ -118,7 +118,9 @@ object FOLHelpers { def asFront(pf: K.AtomicFormula): Formula = asFrontLabel(pf.label).applySeq(pf.args.map(asFront)) def asFront(cf: K.ConnectorFormula): Formula = - asFrontLabel(cf.label).applyUnsafe(cf.args.map(asFront)) + cf.label match + case K.And | K.Or if cf.args.size == 1 => asFront(cf.args(0)) + case _ => asFrontLabel(cf.label).applyUnsafe(cf.args.map(asFront)) def asFront(bf: K.BinderFormula): BinderFormula = asFrontLabel(bf.label).apply(asFrontLabel(bf.bound), asFront(bf.inner)) diff --git a/ml-extract/src/main/scala/main.scala b/ml-extract/src/main/scala/main.scala index d4c3c79d0..0afa54596 100644 --- a/ml-extract/src/main/scala/main.scala +++ b/ml-extract/src/main/scala/main.scala @@ -1,56 +1,58 @@ import lisa.utils.parsing.ProofPrinter._ import lisa.utils.FOLPrinter.* - import lisa.kernel.proof.SequentCalculus.* import lisa.utils.K import lisa.prooflib.ProofTacticLib.* import lisa.fol.FOLHelpers.* -def sequent2code(sq: Sequent): String = prettySequent(sq).replace("⊢", "|-").replace("'", "") -// def sequent2code(sq: Sequent): String = asFront(sq).toString - -def scproof2code(p: K.SCProof): String = { - p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i)).mkString("\n") +def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = 0, varPrefix: String = "s"): String = { + p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i, premises, indent, varPrefix)).mkString("\n") } -def scproofstep2line(ps: SCProofStep, stepNum: Int): String = { +def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], indent: Int, varPrefix: String): String = { + def sequent2code(sq: Sequent): String = asFront(sq).toString.replace("⇒", "==>").replace("⇔", "<=>") + def index2stepvar(i: Int): String = - if i < 0 then s"s${stepNum + i}" - else s"s$i" - - ps match - case Restate(bot, t1) => s"val s$stepNum = have(${sequent2code(bot)}) by Restate(${index2stepvar(t1)})" - case RestateTrue(bot) => s"val s$stepNum = have(${sequent2code(bot)}) by Restate" - case Hypothesis(bot, phi) => s"val s$stepNum = assume(${sequent2code(bot)}) by Hypothesis" - case Cut(bot, t1, t2, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by Cut(${index2stepvar(t1)}, ${index2stepvar(t2)})" - case LeftAnd(bot, t1, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftAnd(${index2stepvar(t1)})" - case LeftOr(bot, t, disjuncts) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftOr(${t.map(index2stepvar).mkString(", ")})" - case LeftImplies(bot, t1, t2, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftImplies(${index2stepvar(t1)}, ${index2stepvar(t2)})" - case LeftIff(bot, t1, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftIff(${index2stepvar(t1)})" - case LeftNot(bot, t1, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftNot(${index2stepvar(t1)})" - case LeftForall(bot, t1, phi, x, t) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftForall(${index2stepvar(t1)})" - case LeftExists(bot, t1, phi, x) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftExists(${index2stepvar(t1)})" - case LeftExistsOne(bot, t1, phi, x) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftExistsOne(${index2stepvar(t1)})" - case RightAnd(bot, t, conjuncts) => s"val s$stepNum = have(${sequent2code(bot)}) by RightAnd(${t.mkString(", ")})" - case RightOr(bot, t1, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightOr(${index2stepvar(t1)})" - case RightImplies(bot, t1, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightImplies(${index2stepvar(t1)})" - case RightIff(bot, t1, t2, phi, psi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightIff(${index2stepvar(t1)}, ${index2stepvar(t2)})" - case RightNot(bot, t1, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightNot(${index2stepvar(t1)})" - case RightForall(bot, t1, phi, x) => s"val s$stepNum = have(${sequent2code(bot)}) by RightForall(${index2stepvar(t1)})" - case RightExists(bot, t1, phi, x, t) => s"val s$stepNum = have(${sequent2code(bot)}) by RightExists(${index2stepvar(t1)})" - case RightExistsOne(bot, t1, phi, x) => s"val s$stepNum = have(${sequent2code(bot)}) by RightExistsOne(${index2stepvar(t1)})" - case Weakening(bot, t1) => s"val s$stepNum = have(${sequent2code(bot)}) by Weakening(${index2stepvar(t1)})" - case LeftRefl(bot, t1, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftRefl(${index2stepvar(t1)})" - case RightRefl(bot, phi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightRefl" - case LeftSubstEq(bot, t1, equals, lambdaPhi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftSubstEq(${index2stepvar(t1)})" - case RightSubstEq(bot, t1, equals, lambdaPhi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightSubstEq(${index2stepvar(t1)})" - case LeftSubstIff(bot, t1, equals, lambdaPhi) => s"val s$stepNum = have(${sequent2code(bot)}) by LeftSubstIff(${index2stepvar(t1)})" - case RightSubstIff(bot, t1, equals, lambdaPhi) => s"val s$stepNum = have(${sequent2code(bot)}) by RightSubstIff(${index2stepvar(t1)})" - case InstSchema(bot, t1, mCon, mPred, mTerm) => s"val s$stepNum = have(${sequent2code(bot)}) by InstSchema(${index2stepvar(t1)})" + if i < -premises.size then throw new Exception(s"step $i is not defined") + else if i < 0 then premises(-i - 1) + else s"$varPrefix$i" + + val varDecl = s"val $varPrefix$stepNum" + " " * indent + (ps match + case Restate(bot, t1) => s"$varDecl = have(${sequent2code(bot)}) by Restate.from(${index2stepvar(t1)})" + case RestateTrue(bot) => s"$varDecl = have(${sequent2code(bot)}) by Restate" + case Hypothesis(bot, phi) => s"$varDecl = have(${sequent2code(bot)}) by Hypothesis" + case Cut(bot, t1, t2, phi) => s"$varDecl = have(${sequent2code(bot)}) by Cut(${index2stepvar(t1)}, ${index2stepvar(t2)})" + case LeftAnd(bot, t1, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by LeftAnd(${index2stepvar(t1)})" + case LeftOr(bot, t, disjuncts) => s"$varDecl = have(${sequent2code(bot)}) by LeftOr(${t.map(index2stepvar).mkString(", ")})" + case LeftImplies(bot, t1, t2, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by LeftImplies(${index2stepvar(t1)}, ${index2stepvar(t2)})" + case LeftIff(bot, t1, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by LeftIff(${index2stepvar(t1)})" + case LeftNot(bot, t1, phi) => s"$varDecl = have(${sequent2code(bot)}) by LeftNot(${index2stepvar(t1)})" + case LeftForall(bot, t1, phi, x, t) => s"$varDecl = have(${sequent2code(bot)}) by LeftForall(${index2stepvar(t1)})" + case LeftExists(bot, t1, phi, x) => s"$varDecl = have(${sequent2code(bot)}) by LeftExists(${index2stepvar(t1)})" + case LeftExistsOne(bot, t1, phi, x) => s"$varDecl = have(${sequent2code(bot)}) by LeftExistsOne(${index2stepvar(t1)})" + case RightAnd(bot, t, conjuncts) => s"$varDecl = have(${sequent2code(bot)}) by RightAnd(${t.mkString(", ")})" + case RightOr(bot, t1, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by RightOr(${index2stepvar(t1)})" + case RightImplies(bot, t1, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by RightImplies(${index2stepvar(t1)})" + case RightIff(bot, t1, t2, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by RightIff(${index2stepvar(t1)}, ${index2stepvar(t2)})" + case RightNot(bot, t1, phi) => s"$varDecl = have(${sequent2code(bot)}) by RightNot(${index2stepvar(t1)})" + case RightForall(bot, t1, phi, x) => s"$varDecl = have(${sequent2code(bot)}) by RightForall(${index2stepvar(t1)})" + case RightExists(bot, t1, phi, x, t) => s"$varDecl = have(${sequent2code(bot)}) by RightExists(${index2stepvar(t1)})" + case RightExistsOne(bot, t1, phi, x) => s"$varDecl = have(${sequent2code(bot)}) by RightExistsOne(${index2stepvar(t1)})" + case Weakening(bot, t1) => s"$varDecl = have(${sequent2code(bot)}) by Weakening(${index2stepvar(t1)})" + case LeftRefl(bot, t1, phi) => s"$varDecl = have(${sequent2code(bot)}) by LeftRefl(${index2stepvar(t1)})" + case RightRefl(bot, phi) => s"$varDecl = have(${sequent2code(bot)}) by RightRefl" + case LeftSubstEq(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by LeftSubstEq(${index2stepvar(t1)})" + case RightSubstEq(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by RightSubstEq(${index2stepvar(t1)})" + case LeftSubstIff(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by LeftSubstIff(${index2stepvar(t1)})" + case RightSubstIff(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by RightSubstIff(${index2stepvar(t1)})" + case InstSchema(bot, t1, mCon, mPred, mTerm) => s"$varDecl = have(${sequent2code(bot)}) by InstSchema(${index2stepvar(t1)})" case sp @ SCSubproof(_, _) => - if sp.sp.length == 1 then scproofstep2line(sp.sp.steps(0), stepNum) - else s"have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp) + "\n}" - case Sorry(bot) => s"val s$stepNum = have(${sequent2code(bot)}) by Sorry" + s"$varDecl = have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"$varPrefix$stepNum") + "\n" + " " * indent + "}" + // if sp.sp.length == 1 then scproofstep2line(sp.sp.steps(0), stepNum, sp.premises.map(index2stepvar), indent, varPrefix) + // else s"$varDecl = have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"$varPrefix$stepNum") + "\n" + " " * indent + "}" + case Sorry(bot) => s"$varDecl = have(${sequent2code(bot)}) by Sorry" + ) } object MLExtract extends lisa.Main { @@ -73,6 +75,7 @@ object MLExtract extends lisa.Main { */ val x = variable + val x_1 = variable val y = variable val z = variable val f = function[1] @@ -90,16 +93,26 @@ object MLExtract extends lisa.Main { thenHave(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall } - println(prettyProof(thm1.proof)) - println(prettySCProof(thm1.proof.toSCProof)) - println(scproof2code(thm1.proof.toSCProof)) + // println(prettyProof(thm1.proof)) + // println(prettySCProof(thm1.proof.toSCProof)) + // println(scproof2code(thm1.proof.toSCProof)) val thm11 = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { - val s0 = have(S(x, y) |- S(x, y)) by Restate - val s1 = thenHave(∀(y, S(x, y)) |- S(x, y)) by LeftForall - val s2 = have(∀(y, S(x, y)) |- ∃(x, S(x, y))) by RightExists(s1) - val s3 = have(∃(x, ∀(y, S(x, y))) |- ∃(x, S(x, y))) by LeftExists(s2) - val s4 = have(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall(s3) + val s0 = have(S(x, y) ⊢ S(x, y)) subproof { + val s00 = have(S(x, y) ⊢ S(x, y)) by Restate + } + val s1 = have(∀(y, S(x, y)) ⊢ S(x, y)) subproof { + val s10 = have(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall(s0) + } + val s2 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) subproof { + val s20 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists(s1) + } + val s3 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) subproof { + val s30 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists(s2) + } + val s4 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { + val s40 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall(s3) + } } // A standard and important property of ∀: It distributes over conjunction. This is useful to justify prenex normal form. @@ -131,6 +144,71 @@ object MLExtract extends lisa.Main { // println(prettySCProof(thm2.proof.toSCProof)) // println(scproof2code(thm2.proof.toSCProof)) + val thm21 = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { + val s0 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s00 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) subproof { + val s000 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) by Restate + } + val s01 = have((R(x), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s010 = have((R(x), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s00) + } + val s02 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s020 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s01) + } + val s03 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s030 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall(s02) + } + val s04 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Restate.from(s03) + } + val s1 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { + val s10 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s100 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Hypothesis + } + val s11 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s110 = have((∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s1100 = have((∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by Restate + } + val s111 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s1110 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s110) + } + } + val s12 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) subproof { + val s120 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) by Weakening(s11) + } + val s13 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) subproof { + val s130 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall(s12) + } + val s14 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) subproof { + val s140 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) by Weakening(s11) + } + val s15 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) subproof { + val s150 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall(s14) + } + val s16 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { + val s160 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s13) + val s161 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s15) + val s162 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { + val s1620 = have(() ⊢ ⊤) by Restate + val s1621 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate.from(s1620) + } + val s163 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s160, s162) + val s164 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s161, s163) + } + val s17 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate.from(s16) + } + val s2 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { + val s20 = have(() ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s0) + val s21 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s1) + val s22 = have((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { + val s220 = have(() ⊢ ⊤) by Restate + val s221 = + have((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s220) + } + val s23 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s20, s22) + val s24 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s21, s23) + } + } + // This theorem requires instantiating the assumption twice, once with x and once with f(x), and then combine the two. // Since x is free is the sequent step1, then step 1 is true with anything substituted for x. // We can do such substitution with the "of" keyword. @@ -141,8 +219,96 @@ object MLExtract extends lisa.Main { have(thesis) by Tautology.from(step1, step1 of (x := f(x))) } - // println(prettyProof(thm3.proof)) - // println(prettySCProof(thm3.proof.toSCProof)) - // println(scproof2code(thm3.proof.toSCProof)) + println(prettyProof(thm3.proof)) + println(prettySCProof(thm3.proof.toSCProof)) + println(scproof2code(thm3.proof.toSCProof)) + val thm31 = Theorem(∀(x, Q(x) ==> Q(f(x))) |- Q(x) ==> Q(f(f(x)))) { + val s0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) subproof { + val s00 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) by Hypothesis + } + val s1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s10 = have((∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s100 = have((∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by Restate + } + val s11 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s110 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s10) + } + } + val s2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) subproof { + val s20 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstSchema(s1) + } + val s3 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { + val s30 = have(() ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s1) + val s31 = have(() ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s2) + val s32 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { + val s320 = + have(Q(f(x)) ⊢ ¬(∧(¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), ⊤, ¬(Q(f(f(x)))))), ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(⊤))), ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(f(x))))))) by Restate + val s321 = have( + Q(f(x)) ⊢ ¬( + ∧( + ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), + ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), + ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), + Q(x), + ¬(Q(f(f(x)))) + ) + ) + ) by RightSubstIff(s320) + val s322 = have( + ¬(Q(f(x))) ⊢ ¬(∧(¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), ⊥, ¬(Q(f(f(x)))))), ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(⊥))), ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(f(x)))))) + ) by Restate + val s323 = have( + ¬(Q(f(x))) ⊢ ¬( + ∧( + ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), + ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), + ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), + Q(x), + ¬(Q(f(f(x)))) + ) + ) + ) by RightSubstIff(s322) + val s324 = have( + () ⊢ (Q(f(x)), ¬( + ∧( + ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), + ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), + ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), + Q(x), + ¬(Q(f(f(x)))) + ) + )) + ) by Restate.from(s323) + val s325 = have( + () ⊢ ¬( + ∧( + ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), + ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), + ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), + Q(x), + ¬(Q(f(f(x)))) + ) + ) + ) by Cut(s324, s321) + val s326 = have( + () ⊢ ¬( + ∧( + ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), + ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), + ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), + Q(x), + ¬(Q(f(f(x)))) + ) + ) + ) by Restate.from(s325) + val s327 = + have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from( + s326 + ) + } + val s33 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s30, s32) + val s34 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s31, s33) + } + } } From daa2673b15f91955c201a4cfbff5500e42fb4ec3 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:22 +0100 Subject: [PATCH 04/24] First stable conversion from kernel to code proofs --- .../src/main/scala/lisa/fol/FOLHelpers.scala | 1 + ml-extract/src/main/scala/main.scala | 274 +++++++++++------- 2 files changed, 165 insertions(+), 110 deletions(-) diff --git a/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala b/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala index 7a85439ef..fc03e415e 100644 --- a/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala +++ b/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala @@ -120,6 +120,7 @@ object FOLHelpers { def asFront(cf: K.ConnectorFormula): Formula = cf.label match case K.And | K.Or if cf.args.size == 1 => asFront(cf.args(0)) + case K.And | K.Or => cf.args.map(asFront).reduceLeft((a, b) => asFrontLabel(cf.label)(Seq(a, b))) // TODO: handle this more gracefully case _ => asFrontLabel(cf.label).applyUnsafe(cf.args.map(asFront)) def asFront(bf: K.BinderFormula): BinderFormula = asFrontLabel(bf.label).apply(asFrontLabel(bf.bound), asFront(bf.inner)) diff --git a/ml-extract/src/main/scala/main.scala b/ml-extract/src/main/scala/main.scala index 0afa54596..0c7ef8af7 100644 --- a/ml-extract/src/main/scala/main.scala +++ b/ml-extract/src/main/scala/main.scala @@ -4,6 +4,14 @@ import lisa.kernel.proof.SequentCalculus.* import lisa.utils.K import lisa.prooflib.ProofTacticLib.* import lisa.fol.FOLHelpers.* +import lisa.fol.FOL as F +import lisa.utils.KernelHelpers.lambda +import lisa.utils.ProofsShrink.* +import lisa.automation.Tableau + +// TODO: fix printing of ∧ and ∨ with several arguments +// TODO: fix InstSchema conversion +// TODO: handle LeftSubstIff and RightSubstIff def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = 0, varPrefix: String = "s"): String = { p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i, premises, indent, varPrefix)).mkString("\n") @@ -11,6 +19,7 @@ def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], indent: Int, varPrefix: String): String = { def sequent2code(sq: Sequent): String = asFront(sq).toString.replace("⇒", "==>").replace("⇔", "<=>") + def formula2code(sq: K.Formula): String = asFront(sq).toString.replace("⇒", "==>").replace("⇔", "<=>") def index2stepvar(i: Int): String = if i < -premises.size then throw new Exception(s"step $i is not defined") @@ -44,14 +53,27 @@ def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], inden case RightRefl(bot, phi) => s"$varDecl = have(${sequent2code(bot)}) by RightRefl" case LeftSubstEq(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by LeftSubstEq(${index2stepvar(t1)})" case RightSubstEq(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by RightSubstEq(${index2stepvar(t1)})" - case LeftSubstIff(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by LeftSubstIff(${index2stepvar(t1)})" - case RightSubstIff(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by RightSubstIff(${index2stepvar(t1)})" - case InstSchema(bot, t1, mCon, mPred, mTerm) => s"$varDecl = have(${sequent2code(bot)}) by InstSchema(${index2stepvar(t1)})" + case LeftSubstIff(bot, t1, equals, lambdaPhi) => + s"$varDecl = have(${sequent2code(bot)}) by LeftSubstIff(List(${equals + .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))(${index2stepvar(t1)})" + case RightSubstIff(bot, t1, equals, lambdaPhi) => + s"$varDecl = have(${sequent2code(bot)}) by RightSubstIff(List(${equals + .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))(${index2stepvar(t1)})" + case InstSchema(bot, t1, mCon, mPred, mTerm) => + if mCon.isEmpty && mPred.isEmpty then + s"$varDecl = have(${sequent2code(bot)}) by InstFunSchema(Map(${mTerm.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${asFront(v.body)}") + .mkString(", ")}))(${index2stepvar(t1)})" + else if mCon.isEmpty && mTerm.isEmpty then + s"$varDecl = have(${sequent2code(bot)}) by InstPredSchema(Map(${mPred.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${asFront(v.body)}") + .mkString(", ")}))(${index2stepvar(t1)})" + else throw new Exception("InstSchema not implemented") case sp @ SCSubproof(_, _) => s"$varDecl = have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"$varPrefix$stepNum") + "\n" + " " * indent + "}" - // if sp.sp.length == 1 then scproofstep2line(sp.sp.steps(0), stepNum, sp.premises.map(index2stepvar), indent, varPrefix) - // else s"$varDecl = have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"$varPrefix$stepNum") + "\n" + " " * indent + "}" - case Sorry(bot) => s"$varDecl = have(${sequent2code(bot)}) by Sorry" + case Sorry(bot) => "sorry" ) } @@ -75,7 +97,6 @@ object MLExtract extends lisa.Main { */ val x = variable - val x_1 = variable val y = variable val z = variable val f = function[1] @@ -84,6 +105,11 @@ object MLExtract extends lisa.Main { val R = predicate[1] val S = predicate[2] + val x_1 = variable + val x_2 = variable + val y_1 = variable + val MaRvIn_1 = formulaVariable + // A standard theorem about reordering quantifiers. Does the converse hold? val thm1 = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { have(S(x, y) |- S(x, y)) by Restate @@ -96,8 +122,9 @@ object MLExtract extends lisa.Main { // println(prettyProof(thm1.proof)) // println(prettySCProof(thm1.proof.toSCProof)) // println(scproof2code(thm1.proof.toSCProof)) + // println(scproof2code(optimizeProofIteratively(thm1.proof.toSCProof))) - val thm11 = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + val thm1_raw = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { val s0 = have(S(x, y) ⊢ S(x, y)) subproof { val s00 = have(S(x, y) ⊢ S(x, y)) by Restate } @@ -115,6 +142,14 @@ object MLExtract extends lisa.Main { } } + val thm1_optimized = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + val s0 = have(S(x, y) ⊢ S(x, y)) by Restate + val s1 = have(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall(s0) + val s2 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists(s1) + val s3 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists(s2) + val s4 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall(s3) + } + // A standard and important property of ∀: It distributes over conjunction. This is useful to justify prenex normal form. val thm2 = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { @@ -143,30 +178,31 @@ object MLExtract extends lisa.Main { // println(prettyProof(thm2.proof)) // println(prettySCProof(thm2.proof.toSCProof)) // println(scproof2code(thm2.proof.toSCProof)) + // println(scproof2code(optimizeProofIteratively(thm2.proof.toSCProof))) - val thm21 = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { - val s0 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { - val s00 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) subproof { - val s000 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) by Restate + val thm2_raw = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { + val s0 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s00 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) subproof { + val s000 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) by Restate } - val s01 = have((R(x), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) subproof { - val s010 = have((R(x), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s00) + val s01 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { + val s010 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall(s00) } - val s02 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) subproof { - val s020 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s01) + val s02 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { + val s020 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall(s01) } - val s03 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { - val s030 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall(s02) + val s03 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s030 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall(s02) } - val s04 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Restate.from(s03) + val s04 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Restate.from(s03) } val s1 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { val s10 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { val s100 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Hypothesis } val s11 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { - val s110 = have((∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { - val s1100 = have((∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by Restate + val s110 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { + val s1100 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) by Restate } val s111 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { val s1110 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s110) @@ -185,30 +221,54 @@ object MLExtract extends lisa.Main { val s150 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall(s14) } val s16 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { - val s160 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s13) - val s161 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s15) - val s162 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { - val s1620 = have(() ⊢ ⊤) by Restate - val s1621 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate.from(s1620) + val s160 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s13) + val s161 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s15) + val s162 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { + val s1620 = have(( ) ⊢ ⊤) by Restate + val s1621 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate.from(s1620) } - val s163 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s160, s162) + val s163 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s160, s162) val s164 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s161, s163) } val s17 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate.from(s16) } - val s2 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { - val s20 = have(() ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s0) - val s21 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s1) - val s22 = have((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { - val s220 = have(() ⊢ ⊤) by Restate - val s221 = - have((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s220) + val s2 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { + val s20 = have(( ) ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s0) + val s21 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s1) + val s22 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { + val s220 = have(( ) ⊢ ⊤) by Restate + val s221 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s220) } val s23 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s20, s22) - val s24 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s21, s23) + val s24 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s21, s23) } } + val thm2_optimized = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { + val s0 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) by Restate + val s1 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall(s0) + val s2 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall(s1) + val s3 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall(s2) + val s4 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) by Restate + val s5 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s4) + val s6 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) by Weakening(s5) + val s7 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall(s6) + val s8 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) by Weakening(s5) + val s9 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall(s8) + val s10 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s7) + val s11 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s9) + val s12 = have(( ) ⊢ ⊤) by Restate + val s13 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate.from(s12) + val s14 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s10, s13) + val s15 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s11, s14) + val s16 = have(( ) ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s3) + val s17 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s15) + val s18 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s12) + val s19 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s16, s18) + val s20 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s17, s19) + } + + // This theorem requires instantiating the assumption twice, once with x and once with f(x), and then combine the two. // Since x is free is the sequent step1, then step 1 is true with anything substituted for x. // We can do such substitution with the "of" keyword. @@ -219,96 +279,90 @@ object MLExtract extends lisa.Main { have(thesis) by Tautology.from(step1, step1 of (x := f(x))) } - println(prettyProof(thm3.proof)) - println(prettySCProof(thm3.proof.toSCProof)) - println(scproof2code(thm3.proof.toSCProof)) + // println(prettyProof(thm3.proof)) + // println(prettySCProof(thm3.proof.toSCProof)) + // println(scproof2code(thm3.proof.toSCProof)) + // println(scproof2code(optimizeProofIteratively(thm3.proof.toSCProof))) - val thm31 = Theorem(∀(x, Q(x) ==> Q(f(x))) |- Q(x) ==> Q(f(f(x)))) { + val thm3_raw = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { val s0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) subproof { val s00 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) by Hypothesis } val s1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s10 = have((∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s100 = have((∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by Restate + val s10 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s100 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate } val s11 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { val s110 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s10) } } val s2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) subproof { - val s20 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstSchema(s1) + val s20 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s1) } val s3 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { - val s30 = have(() ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s1) - val s31 = have(() ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s2) - val s32 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { - val s320 = - have(Q(f(x)) ⊢ ¬(∧(¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), ⊤, ¬(Q(f(f(x)))))), ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(⊤))), ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(f(x))))))) by Restate - val s321 = have( - Q(f(x)) ⊢ ¬( - ∧( - ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), - ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), - ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), - Q(x), - ¬(Q(f(f(x)))) - ) - ) - ) by RightSubstIff(s320) - val s322 = have( - ¬(Q(f(x))) ⊢ ¬(∧(¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), ⊥, ¬(Q(f(f(x)))))), ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(⊥))), ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(f(x)))))) - ) by Restate - val s323 = have( - ¬(Q(f(x))) ⊢ ¬( - ∧( - ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), - ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), - ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), - Q(x), - ¬(Q(f(f(x)))) - ) - ) - ) by RightSubstIff(s322) - val s324 = have( - () ⊢ (Q(f(x)), ¬( - ∧( - ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), - ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), - ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), - Q(x), - ¬(Q(f(f(x)))) - ) - )) - ) by Restate.from(s323) - val s325 = have( - () ⊢ ¬( - ∧( - ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), - ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), - ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), - Q(x), - ¬(Q(f(f(x)))) - ) - ) - ) by Cut(s324, s321) - val s326 = have( - () ⊢ ¬( - ∧( - ¬(∧(∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))), Q(f(x)), ¬(Q(f(f(x)))))), - ¬(∧(∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), Q(x), ¬(Q(f(x))))), - ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))), - Q(x), - ¬(Q(f(f(x)))) - ) - ) - ) by Restate.from(s325) - val s327 = - have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from( - s326 - ) + val s30 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s1) + val s31 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s2) + val s32 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { + val s320 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s321 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊤))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))))(s320) + val s322 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s323 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊥))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))))(s322) + val s324 = have(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate.from(s323) + val s325 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut(s324, s321) + val s326 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate.from(s325) + val s327 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from(s326) } - val s33 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s30, s32) + val s33 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s30, s32) val s34 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s31, s33) } } + + val thm3_optimized = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { + val s0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate + val s1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s0) + val s2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s1) + val s3 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s1) + val s4 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s2) + val s5 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s6 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate.from(s5) + val s7 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s8 = have(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate.from(s7) + val s9 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut(s8, s6) + val s10 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from(s9) + val s11 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s3, s10) + val s12 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s4, s11) + } + + + val thm1bis = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + have(thesis) by Tableau + } + + // println(prettyProof(thm1bis.proof)) + // println(prettySCProof(thm1bis.proof.toSCProof)) + // println(scproof2code(thm1bis.proof.toSCProof)) + // println(scproof2code(optimizeProofIteratively(thm1bis.proof.toSCProof))) + + val thm1bis_raw = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + val s0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { + val s00 = have(( S(x, y_1), ¬(S(x, y_1)) ) ⊢ ( )) by Restate + val s01 = have(( ¬(S(x, y_1)), ∀(y, S(x, y)) ) ⊢ ( )) by LeftForall(s00) + val s02 = have(( ∀(y, S(x, y)), ∀(x_2, ¬(S(x_2, y_1))) ) ⊢ ( )) by LeftForall(s01) + val s03 = have(( ∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y))) ) ⊢ ( )) by LeftExists(s02) + val s04 = have(( ∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1)))) ) ⊢ ( )) by LeftExists(s03) + val s05 = have((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ( )) by Weakening(s04) + val s06 = have((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ( )) by Weakening(s05) + val s07 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by Restate.from(s06) + } + } + + val thm1bis_optimized = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + val s0 = have(( S(x, y_1), ¬(S(x, y_1)) ) ⊢ ( )) by Restate + val s1 = have(( ¬(S(x, y_1)), ∀(y, S(x, y)) ) ⊢ ( )) by LeftForall(s0) + val s2 = have(( ∀(y, S(x, y)), ∀(x_2, ¬(S(x_2, y_1))) ) ⊢ ( )) by LeftForall(s1) + val s3 = have(( ∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y))) ) ⊢ ( )) by LeftExists(s2) + val s4 = have(( ∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1)))) ) ⊢ ( )) by LeftExists(s3) + val s5 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by Restate.from(s4) + } + } From 49acfbfe217bb2c8ac41e35d077542e3f9e11b03 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:22 +0100 Subject: [PATCH 05/24] Refactor code + thenHave --- ml-extract/src/main/scala/main.scala | 213 ++++++++++++++------------- 1 file changed, 110 insertions(+), 103 deletions(-) diff --git a/ml-extract/src/main/scala/main.scala b/ml-extract/src/main/scala/main.scala index 0c7ef8af7..d530ce78b 100644 --- a/ml-extract/src/main/scala/main.scala +++ b/ml-extract/src/main/scala/main.scala @@ -10,8 +10,7 @@ import lisa.utils.ProofsShrink.* import lisa.automation.Tableau // TODO: fix printing of ∧ and ∨ with several arguments -// TODO: fix InstSchema conversion -// TODO: handle LeftSubstIff and RightSubstIff +// TODO: make sure that all proofsteps arguments are used when needed def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = 0, varPrefix: String = "s"): String = { p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i, premises, indent, varPrefix)).mkString("\n") @@ -24,57 +23,65 @@ def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], inden def index2stepvar(i: Int): String = if i < -premises.size then throw new Exception(s"step $i is not defined") else if i < 0 then premises(-i - 1) - else s"$varPrefix$i" - - val varDecl = s"val $varPrefix$stepNum" - " " * indent + (ps match - case Restate(bot, t1) => s"$varDecl = have(${sequent2code(bot)}) by Restate.from(${index2stepvar(t1)})" - case RestateTrue(bot) => s"$varDecl = have(${sequent2code(bot)}) by Restate" - case Hypothesis(bot, phi) => s"$varDecl = have(${sequent2code(bot)}) by Hypothesis" - case Cut(bot, t1, t2, phi) => s"$varDecl = have(${sequent2code(bot)}) by Cut(${index2stepvar(t1)}, ${index2stepvar(t2)})" - case LeftAnd(bot, t1, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by LeftAnd(${index2stepvar(t1)})" - case LeftOr(bot, t, disjuncts) => s"$varDecl = have(${sequent2code(bot)}) by LeftOr(${t.map(index2stepvar).mkString(", ")})" - case LeftImplies(bot, t1, t2, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by LeftImplies(${index2stepvar(t1)}, ${index2stepvar(t2)})" - case LeftIff(bot, t1, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by LeftIff(${index2stepvar(t1)})" - case LeftNot(bot, t1, phi) => s"$varDecl = have(${sequent2code(bot)}) by LeftNot(${index2stepvar(t1)})" - case LeftForall(bot, t1, phi, x, t) => s"$varDecl = have(${sequent2code(bot)}) by LeftForall(${index2stepvar(t1)})" - case LeftExists(bot, t1, phi, x) => s"$varDecl = have(${sequent2code(bot)}) by LeftExists(${index2stepvar(t1)})" - case LeftExistsOne(bot, t1, phi, x) => s"$varDecl = have(${sequent2code(bot)}) by LeftExistsOne(${index2stepvar(t1)})" - case RightAnd(bot, t, conjuncts) => s"$varDecl = have(${sequent2code(bot)}) by RightAnd(${t.mkString(", ")})" - case RightOr(bot, t1, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by RightOr(${index2stepvar(t1)})" - case RightImplies(bot, t1, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by RightImplies(${index2stepvar(t1)})" - case RightIff(bot, t1, t2, phi, psi) => s"$varDecl = have(${sequent2code(bot)}) by RightIff(${index2stepvar(t1)}, ${index2stepvar(t2)})" - case RightNot(bot, t1, phi) => s"$varDecl = have(${sequent2code(bot)}) by RightNot(${index2stepvar(t1)})" - case RightForall(bot, t1, phi, x) => s"$varDecl = have(${sequent2code(bot)}) by RightForall(${index2stepvar(t1)})" - case RightExists(bot, t1, phi, x, t) => s"$varDecl = have(${sequent2code(bot)}) by RightExists(${index2stepvar(t1)})" - case RightExistsOne(bot, t1, phi, x) => s"$varDecl = have(${sequent2code(bot)}) by RightExistsOne(${index2stepvar(t1)})" - case Weakening(bot, t1) => s"$varDecl = have(${sequent2code(bot)}) by Weakening(${index2stepvar(t1)})" - case LeftRefl(bot, t1, phi) => s"$varDecl = have(${sequent2code(bot)}) by LeftRefl(${index2stepvar(t1)})" - case RightRefl(bot, phi) => s"$varDecl = have(${sequent2code(bot)}) by RightRefl" - case LeftSubstEq(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by LeftSubstEq(${index2stepvar(t1)})" - case RightSubstEq(bot, t1, equals, lambdaPhi) => s"$varDecl = have(${sequent2code(bot)}) by RightSubstEq(${index2stepvar(t1)})" - case LeftSubstIff(bot, t1, equals, lambdaPhi) => - s"$varDecl = have(${sequent2code(bot)}) by LeftSubstIff(List(${equals - .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))(${index2stepvar(t1)})" - case RightSubstIff(bot, t1, equals, lambdaPhi) => - s"$varDecl = have(${sequent2code(bot)}) by RightSubstIff(List(${equals - .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))(${index2stepvar(t1)})" - case InstSchema(bot, t1, mCon, mPred, mTerm) => - if mCon.isEmpty && mPred.isEmpty then - s"$varDecl = have(${sequent2code(bot)}) by InstFunSchema(Map(${mTerm.toList - .map((k, v) => s"${asFrontLabel(k)} -> ${asFront(v.body)}") - .mkString(", ")}))(${index2stepvar(t1)})" - else if mCon.isEmpty && mTerm.isEmpty then - s"$varDecl = have(${sequent2code(bot)}) by InstPredSchema(Map(${mPred.toList - .map((k, v) => s"${asFrontLabel(k)} -> ${asFront(v.body)}") - .mkString(", ")}))(${index2stepvar(t1)})" - else throw new Exception("InstSchema not implemented") + else s"${varPrefix}_$i" + + val varDecl = " " * indent + s"val ${varPrefix}_$stepNum = " + ps match + case Sorry(_) => "sorry" case sp @ SCSubproof(_, _) => - s"$varDecl = have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"$varPrefix$stepNum") + "\n" + " " * indent + "}" - case Sorry(bot) => "sorry" - ) + varDecl + s"have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"${varPrefix}_$stepNum") + "\n" + " " * indent + "}" + case _ => + val (bot_, step_ref_seq, tactic_name, opening, closing) = (ps match + case Restate(bot, t1) => (bot, Seq(t1), "Restate", ".from(", ")") + case RestateTrue(bot) => (bot, null, "Restate", null, null) + case Hypothesis(bot, phi) => (bot, null, "Hypothesis", null, null) + case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2), "Cut", "(", ")") + case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1), "LeftAnd", "(", ")") + case LeftOr(bot, t, disjuncts) => (bot, t, "LeftOr", "(", ")") + case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), "LeftImplies", "(", ")") + case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1), "LeftIff", "(", ")") + case LeftNot(bot, t1, phi) => (bot, Seq(t1), "LeftNot", "(", ")") + case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1), "LeftForall", "(", ")") + case LeftExists(bot, t1, phi, x) => (bot, Seq(t1), "LeftExists", "(", ")") + case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1), "LeftExistsOne", "(", ")") + case RightAnd(bot, t, conjuncts) => (bot, t, "RightAnd", "(", ")") + case RightOr(bot, t1, phi, psi) => (bot, Seq(t1), "RightOr", "(", ")") + case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1), "RightImplies", "(", ")") + case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), "RightIff", "(", ")") + case RightNot(bot, t1, phi) => (bot, Seq(t1), "RightNot", "(", ")") + case RightForall(bot, t1, phi, x) => (bot, Seq(t1), "RightForall", "(", ")") + case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1), "RightExists", "(", ")") + case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1), "RightExistsOne", "(", ")") + case Weakening(bot, t1) => (bot, Seq(t1), "Weakening", "(", ")") + case LeftRefl(bot, t1, phi) => (bot, Seq(t1), "LeftRefl", "(", ")") + case RightRefl(bot, phi) => (bot, null, "RightRefl", null, null) + case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), "LeftSubstEq", "(", ")") + case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), "RightSubstEq", "(", ")") + case LeftSubstIff(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"LeftSubstIff(List(${equals + .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") + case RightSubstIff(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"RightSubstIff(List(${equals + .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") + case InstSchema(bot, t1, mCon, mPred, mTerm) => + if mCon.isEmpty && mPred.isEmpty then + (bot, Seq(t1), s"InstFunSchema(Map(${mTerm.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${asFront(v.body)}") + .mkString(", ")}))", "(", ")") + else if mCon.isEmpty && mTerm.isEmpty then + (bot, Seq(t1), s"InstPredSchema(Map(${mPred.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${asFront(v.body)}") + .mkString(", ")}))", "(", ")") + else throw new Exception("InstSchema not implemented") + case _ => throw new Exception(s"tactic ${ps.getClass.getName} not implemented") + ) + + var res = varDecl + if (step_ref_seq != null && step_ref_seq.size == 1 && stepNum > 0 && step_ref_seq.head + 1 == stepNum) then res + s"thenHave(${sequent2code(bot_)}) by $tactic_name" + else + res += s"have(${sequent2code(bot_)}) by $tactic_name" + if step_ref_seq == null then res + else res + s"$opening${step_ref_seq.map(index2stepvar).mkString(", ")}$closing" } object MLExtract extends lisa.Main { @@ -125,29 +132,29 @@ object MLExtract extends lisa.Main { // println(scproof2code(optimizeProofIteratively(thm1.proof.toSCProof))) val thm1_raw = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { - val s0 = have(S(x, y) ⊢ S(x, y)) subproof { - val s00 = have(S(x, y) ⊢ S(x, y)) by Restate + val s_0 = have(S(x, y) ⊢ S(x, y)) subproof { + val s_0_0 = have(S(x, y) ⊢ S(x, y)) by Restate } - val s1 = have(∀(y, S(x, y)) ⊢ S(x, y)) subproof { - val s10 = have(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall(s0) + val s_1 = have(∀(y, S(x, y)) ⊢ S(x, y)) subproof { + val s_1_0 = have(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall(s_0) } - val s2 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) subproof { - val s20 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists(s1) + val s_2 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) subproof { + val s_2_0 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists(s_1) } - val s3 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) subproof { - val s30 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists(s2) + val s_3 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) subproof { + val s_3_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists(s_2) } - val s4 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { - val s40 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall(s3) + val s_4 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { + val s_4_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall(s_3) } } val thm1_optimized = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { - val s0 = have(S(x, y) ⊢ S(x, y)) by Restate - val s1 = have(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall(s0) - val s2 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists(s1) - val s3 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists(s2) - val s4 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall(s3) + val s_0 = have(S(x, y) ⊢ S(x, y)) by Restate + val s_1 = thenHave(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall + val s_2 = thenHave(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists + val s_3 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists + val s_4 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall } // A standard and important property of ∀: It distributes over conjunction. This is useful to justify prenex normal form. @@ -285,52 +292,52 @@ object MLExtract extends lisa.Main { // println(scproof2code(optimizeProofIteratively(thm3.proof.toSCProof))) val thm3_raw = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { - val s0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) subproof { - val s00 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) by Hypothesis + val s_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) subproof { + val s0_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) by Hypothesis } - val s1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s10 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s100 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate + val s_1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s1_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s10_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate } - val s11 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s110 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s10) + val s1_1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s11_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s1_0) } } - val s2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) subproof { - val s20 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s1) + val s_2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) subproof { + val s2_0 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s_1) } - val s3 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { - val s30 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s1) - val s31 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s2) - val s32 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { - val s320 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s321 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊤))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))))(s320) - val s322 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s323 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊥))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))))(s322) - val s324 = have(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate.from(s323) - val s325 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut(s324, s321) - val s326 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate.from(s325) - val s327 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from(s326) + val s_3 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { + val s3_0 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) + val s3_1 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) + val s3_2 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { + val s32_0 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s32_1 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊤))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))))(s32_0) + val s32_2 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s32_3 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊥))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))))(s32_2) + val s32_4 = have(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate.from(s32_3) + val s32_5 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut(s32_4, s32_1) + val s32_6 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate.from(s32_5) + val s32_7 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from(s32_6) } - val s33 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s30, s32) - val s34 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s31, s33) + val s3_3 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s3_0, s3_2) + val s3_4 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s3_1, s3_3) } } val thm3_optimized = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { - val s0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate - val s1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s0) - val s2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s1) - val s3 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s1) - val s4 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s2) - val s5 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s6 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate.from(s5) - val s7 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s8 = have(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate.from(s7) - val s9 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut(s8, s6) - val s10 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from(s9) - val s11 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s3, s10) - val s12 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s4, s11) + val s_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate + val s_1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s_0) + val s_2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s_1) + val s_3 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) + val s_4 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) + val s_5 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s_6 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate.from(s_5) + val s_7 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s_8 = have(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate.from(s_7) + val s_9 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut(s_8, s_6) + val s_10 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from(s_9) + val s_11 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_3, s_10) + val s_12 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_4, s_11) } From 22322b341688e046ec7afc6c687de64de59b6c6b Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:23 +0100 Subject: [PATCH 06/24] Handle more cases --- ml-extract/src/main/scala/main.scala | 400 +++++++++++++++------------ 1 file changed, 216 insertions(+), 184 deletions(-) diff --git a/ml-extract/src/main/scala/main.scala b/ml-extract/src/main/scala/main.scala index d530ce78b..44a0aee52 100644 --- a/ml-extract/src/main/scala/main.scala +++ b/ml-extract/src/main/scala/main.scala @@ -9,79 +9,111 @@ import lisa.utils.KernelHelpers.lambda import lisa.utils.ProofsShrink.* import lisa.automation.Tableau -// TODO: fix printing of ∧ and ∨ with several arguments -// TODO: make sure that all proofsteps arguments are used when needed +// TODO: fix printing of ∧ and ∨ with > 2 arguments +// TODO: determine when calling withParameters is necessary instead of using it by default +// TODO: remove unnecessary variables "val s_..." in generated proofs +// TODO: generate better random variable names +// TODO: handle automatic variable declaration before theorems/proofs def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = 0, varPrefix: String = "s"): String = { - p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i, premises, indent, varPrefix)).mkString("\n") -} + def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], indent: Int, varPrefix: String): String = { + def sequent2code(sq: Sequent): String = asFront(sq).toString.replace("⇒", "==>").replace("⇔", "<=>") + def formula2code(form: K.Formula): String = asFront(form).toString.replace("⇒", "==>").replace("⇔", "<=>") + def term2code(term: K.Term): String = asFront(term).toString.replace("⇒", "==>").replace("⇔", "<=>") + + def index2stepvar(i: Int): String = + if i < -premises.size then throw new Exception(s"step $i is not defined") + else if i < 0 then premises(-i - 1) + else s"${varPrefix}_$i" + + val varDecl = " " * indent + s"val ${varPrefix}_$stepNum = " + ps match + case Sorry(_) => "sorry" + case sp @ SCSubproof(_, _) => + varDecl + s"have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"${varPrefix}_$stepNum") + "\n" + " " * indent + "}" + case _ => + val (bot_, step_ref_seq, tactic_name, opening, closing) = (ps match + case Restate(bot, t1) => (bot, Seq(t1), "Restate", ".from(", ")") + case RestateTrue(bot) => (bot, null, "Restate", null, null) + case Hypothesis(bot, phi) => (bot, null, "Hypothesis", null, null) + // case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2), "Cut", "(", ")") + case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2), s"Cut.withParameters(${formula2code(phi)})", "(", ")") + // case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1), "LeftAnd", "(", ")") + case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1), s"LeftAnd.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") + // case LeftOr(bot, t, disjuncts) => (bot, t, "LeftOr", "(", ")") + case LeftOr(bot, t, disjuncts) => (bot, t, s"LeftOr.withParameters(${disjuncts.map(formula2code).mkString(", ")})", "(", ")") + // case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), "LeftImplies", "(", ")") + case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), s"LeftImplies.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") + // case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1), "LeftIff", "(", ")") + case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1), s"LeftIff.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") + // case LeftNot(bot, t1, phi) => (bot, Seq(t1), "LeftNot", "(", ")") + case LeftNot(bot, t1, phi) => (bot, Seq(t1), s"LeftNot.withParameters(${formula2code(phi)})", "(", ")") + // case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1), "LeftForall", "(", ")") + case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1), s"LeftForall.withParameters(${formula2code(phi)}, ${asFrontLabel(x)}, ${term2code(t)})", "(", ")") + // case LeftExists(bot, t1, phi, x) => (bot, Seq(t1), "LeftExists", "(", ")") + case LeftExists(bot, t1, phi, x) => (bot, Seq(t1), s"LeftExists.withParameters(${formula2code(phi)}, ${asFrontLabel(x)})", "(", ")") + // case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1), "LeftExistsOne", "(", ")") + case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1), s"LeftExistsOne.withParameters(${formula2code(phi)}, ${asFrontLabel(x)})", "(", ")") + // case RightAnd(bot, t, conjuncts) => (bot, t, "RightAnd", "(", ")") + case RightAnd(bot, t, conjuncts) => (bot, t, s"RightAnd.withParameters(${conjuncts.map(formula2code).mkString(", ")})", "(", ")") + // case RightOr(bot, t1, phi, psi) => (bot, Seq(t1), "RightOr", "(", ")") + case RightOr(bot, t1, phi, psi) => (bot, Seq(t1), s"RightOr.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") + // case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1), "RightImplies", "(", ")") + case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1), s"RightImplies.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") + // case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), "RightIff", "(", ")") + case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), s"RightIff.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") + // case RightNot(bot, t1, phi) => (bot, Seq(t1), "RightNot", "(", ")") + case RightNot(bot, t1, phi) => (bot, Seq(t1), s"RightNot.withParameters(${formula2code(phi)})", "(", ")") + // case RightForall(bot, t1, phi, x) => (bot, Seq(t1), "RightForall", "(", ")") + case RightForall(bot, t1, phi, x) => (bot, Seq(t1), s"RightForall.withParameters(${formula2code(phi)}, ${asFrontLabel(x)})", "(", ")") + // case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1), "RightExists", "(", ")") + case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1), s"RightExists.withParameters(${formula2code(phi)}, ${asFrontLabel(x)}, ${term2code(t)})", "(", ")") + // case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1), "RightExistsOne", "(", ")") + case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1), s"RightExistsOne.withParameters(${formula2code(phi)}, ${asFrontLabel(x)})", "(", ")") + case Weakening(bot, t1) => (bot, Seq(t1), "Weakening", "(", ")") + // case LeftRefl(bot, t1, phi) => (bot, Seq(t1), "LeftRefl", "(", ")") + case LeftRefl(bot, t1, phi) => (bot, Seq(t1), s"LeftRefl.withParameters(${formula2code(phi)})", "(", ")") + // case RightRefl(bot, phi) => (bot, null, "RightRefl", null, null) + case RightRefl(bot, phi) => (bot, null, s"RightRefl.withParameters(${formula2code(phi)})", null, null) + // case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), "LeftSubstEq", "(", ")") + case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"LeftSubstEq.withParameters(List(${equals + .map((a, b) => s"((${term2code(a)}), (${term2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") + // case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), "RightSubstEq", "(", ")") + case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"RightSubstEq.withParameters(List(${equals + .map((a, b) => s"((${term2code(a)}), (${term2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") + case LeftSubstIff(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"LeftSubstIff(List(${equals + .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") + case RightSubstIff(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"RightSubstIff(List(${equals + .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") + case InstSchema(bot, t1, mCon, mPred, mTerm) => + if mCon.isEmpty && mPred.isEmpty then + (bot, Seq(t1), s"InstFunSchema(Map(${mTerm.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${term2code(v.body)}") + .mkString(", ")}))", "(", ")") + else if mCon.isEmpty && mTerm.isEmpty then + (bot, Seq(t1), s"InstPredSchema(Map(${mPred.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${formula2code(v.body)}") + .mkString(", ")}))", "(", ")") + else throw new Exception("InstSchema not implemented") + case _ => throw new Exception(s"tactic ${ps.getClass.getName} not implemented") + ) + + varDecl + ( + if (step_ref_seq != null && step_ref_seq.size == 1 && stepNum > 0 && step_ref_seq.head + 1 == stepNum) + then s"thenHave(${sequent2code(bot_)}) by $tactic_name" + else + s"have(${sequent2code(bot_)}) by $tactic_name" + ( + if step_ref_seq == null then "" + else s"$opening${step_ref_seq.map(index2stepvar).mkString(", ")}$closing" + ) + ) + } -def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], indent: Int, varPrefix: String): String = { - def sequent2code(sq: Sequent): String = asFront(sq).toString.replace("⇒", "==>").replace("⇔", "<=>") - def formula2code(sq: K.Formula): String = asFront(sq).toString.replace("⇒", "==>").replace("⇔", "<=>") - - def index2stepvar(i: Int): String = - if i < -premises.size then throw new Exception(s"step $i is not defined") - else if i < 0 then premises(-i - 1) - else s"${varPrefix}_$i" - - val varDecl = " " * indent + s"val ${varPrefix}_$stepNum = " - ps match - case Sorry(_) => "sorry" - case sp @ SCSubproof(_, _) => - varDecl + s"have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"${varPrefix}_$stepNum") + "\n" + " " * indent + "}" - case _ => - val (bot_, step_ref_seq, tactic_name, opening, closing) = (ps match - case Restate(bot, t1) => (bot, Seq(t1), "Restate", ".from(", ")") - case RestateTrue(bot) => (bot, null, "Restate", null, null) - case Hypothesis(bot, phi) => (bot, null, "Hypothesis", null, null) - case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2), "Cut", "(", ")") - case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1), "LeftAnd", "(", ")") - case LeftOr(bot, t, disjuncts) => (bot, t, "LeftOr", "(", ")") - case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), "LeftImplies", "(", ")") - case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1), "LeftIff", "(", ")") - case LeftNot(bot, t1, phi) => (bot, Seq(t1), "LeftNot", "(", ")") - case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1), "LeftForall", "(", ")") - case LeftExists(bot, t1, phi, x) => (bot, Seq(t1), "LeftExists", "(", ")") - case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1), "LeftExistsOne", "(", ")") - case RightAnd(bot, t, conjuncts) => (bot, t, "RightAnd", "(", ")") - case RightOr(bot, t1, phi, psi) => (bot, Seq(t1), "RightOr", "(", ")") - case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1), "RightImplies", "(", ")") - case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), "RightIff", "(", ")") - case RightNot(bot, t1, phi) => (bot, Seq(t1), "RightNot", "(", ")") - case RightForall(bot, t1, phi, x) => (bot, Seq(t1), "RightForall", "(", ")") - case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1), "RightExists", "(", ")") - case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1), "RightExistsOne", "(", ")") - case Weakening(bot, t1) => (bot, Seq(t1), "Weakening", "(", ")") - case LeftRefl(bot, t1, phi) => (bot, Seq(t1), "LeftRefl", "(", ")") - case RightRefl(bot, phi) => (bot, null, "RightRefl", null, null) - case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), "LeftSubstEq", "(", ")") - case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), "RightSubstEq", "(", ")") - case LeftSubstIff(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"LeftSubstIff(List(${equals - .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") - case RightSubstIff(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"RightSubstIff(List(${equals - .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") - case InstSchema(bot, t1, mCon, mPred, mTerm) => - if mCon.isEmpty && mPred.isEmpty then - (bot, Seq(t1), s"InstFunSchema(Map(${mTerm.toList - .map((k, v) => s"${asFrontLabel(k)} -> ${asFront(v.body)}") - .mkString(", ")}))", "(", ")") - else if mCon.isEmpty && mTerm.isEmpty then - (bot, Seq(t1), s"InstPredSchema(Map(${mPred.toList - .map((k, v) => s"${asFrontLabel(k)} -> ${asFront(v.body)}") - .mkString(", ")}))", "(", ")") - else throw new Exception("InstSchema not implemented") - case _ => throw new Exception(s"tactic ${ps.getClass.getName} not implemented") - ) - - var res = varDecl - if (step_ref_seq != null && step_ref_seq.size == 1 && stepNum > 0 && step_ref_seq.head + 1 == stepNum) then res + s"thenHave(${sequent2code(bot_)}) by $tactic_name" - else - res += s"have(${sequent2code(bot_)}) by $tactic_name" - if step_ref_seq == null then res - else res + s"$opening${step_ref_seq.map(index2stepvar).mkString(", ")}$closing" + p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i, premises, indent, varPrefix)).mkString("\n") } object MLExtract extends lisa.Main { @@ -136,25 +168,25 @@ object MLExtract extends lisa.Main { val s_0_0 = have(S(x, y) ⊢ S(x, y)) by Restate } val s_1 = have(∀(y, S(x, y)) ⊢ S(x, y)) subproof { - val s_1_0 = have(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall(s_0) + val s_1_0 = have(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall.withParameters(S(x, y), y, y)(s_0) } val s_2 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) subproof { - val s_2_0 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists(s_1) + val s_2_0 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists.withParameters(S(x, y), x, x)(s_1) } val s_3 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) subproof { - val s_3_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists(s_2) + val s_3_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists.withParameters(∀(y, S(x, y)), x)(s_2) } val s_4 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { - val s_4_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall(s_3) + val s_4_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall.withParameters(∃(x, S(x, y)), y)(s_3) } } val thm1_optimized = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { val s_0 = have(S(x, y) ⊢ S(x, y)) by Restate - val s_1 = thenHave(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall - val s_2 = thenHave(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists - val s_3 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists - val s_4 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall + val s_1 = thenHave(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall.withParameters(S(x, y), y, y) + val s_2 = thenHave(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists.withParameters(S(x, y), x, x) + val s_3 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists.withParameters(∀(y, S(x, y)), x) + val s_4 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall.withParameters(∃(x, S(x, y)), y) } // A standard and important property of ∀: It distributes over conjunction. This is useful to justify prenex normal form. @@ -188,91 +220,91 @@ object MLExtract extends lisa.Main { // println(scproof2code(optimizeProofIteratively(thm2.proof.toSCProof))) val thm2_raw = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { - val s0 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { - val s00 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) subproof { - val s000 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) by Restate + val s_0 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s_0_0 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) subproof { + val s_0_0_0 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) by Restate } - val s01 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { - val s010 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall(s00) + val s_0_1 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { + val s_0_1_0 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters(Q(x), x, x)(s_0_0) } - val s02 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { - val s020 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall(s01) + val s_0_2 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { + val s_0_2_0 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters(R(x), x, x)(s_0_1) } - val s03 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { - val s030 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall(s02) + val s_0_3 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s_0_3_0 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall.withParameters((Q(x) ∧ R(x)), x)(s_0_2) } - val s04 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Restate.from(s03) + val s_0_4 = thenHave(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Restate } - val s1 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { - val s10 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { - val s100 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Hypothesis + val s_1 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { + val s_1_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s_1_0_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Hypothesis } - val s11 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { - val s110 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { - val s1100 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) by Restate + val s_1_1 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s_1_1_0 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { + val s_1_1_0_0 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) by Restate } - val s111 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { - val s1110 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s110) + val s_1_1_1 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s_1_1_1_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters((Q(x) ∧ R(x)), x, x)(s_1_1_0) } } - val s12 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) subproof { - val s120 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) by Weakening(s11) + val s_1_2 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) subproof { + val s_1_2_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) by Weakening(s_1_1) } - val s13 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) subproof { - val s130 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall(s12) + val s_1_3 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) subproof { + val s_1_3_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall.withParameters(Q(x), x)(s_1_2) } - val s14 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) subproof { - val s140 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) by Weakening(s11) + val s_1_4 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) subproof { + val s_1_4_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) by Weakening(s_1_1) } - val s15 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) subproof { - val s150 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall(s14) + val s_1_5 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) subproof { + val s_1_5_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall.withParameters(R(x), x)(s_1_4) } - val s16 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { - val s160 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s13) - val s161 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s15) - val s162 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { - val s1620 = have(( ) ⊢ ⊤) by Restate - val s1621 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate.from(s1620) + val s_1_6 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { + val s_1_6_0 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_1_3) + val s_1_6_1 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_1_5) + val s_1_6_2 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { + val s_1_6_2_0 = have(( ) ⊢ ⊤) by Restate + val s_1_6_2_1 = thenHave(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate } - val s163 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s160, s162) - val s164 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s161, s163) + val s_1_6_3 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))))(s_1_6_0, s_1_6_2) + val s_1_6_4 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))))(s_1_6_1, s_1_6_3) } - val s17 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate.from(s16) + val s_1_7 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate } - val s2 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { - val s20 = have(( ) ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s0) - val s21 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s1) - val s22 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { - val s220 = have(( ) ⊢ ⊤) by Restate - val s221 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s220) + val s_2 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { + val s_2_0 = have(( ) ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_0) + val s_2_1 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_1) + val s_2_2 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { + val s_2_2_0 = have(( ) ⊢ ⊤) by Restate + val s_2_2_1 = thenHave(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate } - val s23 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s20, s22) - val s24 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s21, s23) + val s_2_3 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut.withParameters(((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))))(s_2_0, s_2_2) + val s_2_4 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))))(s_2_1, s_2_3) } } val thm2_optimized = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { - val s0 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) by Restate - val s1 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall(s0) - val s2 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall(s1) - val s3 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall(s2) - val s4 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) by Restate - val s5 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s4) - val s6 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) by Weakening(s5) - val s7 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall(s6) - val s8 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) by Weakening(s5) - val s9 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall(s8) - val s10 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s7) - val s11 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s9) - val s12 = have(( ) ⊢ ⊤) by Restate - val s13 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate.from(s12) - val s14 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s10, s13) - val s15 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s11, s14) - val s16 = have(( ) ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s3) - val s17 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s15) - val s18 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s12) - val s19 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s16, s18) - val s20 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s17, s19) + val s_0 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) by Restate + val s_1 = thenHave(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters(Q(x), x, x) + val s_2 = thenHave(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters(R(x), x, x) + val s_3 = thenHave(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall.withParameters((Q(x) ∧ R(x)), x) + val s_4 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) by Restate + val s_5 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters((Q(x) ∧ R(x)), x, x) + val s_6 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) by Weakening + val s_7 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall.withParameters(Q(x), x) + val s_8 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) by Weakening(s_5) + val s_9 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall.withParameters(R(x), x) + val s_10 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_7) + val s_11 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_9) + val s_12 = have(( ) ⊢ ⊤) by Restate + val s_13 = thenHave(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate + val s_14 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))))(s_10, s_13) + val s_15 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))))(s_11, s_14) + val s_16 = have(( ) ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_3) + val s_17 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_15) + val s_18 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_12) + val s_19 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut.withParameters(((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))))(s_16, s_18) + val s_20 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))))(s_17, s_19) } @@ -293,51 +325,51 @@ object MLExtract extends lisa.Main { val thm3_raw = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { val s_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) subproof { - val s0_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) by Hypothesis + val s_0_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) by Hypothesis } val s_1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s1_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s10_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate + val s_1_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s_1_0_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate } - val s1_1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s11_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s1_0) + val s_1_1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s_1_1_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall.withParameters((Q(x) ==> Q(f(x))), x, x)(s_1_0) } } val s_2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) subproof { - val s2_0 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s_1) + val s_2_0 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s_1) } val s_3 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { - val s3_0 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) - val s3_1 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) - val s3_2 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { - val s32_0 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s32_1 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊤))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))))(s32_0) - val s32_2 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s32_3 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊥))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))))(s32_2) - val s32_4 = have(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate.from(s32_3) - val s32_5 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut(s32_4, s32_1) - val s32_6 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate.from(s32_5) - val s32_7 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from(s32_6) + val s_3_0 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) + val s_3_1 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) + val s_3_2 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { + val s_3_2_0 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s_3_2_1 = thenHave(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊤))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))))) + val s_3_2_2 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s_3_2_3 = thenHave(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊥))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))))) + val s_3_2_4 = thenHave(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate + val s_3_2_5 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut.withParameters(Q(f(x)))(s_3_2_4, s_3_2_1) + val s_3_2_6 = thenHave(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate + val s_3_2_7 = thenHave(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate } - val s3_3 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s3_0, s3_2) - val s3_4 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s3_1, s3_3) + val s_3_3 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut.withParameters((∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))))(s_3_0, s_3_2) + val s_3_4 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut.withParameters((∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))))(s_3_1, s_3_3) } } val thm3_optimized = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { val s_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate - val s_1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s_0) - val s_2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s_1) + val s_1 = thenHave(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall.withParameters((Q(x) ==> Q(f(x))), x, x) + val s_2 = thenHave(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x))) val s_3 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) val s_4 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) val s_5 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s_6 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate.from(s_5) + val s_6 = thenHave(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate val s_7 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s_8 = have(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate.from(s_7) - val s_9 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut(s_8, s_6) - val s_10 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate.from(s_9) - val s_11 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_3, s_10) - val s_12 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_4, s_11) + val s_8 = thenHave(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate + val s_9 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut.withParameters(Q(f(x)))(s_8, s_6) + val s_10 = thenHave(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate + val s_11 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut.withParameters((∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))))(s_3, s_10) + val s_12 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut.withParameters((∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))))(s_4, s_11) } @@ -351,25 +383,25 @@ object MLExtract extends lisa.Main { // println(scproof2code(optimizeProofIteratively(thm1bis.proof.toSCProof))) val thm1bis_raw = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { - val s0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { - val s00 = have(( S(x, y_1), ¬(S(x, y_1)) ) ⊢ ( )) by Restate - val s01 = have(( ¬(S(x, y_1)), ∀(y, S(x, y)) ) ⊢ ( )) by LeftForall(s00) - val s02 = have(( ∀(y, S(x, y)), ∀(x_2, ¬(S(x_2, y_1))) ) ⊢ ( )) by LeftForall(s01) - val s03 = have(( ∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y))) ) ⊢ ( )) by LeftExists(s02) - val s04 = have(( ∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1)))) ) ⊢ ( )) by LeftExists(s03) - val s05 = have((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ( )) by Weakening(s04) - val s06 = have((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ( )) by Weakening(s05) - val s07 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by Restate.from(s06) + val s_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { + val s_0_0 = have(( S(x, y_1), ¬(S(x, y_1)) ) ⊢ ( )) by Restate + val s_0_1 = thenHave(( ¬(S(x, y_1)), ∀(y, S(x, y)) ) ⊢ ( )) by LeftForall.withParameters(S(x, y), y, y_1) + val s_0_2 = thenHave(( ∀(y, S(x, y)), ∀(x_2, ¬(S(x_2, y_1))) ) ⊢ ( )) by LeftForall.withParameters(¬(S(x_2, y_1)), x_2, x) + val s_0_3 = thenHave(( ∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y))) ) ⊢ ( )) by LeftExists.withParameters(∀(y, S(x, y)), x) + val s_0_4 = thenHave(( ∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1)))) ) ⊢ ( )) by LeftExists.withParameters(∀(x_2, ¬(S(x_2, y_1))), y_1) + val s_0_5 = thenHave((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ( )) by Weakening + val s_0_6 = thenHave((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ( )) by Weakening + val s_0_7 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by Restate } } val thm1bis_optimized = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { - val s0 = have(( S(x, y_1), ¬(S(x, y_1)) ) ⊢ ( )) by Restate - val s1 = have(( ¬(S(x, y_1)), ∀(y, S(x, y)) ) ⊢ ( )) by LeftForall(s0) - val s2 = have(( ∀(y, S(x, y)), ∀(x_2, ¬(S(x_2, y_1))) ) ⊢ ( )) by LeftForall(s1) - val s3 = have(( ∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y))) ) ⊢ ( )) by LeftExists(s2) - val s4 = have(( ∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1)))) ) ⊢ ( )) by LeftExists(s3) - val s5 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by Restate.from(s4) + val s_0 = have(( S(x, y_1), ¬(S(x, y_1)) ) ⊢ ( )) by Restate + val s_1 = thenHave(( ¬(S(x, y_1)), ∀(y, S(x, y)) ) ⊢ ( )) by LeftForall.withParameters(S(x, y), y, y_1) + val s_2 = thenHave(( ∀(y, S(x, y)), ∀(x_2, ¬(S(x_2, y_1))) ) ⊢ ( )) by LeftForall.withParameters(¬(S(x_2, y_1)), x_2, x) + val s_3 = thenHave(( ∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y))) ) ⊢ ( )) by LeftExists.withParameters(∀(y, S(x, y)), x) + val s_4 = thenHave(( ∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1)))) ) ⊢ ( )) by LeftExists.withParameters(∀(x_2, ¬(S(x_2, y_1))), y_1) + val s_5 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by Restate } } From 38a73bb6d357856f1e16c688081f4bd2fc17666d Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:23 +0100 Subject: [PATCH 07/24] Add todo list --- ml-extract/src/main/scala/main.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ml-extract/src/main/scala/main.scala b/ml-extract/src/main/scala/main.scala index 44a0aee52..434165e17 100644 --- a/ml-extract/src/main/scala/main.scala +++ b/ml-extract/src/main/scala/main.scala @@ -9,11 +9,11 @@ import lisa.utils.KernelHelpers.lambda import lisa.utils.ProofsShrink.* import lisa.automation.Tableau -// TODO: fix printing of ∧ and ∨ with > 2 arguments -// TODO: determine when calling withParameters is necessary instead of using it by default +// TODO: fix printing of ∧ and ∨ with > 2 arguments, currently handled as recursive binary operators +// TODO: determine when calling withParameters is necessary instead of using it by default -> build the high level proof tree // TODO: remove unnecessary variables "val s_..." in generated proofs -// TODO: generate better random variable names -// TODO: handle automatic variable declaration before theorems/proofs +// TODO: generate more realistic variable names +// TODO: handle automatic global variable declaration before theorems/proofs def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = 0, varPrefix: String = "s"): String = { def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], indent: Int, varPrefix: String): String = { From 386ab961abfec13e924665303638efddf5675557 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:23 +0100 Subject: [PATCH 08/24] Update and clean scproof2code method --- ml-extract/src/main/scala/main.scala | 406 +++++++++++++++------------ 1 file changed, 228 insertions(+), 178 deletions(-) diff --git a/ml-extract/src/main/scala/main.scala b/ml-extract/src/main/scala/main.scala index 434165e17..491a0c31b 100644 --- a/ml-extract/src/main/scala/main.scala +++ b/ml-extract/src/main/scala/main.scala @@ -10,7 +10,6 @@ import lisa.utils.ProofsShrink.* import lisa.automation.Tableau // TODO: fix printing of ∧ and ∨ with > 2 arguments, currently handled as recursive binary operators -// TODO: determine when calling withParameters is necessary instead of using it by default -> build the high level proof tree // TODO: remove unnecessary variables "val s_..." in generated proofs // TODO: generate more realistic variable names // TODO: handle automatic global variable declaration before theorems/proofs @@ -32,81 +31,69 @@ def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = case sp @ SCSubproof(_, _) => varDecl + s"have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"${varPrefix}_$stepNum") + "\n" + " " * indent + "}" case _ => - val (bot_, step_ref_seq, tactic_name, opening, closing) = (ps match - case Restate(bot, t1) => (bot, Seq(t1), "Restate", ".from(", ")") - case RestateTrue(bot) => (bot, null, "Restate", null, null) - case Hypothesis(bot, phi) => (bot, null, "Hypothesis", null, null) - // case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2), "Cut", "(", ")") - case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2), s"Cut.withParameters(${formula2code(phi)})", "(", ")") - // case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1), "LeftAnd", "(", ")") - case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1), s"LeftAnd.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") - // case LeftOr(bot, t, disjuncts) => (bot, t, "LeftOr", "(", ")") - case LeftOr(bot, t, disjuncts) => (bot, t, s"LeftOr.withParameters(${disjuncts.map(formula2code).mkString(", ")})", "(", ")") - // case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), "LeftImplies", "(", ")") - case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), s"LeftImplies.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") - // case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1), "LeftIff", "(", ")") - case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1), s"LeftIff.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") - // case LeftNot(bot, t1, phi) => (bot, Seq(t1), "LeftNot", "(", ")") - case LeftNot(bot, t1, phi) => (bot, Seq(t1), s"LeftNot.withParameters(${formula2code(phi)})", "(", ")") - // case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1), "LeftForall", "(", ")") - case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1), s"LeftForall.withParameters(${formula2code(phi)}, ${asFrontLabel(x)}, ${term2code(t)})", "(", ")") - // case LeftExists(bot, t1, phi, x) => (bot, Seq(t1), "LeftExists", "(", ")") - case LeftExists(bot, t1, phi, x) => (bot, Seq(t1), s"LeftExists.withParameters(${formula2code(phi)}, ${asFrontLabel(x)})", "(", ")") - // case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1), "LeftExistsOne", "(", ")") - case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1), s"LeftExistsOne.withParameters(${formula2code(phi)}, ${asFrontLabel(x)})", "(", ")") - // case RightAnd(bot, t, conjuncts) => (bot, t, "RightAnd", "(", ")") - case RightAnd(bot, t, conjuncts) => (bot, t, s"RightAnd.withParameters(${conjuncts.map(formula2code).mkString(", ")})", "(", ")") - // case RightOr(bot, t1, phi, psi) => (bot, Seq(t1), "RightOr", "(", ")") - case RightOr(bot, t1, phi, psi) => (bot, Seq(t1), s"RightOr.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") - // case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1), "RightImplies", "(", ")") - case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1), s"RightImplies.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") - // case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), "RightIff", "(", ")") - case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2), s"RightIff.withParameters(${formula2code(phi)}, ${formula2code(psi)})", "(", ")") - // case RightNot(bot, t1, phi) => (bot, Seq(t1), "RightNot", "(", ")") - case RightNot(bot, t1, phi) => (bot, Seq(t1), s"RightNot.withParameters(${formula2code(phi)})", "(", ")") - // case RightForall(bot, t1, phi, x) => (bot, Seq(t1), "RightForall", "(", ")") - case RightForall(bot, t1, phi, x) => (bot, Seq(t1), s"RightForall.withParameters(${formula2code(phi)}, ${asFrontLabel(x)})", "(", ")") - // case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1), "RightExists", "(", ")") - case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1), s"RightExists.withParameters(${formula2code(phi)}, ${asFrontLabel(x)}, ${term2code(t)})", "(", ")") - // case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1), "RightExistsOne", "(", ")") - case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1), s"RightExistsOne.withParameters(${formula2code(phi)}, ${asFrontLabel(x)})", "(", ")") - case Weakening(bot, t1) => (bot, Seq(t1), "Weakening", "(", ")") - // case LeftRefl(bot, t1, phi) => (bot, Seq(t1), "LeftRefl", "(", ")") - case LeftRefl(bot, t1, phi) => (bot, Seq(t1), s"LeftRefl.withParameters(${formula2code(phi)})", "(", ")") - // case RightRefl(bot, phi) => (bot, null, "RightRefl", null, null) - case RightRefl(bot, phi) => (bot, null, s"RightRefl.withParameters(${formula2code(phi)})", null, null) - // case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), "LeftSubstEq", "(", ")") - case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"LeftSubstEq.withParameters(List(${equals - .map((a, b) => s"((${term2code(a)}), (${term2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") - // case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), "RightSubstEq", "(", ")") - case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"RightSubstEq.withParameters(List(${equals - .map((a, b) => s"((${term2code(a)}), (${term2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") - case LeftSubstIff(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"LeftSubstIff(List(${equals + var tacticName = ps.getClass.getSimpleName + var opening = "(" + var closing = ")" + val (bot_, step_ref_seq) = (ps match + case Restate(bot, t1) => + opening = ".from(" + (bot, Seq(t1)) + case RestateTrue(bot) => + tacticName = "Restate" + (bot, null) + case Hypothesis(bot, phi) => (bot, null) + case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2)) + case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1)) + case LeftOr(bot, t, disjuncts) => (bot, t) + case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) + case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1)) + case LeftNot(bot, t1, phi) => (bot, Seq(t1)) + case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1)) + case LeftExists(bot, t1, phi, x) => (bot, Seq(t1)) + case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) + case RightAnd(bot, t, conjuncts) => (bot, t) + case RightOr(bot, t1, phi, psi) => (bot, Seq(t1)) + case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1)) + case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) + case RightNot(bot, t1, phi) => (bot, Seq(t1)) + case RightForall(bot, t1, phi, x) => (bot, Seq(t1)) + case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1)) + case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) + case Weakening(bot, t1) => (bot, Seq(t1)) + case LeftRefl(bot, t1, phi) => (bot, Seq(t1)) + case RightRefl(bot, phi) => (bot, null) + case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) + case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) + case LeftSubstIff(bot, t1, equals, lambdaPhi) => + tacticName = s"LeftSubstIff(List(${equals .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") - case RightSubstIff(bot, t1, equals, lambdaPhi) => (bot, Seq(t1), s"RightSubstIff(List(${equals + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))" + (bot, Seq(t1)) + case RightSubstIff(bot, t1, equals, lambdaPhi) => + tacticName = s"RightSubstIff(List(${equals .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))", "(", ")") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))" + (bot, Seq(t1)) case InstSchema(bot, t1, mCon, mPred, mTerm) => if mCon.isEmpty && mPred.isEmpty then - (bot, Seq(t1), s"InstFunSchema(Map(${mTerm.toList + tacticName = s"InstFunSchema(Map(${mTerm.toList .map((k, v) => s"${asFrontLabel(k)} -> ${term2code(v.body)}") - .mkString(", ")}))", "(", ")") + .mkString(", ")}))" + (bot, Seq(t1)) else if mCon.isEmpty && mTerm.isEmpty then - (bot, Seq(t1), s"InstPredSchema(Map(${mPred.toList + tacticName = s"InstPredSchema(Map(${mPred.toList .map((k, v) => s"${asFrontLabel(k)} -> ${formula2code(v.body)}") - .mkString(", ")}))", "(", ")") + .mkString(", ")}))" + (bot, Seq(t1)) else throw new Exception("InstSchema not implemented") - case _ => throw new Exception(s"tactic ${ps.getClass.getName} not implemented") + case _ => throw new Exception(s"Tactic ${ps.getClass.getName} not implemented") ) varDecl + ( if (step_ref_seq != null && step_ref_seq.size == 1 && stepNum > 0 && step_ref_seq.head + 1 == stepNum) - then s"thenHave(${sequent2code(bot_)}) by $tactic_name" + then s"thenHave(${sequent2code(bot_)}) by $tacticName" else - s"have(${sequent2code(bot_)}) by $tactic_name" + ( + s"have(${sequent2code(bot_)}) by $tacticName" + ( if step_ref_seq == null then "" else s"$opening${step_ref_seq.map(index2stepvar).mkString(", ")}$closing" ) @@ -158,35 +145,35 @@ object MLExtract extends lisa.Main { thenHave(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall } - // println(prettyProof(thm1.proof)) - // println(prettySCProof(thm1.proof.toSCProof)) - // println(scproof2code(thm1.proof.toSCProof)) - // println(scproof2code(optimizeProofIteratively(thm1.proof.toSCProof))) + // println(prettyProof(thm1.highProof.get)) + // println(prettySCProof(thm1.kernelProof.get)) + // println(scproof2code(thm1.kernelProof.get)) + // println(scproof2code(optimizeProofIteratively(thm1.kernelProof.get))) val thm1_raw = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { val s_0 = have(S(x, y) ⊢ S(x, y)) subproof { val s_0_0 = have(S(x, y) ⊢ S(x, y)) by Restate } val s_1 = have(∀(y, S(x, y)) ⊢ S(x, y)) subproof { - val s_1_0 = have(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall.withParameters(S(x, y), y, y)(s_0) + val s_1_0 = have(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall(s_0) } val s_2 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) subproof { - val s_2_0 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists.withParameters(S(x, y), x, x)(s_1) + val s_2_0 = have(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists(s_1) } val s_3 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) subproof { - val s_3_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists.withParameters(∀(y, S(x, y)), x)(s_2) + val s_3_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists(s_2) } val s_4 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { - val s_4_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall.withParameters(∃(x, S(x, y)), y)(s_3) + val s_4_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall(s_3) } } val thm1_optimized = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { val s_0 = have(S(x, y) ⊢ S(x, y)) by Restate - val s_1 = thenHave(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall.withParameters(S(x, y), y, y) - val s_2 = thenHave(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists.withParameters(S(x, y), x, x) - val s_3 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists.withParameters(∀(y, S(x, y)), x) - val s_4 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall.withParameters(∃(x, S(x, y)), y) + val s_1 = thenHave(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall + val s_2 = thenHave(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists + val s_3 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∃(x, S(x, y))) by LeftExists + val s_4 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by RightForall } // A standard and important property of ∀: It distributes over conjunction. This is useful to justify prenex normal form. @@ -214,100 +201,101 @@ object MLExtract extends lisa.Main { have(thesis) by Tautology.from(forward, backward) } - // println(prettyProof(thm2.proof)) - // println(prettySCProof(thm2.proof.toSCProof)) - // println(scproof2code(thm2.proof.toSCProof)) - // println(scproof2code(optimizeProofIteratively(thm2.proof.toSCProof))) + // println(prettyProof(thm2.highProof.get)) + // println(prettySCProof(thm2.kernelProof.get)) + // println(scproof2code(thm2.kernelProof.get)) + // println(scproof2code(optimizeProofIteratively(thm2.kernelProof.get))) val thm2_raw = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { - val s_0 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { - val s_0_0 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) subproof { - val s_0_0_0 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) by Restate + val s_0 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s_0_0 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) subproof { + val s_0_0_0 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) by Restate } - val s_0_1 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { - val s_0_1_0 = have(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters(Q(x), x, x)(s_0_0) + val s_0_1 = have((R(x), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s_0_1_0 = have((R(x), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s_0_0) } - val s_0_2 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { - val s_0_2_0 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters(R(x), x, x)(s_0_1) + val s_0_2 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s_0_2_0 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s_0_1) } - val s_0_3 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { - val s_0_3_0 = have(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall.withParameters((Q(x) ∧ R(x)), x)(s_0_2) + val s_0_3 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { + val s_0_3_0 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall(s_0_2) } - val s_0_4 = thenHave(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Restate + val s_0_4 = thenHave((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Restate } val s_1 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { val s_1_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { val s_1_0_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by Hypothesis } val s_1_1 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { - val s_1_1_0 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) subproof { - val s_1_1_0_0 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) by Restate + val s_1_1_0 = have((∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { + val s_1_1_0_0 = have((∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by Restate } val s_1_1_1 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) subproof { - val s_1_1_1_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters((Q(x) ∧ R(x)), x, x)(s_1_1_0) + val s_1_1_1_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall(s_1_1_0) } } val s_1_2 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) subproof { val s_1_2_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) by Weakening(s_1_1) } val s_1_3 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) subproof { - val s_1_3_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall.withParameters(Q(x), x)(s_1_2) + val s_1_3_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall(s_1_2) } val s_1_4 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) subproof { val s_1_4_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) by Weakening(s_1_1) } val s_1_5 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) subproof { - val s_1_5_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall.withParameters(R(x), x)(s_1_4) + val s_1_5_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall(s_1_4) } val s_1_6 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { - val s_1_6_0 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_1_3) - val s_1_6_1 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_1_5) - val s_1_6_2 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { - val s_1_6_2_0 = have(( ) ⊢ ⊤) by Restate - val s_1_6_2_1 = thenHave(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate + val s_1_6_0 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_1_3) + val s_1_6_1 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_1_5) + val s_1_6_2 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { + val s_1_6_2_0 = have(() ⊢ ⊤) by Restate + val s_1_6_2_1 = thenHave((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate } - val s_1_6_3 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))))(s_1_6_0, s_1_6_2) - val s_1_6_4 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))))(s_1_6_1, s_1_6_3) + val s_1_6_3 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s_1_6_0, s_1_6_2) + val s_1_6_4 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s_1_6_1, s_1_6_3) } val s_1_7 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate } - val s_2 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { - val s_2_0 = have(( ) ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_0) - val s_2_1 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_1) - val s_2_2 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { - val s_2_2_0 = have(( ) ⊢ ⊤) by Restate - val s_2_2_1 = thenHave(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate + val s_2 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { + val s_2_0 = have(() ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_0) + val s_2_1 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_1) + val s_2_2 = have((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { + val s_2_2_0 = have(() ⊢ ⊤) by Restate + val s_2_2_1 = + thenHave((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate } - val s_2_3 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut.withParameters(((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))))(s_2_0, s_2_2) - val s_2_4 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))))(s_2_1, s_2_3) + val s_2_3 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_2_0, s_2_2) + val s_2_4 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_2_1, s_2_3) } } val thm2_optimized = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { - val s_0 = have(( R(x), Q(x) ) ⊢ (Q(x) ∧ R(x))) by Restate - val s_1 = thenHave(( R(x), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters(Q(x), x, x) - val s_2 = thenHave(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters(R(x), x, x) - val s_3 = thenHave(( ∀(x, R(x)), ∀(x, Q(x)) ) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall.withParameters((Q(x) ∧ R(x)), x) - val s_4 = have(( ∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x)) ) ⊢ (Q(x) ∧ R(x))) by Restate - val s_5 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall.withParameters((Q(x) ∧ R(x)), x, x) + val s_0 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) by Restate + val s_1 = thenHave((R(x), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall + val s_2 = thenHave((∀(x, R(x)), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall + val s_3 = thenHave((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) by RightForall + val s_4 = have((∀(x, (Q(x) ∧ R(x))), (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by Restate + val s_5 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall val s_6 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ Q(x)) by Weakening - val s_7 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall.withParameters(Q(x), x) + val s_7 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall val s_8 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) by Weakening(s_5) - val s_9 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall.withParameters(R(x), x) - val s_10 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_7) - val s_11 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_9) - val s_12 = have(( ) ⊢ ⊤) by Restate - val s_13 = thenHave(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate - val s_14 = have(( ∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))) ) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))))(s_10, s_13) - val s_15 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x))))(s_11, s_14) - val s_16 = have(( ) ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_3) - val s_17 = have(( ) ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_15) - val s_18 = have(( ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_12) - val s_19 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut.withParameters(((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))))(s_16, s_18) - val s_20 = have(( ) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut.withParameters((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))))(s_17, s_19) + val s_9 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall + val s_10 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_7) + val s_11 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_9) + val s_12 = have(() ⊢ ⊤) by Restate + val s_13 = thenHave((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate + val s_14 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s_10, s_13) + val s_15 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s_11, s_14) + val s_16 = have(() ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_3) + val s_17 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_15) + val s_18 = + have((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_12) + val s_19 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_16, s_18) + val s_20 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_17, s_19) } - // This theorem requires instantiating the assumption twice, once with x and once with f(x), and then combine the two. // Since x is free is the sequent step1, then step 1 is true with anything substituted for x. // We can do such substitution with the "of" keyword. @@ -318,89 +306,151 @@ object MLExtract extends lisa.Main { have(thesis) by Tautology.from(step1, step1 of (x := f(x))) } - // println(prettyProof(thm3.proof)) - // println(prettySCProof(thm3.proof.toSCProof)) - // println(scproof2code(thm3.proof.toSCProof)) - // println(scproof2code(optimizeProofIteratively(thm3.proof.toSCProof))) + // println(prettyProof(thm3.highProof.get)) + // println(prettySCProof(thm3.kernelProof.get)) + // println(scproof2code(thm3.kernelProof.get)) + // println(scproof2code(optimizeProofIteratively(thm3.kernelProof.get))) val thm3_raw = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { val s_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) subproof { val s_0_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) by Hypothesis } val s_1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s_1_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s_1_0_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate + val s_1_0 = have((∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { + val s_1_0_0 = have((∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by Restate } val s_1_1 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) subproof { - val s_1_1_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall.withParameters((Q(x) ==> Q(f(x))), x, x)(s_1_0) + val s_1_1_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall(s_1_0) } } val s_2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) subproof { val s_2_0 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s_1) } val s_3 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { - val s_3_0 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) - val s_3_1 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) - val s_3_2 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { - val s_3_2_0 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s_3_2_1 = thenHave(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊤))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))))) - val s_3_2_2 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s_3_2_3 = thenHave(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by RightSubstIff(List(((Q(f(x))), (⊥))), lambda(Seq(MaRvIn_1), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))))) - val s_3_2_4 = thenHave(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate - val s_3_2_5 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut.withParameters(Q(f(x)))(s_3_2_4, s_3_2_1) - val s_3_2_6 = thenHave(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s_3_2_7 = thenHave(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate + val s_3_0 = have(() ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) + val s_3_1 = have(() ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) + val s_3_2 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { + val s_3_2_0 = have( + Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) + ) by Restate + val s_3_2_1 = thenHave( + Q(f(x)) ⊢ ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + ) + ) by RightSubstIff( + List(((Q(f(x))), (⊤))), + lambda( + Seq(MaRvIn_1), + ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬( + Q(f(f(x))) + )) + ) + ) + ) + val s_3_2_2 = have( + ¬(Q(f(x))) ⊢ ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + ) + ) by Restate + val s_3_2_3 = thenHave( + ¬(Q(f(x))) ⊢ ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + ) + ) by RightSubstIff( + List(((Q(f(x))), (⊥))), + lambda( + Seq(MaRvIn_1), + ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬( + Q(f(f(x))) + )) + ) + ) + ) + val s_3_2_4 = thenHave( + () ⊢ (Q(f(x)), ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + )) + ) by Restate + val s_3_2_5 = have( + () ⊢ ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + ) + ) by Cut(s_3_2_4, s_3_2_1) + val s_3_2_6 = thenHave( + () ⊢ ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + ) + ) by Restate + val s_3_2_7 = + thenHave((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate } - val s_3_3 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut.withParameters((∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))))(s_3_0, s_3_2) - val s_3_4 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut.withParameters((∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))))(s_3_1, s_3_3) + val s_3_3 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_3_0, s_3_2) + val s_3_4 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_3_1, s_3_3) } } val thm3_optimized = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { - val s_0 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x))) ) ⊢ (Q(x) ==> Q(f(x)))) by Restate - val s_1 = thenHave(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall.withParameters((Q(x) ==> Q(f(x))), x, x) + val s_0 = have((∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by Restate + val s_1 = thenHave(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall val s_2 = thenHave(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x))) - val s_3 = have(( ) ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) - val s_4 = have(( ) ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) - val s_5 = have(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s_6 = thenHave(Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s_7 = have(¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Restate - val s_8 = thenHave(( ) ⊢ ( Q(f(x)), ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) )) by Restate - val s_9 = have(( ) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))))) by Cut.withParameters(Q(f(x)))(s_8, s_6) - val s_10 = thenHave(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate - val s_11 = have(( ∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))) ) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut.withParameters((∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))))(s_3, s_10) - val s_12 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut.withParameters((∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x))))))(s_4, s_11) + val s_3 = have(() ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) + val s_4 = have(() ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) + val s_5 = have( + Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) + ) by Restate + val s_6 = thenHave( + Q(f(x)) ⊢ ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + ) + ) by Restate + val s_7 = have( + ¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) + ) by Restate + val s_8 = thenHave( + () ⊢ (Q(f(x)), ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + )) + ) by Restate + val s_9 = have( + () ⊢ ¬( + ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + ) + ) by Cut(s_8, s_6) + val s_10 = thenHave((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate + val s_11 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_3, s_10) + val s_12 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_4, s_11) } - val thm1bis = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { have(thesis) by Tableau } - // println(prettyProof(thm1bis.proof)) - // println(prettySCProof(thm1bis.proof.toSCProof)) - // println(scproof2code(thm1bis.proof.toSCProof)) - // println(scproof2code(optimizeProofIteratively(thm1bis.proof.toSCProof))) + // println(prettyProof(thm1bis.highProof.get)) + // println(prettySCProof(thm1bis.kernelProof.get)) + // println(scproof2code(thm1bis.kernelProof.get)) + // println(scproof2code(optimizeProofIteratively(thm1bis.kernelProof.get))) val thm1bis_raw = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { val s_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { - val s_0_0 = have(( S(x, y_1), ¬(S(x, y_1)) ) ⊢ ( )) by Restate - val s_0_1 = thenHave(( ¬(S(x, y_1)), ∀(y, S(x, y)) ) ⊢ ( )) by LeftForall.withParameters(S(x, y), y, y_1) - val s_0_2 = thenHave(( ∀(y, S(x, y)), ∀(x_2, ¬(S(x_2, y_1))) ) ⊢ ( )) by LeftForall.withParameters(¬(S(x_2, y_1)), x_2, x) - val s_0_3 = thenHave(( ∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y))) ) ⊢ ( )) by LeftExists.withParameters(∀(y, S(x, y)), x) - val s_0_4 = thenHave(( ∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1)))) ) ⊢ ( )) by LeftExists.withParameters(∀(x_2, ¬(S(x_2, y_1))), y_1) - val s_0_5 = thenHave((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ( )) by Weakening - val s_0_6 = thenHave((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ( )) by Weakening + val s_0_0 = have((S(x, y_1), ¬(S(x, y_1))) ⊢ ()) by Restate + val s_0_1 = thenHave((S(x, y_1), ∀(x_2, ¬(S(x_2, y_1)))) ⊢ ()) by LeftForall + val s_0_2 = thenHave((∀(x_2, ¬(S(x_2, y_1))), ∀(y, S(x, y))) ⊢ ()) by LeftForall + val s_0_3 = thenHave((∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y)))) ⊢ ()) by LeftExists + val s_0_4 = thenHave((∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ()) by LeftExists + val s_0_5 = thenHave((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ()) by Weakening + val s_0_6 = thenHave((∃(x, ∀(y, S(x, y))) ∧ ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ()) by Weakening val s_0_7 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by Restate } } val thm1bis_optimized = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { - val s_0 = have(( S(x, y_1), ¬(S(x, y_1)) ) ⊢ ( )) by Restate - val s_1 = thenHave(( ¬(S(x, y_1)), ∀(y, S(x, y)) ) ⊢ ( )) by LeftForall.withParameters(S(x, y), y, y_1) - val s_2 = thenHave(( ∀(y, S(x, y)), ∀(x_2, ¬(S(x_2, y_1))) ) ⊢ ( )) by LeftForall.withParameters(¬(S(x_2, y_1)), x_2, x) - val s_3 = thenHave(( ∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y))) ) ⊢ ( )) by LeftExists.withParameters(∀(y, S(x, y)), x) - val s_4 = thenHave(( ∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1)))) ) ⊢ ( )) by LeftExists.withParameters(∀(x_2, ¬(S(x_2, y_1))), y_1) + val s_0 = have((S(x, y_1), ¬(S(x, y_1))) ⊢ ()) by Restate + val s_1 = thenHave((S(x, y_1), ∀(x_2, ¬(S(x_2, y_1)))) ⊢ ()) by LeftForall + val s_2 = thenHave((∀(x_2, ¬(S(x_2, y_1))), ∀(y, S(x, y))) ⊢ ()) by LeftForall + val s_3 = thenHave((∀(x_2, ¬(S(x_2, y_1))), ∃(x, ∀(y, S(x, y)))) ⊢ ()) by LeftExists + val s_4 = thenHave((∃(x, ∀(y, S(x, y))), ∃(y_1, ∀(x_2, ¬(S(x_2, y_1))))) ⊢ ()) by LeftExists val s_5 = thenHave(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) by Restate } From f23659f1ea534debb588167d487ba90b5366cc4c Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:24 +0100 Subject: [PATCH 09/24] Refactor files --- build.sbt | 8 -- .../src/main/scala/Kernel2Code.scala | 122 +----------------- .../scala/lisa/utils/ProofsConverter.scala | 106 +++++++++++++++ 3 files changed, 109 insertions(+), 127 deletions(-) rename ml-extract/src/main/scala/main.scala => lisa-examples/src/main/scala/Kernel2Code.scala (76%) create mode 100644 lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala diff --git a/build.sbt b/build.sbt index 09a613beb..5b1996c96 100644 --- a/build.sbt +++ b/build.sbt @@ -110,11 +110,3 @@ lazy val examples = Project( .settings(commonSettings) .settings(commonSettings3) .dependsOn(root) - -lazy val mlextract = Project( - id = "ml-extract", - base = file("ml-extract") -) - .settings(commonSettings) - .settings(commonSettings3) - .dependsOn(root) diff --git a/ml-extract/src/main/scala/main.scala b/lisa-examples/src/main/scala/Kernel2Code.scala similarity index 76% rename from ml-extract/src/main/scala/main.scala rename to lisa-examples/src/main/scala/Kernel2Code.scala index 491a0c31b..b36bc6b23 100644 --- a/ml-extract/src/main/scala/main.scala +++ b/lisa-examples/src/main/scala/Kernel2Code.scala @@ -1,126 +1,10 @@ +import lisa.automation.Tableau +import lisa.utils.ProofsConverter.* import lisa.utils.parsing.ProofPrinter._ import lisa.utils.FOLPrinter.* -import lisa.kernel.proof.SequentCalculus.* -import lisa.utils.K -import lisa.prooflib.ProofTacticLib.* -import lisa.fol.FOLHelpers.* -import lisa.fol.FOL as F -import lisa.utils.KernelHelpers.lambda import lisa.utils.ProofsShrink.* -import lisa.automation.Tableau - -// TODO: fix printing of ∧ and ∨ with > 2 arguments, currently handled as recursive binary operators -// TODO: remove unnecessary variables "val s_..." in generated proofs -// TODO: generate more realistic variable names -// TODO: handle automatic global variable declaration before theorems/proofs - -def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = 0, varPrefix: String = "s"): String = { - def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], indent: Int, varPrefix: String): String = { - def sequent2code(sq: Sequent): String = asFront(sq).toString.replace("⇒", "==>").replace("⇔", "<=>") - def formula2code(form: K.Formula): String = asFront(form).toString.replace("⇒", "==>").replace("⇔", "<=>") - def term2code(term: K.Term): String = asFront(term).toString.replace("⇒", "==>").replace("⇔", "<=>") - - def index2stepvar(i: Int): String = - if i < -premises.size then throw new Exception(s"step $i is not defined") - else if i < 0 then premises(-i - 1) - else s"${varPrefix}_$i" - - val varDecl = " " * indent + s"val ${varPrefix}_$stepNum = " - ps match - case Sorry(_) => "sorry" - case sp @ SCSubproof(_, _) => - varDecl + s"have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"${varPrefix}_$stepNum") + "\n" + " " * indent + "}" - case _ => - var tacticName = ps.getClass.getSimpleName - var opening = "(" - var closing = ")" - val (bot_, step_ref_seq) = (ps match - case Restate(bot, t1) => - opening = ".from(" - (bot, Seq(t1)) - case RestateTrue(bot) => - tacticName = "Restate" - (bot, null) - case Hypothesis(bot, phi) => (bot, null) - case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2)) - case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1)) - case LeftOr(bot, t, disjuncts) => (bot, t) - case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) - case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1)) - case LeftNot(bot, t1, phi) => (bot, Seq(t1)) - case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1)) - case LeftExists(bot, t1, phi, x) => (bot, Seq(t1)) - case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) - case RightAnd(bot, t, conjuncts) => (bot, t) - case RightOr(bot, t1, phi, psi) => (bot, Seq(t1)) - case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1)) - case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) - case RightNot(bot, t1, phi) => (bot, Seq(t1)) - case RightForall(bot, t1, phi, x) => (bot, Seq(t1)) - case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1)) - case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) - case Weakening(bot, t1) => (bot, Seq(t1)) - case LeftRefl(bot, t1, phi) => (bot, Seq(t1)) - case RightRefl(bot, phi) => (bot, null) - case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) - case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) - case LeftSubstIff(bot, t1, equals, lambdaPhi) => - tacticName = s"LeftSubstIff(List(${equals - .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))" - (bot, Seq(t1)) - case RightSubstIff(bot, t1, equals, lambdaPhi) => - tacticName = s"RightSubstIff(List(${equals - .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))" - (bot, Seq(t1)) - case InstSchema(bot, t1, mCon, mPred, mTerm) => - if mCon.isEmpty && mPred.isEmpty then - tacticName = s"InstFunSchema(Map(${mTerm.toList - .map((k, v) => s"${asFrontLabel(k)} -> ${term2code(v.body)}") - .mkString(", ")}))" - (bot, Seq(t1)) - else if mCon.isEmpty && mTerm.isEmpty then - tacticName = s"InstPredSchema(Map(${mPred.toList - .map((k, v) => s"${asFrontLabel(k)} -> ${formula2code(v.body)}") - .mkString(", ")}))" - (bot, Seq(t1)) - else throw new Exception("InstSchema not implemented") - case _ => throw new Exception(s"Tactic ${ps.getClass.getName} not implemented") - ) - - varDecl + ( - if (step_ref_seq != null && step_ref_seq.size == 1 && stepNum > 0 && step_ref_seq.head + 1 == stepNum) - then s"thenHave(${sequent2code(bot_)}) by $tacticName" - else - s"have(${sequent2code(bot_)}) by $tacticName" + ( - if step_ref_seq == null then "" - else s"$opening${step_ref_seq.map(index2stepvar).mkString(", ")}$closing" - ) - ) - } - - p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i, premises, indent, varPrefix)).mkString("\n") -} - -object MLExtract extends lisa.Main { - - /* - You may use the following tactics: - - Restate | "Trivially" true Sequent. Deals with alpha equivalence and most propositional rules but not distributivity - - Weakening | "Trivially" weaker sequent (than the previous one). - - Tautology.from | Anything that can be solved by propositional reasoning alone - - - LeftForall | To introduce a ∀ quantifier in an assumption - - LeftExists | To introduce a ∃ quantifier in an assumption (the variable must not be free somewhere else) - - RightForall | To introduce a ∀ quantifier in the conclusion (the variable must not be free somewhere else) - - RightExists | To introduce a ∃ quantifier in the conclusion - - InstantiateForall | To obtain a formula of the form P(t) from a quantified assumption ∀(x, P(x)) - - - thm1 and thm2 illustrate how those tactics can be used, as well as the usage of "assume", "have", "thenHave", "by", "thesis", "of" and "subproof". - */ +object Kernel2Code extends lisa.Main { val x = variable val y = variable diff --git a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala new file mode 100644 index 000000000..aa7d9efbf --- /dev/null +++ b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala @@ -0,0 +1,106 @@ +package lisa.utils + +import lisa.kernel.proof.SequentCalculus.* +import lisa.utils.K +import lisa.prooflib.ProofTacticLib.* +import lisa.fol.FOLHelpers.* +import lisa.fol.FOL as F +import lisa.utils.KernelHelpers.lambda + +object ProofsConverter { + +// TODO: fix printing of ∧ and ∨ with > 2 arguments, currently handled as recursive binary operators +// TODO: remove unnecessary variables "val s_..." in generated proofs -> need to keep track of which steps are used in other steps +// TODO: generate more realistic variable names +// TODO: handle automatic global variable declaration before theorems/proofs + + def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = 0, varPrefix: String = "s"): String = { + def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], indent: Int, varPrefix: String): String = { + def sequent2code(sq: Sequent): String = asFront(sq).toString.replace("⇒", "==>").replace("⇔", "<=>") + def formula2code(form: K.Formula): String = asFront(form).toString.replace("⇒", "==>").replace("⇔", "<=>") + def term2code(term: K.Term): String = asFront(term).toString.replace("⇒", "==>").replace("⇔", "<=>") + + def index2stepvar(i: Int): String = + if i < -premises.size then throw new Exception(s"step $i is not defined") + else if i < 0 then premises(-i - 1) + else s"${varPrefix}_$i" + + val varDecl = " " * indent + s"val ${varPrefix}_$stepNum = " + ps match + case Sorry(_) => "sorry" + case sp @ SCSubproof(_, _) => + varDecl + s"have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"${varPrefix}_$stepNum") + "\n" + " " * indent + "}" + case _ => + var tacticName = ps.getClass.getSimpleName + var opening = "(" + var closing = ")" + val (bot_, step_ref_seq) = (ps match + case Restate(bot, t1) => + opening = ".from(" + (bot, Seq(t1)) + case RestateTrue(bot) => + tacticName = "Restate" + (bot, null) + case Hypothesis(bot, phi) => (bot, null) + case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2)) + case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1)) + case LeftOr(bot, t, disjuncts) => (bot, t) + case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) + case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1)) + case LeftNot(bot, t1, phi) => (bot, Seq(t1)) + case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1)) + case LeftExists(bot, t1, phi, x) => (bot, Seq(t1)) + case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) + case RightAnd(bot, t, conjuncts) => (bot, t) + case RightOr(bot, t1, phi, psi) => (bot, Seq(t1)) + case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1)) + case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) + case RightNot(bot, t1, phi) => (bot, Seq(t1)) + case RightForall(bot, t1, phi, x) => (bot, Seq(t1)) + case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1)) + case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) + case Weakening(bot, t1) => (bot, Seq(t1)) + case LeftRefl(bot, t1, phi) => (bot, Seq(t1)) + case RightRefl(bot, phi) => (bot, null) + case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) + case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) + case LeftSubstIff(bot, t1, equals, lambdaPhi) => + tacticName = s"LeftSubstIff(List(${equals + .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))" + (bot, Seq(t1)) + case RightSubstIff(bot, t1, equals, lambdaPhi) => + tacticName = s"RightSubstIff(List(${equals + .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))" + (bot, Seq(t1)) + case InstSchema(bot, t1, mCon, mPred, mTerm) => + if mCon.isEmpty && mPred.isEmpty then + tacticName = s"InstFunSchema(Map(${mTerm.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${term2code(v.body)}") + .mkString(", ")}))" + (bot, Seq(t1)) + else if mCon.isEmpty && mTerm.isEmpty then + tacticName = s"InstPredSchema(Map(${mPred.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${formula2code(v.body)}") + .mkString(", ")}))" + (bot, Seq(t1)) + else throw new Exception("InstSchema not implemented") + case _ => throw new Exception(s"Tactic ${ps.getClass.getName} not implemented") + ) + + varDecl + ( + if (step_ref_seq != null && step_ref_seq.size == 1 && stepNum > 0 && step_ref_seq.head + 1 == stepNum) + then s"thenHave(${sequent2code(bot_)}) by $tacticName" + else + s"have(${sequent2code(bot_)}) by $tacticName" + ( + if step_ref_seq == null then "" + else s"$opening${step_ref_seq.map(index2stepvar).mkString(", ")}$closing" + ) + ) + } + + p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i, premises, indent, varPrefix)).mkString("\n") + } + +} From 392b1d6e41fbbb0a12669ec2ada5f6993b2cb3e5 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:24 +0100 Subject: [PATCH 10/24] Update + fix TPTP problem parser --- .gitignore | 3 ++ .../scala/lisa/utils/tptp/KernelParser.scala | 44 ++++++++++++++----- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 1727a24e8..90ddd1034 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ cache # data extracted data_extract + +# TPTP data +lisa-utils/src/main/resources diff --git a/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala b/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala index 18202949f..ee57f4ae3 100644 --- a/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala +++ b/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala @@ -10,6 +10,7 @@ import lisa.utils.KernelHelpers.* import lisa.utils.KernelHelpers.given_Conversion_Identifier_String import lisa.utils.KernelHelpers.given_Conversion_String_Identifier import lisa.utils.tptp.* +import lisa.kernel.fol.FOL.* import java.io.File import scala.util.matching.Regex @@ -26,13 +27,15 @@ object KernelParser { */ def parseToKernel(formula: String): K.Formula = convertToKernel(Parser.fof(formula)) + def cleanVarname(f: String): String = f.replaceAll(Identifier.counterSeparator.toString, "") + /** * @param formula a tptp formula in leo parser * @return the same formula in LISA */ def convertToKernel(formula: FOF.Formula): K.Formula = { formula match { - case FOF.AtomicFormula(f, args) => K.AtomicFormula(K.ConstantAtomicLabel(f, args.size), args map convertTermToKernel) + case FOF.AtomicFormula(f, args) => K.AtomicFormula(K.ConstantAtomicLabel(cleanVarname(f), args.size), args map convertTermToKernel) case FOF.QuantifiedFormula(quantifier, variableList, body) => quantifier match { case FOF.! => variableList.foldRight(convertToKernel(body))((s, f) => K.Forall(K.VariableLabel(s), f)) @@ -63,8 +66,8 @@ object KernelParser { K.ConnectorFormula( K.Or, formula.map { - case CNF.PositiveAtomic(formula) => K.AtomicFormula(K.ConstantAtomicLabel(formula.f, formula.args.size), formula.args.map(convertTermToKernel).toList) - case CNF.NegativeAtomic(formula) => !K.AtomicFormula(K.ConstantAtomicLabel(formula.f, formula.args.size), formula.args.map(convertTermToKernel).toList) + case CNF.PositiveAtomic(formula) => K.AtomicFormula(K.ConstantAtomicLabel(cleanVarname(formula.f), formula.args.size), formula.args.map(convertTermToKernel).toList) + case CNF.NegativeAtomic(formula) => !K.AtomicFormula(K.ConstantAtomicLabel(cleanVarname(formula.f), formula.args.size), formula.args.map(convertTermToKernel).toList) case CNF.Equality(left, right) => K.equality(convertTermToKernel(left), convertTermToKernel(right)) case CNF.Inequality(left, right) => !K.equality(convertTermToKernel(left), convertTermToKernel(right)) } @@ -76,7 +79,7 @@ object KernelParser { * @return the same term in LISA */ def convertTermToKernel(term: CNF.Term): K.Term = term match { - case CNF.AtomicTerm(f, args) => K.Term(K.ConstantFunctionLabel(f, args.size), args map convertTermToKernel) + case CNF.AtomicTerm(f, args) => K.Term(K.ConstantFunctionLabel(cleanVarname(f), args.size), args map convertTermToKernel) case CNF.Variable(name) => K.VariableTerm(K.VariableLabel(name)) case CNF.DistinctObject(name) => ??? } @@ -87,7 +90,7 @@ object KernelParser { */ def convertTermToKernel(term: FOF.Term): K.Term = term match { case FOF.AtomicTerm(f, args) => - K.Term(K.ConstantFunctionLabel(f, args.size), args map convertTermToKernel) + K.Term(K.ConstantFunctionLabel(cleanVarname(f), args.size), args map convertTermToKernel) case FOF.Variable(name) => K.VariableTerm(K.VariableLabel(name)) case FOF.DistinctObject(name) => ??? case FOF.NumberTerm(value) => ??? @@ -174,11 +177,15 @@ object KernelParser { if (d.isDirectory) { if (d.listFiles().isEmpty) println("empty directory") d.listFiles.filter(_.isDirectory) - } else throw new Exception("Specified path is not a directory.") } else throw new Exception("Specified path does not exist.") - probfiles.map(d => gatherFormulas(spc, d.getPath)).toSeq + probfiles.zipWithIndex + .map((d, i) => { + println("[ " + (i + 1) + " / " + probfiles.size + " ] Gathering formulas from " + d.getName()) + gatherFormulas(spc, d.getPath) + }) + .toSeq } def gatherFormulas(spc: Seq[String], path: String): Seq[Problem] = { @@ -187,14 +194,27 @@ object KernelParser { if (d.isDirectory) { if (d.listFiles().isEmpty) println("empty directory") d.listFiles.filter(_.isFile) - } else throw new Exception("Specified path is not a directory.") } else throw new Exception("Specified path does not exist.") - val r = probfiles.foldRight(List.empty[Problem])((p, current) => { - val md = getProblemInfos(p) - if (md.spc.exists(spc.contains)) problemToKernel(p, md) :: current - else current + val r = probfiles.zipWithIndex.foldLeft(List.empty[Problem])((current, p_i) => { + val (p, i) = p_i + + // Progress bar + if ((i + 1) % 100 == 0 || i + 1 == probfiles.size) { + val pbarLength = 30 + var pbarContent = "=" * (((i + 1) * pbarLength) / probfiles.size) + pbarContent += " " * (pbarLength - pbarContent.length) + println("\t[" + pbarContent + "] (" + (i + 1) + " / " + probfiles.size + ") " + d.getName()) + } + + try { + val md = getProblemInfos(p) + if (md.spc.exists(spc.contains)) current :+ problemToKernel(p, md) + else current + } catch { + case _ => current + } }) r } From b1b6308b18fcfb92a072bbf58099c8ece53f60a7 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:24 +0100 Subject: [PATCH 11/24] Add TPTPSolver class for solving problems from TPTP library using Tableau tactic --- lisa-examples/src/main/scala/TPTPSolver.scala | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 lisa-examples/src/main/scala/TPTPSolver.scala diff --git a/lisa-examples/src/main/scala/TPTPSolver.scala b/lisa-examples/src/main/scala/TPTPSolver.scala new file mode 100644 index 000000000..1aaf526e8 --- /dev/null +++ b/lisa-examples/src/main/scala/TPTPSolver.scala @@ -0,0 +1,141 @@ +import scala.concurrent.duration._ +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent._ +import java.util.concurrent.CancellationException + +import lisa.utils.tptp.Example.* +import lisa.utils.tptp.KernelParser.annotatedFormulaToKernel +import lisa.utils.tptp.KernelParser.parseToKernel +import lisa.utils.tptp.KernelParser.problemToSequent +import lisa.utils.tptp.ProblemGatherer.getPRPproblems +import lisa.utils.ProofsConverter.* + +object TPTPSolver extends lisa.Main { + try { + println("Fetching problems from TPTP library...") + val probs = getPRPproblems + + println("Number of problems found: " + probs.size) + + // We limit the execution time to solve each problem + val timeoutTableau = 1.second + val timeoutTautology = 1.second + + var tableauProofs = List[Option[SCProof]]() + var tautologyProofs = List[Option[SCProof]]() + + for ((p, i) <- probs.zipWithIndex) { + // Progress bar + if ((i + 1) % 10 == 0 || i + 1 == probs.size) { + val pbarLength = 30 + var pbarContent = "=" * (((i + 1) * pbarLength) / probs.size) + pbarContent += " " * (pbarLength - pbarContent.length) + print("[" + pbarContent + "]") + print(" -- Processed " + (i + 1) + "/" + probs.size) + print(" -- " + tableauProofs.count(_.isDefined) + " solved by Tableau") + println(" -- " + tautologyProofs.count(_.isDefined) + " solved by Tautology") + } + + val seq = problemToSequent(p) + + // Attempting proof by Tableau + val (futureTableau, cancelTableau) = Future.interruptibly { Tableau.solve(seq) } + tableauProofs = tableauProofs :+ ( + try Await.result(futureTableau, timeoutTableau) + catch + case _ => + cancelTableau() + None + ) + + // Attempting proof by Tautology + val (futureTautology, cancelTautology) = Future.interruptibly { + Tautology.solveSequent(seq) match + case Left(proof) => Some(proof) + case _ => None + } + tautologyProofs = tautologyProofs :+ ( + try Await.result(futureTautology, timeoutTautology) + catch + case _ => + cancelTautology() + None + ) + } + } catch { + case error: NullPointerException => println("You can download the tptp library at http://www.tptp.org/ and put it in main/resources") + } +} + +final class Interrupt extends (() => Boolean) { + // We need a state-machine to track the progress. + // It can have the following states: + // a null reference means execution has not started. + // a Thread reference means that the execution has started but is not done. + // a this reference means that it is already cancelled or is already too late. + private[this] final var state: AnyRef = null + + /** + * This is the signal to cancel the execution of the logic. + * Returns whether the cancellation signal was successully issued or not. + */ + override final def apply(): Boolean = this.synchronized { + state match { + case null => + state = this + true + case _: this.type => false + case t: Thread => + state = this + // t.interrupt() + t.stop() + true + } + } + + // Initializes right before execution of logic and + // allows to not run the logic at all if already cancelled. + private[this] final def enter(): Boolean = + this.synchronized { + state match { + case _: this.type => false + case null => + state = Thread.currentThread + true + } + } + + // Cleans up after the logic has executed + // Prevents cancellation to occur "too late" + private[this] final def exit(): Boolean = + this.synchronized { + state match { + case _: this.type => false + case t: Thread => + state = this + true + } + } + + /** + * Executes the suplied block of logic and returns the result. + * Throws CancellationException if the block was interrupted. + */ + def interruptibly[T](block: => T): T = + if (enter()) { + try block + catch { + case ie: InterruptedException => throw new CancellationException() + } finally { + if (!exit() && Thread.interrupted()) + () // If we were interrupted and flag was not cleared + } + } else throw new CancellationException() +} + +implicit class FutureInterrupt(val future: Future.type) extends AnyVal { + def interruptibly[T](block: => T)(implicit ec: ExecutionContext): (Future[T], () => Boolean) = { + val interrupt = new Interrupt() + (Future(interrupt.interruptibly(block))(ec), interrupt) + } +} From 0799347b8e166611555c1c4a7e1e773f925d9701 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:25 +0100 Subject: [PATCH 12/24] Update TPTP problem solver code --- lisa-examples/src/main/scala/TPTPSolver.scala | 121 ++++++++++++------ .../scala/lisa/utils/tptp/KernelParser.scala | 21 +-- .../lisa/utils/tptp/ProblemGatherer.scala | 21 ++- 3 files changed, 100 insertions(+), 63 deletions(-) diff --git a/lisa-examples/src/main/scala/TPTPSolver.scala b/lisa-examples/src/main/scala/TPTPSolver.scala index 1aaf526e8..98ea5f19a 100644 --- a/lisa-examples/src/main/scala/TPTPSolver.scala +++ b/lisa-examples/src/main/scala/TPTPSolver.scala @@ -2,71 +2,108 @@ import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent._ import java.util.concurrent.CancellationException +import java.io.File -import lisa.utils.tptp.Example.* -import lisa.utils.tptp.KernelParser.annotatedFormulaToKernel -import lisa.utils.tptp.KernelParser.parseToKernel -import lisa.utils.tptp.KernelParser.problemToSequent -import lisa.utils.tptp.ProblemGatherer.getPRPproblems +import lisa.utils.tptp.* +import lisa.utils.tptp.KernelParser.* +import lisa.utils.tptp.KernelParser.getProblemInfos +import lisa.utils.tptp.ProblemGatherer.* import lisa.utils.ProofsConverter.* +import lisa.kernel.proof.SCProof +import java.io.FileWriter +import lisa.kernel.proof.SequentCalculus.Sequent object TPTPSolver extends lisa.Main { try { - println("Fetching problems from TPTP library...") - val probs = getPRPproblems + val spc = Seq("PRP", "FOF") // type of problems we want to extract and solve + // val spc = Seq("PRP", "FOF", "CNF") // almost no CNF problems are solved by Tableau, TODO: investigate why - println("Number of problems found: " + probs.size) + // val d = new File(TPTPProblemPath) + // val libraries = d.listFiles.filter(_.isDirectory) + // val probfiles = libraries.flatMap(_.listFiles).filter(_.isFile) + + val d = new File(TPTPProblemPath + "SYN/") + val probfiles = d.listFiles.filter(_.isFile) // We limit the execution time to solve each problem - val timeoutTableau = 1.second - val timeoutTautology = 1.second + val timeoutTableau = .2.second + val timeoutTautology = .2.second - var tableauProofs = List[Option[SCProof]]() - var tautologyProofs = List[Option[SCProof]]() + var problems = List[Problem]() + var tableauProofs = List[SolverResult]() + var tautologyProofs = List[SolverResult]() - for ((p, i) <- probs.zipWithIndex) { + for ((probfile, i) <- probfiles.zipWithIndex) { // Progress bar - if ((i + 1) % 10 == 0 || i + 1 == probs.size) { + if ((i + 1) % 10 == 0 || i + 1 == probfiles.size) { val pbarLength = 30 - var pbarContent = "=" * (((i + 1) * pbarLength) / probs.size) + var pbarContent = "=" * (((i + 1) * pbarLength) / probfiles.size) pbarContent += " " * (pbarLength - pbarContent.length) print("[" + pbarContent + "]") - print(" -- Processed " + (i + 1) + "/" + probs.size) - print(" -- " + tableauProofs.count(_.isDefined) + " solved by Tableau") - println(" -- " + tautologyProofs.count(_.isDefined) + " solved by Tautology") + print(" -- " + (i + 1) + "/" + probfiles.size + " processed files") + print(" -- " + problems.size + " extracted problems") + print(" -- Tableau: " + tableauProofs.count(_.isInstanceOf[Solved]) + " solved") + println(" -- Tautology: " + tautologyProofs.count(_.isInstanceOf[Solved]) + " solved") } - val seq = problemToSequent(p) - - // Attempting proof by Tableau - val (futureTableau, cancelTableau) = Future.interruptibly { Tableau.solve(seq) } - tableauProofs = tableauProofs :+ ( - try Await.result(futureTableau, timeoutTableau) - catch - case _ => - cancelTableau() - None - ) - - // Attempting proof by Tautology - val (futureTautology, cancelTautology) = Future.interruptibly { - Tautology.solveSequent(seq) match - case Left(proof) => Some(proof) - case _ => None + // Try to extract the problem + try { + val md = getProblemInfos(probfile) + if (md.spc.exists(spc.contains)) { + val p = problemToKernel(probfile, md) + problems = problems :+ p + val seq = problemToSequent(p) + + // Attempting proof by Tableau + tableauProofs = tableauProofs :+ solveProblem(p, timeoutTableau, Tableau.solve) + + // Attempting proof by Tautology + def tautologySolver(s: lisa.utils.K.Sequent): Option[SCProof] = Tautology.solveSequent(s) match + case Left(proof) => Some(proof) + case _ => None + tautologyProofs = tautologyProofs :+ solveProblem(p, timeoutTautology, tautologySolver) + } + } catch { + case _ => () } - tautologyProofs = tautologyProofs :+ ( - try Await.result(futureTautology, timeoutTautology) - catch - case _ => - cancelTautology() - None - ) + } } catch { case error: NullPointerException => println("You can download the tptp library at http://www.tptp.org/ and put it in main/resources") } } +sealed trait SolverResult +case class Solved(proof: SCProof) extends SolverResult +case object Unsolved extends SolverResult +case object Timeout extends SolverResult +case object Error extends SolverResult + +def solveProblem(problem: Problem, timeout: FiniteDuration, solver: Sequent => Option[SCProof]): SolverResult = { + val seq = problemToSequent(problem) + val (futureSolver, cancelSolver) = Future.interruptibly { solver(seq) } + try + Await.result(futureSolver, timeout) match + case Some(proof) => Solved(proof) + case None => Unsolved + catch + case e: TimeoutException => + cancelSolver() + Timeout + case _ => + cancelSolver() + Error +} + +def writeProof(problem: Problem, proof: SCProof, path: String): Unit = { + // TODO + val file = new File(path + problem.name + ".sc") + val bw = new FileWriter(file) + val proofCode = scproof2code(proof) + bw.write(proof.toString) + bw.close() +} + final class Interrupt extends (() => Boolean) { // We need a state-machine to track the progress. // It can have the following states: diff --git a/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala b/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala index ee57f4ae3..c0c4ceaea 100644 --- a/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala +++ b/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala @@ -19,7 +19,7 @@ import Parser.TPTPParseException object KernelParser { - private case class ProblemMetadata(file: String, domain: String, problem: String, status: String, spc: Seq[String]) + case class ProblemMetadata(file: String, domain: String, problem: String, status: String, spc: Seq[String]) /** * @param formula A formula in the tptp language @@ -107,13 +107,8 @@ object KernelParser { } } - private def problemToKernel(problemFile: File, md: ProblemMetadata): Problem = { + def problemToKernel(problemFile: File, md: ProblemMetadata): Problem = { val file = io.Source.fromFile(problemFile) - val pattern = "SPC\\s*:\\s*[A-z]{3}(_[A-z]{3})*".r - val g = file.getLines() - - def search(): String = pattern.findFirstIn(g.next()).getOrElse(search()) - val i = Parser.problem(file) val sq = i.formulas map { case TPTP.FOFAnnotated(name, role, formula, annotations) => @@ -208,13 +203,9 @@ object KernelParser { println("\t[" + pbarContent + "] (" + (i + 1) + " / " + probfiles.size + ") " + d.getName()) } - try { - val md = getProblemInfos(p) - if (md.spc.exists(spc.contains)) current :+ problemToKernel(p, md) - else current - } catch { - case _ => current - } + val md = getProblemInfos(p) + if (md.spc.exists(spc.contains)) current :+ problemToKernel(p, md) + else current }) r } @@ -223,7 +214,7 @@ object KernelParser { * @param file a file containing a tptp problem * @return the metadata info (file name, domain, problem, status and spc) in the file */ - private def getProblemInfos(file: File): ProblemMetadata = { + def getProblemInfos(file: File): ProblemMetadata = { val pattern = "((File)|(Domain)|(Problem)|(Status)|(SPC))\\s*:.*".r val s = io.Source.fromFile(file) val g = s.getLines() diff --git a/lisa-utils/src/main/scala/lisa/utils/tptp/ProblemGatherer.scala b/lisa-utils/src/main/scala/lisa/utils/tptp/ProblemGatherer.scala index b635c5a72..2f87e96b4 100644 --- a/lisa-utils/src/main/scala/lisa/utils/tptp/ProblemGatherer.scala +++ b/lisa-utils/src/main/scala/lisa/utils/tptp/ProblemGatherer.scala @@ -3,14 +3,23 @@ package lisa.utils.tptp import lisa.utils.tptp.KernelParser.* object ProblemGatherer { + // Path to the TPTP problems directory + // val path = getClass.getResource("/TPTP/Problems/").getPath + val TPTPProblemPath = "/home/auguste/Documents/EPFL/PhD/Projects/TPTP-v8.2.0/Problems/" /** - * The tptp library needs to be included in main/resources. It can be found at http://www.tptp.org/ - * @return sequence of tptp problems with the PRP (propositional) tag. + * @return sequence of tptp problems in the library lib with the tags in spc. + */ + def getLibProblems(spc: Seq[String], lib: String): Seq[Problem] = gatherFormulas(spc, TPTPProblemPath + lib + "/") + + /** + * This takes up to several minutes to run. + * @return sequence of all tptp problems with the tags in spc. */ - def getPRPproblems: Seq[Problem] = { - val path = getClass.getResource("/TPTP/Problems/SYN/").getPath - gatherFormulas(Seq("PRP"), path) - } + def getAllProblems(spc: Seq[String]): Seq[Problem] = gatherAllTPTPFormulas(spc, TPTPProblemPath).flatten + /** + * @return sequence of tptp problems with the PRP (propositional) tag. + */ + def getPRPproblems: Seq[Problem] = getLibProblems(Seq("PRP"), "SYN") } From cdd2c12c42217791c0af702d27fe2ba48df99139 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:25 +0100 Subject: [PATCH 13/24] Separate the solver runner logic from the TPTP data extraction --- lisa-examples/src/main/scala/TPTPSolver.scala | 146 ++++-------------- .../scala/lisa/utils/ProofsConverter.scala | 2 +- .../src/main/scala/lisa/utils/RunSolver.scala | 110 +++++++++++++ 3 files changed, 140 insertions(+), 118 deletions(-) create mode 100644 lisa-utils/src/main/scala/lisa/utils/RunSolver.scala diff --git a/lisa-examples/src/main/scala/TPTPSolver.scala b/lisa-examples/src/main/scala/TPTPSolver.scala index 98ea5f19a..796787a46 100644 --- a/lisa-examples/src/main/scala/TPTPSolver.scala +++ b/lisa-examples/src/main/scala/TPTPSolver.scala @@ -1,16 +1,14 @@ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent._ -import java.util.concurrent.CancellationException import java.io.File +import java.io.FileWriter + +import scala.concurrent.duration._ +import lisa.utils.ProofsConverter.* +import lisa.utils.RunSolver.* import lisa.utils.tptp.* import lisa.utils.tptp.KernelParser.* -import lisa.utils.tptp.KernelParser.getProblemInfos import lisa.utils.tptp.ProblemGatherer.* -import lisa.utils.ProofsConverter.* import lisa.kernel.proof.SCProof -import java.io.FileWriter import lisa.kernel.proof.SequentCalculus.Sequent object TPTPSolver extends lisa.Main { @@ -26,12 +24,12 @@ object TPTPSolver extends lisa.Main { val probfiles = d.listFiles.filter(_.isFile) // We limit the execution time to solve each problem - val timeoutTableau = .2.second - val timeoutTautology = .2.second + val timeoutTableau = .1.second + val timeoutTautology = .1.second - var problems = List[Problem]() - var tableauProofs = List[SolverResult]() - var tautologyProofs = List[SolverResult]() + var nbProblemsExtracted = 0 + var nbProblemsSolvedByTableau = 0 + var nbProblemsSolvedByTautology = 0 for ((probfile, i) <- probfiles.zipWithIndex) { // Progress bar @@ -39,62 +37,49 @@ object TPTPSolver extends lisa.Main { val pbarLength = 30 var pbarContent = "=" * (((i + 1) * pbarLength) / probfiles.size) pbarContent += " " * (pbarLength - pbarContent.length) - print("[" + pbarContent + "]") - print(" -- " + (i + 1) + "/" + probfiles.size + " processed files") - print(" -- " + problems.size + " extracted problems") - print(" -- Tableau: " + tableauProofs.count(_.isInstanceOf[Solved]) + " solved") - println(" -- Tautology: " + tautologyProofs.count(_.isInstanceOf[Solved]) + " solved") + print(s"[$pbarContent]") + print(s" -- ${i + 1}/${probfiles.size} processed files") + print(s" -- $nbProblemsExtracted extracted problems") + print(s" -- Tableau: $nbProblemsSolvedByTableau solved") + println(s" -- Tautology: $nbProblemsSolvedByTautology solved") } - // Try to extract the problem + // Try to extract and solve the problem try { val md = getProblemInfos(probfile) if (md.spc.exists(spc.contains)) { val p = problemToKernel(probfile, md) - problems = problems :+ p val seq = problemToSequent(p) + nbProblemsExtracted += 1 // Attempting proof by Tableau - tableauProofs = tableauProofs :+ solveProblem(p, timeoutTableau, Tableau.solve) + proveSequent(seq, timeoutTableau, Tableau.solve) match { + case Solved(proof) => + nbProblemsSolvedByTableau += 1 + // writeProof(p, proof, "examples/proofs/tableau/") + case _ => () + } // Attempting proof by Tautology def tautologySolver(s: lisa.utils.K.Sequent): Option[SCProof] = Tautology.solveSequent(s) match case Left(proof) => Some(proof) case _ => None - tautologyProofs = tautologyProofs :+ solveProblem(p, timeoutTautology, tautologySolver) + proveSequent(seq, timeoutTautology, tautologySolver) match { + case Solved(proof) => + nbProblemsSolvedByTautology += 1 + // writeProof(p, proof, "examples/proofs/tautology/") + case _ => () + } } } catch { case _ => () } - } } catch { case error: NullPointerException => println("You can download the tptp library at http://www.tptp.org/ and put it in main/resources") } } -sealed trait SolverResult -case class Solved(proof: SCProof) extends SolverResult -case object Unsolved extends SolverResult -case object Timeout extends SolverResult -case object Error extends SolverResult - -def solveProblem(problem: Problem, timeout: FiniteDuration, solver: Sequent => Option[SCProof]): SolverResult = { - val seq = problemToSequent(problem) - val (futureSolver, cancelSolver) = Future.interruptibly { solver(seq) } - try - Await.result(futureSolver, timeout) match - case Some(proof) => Solved(proof) - case None => Unsolved - catch - case e: TimeoutException => - cancelSolver() - Timeout - case _ => - cancelSolver() - Error -} - def writeProof(problem: Problem, proof: SCProof, path: String): Unit = { // TODO val file = new File(path + problem.name + ".sc") @@ -103,76 +88,3 @@ def writeProof(problem: Problem, proof: SCProof, path: String): Unit = { bw.write(proof.toString) bw.close() } - -final class Interrupt extends (() => Boolean) { - // We need a state-machine to track the progress. - // It can have the following states: - // a null reference means execution has not started. - // a Thread reference means that the execution has started but is not done. - // a this reference means that it is already cancelled or is already too late. - private[this] final var state: AnyRef = null - - /** - * This is the signal to cancel the execution of the logic. - * Returns whether the cancellation signal was successully issued or not. - */ - override final def apply(): Boolean = this.synchronized { - state match { - case null => - state = this - true - case _: this.type => false - case t: Thread => - state = this - // t.interrupt() - t.stop() - true - } - } - - // Initializes right before execution of logic and - // allows to not run the logic at all if already cancelled. - private[this] final def enter(): Boolean = - this.synchronized { - state match { - case _: this.type => false - case null => - state = Thread.currentThread - true - } - } - - // Cleans up after the logic has executed - // Prevents cancellation to occur "too late" - private[this] final def exit(): Boolean = - this.synchronized { - state match { - case _: this.type => false - case t: Thread => - state = this - true - } - } - - /** - * Executes the suplied block of logic and returns the result. - * Throws CancellationException if the block was interrupted. - */ - def interruptibly[T](block: => T): T = - if (enter()) { - try block - catch { - case ie: InterruptedException => throw new CancellationException() - } finally { - if (!exit() && Thread.interrupted()) - () // If we were interrupted and flag was not cleared - } - } else throw new CancellationException() -} - -implicit class FutureInterrupt(val future: Future.type) extends AnyVal { - def interruptibly[T](block: => T)(implicit ec: ExecutionContext): (Future[T], () => Boolean) = { - val interrupt = new Interrupt() - (Future(interrupt.interruptibly(block))(ec), interrupt) - } -} diff --git a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala index aa7d9efbf..26c510a59 100644 --- a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala +++ b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala @@ -9,7 +9,7 @@ import lisa.utils.KernelHelpers.lambda object ProofsConverter { -// TODO: fix printing of ∧ and ∨ with > 2 arguments, currently handled as recursive binary operators +// TODO: fix printing of ∧ and ∨ with > 2 arguments, currently handled as recursive binary operators (see FOLHelpers.scala) // TODO: remove unnecessary variables "val s_..." in generated proofs -> need to keep track of which steps are used in other steps // TODO: generate more realistic variable names // TODO: handle automatic global variable declaration before theorems/proofs diff --git a/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala b/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala new file mode 100644 index 000000000..18d4c45a4 --- /dev/null +++ b/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala @@ -0,0 +1,110 @@ +package lisa.utils + +import scala.concurrent.duration._ +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent._ +import java.util.concurrent.CancellationException + +import lisa.kernel.proof.SCProof +import lisa.kernel.proof.SequentCalculus.Sequent + +object RunSolver { + sealed trait SolverResult + case class Solved(proof: SCProof) extends SolverResult + case object Unsolved extends SolverResult + case object Timeout extends SolverResult + case class SolverException(e: Exception) extends SolverResult + + def proveSequent(sequent: Sequent, timeout: Duration, solver: Sequent => Option[SCProof]): SolverResult = { + val (futureSolver, cancelSolver) = Future.interruptibly { solver(sequent) } + try + Await.result(futureSolver, timeout) match + case Some(proof) => Solved(proof) + case None => Unsolved + catch + case _: TimeoutException => + cancelSolver() + Timeout + case e: Exception => + cancelSolver() + SolverException(e) + } + + // Class to handle future cancellation + // Source: https://viktorklang.com/blog/Futures-in-Scala-protips-6.html + final class Interrupt extends (() => Boolean) { + // We need a state-machine to track the progress. + // It can have the following states: + // a null reference means execution has not started. + // a Thread reference means that the execution has started but is not done. + // a this reference means that it is already cancelled or is already too late. + private[this] final var state: AnyRef = null + + /** + * This is the signal to cancel the execution of the logic. + * Returns whether the cancellation signal was successully issued or not. + */ + override final def apply(): Boolean = this.synchronized { + state match { + case null => + state = this + true + case _: this.type => false + case t: Thread => + state = this + // def kill = t.interrupt() // ask nicely for interruption, but this requires cooperation from the thread (involves checking isInterrupted() regularly) + @annotation.nowarn + def kill = t.stop() // brutally kill the thread without asking, more portable but less "safe". I believe it's safe here because we don't share any resources with the thread. + kill + true + } + } + + // Initializes right before execution of logic and + // allows to not run the logic at all if already cancelled. + private[this] final def enter(): Boolean = + this.synchronized { + state match { + case _: this.type => false + case null => + state = Thread.currentThread + true + } + } + + // Cleans up after the logic has executed + // Prevents cancellation to occur "too late" + private[this] final def exit(): Boolean = + this.synchronized { + state match { + case _: this.type => false + case t: Thread => + state = this + true + } + } + + /** + * Executes the suplied block of logic and returns the result. + * Throws CancellationException if the block was interrupted. + */ + def interruptibly[T](block: => T): T = + if (enter()) { + try block + catch { + case ie: InterruptedException => throw new CancellationException() + case td: ThreadDeath => throw new CancellationException() + } finally { + if (!exit() && Thread.interrupted()) + () // If we were interrupted and flag was not cleared + } + } else throw new CancellationException() + } + + implicit class FutureInterrupt(val future: Future.type) extends AnyVal { + def interruptibly[T](block: => T)(implicit ec: ExecutionContext): (Future[T], () => Boolean) = { + val interrupt = new Interrupt() + (Future(interrupt.interruptibly(block))(ec), interrupt) + } + } +} From 07c4f3d234b2dcfdbdc1d4257cab709ab9c60a0f Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:26 +0100 Subject: [PATCH 14/24] Fix and improve kernel2code and asFront methods --- .../src/main/scala/Kernel2Code.scala | 53 ++++++------------- .../src/main/scala/lisa/fol/Common.scala | 6 ++- .../src/main/scala/lisa/fol/FOLHelpers.scala | 5 +- .../src/main/scala/lisa/fol/Sequents.scala | 4 +- .../scala/lisa/utils/ProofsConverter.scala | 13 +++-- .../lisa/utils/tptp/ProblemGatherer.scala | 3 +- 6 files changed, 32 insertions(+), 52 deletions(-) diff --git a/lisa-examples/src/main/scala/Kernel2Code.scala b/lisa-examples/src/main/scala/Kernel2Code.scala index b36bc6b23..bc8592b03 100644 --- a/lisa-examples/src/main/scala/Kernel2Code.scala +++ b/lisa-examples/src/main/scala/Kernel2Code.scala @@ -209,63 +209,48 @@ object Kernel2Code extends lisa.Main { } val s_2 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) subproof { val s_2_0 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s_1) + val s_2_1 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s_1) } val s_3 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { val s_3_0 = have(() ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) val s_3_1 = have(() ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) val s_3_2 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { val s_3_2_0 = have( - Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) + Q(f(x)) ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤ ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(⊤))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Restate val s_3_2_1 = thenHave( - Q(f(x)) ⊢ ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) - ) - ) by RightSubstIff( + Q(f(x)) ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) + ) by RightSubstIff.withParametersSimple( List(((Q(f(x))), (⊤))), lambda( Seq(MaRvIn_1), - ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬( - Q(f(f(x))) - )) - ) + ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1 ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(MaRvIn_1))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) ) val s_3_2_2 = have( - ¬(Q(f(x))) ⊢ ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) - ) + ¬(Q(f(x))) ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥ ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(⊥))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Restate val s_3_2_3 = thenHave( ¬(Q(f(x))) ⊢ ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + (¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x))))) ) - ) by RightSubstIff( + ) by RightSubstIff.withParametersSimple( List(((Q(f(x))), (⊥))), lambda( Seq(MaRvIn_1), - ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(MaRvIn_1)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬( - Q(f(f(x))) - )) - ) + ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ MaRvIn_1 ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(MaRvIn_1))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) ) val s_3_2_4 = thenHave( () ⊢ (Q(f(x)), ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + (¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x))))) )) ) by Restate val s_3_2_5 = have( - () ⊢ ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) - ) + () ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Cut(s_3_2_4, s_3_2_1) val s_3_2_6 = thenHave( - () ⊢ ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) - ) + () ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Restate val s_3_2_7 = thenHave((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate @@ -282,25 +267,21 @@ object Kernel2Code extends lisa.Main { val s_3 = have(() ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) val s_4 = have(() ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) val s_5 = have( - Q(f(x)) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊤)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) + Q(f(x)) ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤ ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(⊤))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Restate val s_6 = thenHave( - Q(f(x)) ⊢ ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) - ) + Q(f(x)) ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Restate val s_7 = have( - ¬(Q(f(x))) ⊢ ¬(((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(⊥)))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x)))))) + ¬(Q(f(x))) ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊥ ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(⊥))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Restate val s_8 = thenHave( () ⊢ (Q(f(x)), ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) + (¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x))))) )) ) by Restate val s_9 = have( - () ⊢ ¬( - ((((¬(((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x))) ∧ ¬(Q(f(f(x)))))) ∧ ¬(((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x)) ∧ ¬(Q(f(x)))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x))))))) ∧ Q(x)) ∧ ¬(Q(f(f(x))))) - ) + () ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Cut(s_8, s_6) val s_10 = thenHave((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate val s_11 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_3, s_10) diff --git a/lisa-utils/src/main/scala/lisa/fol/Common.scala b/lisa-utils/src/main/scala/lisa/fol/Common.scala index cb1ca1eeb..4cb238c61 100644 --- a/lisa-utils/src/main/scala/lisa/fol/Common.scala +++ b/lisa-utils/src/main/scala/lisa/fol/Common.scala @@ -708,7 +708,11 @@ trait Common { def rename(newid: Identifier): ConstantConnectorLabel[N] = throw new Error("Can't rename a constant connector label") def freshRename(taken: Iterable[Identifier]): ConstantConnectorLabel[N] = rename(K.freshId(taken, id)) override def toString(): String = id - def mkString(args: Seq[Formula]): String = if (args.length == 2) (args(0).toString() + " " + toString() + " " + args(1).toString()) else toString() + "(" + args.mkString(", ") + ")" + def mkString(args: Seq[Formula]): String = if (args.length == 1) { + underlyingLabel match + case K.Neg => toString() + "(" + args(0).toString() + ")" + case _ => args(0).toString() + } else "(" + args.mkString(" " + toString() + " ") + ")" override def mkStringSeparated(args: Seq[Formula]): String = if (args.length == 2) "(" + mkString(args) + ")" else mkString(args) } diff --git a/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala b/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala index fc03e415e..576a279c3 100644 --- a/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala +++ b/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala @@ -118,10 +118,7 @@ object FOLHelpers { def asFront(pf: K.AtomicFormula): Formula = asFrontLabel(pf.label).applySeq(pf.args.map(asFront)) def asFront(cf: K.ConnectorFormula): Formula = - cf.label match - case K.And | K.Or if cf.args.size == 1 => asFront(cf.args(0)) - case K.And | K.Or => cf.args.map(asFront).reduceLeft((a, b) => asFrontLabel(cf.label)(Seq(a, b))) // TODO: handle this more gracefully - case _ => asFrontLabel(cf.label).applyUnsafe(cf.args.map(asFront)) + asFrontLabel(cf.label).applyUnsafe(cf.args.map(asFront)) def asFront(bf: K.BinderFormula): BinderFormula = asFrontLabel(bf.label).apply(asFrontLabel(bf.bound), asFront(bf.inner)) diff --git a/lisa-utils/src/main/scala/lisa/fol/Sequents.scala b/lisa-utils/src/main/scala/lisa/fol/Sequents.scala index 1f13bf849..27567e3c9 100644 --- a/lisa-utils/src/main/scala/lisa/fol/Sequents.scala +++ b/lisa-utils/src/main/scala/lisa/fol/Sequents.scala @@ -168,9 +168,9 @@ trait Sequents extends Common with lisa.fol.Lambdas with Predef { infix def ++?(s1: Sequent): Sequent = this addAllIfNotExists s1 override def toString = - (if left.size == 0 then "" else if left.size == 1 then left.head.toString else "( " + left.mkString(", ") + " )") + + (if left.size == 0 then "" else if left.size == 1 then left.head.toString else "(" + left.mkString(", ") + ")") + " ⊢ " + - (if right.size == 0 then "" else if right.size == 1 then right.head.toString else "( " + right.mkString(", ") + " )") + (if right.size == 0 then "" else if right.size == 1 then right.head.toString else "(" + right.mkString(", ") + ")") } diff --git a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala index 26c510a59..c27fe597a 100644 --- a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala +++ b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala @@ -9,7 +9,6 @@ import lisa.utils.KernelHelpers.lambda object ProofsConverter { -// TODO: fix printing of ∧ and ∨ with > 2 arguments, currently handled as recursive binary operators (see FOLHelpers.scala) // TODO: remove unnecessary variables "val s_..." in generated proofs -> need to keep track of which steps are used in other steps // TODO: generate more realistic variable names // TODO: handle automatic global variable declaration before theorems/proofs @@ -65,14 +64,14 @@ object ProofsConverter { case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) case LeftSubstIff(bot, t1, equals, lambdaPhi) => - tacticName = s"LeftSubstIff(List(${equals - .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))" + tacticName = s"LeftSubstIff.withParametersSimple(List(${equals + .map((a, b) => s"((${formula2code(a.body)}), (${formula2code(b.body)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi._2)}))" (bot, Seq(t1)) case RightSubstIff(bot, t1, equals, lambdaPhi) => - tacticName = s"RightSubstIff(List(${equals - .map((a, b) => s"((${formula2code(a)}), (${formula2code(b)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi.vars.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi.body)}))" + tacticName = s"RightSubstIff.withParametersSimple(List(${equals + .map((a, b) => s"((${formula2code(a.body)}), (${formula2code(b.body)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi._2)}))" (bot, Seq(t1)) case InstSchema(bot, t1, mCon, mPred, mTerm) => if mCon.isEmpty && mPred.isEmpty then diff --git a/lisa-utils/src/main/scala/lisa/utils/tptp/ProblemGatherer.scala b/lisa-utils/src/main/scala/lisa/utils/tptp/ProblemGatherer.scala index 2f87e96b4..53c834697 100644 --- a/lisa-utils/src/main/scala/lisa/utils/tptp/ProblemGatherer.scala +++ b/lisa-utils/src/main/scala/lisa/utils/tptp/ProblemGatherer.scala @@ -4,8 +4,7 @@ import lisa.utils.tptp.KernelParser.* object ProblemGatherer { // Path to the TPTP problems directory - // val path = getClass.getResource("/TPTP/Problems/").getPath - val TPTPProblemPath = "/home/auguste/Documents/EPFL/PhD/Projects/TPTP-v8.2.0/Problems/" + val TPTPProblemPath: String = getClass.getResource("/TPTP/Problems/").getPath /** * @return sequence of tptp problems in the library lib with the tags in spc. From 5dd0c46db53b74ad4b02a345eb8131e740ce8eff Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:26 +0100 Subject: [PATCH 15/24] Fix Sequent toString method --- .../src/main/scala/Kernel2Code.scala | 42 +++++++++---------- .../src/main/scala/lisa/fol/Sequents.scala | 5 +-- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/lisa-examples/src/main/scala/Kernel2Code.scala b/lisa-examples/src/main/scala/Kernel2Code.scala index bc8592b03..e803474d4 100644 --- a/lisa-examples/src/main/scala/Kernel2Code.scala +++ b/lisa-examples/src/main/scala/Kernel2Code.scala @@ -131,10 +131,10 @@ object Kernel2Code extends lisa.Main { val s_1_5_0 = have(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall(s_1_4) } val s_1_6 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { - val s_1_6_0 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_1_3) - val s_1_6_1 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_1_5) + val s_1_6_0 = have((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_1_3) + val s_1_6_1 = have((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_1_5) val s_1_6_2 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) subproof { - val s_1_6_2_0 = have(() ⊢ ⊤) by Restate + val s_1_6_2_0 = have(⊤) by Restate val s_1_6_2_1 = thenHave((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate } val s_1_6_3 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s_1_6_0, s_1_6_2) @@ -142,16 +142,16 @@ object Kernel2Code extends lisa.Main { } val s_1_7 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate } - val s_2 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { - val s_2_0 = have(() ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_0) - val s_2_1 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_1) + val s_2 = have(((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { + val s_2_0 = have(((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_0) + val s_2_1 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_1) val s_2_2 = have((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) subproof { - val s_2_2_0 = have(() ⊢ ⊤) by Restate + val s_2_2_0 = have(⊤) by Restate val s_2_2_1 = thenHave((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate } val s_2_3 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_2_0, s_2_2) - val s_2_4 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_2_1, s_2_3) + val s_2_4 = have(((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_2_1, s_2_3) } } @@ -166,18 +166,18 @@ object Kernel2Code extends lisa.Main { val s_7 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, Q(x))) by RightForall val s_8 = have(∀(x, (Q(x) ∧ R(x))) ⊢ R(x)) by Weakening(s_5) val s_9 = thenHave(∀(x, (Q(x) ∧ R(x))) ⊢ ∀(x, R(x))) by RightForall - val s_10 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_7) - val s_11 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_9) - val s_12 = have(() ⊢ ⊤) by Restate + val s_10 = have((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x)))) by Restate.from(s_7) + val s_11 = have((∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) by Restate.from(s_9) + val s_12 = have(⊤) by Restate val s_13 = thenHave((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, Q(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Restate val s_14 = have((∀(x, (Q(x) ∧ R(x))), (∀(x, (Q(x) ∧ R(x))) ==> ∀(x, R(x)))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s_10, s_13) val s_15 = have(∀(x, (Q(x) ∧ R(x))) ⊢ (∀(x, Q(x)) ∧ ∀(x, R(x)))) by Cut(s_11, s_14) - val s_16 = have(() ⊢ ((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_3) - val s_17 = have(() ⊢ (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_15) + val s_16 = have(((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_3) + val s_17 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) by Restate.from(s_15) val s_18 = have((((∀(x, R(x)) ∧ ∀(x, Q(x))) ==> ∀(x, (Q(x) ∧ R(x)))), (∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x))))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Restate.from(s_12) val s_19 = have((∀(x, (Q(x) ∧ R(x))) ==> (∀(x, Q(x)) ∧ ∀(x, R(x)))) ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_16, s_18) - val s_20 = have(() ⊢ ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_17, s_19) + val s_20 = have(((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x))))) by Cut(s_17, s_19) } // This theorem requires instantiating the assumption twice, once with x and once with f(x), and then combine the two. @@ -212,8 +212,8 @@ object Kernel2Code extends lisa.Main { val s_2_1 = have(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x)))(s_1) } val s_3 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { - val s_3_0 = have(() ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) - val s_3_1 = have(() ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) + val s_3_0 = have((∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) + val s_3_1 = have((∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) val s_3_2 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) subproof { val s_3_2_0 = have( Q(f(x)) ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤ ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(⊤))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) @@ -247,10 +247,10 @@ object Kernel2Code extends lisa.Main { )) ) by Restate val s_3_2_5 = have( - () ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) + ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Cut(s_3_2_4, s_3_2_1) val s_3_2_6 = thenHave( - () ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) + ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Restate val s_3_2_7 = thenHave((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate @@ -264,8 +264,8 @@ object Kernel2Code extends lisa.Main { val s_0 = have((∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by Restate val s_1 = thenHave(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall val s_2 = thenHave(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x))) - val s_3 = have(() ⊢ (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) - val s_4 = have(() ⊢ (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) + val s_3 = have((∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x))))) by Restate.from(s_1) + val s_4 = have((∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) by Restate.from(s_2) val s_5 = have( Q(f(x)) ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ ⊤ ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(⊤))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Restate @@ -281,7 +281,7 @@ object Kernel2Code extends lisa.Main { )) ) by Restate val s_9 = have( - () ⊢ ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) + ¬((¬((∀(x_1, ¬((Q(x_1) ∧ ¬(Q(f(x_1)))))) ∧ Q(f(x)) ∧ ¬(Q(f(f(x)))))) ∧ ¬((∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(x))))) ∧ ∀(x, ¬((Q(x) ∧ ¬(Q(f(x)))))) ∧ Q(x) ∧ ¬(Q(f(f(x)))))) ) by Cut(s_8, s_6) val s_10 = thenHave((∀(x, (Q(x) ==> Q(f(x)))), (∀(x, (Q(x) ==> Q(f(x)))) ==> (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Restate val s_11 = have((∀(x, (Q(x) ==> Q(f(x)))), (∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ==> (Q(f(x)) ==> Q(f(f(x)))))) ⊢ (Q(x) ==> Q(f(f(x))))) by Cut(s_3, s_10) diff --git a/lisa-utils/src/main/scala/lisa/fol/Sequents.scala b/lisa-utils/src/main/scala/lisa/fol/Sequents.scala index 27567e3c9..dc1aadaaa 100644 --- a/lisa-utils/src/main/scala/lisa/fol/Sequents.scala +++ b/lisa-utils/src/main/scala/lisa/fol/Sequents.scala @@ -168,9 +168,8 @@ trait Sequents extends Common with lisa.fol.Lambdas with Predef { infix def ++?(s1: Sequent): Sequent = this addAllIfNotExists s1 override def toString = - (if left.size == 0 then "" else if left.size == 1 then left.head.toString else "(" + left.mkString(", ") + ")") + - " ⊢ " + - (if right.size == 0 then "" else if right.size == 1 then right.head.toString else "(" + right.mkString(", ") + ")") + (if (left.size == 0 && right.size <= 1) then "" else if left.size == 1 then left.head.toString + " ⊢ " else "(" + left.mkString(", ") + ") ⊢ ") + + (if right.size == 1 then right.head.toString else "(" + right.mkString(", ") + ")") } From 860fc1f0e79c00b485df9ebc160d6e120ea70e33 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:27 +0100 Subject: [PATCH 16/24] Add proof checks in TPTPSolver --- lisa-examples/src/main/scala/TPTPSolver.scala | 15 ++++++++++----- .../src/main/scala/lisa/utils/RunSolver.scala | 7 ++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lisa-examples/src/main/scala/TPTPSolver.scala b/lisa-examples/src/main/scala/TPTPSolver.scala index 796787a46..3e11f4110 100644 --- a/lisa-examples/src/main/scala/TPTPSolver.scala +++ b/lisa-examples/src/main/scala/TPTPSolver.scala @@ -10,6 +10,7 @@ import lisa.utils.tptp.KernelParser.* import lisa.utils.tptp.ProblemGatherer.* import lisa.kernel.proof.SCProof import lisa.kernel.proof.SequentCalculus.Sequent +import lisa.kernel.proof.SCProofChecker.checkSCProof object TPTPSolver extends lisa.Main { try { @@ -55,8 +56,10 @@ object TPTPSolver extends lisa.Main { // Attempting proof by Tableau proveSequent(seq, timeoutTableau, Tableau.solve) match { case Solved(proof) => - nbProblemsSolvedByTableau += 1 - // writeProof(p, proof, "examples/proofs/tableau/") + if (checkSCProof(proof).isValid) + nbProblemsSolvedByTableau += 1 + // writeProof(p, proof, "examples/proofs/tableau/") + else throw new Exception("Tableau proof is not valid") case _ => () } @@ -66,13 +69,15 @@ object TPTPSolver extends lisa.Main { case _ => None proveSequent(seq, timeoutTautology, tautologySolver) match { case Solved(proof) => - nbProblemsSolvedByTautology += 1 - // writeProof(p, proof, "examples/proofs/tautology/") + if (checkSCProof(proof).isValid) + nbProblemsSolvedByTautology += 1 + // writeProof(p, proof, "examples/proofs/tautology/") + else throw new Exception("Tautology proof is not valid") case _ => () } } } catch { - case _ => () + case e => println(s"Error while processing $probfile: $e") } } } catch { diff --git a/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala b/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala index 18d4c45a4..29be3fc76 100644 --- a/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala +++ b/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala @@ -13,7 +13,7 @@ object RunSolver { case class Solved(proof: SCProof) extends SolverResult case object Unsolved extends SolverResult case object Timeout extends SolverResult - case class SolverException(e: Exception) extends SolverResult + case class SolverThrow(t: Throwable) extends SolverResult def proveSequent(sequent: Sequent, timeout: Duration, solver: Sequent => Option[SCProof]): SolverResult = { val (futureSolver, cancelSolver) = Future.interruptibly { solver(sequent) } @@ -25,9 +25,9 @@ object RunSolver { case _: TimeoutException => cancelSolver() Timeout - case e: Exception => + case t: Throwable => cancelSolver() - SolverException(e) + SolverThrow(t) } // Class to handle future cancellation @@ -94,6 +94,7 @@ object RunSolver { catch { case ie: InterruptedException => throw new CancellationException() case td: ThreadDeath => throw new CancellationException() + case t: Throwable => throw t } finally { if (!exit() && Thread.interrupted()) () // If we were interrupted and flag was not cleared From 1608480c3a55754cbe44d8831f53f997d9d0ae04 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:27 +0100 Subject: [PATCH 17/24] Improve conversion from kernel to code --- .../src/main/scala/Kernel2Code.scala | 60 +++--- .../scala/lisa/utils/ProofsConverter.scala | 192 ++++++++++-------- 2 files changed, 147 insertions(+), 105 deletions(-) diff --git a/lisa-examples/src/main/scala/Kernel2Code.scala b/lisa-examples/src/main/scala/Kernel2Code.scala index e803474d4..3edede62b 100644 --- a/lisa-examples/src/main/scala/Kernel2Code.scala +++ b/lisa-examples/src/main/scala/Kernel2Code.scala @@ -29,12 +29,13 @@ object Kernel2Code extends lisa.Main { thenHave(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall } - // println(prettyProof(thm1.highProof.get)) - // println(prettySCProof(thm1.kernelProof.get)) - // println(scproof2code(thm1.kernelProof.get)) - // println(scproof2code(optimizeProofIteratively(thm1.kernelProof.get))) + // println(generateTheoremCode("thm1_raw", thm1.statement.underlying, thm1.kernelProof.get)) + // println() + // println(generateTheoremCode("thm1_optimized", thm1.statement.underlying, optimizeProofIteratively(thm1.kernelProof.get))) - val thm1_raw = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + val thm1_raw = Theorem( + ∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y))) + ) { val s_0 = have(S(x, y) ⊢ S(x, y)) subproof { val s_0_0 = have(S(x, y) ⊢ S(x, y)) by Restate } @@ -52,7 +53,9 @@ object Kernel2Code extends lisa.Main { } } - val thm1_optimized = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + val thm1_optimized = Theorem( + ∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y))) + ) { val s_0 = have(S(x, y) ⊢ S(x, y)) by Restate val s_1 = thenHave(∀(y, S(x, y)) ⊢ S(x, y)) by LeftForall val s_2 = thenHave(∀(y, S(x, y)) ⊢ ∃(x, S(x, y))) by RightExists @@ -85,12 +88,13 @@ object Kernel2Code extends lisa.Main { have(thesis) by Tautology.from(forward, backward) } - // println(prettyProof(thm2.highProof.get)) - // println(prettySCProof(thm2.kernelProof.get)) - // println(scproof2code(thm2.kernelProof.get)) - // println(scproof2code(optimizeProofIteratively(thm2.kernelProof.get))) + // println(generateTheoremCode("thm2_raw", thm2.statement.underlying, thm2.kernelProof.get)) + // println() + // println(generateTheoremCode("thm2_optimized", thm2.statement.underlying, optimizeProofIteratively(thm2.kernelProof.get))) - val thm2_raw = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { + val thm2_raw = Theorem( + ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x)))) + ) { val s_0 = have((∀(x, R(x)), ∀(x, Q(x))) ⊢ ∀(x, (Q(x) ∧ R(x)))) subproof { val s_0_0 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) subproof { val s_0_0_0 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) by Restate @@ -155,7 +159,9 @@ object Kernel2Code extends lisa.Main { } } - val thm2_optimized = Theorem((∀(x, Q(x)) /\ ∀(x, R(x))) <=> ∀(x, Q(x) /\ R(x))) { + val thm2_optimized = Theorem( + ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x)))) + ) { val s_0 = have((R(x), Q(x)) ⊢ (Q(x) ∧ R(x))) by Restate val s_1 = thenHave((R(x), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall val s_2 = thenHave((∀(x, R(x)), ∀(x, Q(x))) ⊢ (Q(x) ∧ R(x))) by LeftForall @@ -190,12 +196,13 @@ object Kernel2Code extends lisa.Main { have(thesis) by Tautology.from(step1, step1 of (x := f(x))) } - // println(prettyProof(thm3.highProof.get)) - // println(prettySCProof(thm3.kernelProof.get)) - // println(scproof2code(thm3.kernelProof.get)) - // println(scproof2code(optimizeProofIteratively(thm3.kernelProof.get))) + // println(generateTheoremCode("thm3_raw", thm3.statement.underlying, thm3.kernelProof.get)) + // println() + // println(generateTheoremCode("thm3_optimized", thm3.statement.underlying, optimizeProofIteratively(thm3.kernelProof.get))) - val thm3_raw = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { + val thm3_raw = Theorem( + ∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x)))) + ) { val s_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) subproof { val s_0_0 = have(∀(x, (Q(x) ==> Q(f(x)))) ⊢ ∀(x, (Q(x) ==> Q(f(x))))) by Hypothesis } @@ -260,7 +267,9 @@ object Kernel2Code extends lisa.Main { } } - val thm3_optimized = Theorem(∀(x, Q(x) ==> Q(f(x))) |- (Q(x) ==> Q(f(f(x))))) { + val thm3_optimized = Theorem( + ∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x)))) + ) { val s_0 = have((∀(x, (Q(x) ==> Q(f(x)))), (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by Restate val s_1 = thenHave(∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(x)))) by LeftForall val s_2 = thenHave(∀(x_1, (Q(x_1) ==> Q(f(x_1)))) ⊢ (Q(f(x)) ==> Q(f(f(x))))) by InstFunSchema(Map(x -> f(x))) @@ -292,12 +301,13 @@ object Kernel2Code extends lisa.Main { have(thesis) by Tableau } - // println(prettyProof(thm1bis.highProof.get)) - // println(prettySCProof(thm1bis.kernelProof.get)) - // println(scproof2code(thm1bis.kernelProof.get)) - // println(scproof2code(optimizeProofIteratively(thm1bis.kernelProof.get))) + // println(generateTheoremCode("thm1bis_raw", thm1bis.statement.underlying, thm1bis.kernelProof.get)) + // println() + // println(generateTheoremCode("thm1bis_optimized", thm1bis.statement.underlying, optimizeProofIteratively(thm1bis.kernelProof.get))) - val thm1bis_raw = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + val thm1bis_raw = Theorem( + ∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y))) + ) { val s_0 = have(∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y)))) subproof { val s_0_0 = have((S(x, y_1), ¬(S(x, y_1))) ⊢ ()) by Restate val s_0_1 = thenHave((S(x, y_1), ∀(x_2, ¬(S(x_2, y_1)))) ⊢ ()) by LeftForall @@ -310,7 +320,9 @@ object Kernel2Code extends lisa.Main { } } - val thm1bis_optimized = Theorem(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) { + val thm1bis_optimized = Theorem( + ∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y))) + ) { val s_0 = have((S(x, y_1), ¬(S(x, y_1))) ⊢ ()) by Restate val s_1 = thenHave((S(x, y_1), ∀(x_2, ¬(S(x_2, y_1)))) ⊢ ()) by LeftForall val s_2 = thenHave((∀(x_2, ¬(S(x_2, y_1))), ∀(y, S(x, y))) ⊢ ()) by LeftForall diff --git a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala index c27fe597a..7b07a6347 100644 --- a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala +++ b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala @@ -2,10 +2,10 @@ package lisa.utils import lisa.kernel.proof.SequentCalculus.* import lisa.utils.K +import lisa.utils.KernelHelpers.lambda import lisa.prooflib.ProofTacticLib.* -import lisa.fol.FOLHelpers.* import lisa.fol.FOL as F -import lisa.utils.KernelHelpers.lambda +import lisa.fol.FOLHelpers.* object ProofsConverter { @@ -13,93 +13,123 @@ object ProofsConverter { // TODO: generate more realistic variable names // TODO: handle automatic global variable declaration before theorems/proofs - def scproof2code(p: K.SCProof, premises: Seq[String] = Seq.empty, indent: Int = 0, varPrefix: String = "s"): String = { - def scproofstep2line(ps: SCProofStep, stepNum: Int, premises: Seq[String], indent: Int, varPrefix: String): String = { - def sequent2code(sq: Sequent): String = asFront(sq).toString.replace("⇒", "==>").replace("⇔", "<=>") - def formula2code(form: K.Formula): String = asFront(form).toString.replace("⇒", "==>").replace("⇔", "<=>") - def term2code(term: K.Term): String = asFront(term).toString.replace("⇒", "==>").replace("⇔", "<=>") + private def indent(s: String, indent: Int = 2): String = s.split("\n").map(" " * indent + _).mkString("\n") + private def unindent(s: String, indent: Int = 2): String = s.split("\n").map(_.drop(indent)).mkString("\n") + + private def any2code(a: K.Sequent | K.Formula | K.Term): String = (a match + case sq: K.Sequent => asFront(sq) + case form: K.Formula => asFront(form) + case term: K.Term => asFront(term) + ).toString.replace("⇒", "==>").replace("⇔", "<=>") + + def scproof2code(p: K.SCProof): String = { + def scproof2codeAux(p: K.SCProof, varPrefix: String = "s", premises: Seq[String] = Seq.empty): String = { + def scproofstep2code(ps: SCProofStep, stepNum: Int, premises: Seq[String], varPrefix: String): String = { - def index2stepvar(i: Int): String = - if i < -premises.size then throw new Exception(s"step $i is not defined") - else if i < 0 then premises(-i - 1) - else s"${varPrefix}_$i" + def index2stepvar(i: Int): String = + if i < -premises.size then throw new Exception(s"step $i is not defined") + else if i < 0 then premises(-i - 1) + else s"${varPrefix}_$i" - val varDecl = " " * indent + s"val ${varPrefix}_$stepNum = " - ps match - case Sorry(_) => "sorry" - case sp @ SCSubproof(_, _) => - varDecl + s"have(${sequent2code(sp.bot)}) subproof {\n" + scproof2code(sp.sp, sp.premises.map(index2stepvar), indent + 1, s"${varPrefix}_$stepNum") + "\n" + " " * indent + "}" - case _ => - var tacticName = ps.getClass.getSimpleName - var opening = "(" - var closing = ")" - val (bot_, step_ref_seq) = (ps match - case Restate(bot, t1) => - opening = ".from(" - (bot, Seq(t1)) - case RestateTrue(bot) => - tacticName = "Restate" - (bot, null) - case Hypothesis(bot, phi) => (bot, null) - case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2)) - case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1)) - case LeftOr(bot, t, disjuncts) => (bot, t) - case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) - case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1)) - case LeftNot(bot, t1, phi) => (bot, Seq(t1)) - case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1)) - case LeftExists(bot, t1, phi, x) => (bot, Seq(t1)) - case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) - case RightAnd(bot, t, conjuncts) => (bot, t) - case RightOr(bot, t1, phi, psi) => (bot, Seq(t1)) - case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1)) - case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) - case RightNot(bot, t1, phi) => (bot, Seq(t1)) - case RightForall(bot, t1, phi, x) => (bot, Seq(t1)) - case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1)) - case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) - case Weakening(bot, t1) => (bot, Seq(t1)) - case LeftRefl(bot, t1, phi) => (bot, Seq(t1)) - case RightRefl(bot, phi) => (bot, null) - case LeftSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) - case RightSubstEq(bot, t1, equals, lambdaPhi) => (bot, Seq(t1)) - case LeftSubstIff(bot, t1, equals, lambdaPhi) => - tacticName = s"LeftSubstIff.withParametersSimple(List(${equals - .map((a, b) => s"((${formula2code(a.body)}), (${formula2code(b.body)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi._2)}))" - (bot, Seq(t1)) - case RightSubstIff(bot, t1, equals, lambdaPhi) => - tacticName = s"RightSubstIff.withParametersSimple(List(${equals - .map((a, b) => s"((${formula2code(a.body)}), (${formula2code(b.body)}))") - .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${formula2code(lambdaPhi._2)}))" - (bot, Seq(t1)) - case InstSchema(bot, t1, mCon, mPred, mTerm) => - if mCon.isEmpty && mPred.isEmpty then - tacticName = s"InstFunSchema(Map(${mTerm.toList - .map((k, v) => s"${asFrontLabel(k)} -> ${term2code(v.body)}") - .mkString(", ")}))" + ps match + case Sorry(_) => "sorry" + case sp @ SCSubproof(_, _) => + indent( + s"val ${varPrefix}_$stepNum = have(${any2code(sp.bot)}) subproof {\n" + + scproof2codeAux(sp.sp, s"${varPrefix}_$stepNum", sp.premises.map(index2stepvar)) + + "\n}" + ) + case _ => + var tacticName = ps.getClass.getSimpleName + var opening = "(" + var closing = ")" + val (bot_, step_ref_seq) = (ps match + case Restate(bot, t1) => + opening = ".from(" (bot, Seq(t1)) - else if mCon.isEmpty && mTerm.isEmpty then - tacticName = s"InstPredSchema(Map(${mPred.toList - .map((k, v) => s"${asFrontLabel(k)} -> ${formula2code(v.body)}") - .mkString(", ")}))" + case RestateTrue(bot) => + tacticName = "Restate" + (bot, null) + case Hypothesis(bot, phi) => (bot, null) + case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2)) + case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1)) + case LeftOr(bot, t, disjuncts) => (bot, t) + case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) + case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1)) + case LeftNot(bot, t1, phi) => (bot, Seq(t1)) + case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1)) + case LeftExists(bot, t1, phi, x) => (bot, Seq(t1)) + case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) + case RightAnd(bot, t, conjuncts) => (bot, t) + case RightOr(bot, t1, phi, psi) => (bot, Seq(t1)) + case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1)) + case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) + case RightNot(bot, t1, phi) => (bot, Seq(t1)) + case RightForall(bot, t1, phi, x) => (bot, Seq(t1)) + case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1)) + case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) + case Weakening(bot, t1) => (bot, Seq(t1)) + case LeftRefl(bot, t1, phi) => (bot, Seq(t1)) + case RightRefl(bot, phi) => (bot, null) + case LeftSubstEq(bot, t1, equals, lambdaPhi) => + tacticName = s"LeftSubstEq.withParametersSimple(List(${equals + .map((a, b) => s"((${any2code(a.body)}), (${any2code(b.body)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${any2code(lambdaPhi._2)}))" (bot, Seq(t1)) - else throw new Exception("InstSchema not implemented") - case _ => throw new Exception(s"Tactic ${ps.getClass.getName} not implemented") - ) + case RightSubstEq(bot, t1, equals, lambdaPhi) => + tacticName = s"RightSubstEq.withParametersSimple(List(${equals + .map((a, b) => s"((${any2code(a.body)}), (${any2code(b.body)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${any2code(lambdaPhi._2)}))" + (bot, Seq(t1)) + case LeftSubstIff(bot, t1, equals, lambdaPhi) => + tacticName = s"LeftSubstIff.withParametersSimple(List(${equals + .map((a, b) => s"((${any2code(a.body)}), (${any2code(b.body)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${any2code(lambdaPhi._2)}))" + (bot, Seq(t1)) + case RightSubstIff(bot, t1, equals, lambdaPhi) => + tacticName = s"RightSubstIff.withParametersSimple(List(${equals + .map((a, b) => s"((${any2code(a.body)}), (${any2code(b.body)}))") + .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${any2code(lambdaPhi._2)}))" + (bot, Seq(t1)) + case InstSchema(bot, t1, mCon, mPred, mTerm) => + if mCon.isEmpty && mPred.isEmpty then + tacticName = s"InstFunSchema(Map(${mTerm.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${any2code(v.body)}") + .mkString(", ")}))" + (bot, Seq(t1)) + else if mCon.isEmpty && mTerm.isEmpty then + tacticName = s"InstPredSchema(Map(${mPred.toList + .map((k, v) => s"${asFrontLabel(k)} -> ${any2code(v.body)}") + .mkString(", ")}))" + (bot, Seq(t1)) + else throw new Exception("InstSchema not implemented") + case _ => throw new Exception(s"Tactic ${ps.getClass.getName} not implemented") + ) - varDecl + ( - if (step_ref_seq != null && step_ref_seq.size == 1 && stepNum > 0 && step_ref_seq.head + 1 == stepNum) - then s"thenHave(${sequent2code(bot_)}) by $tacticName" - else - s"have(${sequent2code(bot_)}) by $tacticName" + ( - if step_ref_seq == null then "" - else s"$opening${step_ref_seq.map(index2stepvar).mkString(", ")}$closing" + indent( + s"val ${varPrefix}_$stepNum = " + ( + if (step_ref_seq != null && step_ref_seq.size == 1 && stepNum > 0 && step_ref_seq.head + 1 == stepNum) + then s"thenHave(${any2code(bot_)}) by $tacticName" + else + s"have(${any2code(bot_)}) by $tacticName" + ( + if step_ref_seq == null then "" + else s"$opening${step_ref_seq.map(index2stepvar).mkString(", ")}$closing" + ) ) - ) + ) + } + + p.steps.zipWithIndex.map((ps, i) => scproofstep2code(ps, i, premises, varPrefix)).mkString("\n") } + unindent(scproof2codeAux(p)) + } - p.steps.zipWithIndex.map((ps, i) => scproofstep2line(ps, i, premises, indent, varPrefix)).mkString("\n") + def generateTheoremCode(name: String, statement: K.Sequent, proof: K.SCProof): String = { + s"val $name = Theorem(\n" + + indent(any2code(statement)) + + s"\n) {\n" + + indent(scproof2code(proof)) + + s"\n}" } } From d83b9525ec345c613e997914856ec2bf493fa84e Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:28 +0100 Subject: [PATCH 18/24] Add standalone file generator for theorems and proofs + cleanup --- .../src/main/scala/Kernel2Code.scala | 22 +-- lisa-examples/src/main/scala/TPTPSolver.scala | 5 +- .../scala/lisa/utils/ProofsConverter.scala | 138 +++++++++++------- 3 files changed, 93 insertions(+), 72 deletions(-) diff --git a/lisa-examples/src/main/scala/Kernel2Code.scala b/lisa-examples/src/main/scala/Kernel2Code.scala index 3edede62b..f3b6b1f96 100644 --- a/lisa-examples/src/main/scala/Kernel2Code.scala +++ b/lisa-examples/src/main/scala/Kernel2Code.scala @@ -8,9 +8,7 @@ object Kernel2Code extends lisa.Main { val x = variable val y = variable - val z = variable val f = function[1] - val P = formulaVariable val Q = predicate[1] val R = predicate[1] val S = predicate[2] @@ -29,9 +27,8 @@ object Kernel2Code extends lisa.Main { thenHave(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall } - // println(generateTheoremCode("thm1_raw", thm1.statement.underlying, thm1.kernelProof.get)) - // println() - // println(generateTheoremCode("thm1_optimized", thm1.statement.underlying, optimizeProofIteratively(thm1.kernelProof.get))) + // println(generateStandaloneTheoremFileContent("thm1_raw", thm1.statement.underlying, thm1.kernelProof.get)) + // println(generateStandaloneTheoremFileContent("thm1_optimized", thm1.statement.underlying, optimizeProofIteratively(thm1.kernelProof.get))) val thm1_raw = Theorem( ∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y))) @@ -88,9 +85,8 @@ object Kernel2Code extends lisa.Main { have(thesis) by Tautology.from(forward, backward) } - // println(generateTheoremCode("thm2_raw", thm2.statement.underlying, thm2.kernelProof.get)) - // println() - // println(generateTheoremCode("thm2_optimized", thm2.statement.underlying, optimizeProofIteratively(thm2.kernelProof.get))) + // println(generateStandaloneTheoremFileContent("thm2_raw", thm2.statement.underlying, thm2.kernelProof.get)) + // println(generateStandaloneTheoremFileContent("thm2_optimized", thm2.statement.underlying, optimizeProofIteratively(thm2.kernelProof.get))) val thm2_raw = Theorem( ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x)))) @@ -196,9 +192,8 @@ object Kernel2Code extends lisa.Main { have(thesis) by Tautology.from(step1, step1 of (x := f(x))) } - // println(generateTheoremCode("thm3_raw", thm3.statement.underlying, thm3.kernelProof.get)) - // println() - // println(generateTheoremCode("thm3_optimized", thm3.statement.underlying, optimizeProofIteratively(thm3.kernelProof.get))) + // println(generateStandaloneTheoremFileContent("thm3_raw", thm3.statement.underlying, thm3.kernelProof.get)) + // println(generateStandaloneTheoremFileContent("thm3_optimized", thm3.statement.underlying, optimizeProofIteratively(thm3.kernelProof.get))) val thm3_raw = Theorem( ∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x)))) @@ -301,9 +296,8 @@ object Kernel2Code extends lisa.Main { have(thesis) by Tableau } - // println(generateTheoremCode("thm1bis_raw", thm1bis.statement.underlying, thm1bis.kernelProof.get)) - // println() - // println(generateTheoremCode("thm1bis_optimized", thm1bis.statement.underlying, optimizeProofIteratively(thm1bis.kernelProof.get))) + // println(generateStandaloneTheoremFileContent("thm1bis_raw", thm1bis.statement.underlying, thm1bis.kernelProof.get)) + // println(generateStandaloneTheoremFileContent("thm1bis_optimized", thm1bis.statement.underlying, optimizeProofIteratively(thm1bis.kernelProof.get))) val thm1bis_raw = Theorem( ∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y))) diff --git a/lisa-examples/src/main/scala/TPTPSolver.scala b/lisa-examples/src/main/scala/TPTPSolver.scala index 3e11f4110..05ed0ef3d 100644 --- a/lisa-examples/src/main/scala/TPTPSolver.scala +++ b/lisa-examples/src/main/scala/TPTPSolver.scala @@ -86,10 +86,9 @@ object TPTPSolver extends lisa.Main { } def writeProof(problem: Problem, proof: SCProof, path: String): Unit = { - // TODO val file = new File(path + problem.name + ".sc") val bw = new FileWriter(file) - val proofCode = scproof2code(proof) - bw.write(proof.toString) + val fileContent = generateStandaloneTheoremFileContent(problem.name, problemToSequent(problem), proof) + bw.write(fileContent) bw.close() } diff --git a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala index 7b07a6347..1c4875937 100644 --- a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala +++ b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala @@ -9,9 +9,8 @@ import lisa.fol.FOLHelpers.* object ProofsConverter { -// TODO: remove unnecessary variables "val s_..." in generated proofs -> need to keep track of which steps are used in other steps +// TODO: remove unnecessary variables "val s_..." in generated proofs -> need to detect which steps are used later in other steps // TODO: generate more realistic variable names -// TODO: handle automatic global variable declaration before theorems/proofs private def indent(s: String, indent: Int = 2): String = s.split("\n").map(" " * indent + _).mkString("\n") private def unindent(s: String, indent: Int = 2): String = s.split("\n").map(_.drop(indent)).mkString("\n") @@ -22,13 +21,13 @@ object ProofsConverter { case term: K.Term => asFront(term) ).toString.replace("⇒", "==>").replace("⇔", "<=>") - def scproof2code(p: K.SCProof): String = { - def scproof2codeAux(p: K.SCProof, varPrefix: String = "s", premises: Seq[String] = Seq.empty): String = { - def scproofstep2code(ps: SCProofStep, stepNum: Int, premises: Seq[String], varPrefix: String): String = { + private def scproof2code(p: K.SCProof): String = { + def scproof2codeAux(p: K.SCProof, varPrefix: String = "s", implicitPremises: Seq[String] = Seq.empty): String = { + def scproofstep2code(ps: SCProofStep, stepNum: Int, implicitPremises: Seq[String], varPrefix: String): String = { def index2stepvar(i: Int): String = - if i < -premises.size then throw new Exception(s"step $i is not defined") - else if i < 0 then premises(-i - 1) + if i < -implicitPremises.size then throw new Exception(s"step $i is not defined") + else if i < 0 then implicitPremises(-i - 1) else s"${varPrefix}_$i" ps match @@ -43,88 +42,107 @@ object ProofsConverter { var tacticName = ps.getClass.getSimpleName var opening = "(" var closing = ")" - val (bot_, step_ref_seq) = (ps match - case Restate(bot, t1) => - opening = ".from(" - (bot, Seq(t1)) - case RestateTrue(bot) => - tacticName = "Restate" - (bot, null) - case Hypothesis(bot, phi) => (bot, null) - case Cut(bot, t1, t2, phi) => (bot, Seq(t1, t2)) - case LeftAnd(bot, t1, phi, psi) => (bot, Seq(t1)) - case LeftOr(bot, t, disjuncts) => (bot, t) - case LeftImplies(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) - case LeftIff(bot, t1, phi, psi) => (bot, Seq(t1)) - case LeftNot(bot, t1, phi) => (bot, Seq(t1)) - case LeftForall(bot, t1, phi, x, t) => (bot, Seq(t1)) - case LeftExists(bot, t1, phi, x) => (bot, Seq(t1)) - case LeftExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) - case RightAnd(bot, t, conjuncts) => (bot, t) - case RightOr(bot, t1, phi, psi) => (bot, Seq(t1)) - case RightImplies(bot, t1, phi, psi) => (bot, Seq(t1)) - case RightIff(bot, t1, t2, phi, psi) => (bot, Seq(t1, t2)) - case RightNot(bot, t1, phi) => (bot, Seq(t1)) - case RightForall(bot, t1, phi, x) => (bot, Seq(t1)) - case RightExists(bot, t1, phi, x, t) => (bot, Seq(t1)) - case RightExistsOne(bot, t1, phi, x) => (bot, Seq(t1)) - case Weakening(bot, t1) => (bot, Seq(t1)) - case LeftRefl(bot, t1, phi) => (bot, Seq(t1)) - case RightRefl(bot, phi) => (bot, null) - case LeftSubstEq(bot, t1, equals, lambdaPhi) => + ps match + case Restate(_, _) => opening = ".from(" + case RestateTrue(_) => tacticName = "Restate" + case LeftSubstEq(_, _, equals, lambdaPhi) => tacticName = s"LeftSubstEq.withParametersSimple(List(${equals .map((a, b) => s"((${any2code(a.body)}), (${any2code(b.body)}))") .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${any2code(lambdaPhi._2)}))" - (bot, Seq(t1)) - case RightSubstEq(bot, t1, equals, lambdaPhi) => + case RightSubstEq(_, _, equals, lambdaPhi) => tacticName = s"RightSubstEq.withParametersSimple(List(${equals .map((a, b) => s"((${any2code(a.body)}), (${any2code(b.body)}))") .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${any2code(lambdaPhi._2)}))" - (bot, Seq(t1)) - case LeftSubstIff(bot, t1, equals, lambdaPhi) => + case LeftSubstIff(_, _, equals, lambdaPhi) => tacticName = s"LeftSubstIff.withParametersSimple(List(${equals .map((a, b) => s"((${any2code(a.body)}), (${any2code(b.body)}))") .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${any2code(lambdaPhi._2)}))" - (bot, Seq(t1)) - case RightSubstIff(bot, t1, equals, lambdaPhi) => + case RightSubstIff(_, _, equals, lambdaPhi) => tacticName = s"RightSubstIff.withParametersSimple(List(${equals .map((a, b) => s"((${any2code(a.body)}), (${any2code(b.body)}))") .mkString(", ")}), lambda(Seq(${lambdaPhi._1.map(asFrontLabel).mkString(", ")}), ${any2code(lambdaPhi._2)}))" - (bot, Seq(t1)) - case InstSchema(bot, t1, mCon, mPred, mTerm) => + case InstSchema(_, _, mCon, mPred, mTerm) => if mCon.isEmpty && mPred.isEmpty then tacticName = s"InstFunSchema(Map(${mTerm.toList .map((k, v) => s"${asFrontLabel(k)} -> ${any2code(v.body)}") .mkString(", ")}))" - (bot, Seq(t1)) else if mCon.isEmpty && mTerm.isEmpty then tacticName = s"InstPredSchema(Map(${mPred.toList .map((k, v) => s"${asFrontLabel(k)} -> ${any2code(v.body)}") .mkString(", ")}))" - (bot, Seq(t1)) else throw new Exception("InstSchema not implemented") - case _ => throw new Exception(s"Tactic ${ps.getClass.getName} not implemented") - ) + case _ => () indent( s"val ${varPrefix}_$stepNum = " + ( - if (step_ref_seq != null && step_ref_seq.size == 1 && stepNum > 0 && step_ref_seq.head + 1 == stepNum) - then s"thenHave(${any2code(bot_)}) by $tacticName" + if (ps.premises.size == 1 && ps.premises.head + 1 == stepNum && stepNum > 0) + then s"thenHave(${any2code(ps.bot)}) by $tacticName" else - s"have(${any2code(bot_)}) by $tacticName" + ( - if step_ref_seq == null then "" - else s"$opening${step_ref_seq.map(index2stepvar).mkString(", ")}$closing" + s"have(${any2code(ps.bot)}) by $tacticName" + ( + if ps.premises.size == 0 then "" + else s"$opening${ps.premises.map(index2stepvar).mkString(", ")}$closing" ) ) ) } - p.steps.zipWithIndex.map((ps, i) => scproofstep2code(ps, i, premises, varPrefix)).mkString("\n") + p.steps.zipWithIndex.map((ps, i) => scproofstep2code(ps, i, implicitPremises, varPrefix)).mkString("\n") } unindent(scproof2codeAux(p)) } - def generateTheoremCode(name: String, statement: K.Sequent, proof: K.SCProof): String = { + private def extractFormulasFromProof(proof: K.SCProof): Set[K.Formula] = + proof.steps.foldLeft(Set.empty[K.Formula])((prev, next) => { + prev ++ (next match + case sp @ SCSubproof(subproof, _) => extractFormulasFromProof(subproof) + case LeftSubstEq(_, _, _, lambdaPhi) => Seq(lambdaPhi._2, K.sequentToFormula(next.bot)) + case RightSubstEq(_, _, _, lambdaPhi) => Seq(lambdaPhi._2, K.sequentToFormula(next.bot)) + case LeftSubstIff(_, _, _, lambdaPhi) => Seq(lambdaPhi._2, K.sequentToFormula(next.bot)) + case RightSubstIff(_, _, _, lambdaPhi) => Seq(lambdaPhi._2, K.sequentToFormula(next.bot)) + case _ => Seq(K.sequentToFormula(next.bot)) + ) + }) + + private def extractVariables( + formulas: Set[K.Formula] + ): (Set[K.VariableLabel], Set[K.SchematicFunctionLabel], Set[K.VariableFormulaLabel], Set[K.SchematicPredicateLabel], Set[K.SchematicConnectorLabel]) = + def extractVariablesAux( + formula: K.Formula + ): (Set[K.VariableLabel], Set[K.SchematicFunctionLabel], Set[K.VariableFormulaLabel], Set[K.SchematicPredicateLabel], Set[K.SchematicConnectorLabel]) = + var variableSet = formula.schematicTermLabels.collect { case v: K.VariableLabel => v } + var functionSet = formula.schematicTermLabels.collect { case f: K.SchematicFunctionLabel => f } + var formulaVariableSet = formula.schematicAtomicLabels.collect { case v: K.VariableFormulaLabel => v } + var predicateSet = formula.schematicAtomicLabels.collect { case p: K.SchematicPredicateLabel => p } + var connectorSet = formula.schematicConnectorLabels.collect { case c: K.SchematicConnectorLabel => c } + (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) + + formulas.foldLeft( + (Set.empty[K.VariableLabel], Set.empty[K.SchematicFunctionLabel], Set.empty[K.VariableFormulaLabel], Set.empty[K.SchematicPredicateLabel], Set.empty[K.SchematicConnectorLabel]) + )((prev, next) => { + val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = prev + val (variableSet_, functionSet_, formulaVariableSet_, predicateSet_, connectorSet_) = extractVariablesAux(next) + ( + variableSet ++ variableSet_, + functionSet ++ functionSet_, + formulaVariableSet ++ formulaVariableSet_, + predicateSet ++ predicateSet_, + connectorSet ++ connectorSet_ + ) + }) + + private def generateVariablesCode(formulas: Set[K.Formula], accessibility: String): String = + val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = extractVariables(formulas) + val access = if accessibility != "" then accessibility.strip() + " " else "" + (variableSet.map(v => access + s"val ${v.id} = variable").toList.sorted ++ + functionSet.map(f => access + s"val ${f.id} = function[${f.arity}]").toList.sorted ++ + formulaVariableSet.map(v => access + s"val ${v.id} = formulaVariable").toList.sorted ++ + predicateSet.map(p => access + s"val ${p.id} = predicate[${p.arity}]").toList.sorted ++ + connectorSet.map(c => access + s"val ${c.id} = connector[${c.arity}]").toList.sorted).mkString("\n") + + private def generateVariablesCode(statement: K.Sequent, proof: K.SCProof, accessibility: String = "private"): String = + generateVariablesCode(extractFormulasFromProof(proof) + K.sequentToFormula(statement), accessibility) + + private def generateTheoremCode(name: String, statement: K.Sequent, proof: K.SCProof): String = { s"val $name = Theorem(\n" + indent(any2code(statement)) + s"\n) {\n" + @@ -132,4 +150,14 @@ object ProofsConverter { s"\n}" } + def generateStandaloneTheoremFileContent(name: String, statement: K.Sequent, proof: K.SCProof): String = + val camelName = "[A-Za-z0-9]+".r.findAllIn(name).map(_.capitalize).mkString + s"object $camelName extends lisa.Main {\n\n" + + indent( + generateVariablesCode(statement, proof) + + "\n\n" + + generateTheoremCode(name, statement, proof) + ) + + "\n}" + } From dd21c0f9a2ebe9f721bb91719148faed7cf6bed7 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:28 +0100 Subject: [PATCH 19/24] Add documentation to the lisa proof code generator --- .../src/main/scala/Kernel2Code.scala | 16 ++-- lisa-examples/src/main/scala/TPTPSolver.scala | 2 +- .../scala/lisa/utils/ProofsConverter.scala | 90 ++++++++++++++++--- 3 files changed, 88 insertions(+), 20 deletions(-) diff --git a/lisa-examples/src/main/scala/Kernel2Code.scala b/lisa-examples/src/main/scala/Kernel2Code.scala index f3b6b1f96..e3f4690ac 100644 --- a/lisa-examples/src/main/scala/Kernel2Code.scala +++ b/lisa-examples/src/main/scala/Kernel2Code.scala @@ -27,8 +27,8 @@ object Kernel2Code extends lisa.Main { thenHave(∃(x, ∀(y, S(x, y))) |- ∀(y, ∃(x, S(x, y)))) by RightForall } - // println(generateStandaloneTheoremFileContent("thm1_raw", thm1.statement.underlying, thm1.kernelProof.get)) - // println(generateStandaloneTheoremFileContent("thm1_optimized", thm1.statement.underlying, optimizeProofIteratively(thm1.kernelProof.get))) + // println(generateStandaloneTheoremFileContent("thm1_raw", thm1.kernelProof.get)) + // println(generateStandaloneTheoremFileContent("thm1_optimized", optimizeProofIteratively(thm1.kernelProof.get))) val thm1_raw = Theorem( ∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y))) @@ -85,8 +85,8 @@ object Kernel2Code extends lisa.Main { have(thesis) by Tautology.from(forward, backward) } - // println(generateStandaloneTheoremFileContent("thm2_raw", thm2.statement.underlying, thm2.kernelProof.get)) - // println(generateStandaloneTheoremFileContent("thm2_optimized", thm2.statement.underlying, optimizeProofIteratively(thm2.kernelProof.get))) + // println(generateStandaloneTheoremFileContent("thm2_raw", thm2.kernelProof.get)) + // println(generateStandaloneTheoremFileContent("thm2_optimized", optimizeProofIteratively(thm2.kernelProof.get))) val thm2_raw = Theorem( ((∀(x, Q(x)) ∧ ∀(x, R(x))) <=> ∀(x, (Q(x) ∧ R(x)))) @@ -192,8 +192,8 @@ object Kernel2Code extends lisa.Main { have(thesis) by Tautology.from(step1, step1 of (x := f(x))) } - // println(generateStandaloneTheoremFileContent("thm3_raw", thm3.statement.underlying, thm3.kernelProof.get)) - // println(generateStandaloneTheoremFileContent("thm3_optimized", thm3.statement.underlying, optimizeProofIteratively(thm3.kernelProof.get))) + // println(generateStandaloneTheoremFileContent("thm3_raw", thm3.kernelProof.get)) + // println(generateStandaloneTheoremFileContent("thm3_optimized", optimizeProofIteratively(thm3.kernelProof.get))) val thm3_raw = Theorem( ∀(x, (Q(x) ==> Q(f(x)))) ⊢ (Q(x) ==> Q(f(f(x)))) @@ -296,8 +296,8 @@ object Kernel2Code extends lisa.Main { have(thesis) by Tableau } - // println(generateStandaloneTheoremFileContent("thm1bis_raw", thm1bis.statement.underlying, thm1bis.kernelProof.get)) - // println(generateStandaloneTheoremFileContent("thm1bis_optimized", thm1bis.statement.underlying, optimizeProofIteratively(thm1bis.kernelProof.get))) + // println(generateStandaloneTheoremFileContent("thm1bis_raw", thm1bis.kernelProof.get)) + // println(generateStandaloneTheoremFileContent("thm1bis_optimized", optimizeProofIteratively(thm1bis.kernelProof.get))) val thm1bis_raw = Theorem( ∃(x, ∀(y, S(x, y))) ⊢ ∀(y, ∃(x, S(x, y))) diff --git a/lisa-examples/src/main/scala/TPTPSolver.scala b/lisa-examples/src/main/scala/TPTPSolver.scala index 05ed0ef3d..57615b68b 100644 --- a/lisa-examples/src/main/scala/TPTPSolver.scala +++ b/lisa-examples/src/main/scala/TPTPSolver.scala @@ -88,7 +88,7 @@ object TPTPSolver extends lisa.Main { def writeProof(problem: Problem, proof: SCProof, path: String): Unit = { val file = new File(path + problem.name + ".sc") val bw = new FileWriter(file) - val fileContent = generateStandaloneTheoremFileContent(problem.name, problemToSequent(problem), proof) + val fileContent = generateStandaloneTheoremFileContent(problem.name, proof) bw.write(fileContent) bw.close() } diff --git a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala index 1c4875937..4f5481c1e 100644 --- a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala +++ b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala @@ -12,15 +12,27 @@ object ProofsConverter { // TODO: remove unnecessary variables "val s_..." in generated proofs -> need to detect which steps are used later in other steps // TODO: generate more realistic variable names - private def indent(s: String, indent: Int = 2): String = s.split("\n").map(" " * indent + _).mkString("\n") - private def unindent(s: String, indent: Int = 2): String = s.split("\n").map(_.drop(indent)).mkString("\n") - + private def indent(s: String, indent: Int = 2): String = s.split("\n").map(s => if s == "" then "" else " " * indent + s).mkString("\n") + private def unindent(s: String, indent: Int = 2): String = s.split("\n").map(_.stripPrefix(" " * indent)).mkString("\n") + + /** + * Converts a Sequent, Formula or Term to a valid Scala/Lisa code + * + * @param f formula to convert + * @return Scala code representing the formula in string format + */ private def any2code(a: K.Sequent | K.Formula | K.Term): String = (a match case sq: K.Sequent => asFront(sq) case form: K.Formula => asFront(form) case term: K.Term => asFront(term) ).toString.replace("⇒", "==>").replace("⇔", "<=>") + /** + * Converts a SCProof to a valid Scala/Lisa code using tactics. + * + * @param p proof to convert + * @return Scala code representing the proof in string format + */ private def scproof2code(p: K.SCProof): String = { def scproof2codeAux(p: K.SCProof, varPrefix: String = "s", implicitPremises: Seq[String] = Seq.empty): String = { def scproofstep2code(ps: SCProofStep, stepNum: Int, implicitPremises: Seq[String], varPrefix: String): String = { @@ -91,6 +103,12 @@ object ProofsConverter { unindent(scproof2codeAux(p)) } + /** + * Extracts all formulas from a proof + * + * @param proof proof to extract formulas from + * @return set of formulas + */ private def extractFormulasFromProof(proof: K.SCProof): Set[K.Formula] = proof.steps.foldLeft(Set.empty[K.Formula])((prev, next) => { prev ++ (next match @@ -103,6 +121,12 @@ object ProofsConverter { ) }) + /** + * Extracts all variables, functions, formula variables, predicates and connectors from a set of formulas + * + * @param formulas set of formulas to extract variables from + * @return tuple of sets of variables, functions, formula variables, predicates and connectors + */ private def extractVariables( formulas: Set[K.Formula] ): (Set[K.VariableLabel], Set[K.SchematicFunctionLabel], Set[K.VariableFormulaLabel], Set[K.SchematicPredicateLabel], Set[K.SchematicConnectorLabel]) = @@ -130,6 +154,15 @@ object ProofsConverter { ) }) + /** + * Generates a valid Scala/Lisa code to declare variables, functions, formula variables, predicates and connectors + * used in a set of formulas + * + * @param formulas set of formulas to generate variables for + * @param accessibility accessibility of the variables (e.g. "private") + * + * @return Scala code representing the variables in string format + */ private def generateVariablesCode(formulas: Set[K.Formula], accessibility: String): String = val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = extractVariables(formulas) val access = if accessibility != "" then accessibility.strip() + " " else "" @@ -139,25 +172,60 @@ object ProofsConverter { predicateSet.map(p => access + s"val ${p.id} = predicate[${p.arity}]").toList.sorted ++ connectorSet.map(c => access + s"val ${c.id} = connector[${c.arity}]").toList.sorted).mkString("\n") - private def generateVariablesCode(statement: K.Sequent, proof: K.SCProof, accessibility: String = "private"): String = - generateVariablesCode(extractFormulasFromProof(proof) + K.sequentToFormula(statement), accessibility) - - private def generateTheoremCode(name: String, statement: K.Sequent, proof: K.SCProof): String = { + /** + * Generates a valid Scala/Lisa code to declare variables, functions, formula variables, predicates and connectors + * used in a proof + * + * @param proof proof to generate variables for + * @param accessibility accessibility of the variables (e.g. "private") + * + * @return Scala code representing the variables in string format + */ + private def generateVariablesCode(proof: K.SCProof, accessibility: String = "private"): String = + generateVariablesCode(extractFormulasFromProof(proof), accessibility) + + /** + * Generates a valid Scala/Lisa code of a theorem and its proof + * + * @param name name of the theorem + * @param proof proof of the theorem + * + * @return Scala code representing the theorem in string format + */ + private def generateTheoremCode(name: String, proof: K.SCProof): String = { s"val $name = Theorem(\n" + - indent(any2code(statement)) + + indent(any2code(proof.conclusion)) + s"\n) {\n" + indent(scproof2code(proof)) + s"\n}" } - def generateStandaloneTheoremFileContent(name: String, statement: K.Sequent, proof: K.SCProof): String = + /** + * Generates a valid Scala/Lisa code of a theorem and its proof in a standalone file, including the necessary variables declarations. + * The theorem and its proof must be self-contained, i.e. no dependencies to other theorems, axioms, definitions, etc. + * + * @param name name of the theorem + * @param proof proof of the theorem + * + * @return Scala code representing the theorem in string format + */ + def generateStandaloneTheoremFileContent(name: String, proof: K.SCProof): String = val camelName = "[A-Za-z0-9]+".r.findAllIn(name).map(_.capitalize).mkString s"object $camelName extends lisa.Main {\n\n" + indent( - generateVariablesCode(statement, proof) + + generateVariablesCode(proof) + "\n\n" + - generateTheoremCode(name, statement, proof) + generateTheoremCode(name, proof) ) + "\n}" + /** + * Parse and check that a generated theorem file is valid, i.e. that it compiles and the theorem is proven + * @param fileContent content of the generated file + * @return true if the file is valid, false otherwise + */ + def checkGeneratedFileContent(fileContent: String): Boolean = + // TODO + false + } From 15bf01058b46c9907de6cd0ff3cca7212d3cdeab Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:29 +0100 Subject: [PATCH 20/24] Fix TPTP parsing of atomic formula --- .../scala/lisa/utils/tptp/KernelParser.scala | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala b/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala index c0c4ceaea..8a6f02770 100644 --- a/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala +++ b/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala @@ -35,7 +35,12 @@ object KernelParser { */ def convertToKernel(formula: FOF.Formula): K.Formula = { formula match { - case FOF.AtomicFormula(f, args) => K.AtomicFormula(K.ConstantAtomicLabel(cleanVarname(f), args.size), args map convertTermToKernel) + case FOF.AtomicFormula(f, args) => + K.AtomicFormula( + if args.isEmpty then K.VariableFormulaLabel(cleanVarname(f)) + else K.SchematicPredicateLabel(cleanVarname(f), args.size), + args map convertTermToKernel + ) case FOF.QuantifiedFormula(quantifier, variableList, body) => quantifier match { case FOF.! => variableList.foldRight(convertToKernel(body))((s, f) => K.Forall(K.VariableLabel(s), f)) @@ -62,12 +67,18 @@ object KernelParser { } def convertToKernel(formula: CNF.Formula): K.Formula = { + def atomicFormulaToKernel(formula: CNF.AtomicFormula): K.Formula = + K.AtomicFormula( + if formula.args.isEmpty then K.VariableFormulaLabel(cleanVarname(formula.f)) + else K.SchematicPredicateLabel(cleanVarname(formula.f), formula.args.size), + formula.args.map(convertTermToKernel).toList + ) K.ConnectorFormula( K.Or, formula.map { - case CNF.PositiveAtomic(formula) => K.AtomicFormula(K.ConstantAtomicLabel(cleanVarname(formula.f), formula.args.size), formula.args.map(convertTermToKernel).toList) - case CNF.NegativeAtomic(formula) => !K.AtomicFormula(K.ConstantAtomicLabel(cleanVarname(formula.f), formula.args.size), formula.args.map(convertTermToKernel).toList) + case CNF.PositiveAtomic(formula) => atomicFormulaToKernel(formula) + case CNF.NegativeAtomic(formula) => !atomicFormulaToKernel(formula) case CNF.Equality(left, right) => K.equality(convertTermToKernel(left), convertTermToKernel(right)) case CNF.Inequality(left, right) => !K.equality(convertTermToKernel(left), convertTermToKernel(right)) } @@ -79,7 +90,12 @@ object KernelParser { * @return the same term in LISA */ def convertTermToKernel(term: CNF.Term): K.Term = term match { - case CNF.AtomicTerm(f, args) => K.Term(K.ConstantFunctionLabel(cleanVarname(f), args.size), args map convertTermToKernel) + case CNF.AtomicTerm(f, args) => + K.Term( + if args.isEmpty then K.VariableLabel(cleanVarname(f)) + else K.SchematicFunctionLabel(cleanVarname(f), args.size), + args map convertTermToKernel + ) case CNF.Variable(name) => K.VariableTerm(K.VariableLabel(name)) case CNF.DistinctObject(name) => ??? } @@ -90,7 +106,11 @@ object KernelParser { */ def convertTermToKernel(term: FOF.Term): K.Term = term match { case FOF.AtomicTerm(f, args) => - K.Term(K.ConstantFunctionLabel(cleanVarname(f), args.size), args map convertTermToKernel) + K.Term( + if args.isEmpty then K.VariableLabel(cleanVarname(f)) + else K.SchematicFunctionLabel(cleanVarname(f), args.size), + args map convertTermToKernel + ) case FOF.Variable(name) => K.VariableTerm(K.VariableLabel(name)) case FOF.DistinctObject(name) => ??? case FOF.NumberTerm(value) => ??? From 57a57f03a75333d95eaea5770ec280449028c09b Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:29 +0100 Subject: [PATCH 21/24] Improve the Lisa code generator from SCProof --- .../scala/lisa/utils/ProofsConverter.scala | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala index 4f5481c1e..f53aee0ad 100644 --- a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala +++ b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala @@ -21,7 +21,7 @@ object ProofsConverter { * @param f formula to convert * @return Scala code representing the formula in string format */ - private def any2code(a: K.Sequent | K.Formula | K.Term): String = (a match + def any2code(a: K.Sequent | K.Formula | K.Term): String = (a match case sq: K.Sequent => asFront(sq) case form: K.Formula => asFront(form) case term: K.Term => asFront(term) @@ -109,7 +109,7 @@ object ProofsConverter { * @param proof proof to extract formulas from * @return set of formulas */ - private def extractFormulasFromProof(proof: K.SCProof): Set[K.Formula] = + def extractFormulasFromProof(proof: K.SCProof): Set[K.Formula] = proof.steps.foldLeft(Set.empty[K.Formula])((prev, next) => { prev ++ (next match case sp @ SCSubproof(subproof, _) => extractFormulasFromProof(subproof) @@ -122,37 +122,40 @@ object ProofsConverter { }) /** - * Extracts all variables, functions, formula variables, predicates and connectors from a set of formulas + * Extracts all symbols: variables, functions, formula variables, predicates and connectors from a set of formulas * * @param formulas set of formulas to extract variables from * @return tuple of sets of variables, functions, formula variables, predicates and connectors */ - private def extractVariables( + def extractSymbols( formulas: Set[K.Formula] ): (Set[K.VariableLabel], Set[K.SchematicFunctionLabel], Set[K.VariableFormulaLabel], Set[K.SchematicPredicateLabel], Set[K.SchematicConnectorLabel]) = def extractVariablesAux( formula: K.Formula ): (Set[K.VariableLabel], Set[K.SchematicFunctionLabel], Set[K.VariableFormulaLabel], Set[K.SchematicPredicateLabel], Set[K.SchematicConnectorLabel]) = - var variableSet = formula.schematicTermLabels.collect { case v: K.VariableLabel => v } - var functionSet = formula.schematicTermLabels.collect { case f: K.SchematicFunctionLabel => f } - var formulaVariableSet = formula.schematicAtomicLabels.collect { case v: K.VariableFormulaLabel => v } - var predicateSet = formula.schematicAtomicLabels.collect { case p: K.SchematicPredicateLabel => p } - var connectorSet = formula.schematicConnectorLabels.collect { case c: K.SchematicConnectorLabel => c } + val variableSet = formula.schematicTermLabels.collect { case v: K.VariableLabel => v } ++ formula.freeVariables ++ formula.freeSchematicTermLabels.collect { case v: K.VariableLabel => v } + // val constantSet = formula.constantTermLabels.collect { case c: K.ConstantFunctionLabel if c.arity == 0 => c } + val functionSet = formula.schematicTermLabels.collect { case f: K.SchematicFunctionLabel => f } ++ formula.freeSchematicTermLabels.collect { case f: K.SchematicFunctionLabel => f } + // val constantFunctionSet = formula.constantTermLabels.collect { case c: K.ConstantFunctionLabel if c.arity > 0 => c } + val formulaVariableSet = formula.schematicAtomicLabels.collect { case v: K.VariableFormulaLabel => v } ++ formula.freeVariableFormulaLabels + val predicateSet = formula.schematicAtomicLabels.collect { case p: K.SchematicPredicateLabel => p } + // val constantPredicateSet = formula.constantAtomicLabels + val connectorSet = formula.schematicConnectorLabels.collect { case c: K.SchematicConnectorLabel => c } (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) - formulas.foldLeft( - (Set.empty[K.VariableLabel], Set.empty[K.SchematicFunctionLabel], Set.empty[K.VariableFormulaLabel], Set.empty[K.SchematicPredicateLabel], Set.empty[K.SchematicConnectorLabel]) - )((prev, next) => { - val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = prev - val (variableSet_, functionSet_, formulaVariableSet_, predicateSet_, connectorSet_) = extractVariablesAux(next) - ( - variableSet ++ variableSet_, - functionSet ++ functionSet_, - formulaVariableSet ++ formulaVariableSet_, - predicateSet ++ predicateSet_, - connectorSet ++ connectorSet_ - ) - }) + formulas.foldLeft((Set.empty[K.VariableLabel], Set.empty[K.SchematicFunctionLabel], Set.empty[K.VariableFormulaLabel], Set.empty[K.SchematicPredicateLabel], Set.empty[K.SchematicConnectorLabel]))( + (prev, next) => { + val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = prev + val (variableSet_, functionSet_, formulaVariableSet_, predicateSet_, connectorSet_) = extractVariablesAux(next) + ( + variableSet ++ variableSet_, + functionSet ++ functionSet_, + formulaVariableSet ++ formulaVariableSet_, + predicateSet ++ predicateSet_, + connectorSet ++ connectorSet_ + ) + } + ) /** * Generates a valid Scala/Lisa code to declare variables, functions, formula variables, predicates and connectors @@ -164,7 +167,7 @@ object ProofsConverter { * @return Scala code representing the variables in string format */ private def generateVariablesCode(formulas: Set[K.Formula], accessibility: String): String = - val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = extractVariables(formulas) + val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = extractSymbols(formulas) val access = if accessibility != "" then accessibility.strip() + " " else "" (variableSet.map(v => access + s"val ${v.id} = variable").toList.sorted ++ functionSet.map(f => access + s"val ${f.id} = function[${f.arity}]").toList.sorted ++ @@ -181,7 +184,7 @@ object ProofsConverter { * * @return Scala code representing the variables in string format */ - private def generateVariablesCode(proof: K.SCProof, accessibility: String = "private"): String = + def generateVariablesCode(proof: K.SCProof, accessibility: String = "private"): String = generateVariablesCode(extractFormulasFromProof(proof), accessibility) /** @@ -193,7 +196,9 @@ object ProofsConverter { * @return Scala code representing the theorem in string format */ private def generateTheoremCode(name: String, proof: K.SCProof): String = { - s"val $name = Theorem(\n" + + // lowercase and underscore-separated version of the theorem name + val filteredName = "[A-Za-z0-9]+".r.findAllIn(name).mkString("_").toLowerCase + s"val $filteredName = Theorem(\n" + indent(any2code(proof.conclusion)) + s"\n) {\n" + indent(scproof2code(proof)) + From 4a6bbbb1ec6eba2ae392e7f0595c1cd35db6f169 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:29 +0100 Subject: [PATCH 22/24] Export proofs extracted from TPTP to JSON --- build.sbt | 5 +- lisa-examples/src/main/scala/TPTPSolver.scala | 170 +++++++++++------- .../scala/lisa/utils/ProofsConverter.scala | 32 ++-- .../src/main/scala/lisa/utils/RunSolver.scala | 6 +- 4 files changed, 132 insertions(+), 81 deletions(-) diff --git a/build.sbt b/build.sbt index 5b1996c96..9a25d67a1 100644 --- a/build.sbt +++ b/build.sbt @@ -16,9 +16,6 @@ ThisBuild / semanticdbEnabled := true ThisBuild / semanticdbVersion := scalafixSemanticdb.revision ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.6.0" - - - val commonSettings = Seq( crossScalaVersions := Seq("2.12.13", "2.13.4", "3.0.1", "3.2.0"), run / fork := true @@ -41,6 +38,7 @@ val commonSettings3 = commonSettings ++ Seq( ), libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.10" % "test", libraryDependencies += "com.lihaoyi" %% "sourcecode" % "0.3.0", + libraryDependencies += "com.lihaoyi" %% "ujson" % "3.1.0", // libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1", libraryDependencies += ("io.github.uuverifiers" %% "princess" % "2023-06-19").cross(CrossVersion.for3Use2_13), Test / parallelExecution := false @@ -102,7 +100,6 @@ ThisBuild / assemblyMergeStrategy := { oldStrategy(x) } - lazy val examples = Project( id = "lisa-examples", base = file("lisa-examples") diff --git a/lisa-examples/src/main/scala/TPTPSolver.scala b/lisa-examples/src/main/scala/TPTPSolver.scala index 57615b68b..a20ef722a 100644 --- a/lisa-examples/src/main/scala/TPTPSolver.scala +++ b/lisa-examples/src/main/scala/TPTPSolver.scala @@ -7,88 +7,126 @@ import lisa.utils.ProofsConverter.* import lisa.utils.RunSolver.* import lisa.utils.tptp.* import lisa.utils.tptp.KernelParser.* -import lisa.utils.tptp.ProblemGatherer.* import lisa.kernel.proof.SCProof import lisa.kernel.proof.SequentCalculus.Sequent -import lisa.kernel.proof.SCProofChecker.checkSCProof +import lisa.utils.ProofsShrink.optimizeProofIteratively object TPTPSolver extends lisa.Main { - try { - val spc = Seq("PRP", "FOF") // type of problems we want to extract and solve - // val spc = Seq("PRP", "FOF", "CNF") // almost no CNF problems are solved by Tableau, TODO: investigate why - - // val d = new File(TPTPProblemPath) - // val libraries = d.listFiles.filter(_.isDirectory) - // val probfiles = libraries.flatMap(_.listFiles).filter(_.isFile) - - val d = new File(TPTPProblemPath + "SYN/") - val probfiles = d.listFiles.filter(_.isFile) - - // We limit the execution time to solve each problem - val timeoutTableau = .1.second - val timeoutTautology = .1.second - - var nbProblemsExtracted = 0 - var nbProblemsSolvedByTableau = 0 - var nbProblemsSolvedByTautology = 0 - - for ((probfile, i) <- probfiles.zipWithIndex) { - // Progress bar - if ((i + 1) % 10 == 0 || i + 1 == probfiles.size) { - val pbarLength = 30 - var pbarContent = "=" * (((i + 1) * pbarLength) / probfiles.size) - pbarContent += " " * (pbarLength - pbarContent.length) - print(s"[$pbarContent]") - print(s" -- ${i + 1}/${probfiles.size} processed files") - print(s" -- $nbProblemsExtracted extracted problems") - print(s" -- Tableau: $nbProblemsSolvedByTableau solved") - println(s" -- Tautology: $nbProblemsSolvedByTautology solved") - } + sealed trait ProofType + case object BySolver extends ProofType + case object Kernel extends ProofType + case object KernelOptimized extends ProofType + + class ProblemSolverResults(val problem: Problem, val solverName: String, val solverStatus: String, val proofCode: String, val proofType: ProofType) + + val exportOnlySolvedProblems = true + val exportOptimizedProofs = true + val exportBySolverProofs = true + + val jsonResultsPath: String = "/home/auguste/Documents/EPFL/PhD/Projects/lisa/lisa-examples/src/main/resources/TPTPResults.json" + val TPTPProblemPath: String = "/home/auguste/Documents/EPFL/PhD/Projects/TPTP-v8.2.0/Problems/" + + val spc = Seq("PRP", "FOF") // type of problems we want to extract and solve + // val spc = Seq("CNF") // almost no CNF problems are solved by Tableau, TODO: investigate why + + // val d = new File(TPTPProblemPath) + // val libraries = d.listFiles.filter(_.isDirectory) + // val probfiles = libraries.flatMap(_.listFiles).filter(_.isFile) + + val d = new File(TPTPProblemPath + "SYN/") + val probfiles = d.listFiles.filter(_.isFile) + + // We limit the execution time to solve each problem + val timeoutTableau = .1.second + val timeoutTautology = .1.second - // Try to extract and solve the problem - try { - val md = getProblemInfos(probfile) + var nbProblemsExtracted = 0 + var nbProblemsSolved = Map("Tableau" -> 0, "Tautology" -> 0) + var nbInvalidProofs = Map("Tableau" -> 0, "Tautology" -> 0) + var results = Seq.empty[ProblemSolverResults] + + for ((probfile, i) <- probfiles.zipWithIndex) { + // Progress bar + if ((i + 1) % 10 == 0 || i + 1 == probfiles.size) { + val pbarLength = 20 + var pbarContent = "=" * (((i + 1) * pbarLength) / probfiles.size) + pbarContent += " " * (pbarLength - pbarContent.length) + print(s"[$pbarContent]") + print(s" -- ${i + 1}/${probfiles.size} processed files") + print(s" -- $nbProblemsExtracted extracted problems") + print(s" -- Tableau: ${nbProblemsSolved("Tableau")} solved + ${nbInvalidProofs("Tableau")} invalid") + println(s" -- Tautology: ${nbProblemsSolved("Tautology")} solved + ${nbInvalidProofs("Tautology")} invalid") + } + + // Try to extract and solve the problem + try { + val md = getProblemInfos(probfile) + if (!(md.spc.contains("SAT"))) { if (md.spc.exists(spc.contains)) { - val p = problemToKernel(probfile, md) - val seq = problemToSequent(p) + val problem = problemToKernel(probfile, md) + val seq = problemToSequent(problem) nbProblemsExtracted += 1 + def exportResults(problem: Problem, solverName: String, solverResult: SolverResult): Unit = + val solverStatus = solverResult.getClass.getSimpleName.stripSuffix("$") + solverResult match + case Solved(proof) => + nbProblemsSolved += (solverName -> (nbProblemsSolved(solverName) + 1)) + results :+= new ProblemSolverResults(problem, solverName, solverStatus, generateStandaloneTheoremFileContent(problem.name, proof), Kernel) + if (exportOptimizedProofs) + results :+= new ProblemSolverResults(problem, solverName, solverStatus, generateStandaloneTheoremFileContent(problem.name, optimizeProofIteratively(proof)), KernelOptimized) + if (exportBySolverProofs) + val statementString = any2code(seq) + val proofCode = s"have(thesis) by $solverName" + val symbolDeclarations = generateSymbolDeclarationCode(Set(K.sequentToFormula(seq)), "private") + results :+= new ProblemSolverResults(problem, solverName, solverStatus, generateStandaloneTheoremFileContent(problem.name, statementString, proofCode, symbolDeclarations), BySolver) + case InvalidProof(proof) => + nbInvalidProofs += (solverName -> (nbInvalidProofs(solverName) + 1)) + if (!exportOnlySolvedProblems) + results :+= new ProblemSolverResults(problem, solverName, solverStatus, generateStandaloneTheoremFileContent(problem.name, proof), Kernel) + case _ => + if (!exportOnlySolvedProblems) + results :+= new ProblemSolverResults(problem, solverName, solverStatus, "", Kernel) + // Attempting proof by Tableau - proveSequent(seq, timeoutTableau, Tableau.solve) match { - case Solved(proof) => - if (checkSCProof(proof).isValid) - nbProblemsSolvedByTableau += 1 - // writeProof(p, proof, "examples/proofs/tableau/") - else throw new Exception("Tableau proof is not valid") - case _ => () - } + val tableauResult = proveSequent(seq, timeoutTableau, Tableau.solve) + exportResults(problem, "Tableau", tableauResult) // Attempting proof by Tautology def tautologySolver(s: lisa.utils.K.Sequent): Option[SCProof] = Tautology.solveSequent(s) match case Left(proof) => Some(proof) case _ => None - proveSequent(seq, timeoutTautology, tautologySolver) match { - case Solved(proof) => - if (checkSCProof(proof).isValid) - nbProblemsSolvedByTautology += 1 - // writeProof(p, proof, "examples/proofs/tautology/") - else throw new Exception("Tautology proof is not valid") - case _ => () - } + val tautologyResult = proveSequent(seq, timeoutTautology, tautologySolver) + exportResults(problem, "Tautology", tautologyResult) } - } catch { - case e => println(s"Error while processing $probfile: $e") + // } else println(s"Problem $probfile not extracted because of its type: ${md.spc.mkString(",")}") } - } - } catch { - case error: NullPointerException => println("You can download the tptp library at http://www.tptp.org/ and put it in main/resources") + } catch case e => println(s"Error while processing $probfile (index $i): $e") } -} -def writeProof(problem: Problem, proof: SCProof, path: String): Unit = { - val file = new File(path + problem.name + ".sc") - val bw = new FileWriter(file) - val fileContent = generateStandaloneTheoremFileContent(problem.name, proof) - bw.write(fileContent) - bw.close() + // Write results to a JSON file + val jsonResultsFile = new File(jsonResultsPath) + if (!jsonResultsFile.getParentFile.exists()) + jsonResultsFile.getParentFile.mkdirs() + val jsonWriter = new java.io.PrintWriter(jsonResultsPath) + ujson.writeTo( + results.map(r => + ujson.Obj( + "problemName" -> r.problem.name, + "problemDomain" -> r.problem.domain, + "problemStatus" -> r.problem.status, + "problemSPC" -> r.problem.spc.mkString(","), + "problemSequent" -> any2code(problemToSequent(r.problem)), + "problemFile" -> r.problem.file, + "solver" -> r.solverName, + "solverStatus" -> r.solverStatus, + "solverProofCode" -> r.proofCode, + "proofType" -> r.proofType.getClass.getSimpleName.stripSuffix("$") + ) + ), + jsonWriter, + indent = 2 + ) + jsonWriter.close() + } diff --git a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala index f53aee0ad..44edc0843 100644 --- a/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala +++ b/lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala @@ -166,7 +166,7 @@ object ProofsConverter { * * @return Scala code representing the variables in string format */ - private def generateVariablesCode(formulas: Set[K.Formula], accessibility: String): String = + def generateSymbolDeclarationCode(formulas: Set[K.Formula], accessibility: String): String = val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = extractSymbols(formulas) val access = if accessibility != "" then accessibility.strip() + " " else "" (variableSet.map(v => access + s"val ${v.id} = variable").toList.sorted ++ @@ -184,8 +184,8 @@ object ProofsConverter { * * @return Scala code representing the variables in string format */ - def generateVariablesCode(proof: K.SCProof, accessibility: String = "private"): String = - generateVariablesCode(extractFormulasFromProof(proof), accessibility) + def generateSymbolDeclarationCode(proof: K.SCProof, accessibility: String = "private"): String = + generateSymbolDeclarationCode(extractFormulasFromProof(proof), accessibility) /** * Generates a valid Scala/Lisa code of a theorem and its proof @@ -195,13 +195,13 @@ object ProofsConverter { * * @return Scala code representing the theorem in string format */ - private def generateTheoremCode(name: String, proof: K.SCProof): String = { + def generateTheoremCode(name: String, statementString: String, proofCode: String): String = { // lowercase and underscore-separated version of the theorem name val filteredName = "[A-Za-z0-9]+".r.findAllIn(name).mkString("_").toLowerCase s"val $filteredName = Theorem(\n" + - indent(any2code(proof.conclusion)) + + indent(statementString) + s"\n) {\n" + - indent(scproof2code(proof)) + + indent(proofCode) + s"\n}" } @@ -210,20 +210,32 @@ object ProofsConverter { * The theorem and its proof must be self-contained, i.e. no dependencies to other theorems, axioms, definitions, etc. * * @param name name of the theorem - * @param proof proof of the theorem + * @param proofCode code of the proof of the theorem * * @return Scala code representing the theorem in string format */ - def generateStandaloneTheoremFileContent(name: String, proof: K.SCProof): String = + def generateStandaloneTheoremFileContent(name: String, statementString: String, proofCode: String, symbolDeclarations: String): String = val camelName = "[A-Za-z0-9]+".r.findAllIn(name).map(_.capitalize).mkString s"object $camelName extends lisa.Main {\n\n" + indent( - generateVariablesCode(proof) + + symbolDeclarations + "\n\n" + - generateTheoremCode(name, proof) + generateTheoremCode(name, statementString, proofCode) ) + "\n}" + /** + * Generates a valid Scala/Lisa code of a theorem and its proof in a standalone file, including the necessary variables declarations. + * The theorem and its proof must be self-contained, i.e. no dependencies to other theorems, axioms, definitions, etc. + * + * @param name name of the theorem + * @param proof proof of the theorem + * + * @return Scala code representing the theorem in string format + */ + def generateStandaloneTheoremFileContent(name: String, proof: K.SCProof): String = + generateStandaloneTheoremFileContent(name, any2code(proof.conclusion), scproof2code(proof), generateSymbolDeclarationCode(proof)) + /** * Parse and check that a generated theorem file is valid, i.e. that it compiles and the theorem is proven * @param fileContent content of the generated file diff --git a/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala b/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala index 29be3fc76..b0fb2ec8b 100644 --- a/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala +++ b/lisa-utils/src/main/scala/lisa/utils/RunSolver.scala @@ -7,10 +7,12 @@ import java.util.concurrent.CancellationException import lisa.kernel.proof.SCProof import lisa.kernel.proof.SequentCalculus.Sequent +import lisa.kernel.proof.SCProofChecker.checkSCProof object RunSolver { sealed trait SolverResult case class Solved(proof: SCProof) extends SolverResult + case class InvalidProof(proof: SCProof) extends SolverResult case object Unsolved extends SolverResult case object Timeout extends SolverResult case class SolverThrow(t: Throwable) extends SolverResult @@ -19,7 +21,9 @@ object RunSolver { val (futureSolver, cancelSolver) = Future.interruptibly { solver(sequent) } try Await.result(futureSolver, timeout) match - case Some(proof) => Solved(proof) + case Some(proof) => + if (checkSCProof(proof).isValid) Solved(proof) + else InvalidProof(proof) case None => Unsolved catch case _: TimeoutException => From 531ba961389df9dee96476028ed778804bfe6539 Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:30 +0100 Subject: [PATCH 23/24] Fix equality infix printing + parsing issues --- lisa-examples/src/main/scala/TPTPSolver.scala | 28 +++++++++---------- .../src/main/scala/lisa/fol/Common.scala | 3 +- .../src/main/scala/lisa/fol/FOLHelpers.scala | 6 +++- .../scala/lisa/utils/tptp/KernelParser.scala | 11 +++++--- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/lisa-examples/src/main/scala/TPTPSolver.scala b/lisa-examples/src/main/scala/TPTPSolver.scala index a20ef722a..f9ba28b25 100644 --- a/lisa-examples/src/main/scala/TPTPSolver.scala +++ b/lisa-examples/src/main/scala/TPTPSolver.scala @@ -19,6 +19,13 @@ object TPTPSolver extends lisa.Main { class ProblemSolverResults(val problem: Problem, val solverName: String, val solverStatus: String, val proofCode: String, val proofType: ProofType) + val spc = Seq("PRP", "FOF") // type of problems we want to extract and solve + // val spc = Seq("CNF") // almost no CNF problems are solved by Tableau, TODO: investigate why + + // We limit the execution time to solve each problem + val timeoutTableau = .1.second + val timeoutTautology = .1.second + val exportOnlySolvedProblems = true val exportOptimizedProofs = true val exportBySolverProofs = true @@ -26,19 +33,12 @@ object TPTPSolver extends lisa.Main { val jsonResultsPath: String = "/home/auguste/Documents/EPFL/PhD/Projects/lisa/lisa-examples/src/main/resources/TPTPResults.json" val TPTPProblemPath: String = "/home/auguste/Documents/EPFL/PhD/Projects/TPTP-v8.2.0/Problems/" - val spc = Seq("PRP", "FOF") // type of problems we want to extract and solve - // val spc = Seq("CNF") // almost no CNF problems are solved by Tableau, TODO: investigate why - - // val d = new File(TPTPProblemPath) - // val libraries = d.listFiles.filter(_.isDirectory) - // val probfiles = libraries.flatMap(_.listFiles).filter(_.isFile) - - val d = new File(TPTPProblemPath + "SYN/") - val probfiles = d.listFiles.filter(_.isFile) + val d = new File(TPTPProblemPath) + val libraries = d.listFiles.filter(_.isDirectory) + val probfiles = libraries.flatMap(_.listFiles).filter(_.isFile) - // We limit the execution time to solve each problem - val timeoutTableau = .1.second - val timeoutTautology = .1.second + // val d = new File(TPTPProblemPath + "SYN/") + // val probfiles = d.listFiles.filter(_.isFile) var nbProblemsExtracted = 0 var nbProblemsSolved = Map("Tableau" -> 0, "Tautology" -> 0) @@ -120,8 +120,8 @@ object TPTPSolver extends lisa.Main { "problemFile" -> r.problem.file, "solver" -> r.solverName, "solverStatus" -> r.solverStatus, - "solverProofCode" -> r.proofCode, - "proofType" -> r.proofType.getClass.getSimpleName.stripSuffix("$") + "proofType" -> r.proofType.getClass.getSimpleName.stripSuffix("$"), + "solverProofCode" -> r.proofCode ) ), jsonWriter, diff --git a/lisa-utils/src/main/scala/lisa/fol/Common.scala b/lisa-utils/src/main/scala/lisa/fol/Common.scala index 4cb238c61..84800d36b 100644 --- a/lisa-utils/src/main/scala/lisa/fol/Common.scala +++ b/lisa-utils/src/main/scala/lisa/fol/Common.scala @@ -610,7 +610,8 @@ trait Common { def rename(newid: Identifier): ConstantPredicateLabel[N] = ConstantPredicateLabel(newid, arity) def freshRename(taken: Iterable[Identifier]): ConstantPredicateLabel[N] = rename(K.freshId(taken, id)) override def toString(): String = id - def mkString(args: Seq[Term]): String = if (infix) (args(0).toStringSeparated() + " " + toString() + " " + args(1).toStringSeparated()) else toString() + "(" + args.mkString(", ") + ")" + def mkString(args: Seq[Term]): String = + if (infix) ("(" + args(0).toStringSeparated() + " " + toString() + " " + args(1).toStringSeparated() + ")") else toString() + "(" + args.mkString(", ") + ")" override def mkStringSeparated(args: Seq[Term]): String = if (infix) "(" + mkString(args) + ")" else mkString(args) } object ConstantPredicateLabel { diff --git a/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala b/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala index 576a279c3..a3f3bf98d 100644 --- a/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala +++ b/lisa-utils/src/main/scala/lisa/fol/FOLHelpers.scala @@ -84,7 +84,11 @@ object FOLHelpers { case cl: K.SchematicConnectorLabel => asFrontLabel(cl) def asFrontLabel[N <: Arity](cpl: K.ConstantAtomicLabel): ConstantAtomicLabelOfArity[N] = cpl.arity.asInstanceOf[N] match case n: 0 => ConstantFormula(cpl.id) - case n: N => ConstantPredicateLabel(cpl.id, cpl.arity.asInstanceOf) + case n: N => + if (cpl.id == Identifier("=")) + ConstantPredicateLabel.infix("===", cpl.arity.asInstanceOf) + else + ConstantPredicateLabel(cpl.id, cpl.arity.asInstanceOf) def asFrontLabel(sfl: K.SchematicFormulaLabel): SchematicAtomicLabel[?] | SchematicConnectorLabel[?] = sfl match case v: K.VariableFormulaLabel => asFrontLabel(v) diff --git a/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala b/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala index 8a6f02770..d366f4fed 100644 --- a/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala +++ b/lisa-utils/src/main/scala/lisa/utils/tptp/KernelParser.scala @@ -27,7 +27,10 @@ object KernelParser { */ def parseToKernel(formula: String): K.Formula = convertToKernel(Parser.fof(formula)) - def cleanVarname(f: String): String = f.replaceAll(Identifier.counterSeparator.toString, "") + def cleanVarname(f: String): String = + val forbiddenChars = Identifier.forbiddenChars ++ Set('\\', '/', '\'', '"', '`', '.', ',', ';', ':', '!', '%', '^', '&', '*', '|', '-', '+', '=', '<', '>', '~', '@', '#') + // replace all the forbidden chars + whitespaces by '0' + f.map(c => if (forbiddenChars.contains(c) || c.isWhitespace) then '0' else c) /** * @param formula a tptp formula in leo parser @@ -96,7 +99,7 @@ object KernelParser { else K.SchematicFunctionLabel(cleanVarname(f), args.size), args map convertTermToKernel ) - case CNF.Variable(name) => K.VariableTerm(K.VariableLabel(name)) + case CNF.Variable(name) => K.VariableTerm(K.VariableLabel(cleanVarname(name))) case CNF.DistinctObject(name) => ??? } @@ -111,7 +114,7 @@ object KernelParser { else K.SchematicFunctionLabel(cleanVarname(f), args.size), args map convertTermToKernel ) - case FOF.Variable(name) => K.VariableTerm(K.VariableLabel(name)) + case FOF.Variable(name) => K.VariableTerm(K.VariableLabel(cleanVarname(name))) case FOF.DistinctObject(name) => ??? case FOF.NumberTerm(value) => ??? } @@ -171,7 +174,7 @@ object KernelParser { if (problem.spc.contains("CNF")) problem.formulas.map(_.formula) |- () else problem.formulas.foldLeft[LK.Sequent](() |- ())((s, f) => - if (f._1 == "axiom") s +<< f._3 + if (Set("axiom", "hypothesis", "lemma").contains(f._1)) s +<< f._3 else if (f._1 == "conjecture" && s.right.isEmpty) s +>> f._3 else throw Exception("Can only agglomerate axioms and one conjecture into a sequents") ) From 81fb6da8c9974c5618a77fc74d3a273dc550c39d Mon Sep 17 00:00:00 2001 From: augustepoiroux Date: Mon, 12 Feb 2024 17:40:30 +0100 Subject: [PATCH 24/24] Remove user-specific paths --- lisa-examples/src/main/scala/TPTPSolver.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lisa-examples/src/main/scala/TPTPSolver.scala b/lisa-examples/src/main/scala/TPTPSolver.scala index f9ba28b25..3820def23 100644 --- a/lisa-examples/src/main/scala/TPTPSolver.scala +++ b/lisa-examples/src/main/scala/TPTPSolver.scala @@ -11,6 +11,8 @@ import lisa.kernel.proof.SCProof import lisa.kernel.proof.SequentCalculus.Sequent import lisa.utils.ProofsShrink.optimizeProofIteratively +// TODO: separate axioms and definitions from the main sequent and give names to hypotheses + object TPTPSolver extends lisa.Main { sealed trait ProofType case object BySolver extends ProofType @@ -20,7 +22,6 @@ object TPTPSolver extends lisa.Main { class ProblemSolverResults(val problem: Problem, val solverName: String, val solverStatus: String, val proofCode: String, val proofType: ProofType) val spc = Seq("PRP", "FOF") // type of problems we want to extract and solve - // val spc = Seq("CNF") // almost no CNF problems are solved by Tableau, TODO: investigate why // We limit the execution time to solve each problem val timeoutTableau = .1.second @@ -30,8 +31,10 @@ object TPTPSolver extends lisa.Main { val exportOptimizedProofs = true val exportBySolverProofs = true - val jsonResultsPath: String = "/home/auguste/Documents/EPFL/PhD/Projects/lisa/lisa-examples/src/main/resources/TPTPResults.json" - val TPTPProblemPath: String = "/home/auguste/Documents/EPFL/PhD/Projects/TPTP-v8.2.0/Problems/" + val jsonResultsPath: String = null + if (jsonResultsPath == null) throw new Exception("Please specify a path for the JSON results file") + val TPTPProblemPath: String = null + if (TPTPProblemPath == null) throw new Exception("Please specify a path for the TPTP problems") val d = new File(TPTPProblemPath) val libraries = d.listFiles.filter(_.isDirectory)