-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Running solvers on TPTP + converting kernel proofs to Lisa code #208
base: main
Are you sure you want to change the base?
Changes from all commits
2d5ee19
1ff80d9
94f9a6b
daa2673
49acfbf
22322b3
38a73bb
386ab96
f23659f
392b1d6
b1b6308
0799347
cdd2c12
07c4f3d
5dd0c46
860fc1f
1608480
d83b952
dd21c0f
15bf010
57a57f0
4a6bbbb
531ba96
81fb6da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
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.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 | ||
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 spc = Seq("PRP", "FOF") // type of problems we want to extract and solve | ||
|
||
// 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 | ||
|
||
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) | ||
val probfiles = libraries.flatMap(_.listFiles).filter(_.isFile) | ||
|
||
// val d = new File(TPTPProblemPath + "SYN/") | ||
// val probfiles = d.listFiles.filter(_.isFile) | ||
|
||
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 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 | ||
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 | ||
val tautologyResult = proveSequent(seq, timeoutTautology, tautologySolver) | ||
exportResults(problem, "Tautology", tautologyResult) | ||
} | ||
// } else println(s"Problem $probfile not extracted because of its type: ${md.spc.mkString(",")}") | ||
} | ||
} catch case e => println(s"Error while processing $probfile (index $i): $e") | ||
} | ||
|
||
// 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, | ||
"proofType" -> r.proofType.getClass.getSimpleName.stripSuffix("$"), | ||
"solverProofCode" -> r.proofCode | ||
) | ||
), | ||
jsonWriter, | ||
indent = 2 | ||
) | ||
jsonWriter.close() | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't seem correct, because asFrontLabel(K.equals).underlying != K.equals, which is a problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I see, I did this here because I didn't find somewhere else to do it. I will try to do that in lisa.utils then 👍 |
||
else | ||
ConstantPredicateLabel(cpl.id, cpl.arity.asInstanceOf) | ||
def asFrontLabel(sfl: K.SchematicFormulaLabel): SchematicAtomicLabel[?] | SchematicConnectorLabel[?] = | ||
sfl match | ||
case v: K.VariableFormulaLabel => asFrontLabel(v) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change? I think if label is K.Neg then it prints the same result, but we lose the infix notation if args.length == 2 ? Also the representation is not injective because and(A) will be printed as A
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did these changes to get printed results as close as possible to actual Lisa code.
If this is not the appropriate place to do this, or if the main purpose of this string representation is not to be as close as possible to Lisa code, tell me where I should put this :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which parser do you mean? Scala compiler or the FOL parser? If the last one, we're not using it and it anywhere and it has multiple other differences. If the first one, if it doesn't accept and(A) it can be made to accept e.g. and.multi(A).
But printing A instead of and(A) is not correct