Skip to content

Commit dd21c0f

Browse files
Add documentation to the lisa proof code generator
1 parent d83b952 commit dd21c0f

File tree

3 files changed

+88
-20
lines changed

3 files changed

+88
-20
lines changed

lisa-examples/src/main/scala/Kernel2Code.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ object Kernel2Code extends lisa.Main {
2727
thenHave((x, (y, S(x, y))) |- (y, (x, S(x, y)))) by RightForall
2828
}
2929

30-
// println(generateStandaloneTheoremFileContent("thm1_raw", thm1.statement.underlying, thm1.kernelProof.get))
31-
// println(generateStandaloneTheoremFileContent("thm1_optimized", thm1.statement.underlying, optimizeProofIteratively(thm1.kernelProof.get)))
30+
// println(generateStandaloneTheoremFileContent("thm1_raw", thm1.kernelProof.get))
31+
// println(generateStandaloneTheoremFileContent("thm1_optimized", optimizeProofIteratively(thm1.kernelProof.get)))
3232

3333
val thm1_raw = Theorem(
3434
(x, (y, S(x, y))) (y, (x, S(x, y)))
@@ -85,8 +85,8 @@ object Kernel2Code extends lisa.Main {
8585
have(thesis) by Tautology.from(forward, backward)
8686
}
8787

88-
// println(generateStandaloneTheoremFileContent("thm2_raw", thm2.statement.underlying, thm2.kernelProof.get))
89-
// println(generateStandaloneTheoremFileContent("thm2_optimized", thm2.statement.underlying, optimizeProofIteratively(thm2.kernelProof.get)))
88+
// println(generateStandaloneTheoremFileContent("thm2_raw", thm2.kernelProof.get))
89+
// println(generateStandaloneTheoremFileContent("thm2_optimized", optimizeProofIteratively(thm2.kernelProof.get)))
9090

9191
val thm2_raw = Theorem(
9292
(((x, Q(x)) (x, R(x))) <=> (x, (Q(x) R(x))))
@@ -192,8 +192,8 @@ object Kernel2Code extends lisa.Main {
192192
have(thesis) by Tautology.from(step1, step1 of (x := f(x)))
193193
}
194194

195-
// println(generateStandaloneTheoremFileContent("thm3_raw", thm3.statement.underlying, thm3.kernelProof.get))
196-
// println(generateStandaloneTheoremFileContent("thm3_optimized", thm3.statement.underlying, optimizeProofIteratively(thm3.kernelProof.get)))
195+
// println(generateStandaloneTheoremFileContent("thm3_raw", thm3.kernelProof.get))
196+
// println(generateStandaloneTheoremFileContent("thm3_optimized", optimizeProofIteratively(thm3.kernelProof.get)))
197197

198198
val thm3_raw = Theorem(
199199
(x, (Q(x) ==> Q(f(x)))) (Q(x) ==> Q(f(f(x))))
@@ -296,8 +296,8 @@ object Kernel2Code extends lisa.Main {
296296
have(thesis) by Tableau
297297
}
298298

299-
// println(generateStandaloneTheoremFileContent("thm1bis_raw", thm1bis.statement.underlying, thm1bis.kernelProof.get))
300-
// println(generateStandaloneTheoremFileContent("thm1bis_optimized", thm1bis.statement.underlying, optimizeProofIteratively(thm1bis.kernelProof.get)))
299+
// println(generateStandaloneTheoremFileContent("thm1bis_raw", thm1bis.kernelProof.get))
300+
// println(generateStandaloneTheoremFileContent("thm1bis_optimized", optimizeProofIteratively(thm1bis.kernelProof.get)))
301301

302302
val thm1bis_raw = Theorem(
303303
(x, (y, S(x, y))) (y, (x, S(x, y)))

lisa-examples/src/main/scala/TPTPSolver.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ object TPTPSolver extends lisa.Main {
8888
def writeProof(problem: Problem, proof: SCProof, path: String): Unit = {
8989
val file = new File(path + problem.name + ".sc")
9090
val bw = new FileWriter(file)
91-
val fileContent = generateStandaloneTheoremFileContent(problem.name, problemToSequent(problem), proof)
91+
val fileContent = generateStandaloneTheoremFileContent(problem.name, proof)
9292
bw.write(fileContent)
9393
bw.close()
9494
}

lisa-utils/src/main/scala/lisa/utils/ProofsConverter.scala

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,27 @@ object ProofsConverter {
1212
// TODO: remove unnecessary variables "val s_..." in generated proofs -> need to detect which steps are used later in other steps
1313
// TODO: generate more realistic variable names
1414

15-
private def indent(s: String, indent: Int = 2): String = s.split("\n").map(" " * indent + _).mkString("\n")
16-
private def unindent(s: String, indent: Int = 2): String = s.split("\n").map(_.drop(indent)).mkString("\n")
17-
15+
private def indent(s: String, indent: Int = 2): String = s.split("\n").map(s => if s == "" then "" else " " * indent + s).mkString("\n")
16+
private def unindent(s: String, indent: Int = 2): String = s.split("\n").map(_.stripPrefix(" " * indent)).mkString("\n")
17+
18+
/**
19+
* Converts a Sequent, Formula or Term to a valid Scala/Lisa code
20+
*
21+
* @param f formula to convert
22+
* @return Scala code representing the formula in string format
23+
*/
1824
private def any2code(a: K.Sequent | K.Formula | K.Term): String = (a match
1925
case sq: K.Sequent => asFront(sq)
2026
case form: K.Formula => asFront(form)
2127
case term: K.Term => asFront(term)
2228
).toString.replace("", "==>").replace("", "<=>")
2329

30+
/**
31+
* Converts a SCProof to a valid Scala/Lisa code using tactics.
32+
*
33+
* @param p proof to convert
34+
* @return Scala code representing the proof in string format
35+
*/
2436
private def scproof2code(p: K.SCProof): String = {
2537
def scproof2codeAux(p: K.SCProof, varPrefix: String = "s", implicitPremises: Seq[String] = Seq.empty): String = {
2638
def scproofstep2code(ps: SCProofStep, stepNum: Int, implicitPremises: Seq[String], varPrefix: String): String = {
@@ -91,6 +103,12 @@ object ProofsConverter {
91103
unindent(scproof2codeAux(p))
92104
}
93105

106+
/**
107+
* Extracts all formulas from a proof
108+
*
109+
* @param proof proof to extract formulas from
110+
* @return set of formulas
111+
*/
94112
private def extractFormulasFromProof(proof: K.SCProof): Set[K.Formula] =
95113
proof.steps.foldLeft(Set.empty[K.Formula])((prev, next) => {
96114
prev ++ (next match
@@ -103,6 +121,12 @@ object ProofsConverter {
103121
)
104122
})
105123

124+
/**
125+
* Extracts all variables, functions, formula variables, predicates and connectors from a set of formulas
126+
*
127+
* @param formulas set of formulas to extract variables from
128+
* @return tuple of sets of variables, functions, formula variables, predicates and connectors
129+
*/
106130
private def extractVariables(
107131
formulas: Set[K.Formula]
108132
): (Set[K.VariableLabel], Set[K.SchematicFunctionLabel], Set[K.VariableFormulaLabel], Set[K.SchematicPredicateLabel], Set[K.SchematicConnectorLabel]) =
@@ -130,6 +154,15 @@ object ProofsConverter {
130154
)
131155
})
132156

157+
/**
158+
* Generates a valid Scala/Lisa code to declare variables, functions, formula variables, predicates and connectors
159+
* used in a set of formulas
160+
*
161+
* @param formulas set of formulas to generate variables for
162+
* @param accessibility accessibility of the variables (e.g. "private")
163+
*
164+
* @return Scala code representing the variables in string format
165+
*/
133166
private def generateVariablesCode(formulas: Set[K.Formula], accessibility: String): String =
134167
val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = extractVariables(formulas)
135168
val access = if accessibility != "" then accessibility.strip() + " " else ""
@@ -139,25 +172,60 @@ object ProofsConverter {
139172
predicateSet.map(p => access + s"val ${p.id} = predicate[${p.arity}]").toList.sorted ++
140173
connectorSet.map(c => access + s"val ${c.id} = connector[${c.arity}]").toList.sorted).mkString("\n")
141174

142-
private def generateVariablesCode(statement: K.Sequent, proof: K.SCProof, accessibility: String = "private"): String =
143-
generateVariablesCode(extractFormulasFromProof(proof) + K.sequentToFormula(statement), accessibility)
144-
145-
private def generateTheoremCode(name: String, statement: K.Sequent, proof: K.SCProof): String = {
175+
/**
176+
* Generates a valid Scala/Lisa code to declare variables, functions, formula variables, predicates and connectors
177+
* used in a proof
178+
*
179+
* @param proof proof to generate variables for
180+
* @param accessibility accessibility of the variables (e.g. "private")
181+
*
182+
* @return Scala code representing the variables in string format
183+
*/
184+
private def generateVariablesCode(proof: K.SCProof, accessibility: String = "private"): String =
185+
generateVariablesCode(extractFormulasFromProof(proof), accessibility)
186+
187+
/**
188+
* Generates a valid Scala/Lisa code of a theorem and its proof
189+
*
190+
* @param name name of the theorem
191+
* @param proof proof of the theorem
192+
*
193+
* @return Scala code representing the theorem in string format
194+
*/
195+
private def generateTheoremCode(name: String, proof: K.SCProof): String = {
146196
s"val $name = Theorem(\n" +
147-
indent(any2code(statement)) +
197+
indent(any2code(proof.conclusion)) +
148198
s"\n) {\n" +
149199
indent(scproof2code(proof)) +
150200
s"\n}"
151201
}
152202

153-
def generateStandaloneTheoremFileContent(name: String, statement: K.Sequent, proof: K.SCProof): String =
203+
/**
204+
* Generates a valid Scala/Lisa code of a theorem and its proof in a standalone file, including the necessary variables declarations.
205+
* The theorem and its proof must be self-contained, i.e. no dependencies to other theorems, axioms, definitions, etc.
206+
*
207+
* @param name name of the theorem
208+
* @param proof proof of the theorem
209+
*
210+
* @return Scala code representing the theorem in string format
211+
*/
212+
def generateStandaloneTheoremFileContent(name: String, proof: K.SCProof): String =
154213
val camelName = "[A-Za-z0-9]+".r.findAllIn(name).map(_.capitalize).mkString
155214
s"object $camelName extends lisa.Main {\n\n" +
156215
indent(
157-
generateVariablesCode(statement, proof) +
216+
generateVariablesCode(proof) +
158217
"\n\n" +
159-
generateTheoremCode(name, statement, proof)
218+
generateTheoremCode(name, proof)
160219
) +
161220
"\n}"
162221

222+
/**
223+
* Parse and check that a generated theorem file is valid, i.e. that it compiles and the theorem is proven
224+
* @param fileContent content of the generated file
225+
* @return true if the file is valid, false otherwise
226+
*/
227+
def checkGeneratedFileContent(fileContent: String): Boolean =
228+
// TODO
229+
false
230+
163231
}

0 commit comments

Comments
 (0)