|
| 1 | +import scala.concurrent.duration._ |
| 2 | +import scala.concurrent.ExecutionContext.Implicits.global |
| 3 | +import scala.concurrent._ |
| 4 | +import java.util.concurrent.CancellationException |
| 5 | + |
| 6 | +import lisa.utils.tptp.Example.* |
| 7 | +import lisa.utils.tptp.KernelParser.annotatedFormulaToKernel |
| 8 | +import lisa.utils.tptp.KernelParser.parseToKernel |
| 9 | +import lisa.utils.tptp.KernelParser.problemToSequent |
| 10 | +import lisa.utils.tptp.ProblemGatherer.getPRPproblems |
| 11 | +import lisa.utils.ProofsConverter.* |
| 12 | + |
| 13 | +object TPTPSolver extends lisa.Main { |
| 14 | + try { |
| 15 | + println("Fetching problems from TPTP library...") |
| 16 | + val probs = getPRPproblems |
| 17 | + |
| 18 | + println("Number of problems found: " + probs.size) |
| 19 | + |
| 20 | + // We limit the execution time to solve each problem |
| 21 | + val timeoutTableau = 1.second |
| 22 | + val timeoutTautology = 1.second |
| 23 | + |
| 24 | + var tableauProofs = List[Option[SCProof]]() |
| 25 | + var tautologyProofs = List[Option[SCProof]]() |
| 26 | + |
| 27 | + for ((p, i) <- probs.zipWithIndex) { |
| 28 | + // Progress bar |
| 29 | + if ((i + 1) % 10 == 0 || i + 1 == probs.size) { |
| 30 | + val pbarLength = 30 |
| 31 | + var pbarContent = "=" * (((i + 1) * pbarLength) / probs.size) |
| 32 | + pbarContent += " " * (pbarLength - pbarContent.length) |
| 33 | + print("[" + pbarContent + "]") |
| 34 | + print(" -- Processed " + (i + 1) + "/" + probs.size) |
| 35 | + print(" -- " + tableauProofs.count(_.isDefined) + " solved by Tableau") |
| 36 | + println(" -- " + tautologyProofs.count(_.isDefined) + " solved by Tautology") |
| 37 | + } |
| 38 | + |
| 39 | + val seq = problemToSequent(p) |
| 40 | + |
| 41 | + // Attempting proof by Tableau |
| 42 | + val (futureTableau, cancelTableau) = Future.interruptibly { Tableau.solve(seq) } |
| 43 | + tableauProofs = tableauProofs :+ ( |
| 44 | + try Await.result(futureTableau, timeoutTableau) |
| 45 | + catch |
| 46 | + case _ => |
| 47 | + cancelTableau() |
| 48 | + None |
| 49 | + ) |
| 50 | + |
| 51 | + // Attempting proof by Tautology |
| 52 | + val (futureTautology, cancelTautology) = Future.interruptibly { |
| 53 | + Tautology.solveSequent(seq) match |
| 54 | + case Left(proof) => Some(proof) |
| 55 | + case _ => None |
| 56 | + } |
| 57 | + tautologyProofs = tautologyProofs :+ ( |
| 58 | + try Await.result(futureTautology, timeoutTautology) |
| 59 | + catch |
| 60 | + case _ => |
| 61 | + cancelTautology() |
| 62 | + None |
| 63 | + ) |
| 64 | + } |
| 65 | + } catch { |
| 66 | + case error: NullPointerException => println("You can download the tptp library at http://www.tptp.org/ and put it in main/resources") |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +final class Interrupt extends (() => Boolean) { |
| 71 | + // We need a state-machine to track the progress. |
| 72 | + // It can have the following states: |
| 73 | + // a null reference means execution has not started. |
| 74 | + // a Thread reference means that the execution has started but is not done. |
| 75 | + // a this reference means that it is already cancelled or is already too late. |
| 76 | + private[this] final var state: AnyRef = null |
| 77 | + |
| 78 | + /** |
| 79 | + * This is the signal to cancel the execution of the logic. |
| 80 | + * Returns whether the cancellation signal was successully issued or not. |
| 81 | + */ |
| 82 | + override final def apply(): Boolean = this.synchronized { |
| 83 | + state match { |
| 84 | + case null => |
| 85 | + state = this |
| 86 | + true |
| 87 | + case _: this.type => false |
| 88 | + case t: Thread => |
| 89 | + state = this |
| 90 | + // t.interrupt() |
| 91 | + t.stop() |
| 92 | + true |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + // Initializes right before execution of logic and |
| 97 | + // allows to not run the logic at all if already cancelled. |
| 98 | + private[this] final def enter(): Boolean = |
| 99 | + this.synchronized { |
| 100 | + state match { |
| 101 | + case _: this.type => false |
| 102 | + case null => |
| 103 | + state = Thread.currentThread |
| 104 | + true |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + // Cleans up after the logic has executed |
| 109 | + // Prevents cancellation to occur "too late" |
| 110 | + private[this] final def exit(): Boolean = |
| 111 | + this.synchronized { |
| 112 | + state match { |
| 113 | + case _: this.type => false |
| 114 | + case t: Thread => |
| 115 | + state = this |
| 116 | + true |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + /** |
| 121 | + * Executes the suplied block of logic and returns the result. |
| 122 | + * Throws CancellationException if the block was interrupted. |
| 123 | + */ |
| 124 | + def interruptibly[T](block: => T): T = |
| 125 | + if (enter()) { |
| 126 | + try block |
| 127 | + catch { |
| 128 | + case ie: InterruptedException => throw new CancellationException() |
| 129 | + } finally { |
| 130 | + if (!exit() && Thread.interrupted()) |
| 131 | + () // If we were interrupted and flag was not cleared |
| 132 | + } |
| 133 | + } else throw new CancellationException() |
| 134 | +} |
| 135 | + |
| 136 | +implicit class FutureInterrupt(val future: Future.type) extends AnyVal { |
| 137 | + def interruptibly[T](block: => T)(implicit ec: ExecutionContext): (Future[T], () => Boolean) = { |
| 138 | + val interrupt = new Interrupt() |
| 139 | + (Future(interrupt.interruptibly(block))(ec), interrupt) |
| 140 | + } |
| 141 | +} |
0 commit comments