unicode-logic-kit 0.31.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. unicode_logic_kit/__init__.py +385 -0
  2. unicode_logic_kit/__main__.py +520 -0
  3. unicode_logic_kit/_deadline.py +219 -0
  4. unicode_logic_kit/ace/__init__.py +126 -0
  5. unicode_logic_kit/ace/_align.py +135 -0
  6. unicode_logic_kit/ace/chem_lexicon.py +128 -0
  7. unicode_logic_kit/ace/drs_reader.py +570 -0
  8. unicode_logic_kit/ace/mapping.py +666 -0
  9. unicode_logic_kit/ace/reverse_modal.py +138 -0
  10. unicode_logic_kit/ace/runner.py +551 -0
  11. unicode_logic_kit/ace/translate.py +452 -0
  12. unicode_logic_kit/ace/verbalize.py +1070 -0
  13. unicode_logic_kit/api.py +1284 -0
  14. unicode_logic_kit/atp/__init__.py +177 -0
  15. unicode_logic_kit/atp/_ascii_names.py +113 -0
  16. unicode_logic_kit/atp/_html.py +72 -0
  17. unicode_logic_kit/atp/_substructural_input.py +228 -0
  18. unicode_logic_kit/atp/_tff_problem.py +715 -0
  19. unicode_logic_kit/atp/_tptp_problem.py +1111 -0
  20. unicode_logic_kit/atp/_writer_support.py +289 -0
  21. unicode_logic_kit/atp/clingo_backend.py +1180 -0
  22. unicode_logic_kit/atp/cvc5_backend.py +1385 -0
  23. unicode_logic_kit/atp/eprover_backend.py +732 -0
  24. unicode_logic_kit/atp/finite_domain.py +1055 -0
  25. unicode_logic_kit/atp/fitch.py +1547 -0
  26. unicode_logic_kit/atp/fitch_search.py +551 -0
  27. unicode_logic_kit/atp/hets_backend.py +339 -0
  28. unicode_logic_kit/atp/hybrid_down.py +120 -0
  29. unicode_logic_kit/atp/incremental.py +250 -0
  30. unicode_logic_kit/atp/kripke_enum.py +741 -0
  31. unicode_logic_kit/atp/lambek.py +436 -0
  32. unicode_logic_kit/atp/leo3_backend.py +332 -0
  33. unicode_logic_kit/atp/linear.py +738 -0
  34. unicode_logic_kit/atp/lj.py +705 -0
  35. unicode_logic_kit/atp/logic_backends.py +566 -0
  36. unicode_logic_kit/atp/ltl_tableau.py +1084 -0
  37. unicode_logic_kit/atp/minizinc_backend.py +1402 -0
  38. unicode_logic_kit/atp/modal_tableau.py +1382 -0
  39. unicode_logic_kit/atp/nanocop_backend.py +410 -0
  40. unicode_logic_kit/atp/portfolio.py +489 -0
  41. unicode_logic_kit/atp/protocol.py +1803 -0
  42. unicode_logic_kit/atp/prover9_entailment.py +1153 -0
  43. unicode_logic_kit/atp/resolution.py +1376 -0
  44. unicode_logic_kit/atp/resolution_check.py +1114 -0
  45. unicode_logic_kit/atp/sequent.py +1050 -0
  46. unicode_logic_kit/atp/tableau.py +921 -0
  47. unicode_logic_kit/atp/tableau_check.py +543 -0
  48. unicode_logic_kit/atp/tptp_ncl.py +811 -0
  49. unicode_logic_kit/atp/tptp_tff.py +1546 -0
  50. unicode_logic_kit/atp/tstp.py +1333 -0
  51. unicode_logic_kit/atp/tstp_check.py +1096 -0
  52. unicode_logic_kit/atp/twee_backend.py +236 -0
  53. unicode_logic_kit/atp/twee_check.py +711 -0
  54. unicode_logic_kit/atp/twee_entailment.py +953 -0
  55. unicode_logic_kit/atp/vampire_entailment.py +540 -0
  56. unicode_logic_kit/atp/z3_arith.py +470 -0
  57. unicode_logic_kit/atp/z3_equivalence.py +36 -0
  58. unicode_logic_kit/atp/z3_fuzzy.py +362 -0
  59. unicode_logic_kit/atp/z3_input.py +500 -0
  60. unicode_logic_kit/atp/z3_models.py +208 -0
  61. unicode_logic_kit/chem/__init__.py +88 -0
  62. unicode_logic_kit/chem/_naming.py +284 -0
  63. unicode_logic_kit/chem/cache.py +185 -0
  64. unicode_logic_kit/chem/interop.py +244 -0
  65. unicode_logic_kit/chem/mol.py +525 -0
  66. unicode_logic_kit/chem/signature.py +112 -0
  67. unicode_logic_kit/comorphism.py +497 -0
  68. unicode_logic_kit/dl/__init__.py +384 -0
  69. unicode_logic_kit/dl/classification.py +227 -0
  70. unicode_logic_kit/dl/concepts.py +632 -0
  71. unicode_logic_kit/dl/datatypes.py +818 -0
  72. unicode_logic_kit/dl/owl_functional.py +2433 -0
  73. unicode_logic_kit/dl/owl_manchester.py +1637 -0
  74. unicode_logic_kit/dl/owl_reasoner.py +790 -0
  75. unicode_logic_kit/dl/parser.py +391 -0
  76. unicode_logic_kit/dl/tableau.py +4048 -0
  77. unicode_logic_kit/dl/translate.py +2704 -0
  78. unicode_logic_kit/drt/__init__.py +94 -0
  79. unicode_logic_kit/drt/export.py +179 -0
  80. unicode_logic_kit/drt/nodes.py +506 -0
  81. unicode_logic_kit/drt/parser.py +965 -0
  82. unicode_logic_kit/drt/resolve.py +195 -0
  83. unicode_logic_kit/drt/reverse.py +175 -0
  84. unicode_logic_kit/eval/__init__.py +106 -0
  85. unicode_logic_kit/eval/batch.py +382 -0
  86. unicode_logic_kit/eval/canonical.py +663 -0
  87. unicode_logic_kit/eval/chem_batch.py +606 -0
  88. unicode_logic_kit/eval/converses.py +200 -0
  89. unicode_logic_kit/eval/datasets/__init__.py +136 -0
  90. unicode_logic_kit/eval/datasets/_base.py +263 -0
  91. unicode_logic_kit/eval/datasets/_proofwriter_proof.py +422 -0
  92. unicode_logic_kit/eval/datasets/c3po.py +678 -0
  93. unicode_logic_kit/eval/datasets/folio.py +158 -0
  94. unicode_logic_kit/eval/datasets/fracas.py +418 -0
  95. unicode_logic_kit/eval/datasets/groves.py +191 -0
  96. unicode_logic_kit/eval/datasets/logicbench.py +467 -0
  97. unicode_logic_kit/eval/datasets/logicnli.py +303 -0
  98. unicode_logic_kit/eval/datasets/malls.py +133 -0
  99. unicode_logic_kit/eval/datasets/pfolio.py +594 -0
  100. unicode_logic_kit/eval/datasets/pmb.py +242 -0
  101. unicode_logic_kit/eval/datasets/prontoqa.py +611 -0
  102. unicode_logic_kit/eval/datasets/proofwriter.py +1431 -0
  103. unicode_logic_kit/eval/datasets/proverqa.py +674 -0
  104. unicode_logic_kit/eval/datasets/willow.py +478 -0
  105. unicode_logic_kit/eval/equivalence.py +466 -0
  106. unicode_logic_kit/eval/exercise_gen.py +533 -0
  107. unicode_logic_kit/eval/explain.py +791 -0
  108. unicode_logic_kit/eval/generality.py +750 -0
  109. unicode_logic_kit/eval/metric_hf.py +458 -0
  110. unicode_logic_kit/eval/predicate_match.py +343 -0
  111. unicode_logic_kit/eval/theory_check.py +1170 -0
  112. unicode_logic_kit/eval/validate.py +306 -0
  113. unicode_logic_kit/fol/__init__.py +177 -0
  114. unicode_logic_kit/fol/_atom_keys.py +510 -0
  115. unicode_logic_kit/fol/_fol_nodes.py +3586 -0
  116. unicode_logic_kit/fol/_free_parameters.py +105 -0
  117. unicode_logic_kit/fol/_ho_nodes.py +448 -0
  118. unicode_logic_kit/fol/_hybrid_nodes.py +308 -0
  119. unicode_logic_kit/fol/_identifiers.py +1091 -0
  120. unicode_logic_kit/fol/_lambek_nodes.py +112 -0
  121. unicode_logic_kit/fol/_linear_nodes.py +352 -0
  122. unicode_logic_kit/fol/_modal_nodes.py +1467 -0
  123. unicode_logic_kit/fol/_msfl_nodes.py +2196 -0
  124. unicode_logic_kit/fol/_numeral_symbols.py +231 -0
  125. unicode_logic_kit/fol/_so_nodes.py +200 -0
  126. unicode_logic_kit/fol/_symbol_names.py +81 -0
  127. unicode_logic_kit/fol/_team_nodes.py +181 -0
  128. unicode_logic_kit/fol/_tptp_symbols.py +551 -0
  129. unicode_logic_kit/fol/_truth_constants.py +117 -0
  130. unicode_logic_kit/fol/casl_export.py +1135 -0
  131. unicode_logic_kit/fol/casl_import.py +929 -0
  132. unicode_logic_kit/fol/derivation.py +367 -0
  133. unicode_logic_kit/fol/dialect_detect.py +70 -0
  134. unicode_logic_kit/fol/dialect_repair.py +537 -0
  135. unicode_logic_kit/fol/frames.py +637 -0
  136. unicode_logic_kit/fol/grammars/terminals.lark +31 -0
  137. unicode_logic_kit/fol/lambda_tools.py +297 -0
  138. unicode_logic_kit/fol/latex_input.py +429 -0
  139. unicode_logic_kit/fol/modal_translation.py +944 -0
  140. unicode_logic_kit/fol/msflparser.py +1033 -0
  141. unicode_logic_kit/fol/naming.py +422 -0
  142. unicode_logic_kit/fol/nodes.py +241 -0
  143. unicode_logic_kit/fol/normalforms.py +492 -0
  144. unicode_logic_kit/fol/pal.py +287 -0
  145. unicode_logic_kit/fol/prolog_export.py +566 -0
  146. unicode_logic_kit/fol/prolog_input.py +505 -0
  147. unicode_logic_kit/fol/prover9_input.py +1325 -0
  148. unicode_logic_kit/fol/qml.py +1760 -0
  149. unicode_logic_kit/fol/qmltp_input.py +525 -0
  150. unicode_logic_kit/fol/sanitize.py +221 -0
  151. unicode_logic_kit/fol/serialize.py +79 -0
  152. unicode_logic_kit/fol/signature.py +1290 -0
  153. unicode_logic_kit/fol/simplify_check.py +544 -0
  154. unicode_logic_kit/fol/spans.py +594 -0
  155. unicode_logic_kit/fol/tptp_input.py +1503 -0
  156. unicode_logic_kit/fol/tptp_repair.py +941 -0
  157. unicode_logic_kit/fol/unification.py +157 -0
  158. unicode_logic_kit/fol/verbalize.py +263 -0
  159. unicode_logic_kit/hets/__init__.py +163 -0
  160. unicode_logic_kit/hets/bridge.py +142 -0
  161. unicode_logic_kit/hets/client.py +748 -0
  162. unicode_logic_kit/hets/docker.py +420 -0
  163. unicode_logic_kit/hets/dol.py +712 -0
  164. unicode_logic_kit/hets/haskell_json.py +355 -0
  165. unicode_logic_kit/hets/owl_backend.py +794 -0
  166. unicode_logic_kit/hets/owl_cli.py +598 -0
  167. unicode_logic_kit/hets/symbols.py +512 -0
  168. unicode_logic_kit/hol/__init__.py +140 -0
  169. unicode_logic_kit/hol/_ho_common.py +323 -0
  170. unicode_logic_kit/hol/_isabelle_binders.py +125 -0
  171. unicode_logic_kit/hol/classical.py +812 -0
  172. unicode_logic_kit/hol/deepshallow/__init__.py +45 -0
  173. unicode_logic_kit/hol/deepshallow/_common.py +177 -0
  174. unicode_logic_kit/hol/deepshallow/conditional.py +225 -0
  175. unicode_logic_kit/hol/deepshallow/intuitionistic.py +181 -0
  176. unicode_logic_kit/hol/deepshallow/modal.py +217 -0
  177. unicode_logic_kit/hol/deepshallow/qml.py +406 -0
  178. unicode_logic_kit/hol/deepshallow/relevant.py +206 -0
  179. unicode_logic_kit/hol/free.py +753 -0
  180. unicode_logic_kit/hol/goedel.py +336 -0
  181. unicode_logic_kit/hol/ho_modal.py +1743 -0
  182. unicode_logic_kit/hol/intuitionistic.py +403 -0
  183. unicode_logic_kit/hol/isabelle_conditional.py +593 -0
  184. unicode_logic_kit/hol/isabelle_modal.py +1908 -0
  185. unicode_logic_kit/hol/isabelle_relevant.py +412 -0
  186. unicode_logic_kit/hol/isabelle_runner.py +1147 -0
  187. unicode_logic_kit/hol/isabelle_substructural.py +884 -0
  188. unicode_logic_kit/hol/lean.py +1018 -0
  189. unicode_logic_kit/hol/manyvalued.py +921 -0
  190. unicode_logic_kit/hol/secondorder.py +687 -0
  191. unicode_logic_kit/hol/thf_modal.py +941 -0
  192. unicode_logic_kit/hol/thirdorder.py +397 -0
  193. unicode_logic_kit/ilp/__init__.py +89 -0
  194. unicode_logic_kit/ilp/readback.py +389 -0
  195. unicode_logic_kit/ilp/separation.py +153 -0
  196. unicode_logic_kit/ilp/task.py +730 -0
  197. unicode_logic_kit/logic.py +163 -0
  198. unicode_logic_kit/mcp/__init__.py +28 -0
  199. unicode_logic_kit/mcp/__main__.py +5 -0
  200. unicode_logic_kit/mcp/chem_tools.py +1031 -0
  201. unicode_logic_kit/mcp/server.py +2453 -0
  202. unicode_logic_kit/mcp/syntax_spec.py +681 -0
  203. unicode_logic_kit/prob/__init__.py +53 -0
  204. unicode_logic_kit/prob/_bdd.py +225 -0
  205. unicode_logic_kit/prob/_column_gen.py +668 -0
  206. unicode_logic_kit/prob/distribution.py +686 -0
  207. unicode_logic_kit/prob/nilsson.py +470 -0
  208. unicode_logic_kit/py.typed +0 -0
  209. unicode_logic_kit/semantics/__init__.py +137 -0
  210. unicode_logic_kit/semantics/_modal_reject.py +156 -0
  211. unicode_logic_kit/semantics/action_models.py +466 -0
  212. unicode_logic_kit/semantics/asp_models.py +1200 -0
  213. unicode_logic_kit/semantics/conditional.py +580 -0
  214. unicode_logic_kit/semantics/dynamic_epistemic.py +95 -0
  215. unicode_logic_kit/semantics/free_logic.py +913 -0
  216. unicode_logic_kit/semantics/fuzzy.py +384 -0
  217. unicode_logic_kit/semantics/fuzzy_kripke.py +442 -0
  218. unicode_logic_kit/semantics/intuitionistic.py +581 -0
  219. unicode_logic_kit/semantics/kripke.py +1139 -0
  220. unicode_logic_kit/semantics/manyvalued.py +580 -0
  221. unicode_logic_kit/semantics/matrix.py +342 -0
  222. unicode_logic_kit/semantics/model_eval.py +1135 -0
  223. unicode_logic_kit/semantics/modelfinder.py +1036 -0
  224. unicode_logic_kit/semantics/nonmonotonic.py +372 -0
  225. unicode_logic_kit/semantics/relevant.py +331 -0
  226. unicode_logic_kit/semantics/secondorder.py +657 -0
  227. unicode_logic_kit/semantics/structures.py +352 -0
  228. unicode_logic_kit/semantics/tarski.py +975 -0
  229. unicode_logic_kit/semantics/team.py +315 -0
  230. unicode_logic_kit/semantics/team_translation.py +416 -0
  231. unicode_logic_kit/semantics/thirdorder.py +358 -0
  232. unicode_logic_kit/semantics/tnorm.py +85 -0
  233. unicode_logic_kit/semantics/truthtable.py +201 -0
  234. unicode_logic_kit-0.31.0.dist-info/METADATA +333 -0
  235. unicode_logic_kit-0.31.0.dist-info/RECORD +237 -0
  236. unicode_logic_kit-0.31.0.dist-info/WHEEL +4 -0
  237. unicode_logic_kit-0.31.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,236 @@
1
+ """Twee as a :class:`~unicode_logic_kit.atp.protocol.ProverBackend` — verified equational proofs.
2
+
3
+ Wires :mod:`atp.twee_entailment` (the runner + stdout parser) and
4
+ :mod:`atp.twee_check` (the independent checker) into one adapter, following
5
+ the same shape as :class:`atp.protocol.VampireBackend` and
6
+ :class:`atp.cvc5_backend.Cvc5Backend`: ``premises``/``formula`` go in exactly
7
+ as given (no folding into one implication — Twee, like Vampire, takes a list
8
+ of axioms plus a separate conjecture), a :class:`~atp.protocol.Verdict` comes
9
+ out.
10
+
11
+ The one thing this backend does that no other in the kit does: a Twee
12
+ ``Theorem`` is NEVER reported ``PROVED`` on Twee's say-so alone. Every parsed
13
+ proof is run through :func:`atp.twee_check.check_twee_proof` (does every
14
+ rewrite step genuinely follow, and does every restated axiom genuinely match
15
+ a given premise?) AND :func:`atp.twee_check.goal_matches_conclusion` (does
16
+ the proved goal actually restate the requested conclusion, not some other
17
+ formula?) before ``PROVED`` is returned. If either check fails, that is
18
+ reported as ``ERROR``/``"infra"`` — never a silent ``PROVED`` — because a
19
+ Twee bug or an adversarial/corrupted proof text must never pass through
20
+ undetected as an established theorem.
21
+
22
+ **Twee's one-line ``Reflexivity.`` proof.** When the goal is an instance of ``x = x``
23
+ (``a = a``, ``f(a) = f(a)``, ``tuple(a, b) = tuple(a, b)``) Twee prints no rewrite
24
+ chain at all, only ``Proof:`` and ``Reflexivity.``
25
+ (:func:`atp.twee_entailment.parse_twee_proof` reads chains and says it cannot read
26
+ this). It is a proof with ZERO steps, and is read as one: :func:`_reflexivity_proof`
27
+ builds the :class:`~atp.twee_entailment.TweeProof` whose goal chain is the single
28
+ term (no citation), so it goes through the SAME two checks as every other proof. A
29
+ goal whose two sides differ fails the first, and one that is not the requested
30
+ conclusion fails the second; either is ERROR, as ever.
31
+ """
32
+
33
+ import time
34
+ from typing import Sequence
35
+
36
+ from ..fol.nodes import Node
37
+ from .protocol import (
38
+ ERROR, PROVED, REFUTED, UNKNOWN, ProverBackend, Verdict, _rejection_detail,
39
+ )
40
+
41
+ __all__ = ["TweeBackend"]
42
+
43
+
44
+ def _reflexivity_proof(raw_output: str):
45
+ """The :class:`~atp.twee_entailment.TweeProof` of Twee's one-line ``Reflexivity.``
46
+ proof, or ``None`` when ``raw_output`` is anything else.
47
+
48
+ Twee prints it, recorded on Twee 2.6.1, for a goal that is an instance of
49
+ ``x = x``::
50
+
51
+ The conjecture is true! Here is a proof.
52
+
53
+
54
+ Goal 1 (goal): a = a.
55
+ Proof:
56
+ Reflexivity.
57
+
58
+ RESULT: Theorem (the conjecture is true).
59
+
60
+ Nothing is guessed: the text must be exactly those five non-blank lines (no axiom
61
+ is listed, none was used), the goal line must read as an equation, and the chain
62
+ is the goal's left-hand side alone with no citation. Whether the two sides really
63
+ are one term, and whether the goal is the requested conclusion, is for
64
+ :func:`atp.twee_check.check_twee_proof` and
65
+ :func:`atp.twee_check.goal_matches_conclusion` to say, exactly as for any proof.
66
+ """
67
+ from .twee_entailment import (
68
+ _GOAL_RE, TweeChain, TweeEquation, TweeGoal, TweeProof, _parse_term, _split_equation,
69
+ )
70
+
71
+ lines = [line.rstrip() for line in raw_output.splitlines() if line.strip()]
72
+ if (len(lines) != 5 or lines[0] != "The conjecture is true! Here is a proof."
73
+ or lines[2] != "Proof:" or lines[3] != "Reflexivity."
74
+ or not lines[4].startswith("RESULT: Theorem")):
75
+ return None
76
+ goal_line = _GOAL_RE.match(lines[1])
77
+ if goal_line is None:
78
+ return None
79
+ try:
80
+ lhs_text, rhs_text = _split_equation(goal_line.group(3))
81
+ lhs, rhs = _parse_term(lhs_text), _parse_term(rhs_text)
82
+ except ValueError:
83
+ return None
84
+ return TweeProof((), (), TweeGoal(int(goal_line.group(1)), goal_line.group(2),
85
+ TweeEquation(lhs, rhs), TweeChain((lhs,), ())))
86
+
87
+
88
+ def _timed(fn):
89
+ """Run ``fn()`` returning ``(result, seconds)`` — local copy, see cvc5_backend's."""
90
+ start = time.perf_counter()
91
+ result = fn()
92
+ return result, time.perf_counter() - start
93
+
94
+
95
+ class TweeBackend(ProverBackend):
96
+ """Unit equality via Twee, with every ``Theorem`` independently re-checked.
97
+
98
+ ``premises``/``formula`` outside Twee's equational fragment (see
99
+ :mod:`atp.twee_entailment`'s module docstring) come back
100
+ UNKNOWN/``"unsupported"`` — Twee decides pure unit equality only, and
101
+ pretending otherwise (e.g. by silently dropping non-equational premises)
102
+ would be unsound. ``CounterSatisfiable`` becomes REFUTED (Twee's
103
+ completion procedure genuinely certifies this — it is not a "gave up"
104
+ signal, see the module docstring of :mod:`atp.twee_entailment`); a
105
+ subprocess timeout and Twee's own resource-budget ``GaveUp``/other status
106
+ come back UNKNOWN with the honest ``reason``. A missing ``RESULT`` line
107
+ WITHOUT a timeout is Twee refusing the problem (its parse/usage error is on
108
+ stderr) or dying, and is ERROR/``"infra"`` with Twee's own message in
109
+ ``detail`` — never UNKNOWN, which reads like a run that ran out of time.
110
+ """
111
+
112
+ name = "twee"
113
+ logics = frozenset({"fol"})
114
+ external = True
115
+
116
+ def available(self) -> bool:
117
+ return self.available_for({})
118
+
119
+ def available_for(self, options: dict) -> bool:
120
+ """Whether Twee answers where :meth:`decide` will run it: through WSL
121
+ unless ``use_wsl=False``, and as the command ``twee_cmd=`` names (else
122
+ ``$UFK_TWEE_CMD``, else ``~/.local/bin/twee``) -- the two options
123
+ :meth:`decide` forwards to the runner, with its own defaults."""
124
+ from .twee_entailment import twee_available
125
+ return twee_available(use_wsl=options.get("use_wsl", True),
126
+ twee_cmd=options.get("twee_cmd"))
127
+
128
+ def decide(self, formula: Node, premises: Sequence[Node] = (),
129
+ timeout: int = 10000, **options) -> Verdict:
130
+ """Decide ``premises ⊨ formula`` via Twee, verifying any Theorem proof independently.
131
+
132
+ Args:
133
+ formula: the conclusion — must be a (forall-closed) equation or
134
+ conjunction of equations.
135
+ premises: likewise, each must be equational; passed to Twee as
136
+ separate named axioms (NOT folded into one implication).
137
+ timeout: milliseconds, per the :class:`ProverBackend` contract;
138
+ converted to whole seconds (minimum 1) for
139
+ :func:`atp.twee_entailment.check_entailment_twee_detailed`'s
140
+ subprocess timeout.
141
+ **options: ``use_wsl`` (default ``True``) and ``twee_cmd``
142
+ (default: ``$UFK_TWEE_CMD``, else ``~/.local/bin/twee``) are
143
+ forwarded to the runner; no other options are read.
144
+
145
+ Returns:
146
+ PROVED (with ``proof`` = the parsed :class:`~atp.twee_entailment
147
+ .TweeProof`, JSON-serialised via its own ``to_dict()``) only when
148
+ Twee reports ``Theorem`` AND the proof independently verifies
149
+ (see the class docstring); REFUTED on ``CounterSatisfiable``;
150
+ UNKNOWN/``"timeout"`` on a subprocess timeout; ERROR/``"infra"``
151
+ when Twee reports ``Theorem`` but the proof fails independent
152
+ verification (Twee and the checker disagreed — an
153
+ infrastructure-level failure, not "we don't know"), and likewise
154
+ ERROR/``"infra"`` when Twee printed no ``RESULT:`` line although
155
+ the timeout did not fire (it refused the problem — its own message
156
+ is in ``detail``); any other status is UNKNOWN/``"incomplete"``.
157
+ """
158
+ from .twee_check import check_twee_proof, goal_matches_conclusion, goal_mismatch
159
+ from .twee_entailment import check_entailment_twee_detailed
160
+
161
+ premises = list(premises)
162
+ use_wsl = options.pop("use_wsl", True)
163
+ twee_cmd = options.pop("twee_cmd", None)
164
+ seconds = max(1, timeout // 1000)
165
+
166
+ try:
167
+ result, elapsed = _timed(lambda: check_entailment_twee_detailed(
168
+ premises, formula, timeout=seconds, use_wsl=use_wsl, twee_cmd=twee_cmd))
169
+ except NotImplementedError as exc:
170
+ return Verdict(UNKNOWN, self.name, reason="unsupported", detail=str(exc))
171
+ except (OSError, RuntimeError) as exc:
172
+ # RuntimeError covers environmental plumbing below the OSError
173
+ # layer — notably _to_wsl_path's "wslpath could not translate"
174
+ # on a broken WSL distro (review-confirmed leak): decide() must
175
+ # return a Verdict for in-contract input, never raise.
176
+ return Verdict(ERROR, self.name, reason="infra", detail=str(exc))
177
+
178
+ status = result["status"]
179
+
180
+ if status == "Theorem":
181
+ proof = result["proof"]
182
+ reflexivity = proof is None and _reflexivity_proof(result.get("raw_output", ""))
183
+ if reflexivity:
184
+ proof = reflexivity
185
+ if proof is None:
186
+ # Twee said Theorem but its proof text did not parse (see
187
+ # check_entailment_twee_detailed's proof_parse_error key):
188
+ # the policy stands — no independent verification, no
189
+ # PROVED — but this is an ERROR verdict, never a crash.
190
+ return Verdict(
191
+ ERROR, self.name, reason="infra", wall_time=elapsed,
192
+ detail="twee reported Theorem but its proof text was "
193
+ "unparseable — refusing PROVED without "
194
+ "verification: "
195
+ + str(result.get("proof_parse_error")))
196
+ check_result = check_twee_proof(proof, premises)
197
+ matches_goal = goal_matches_conclusion(proof, formula)
198
+ if check_result.ok and matches_goal:
199
+ detail = "proof independently verified by atp.twee_check"
200
+ if reflexivity:
201
+ detail += ("; Twee's proof is the one line 'Reflexivity.' (the goal is "
202
+ "an instance of x = x), a proof with no rewrite step")
203
+ return Verdict(PROVED, self.name, wall_time=elapsed, proof=proof.to_dict(),
204
+ detail=detail)
205
+ problems = []
206
+ if not check_result.ok:
207
+ problems.append(f"check_twee_proof: {check_result.error}")
208
+ if not matches_goal:
209
+ reason = goal_mismatch(proof, formula)
210
+ problems.append("goal_matches_conclusion: the proved goal does not "
211
+ "restate the requested conclusion"
212
+ + (f" ({reason})" if reason else ""))
213
+ return Verdict(ERROR, self.name, reason="infra", wall_time=elapsed,
214
+ detail="twee reported Theorem but its proof failed independent "
215
+ "verification: " + "; ".join(problems))
216
+
217
+ if status == "CounterSatisfiable":
218
+ return Verdict(REFUTED, self.name, wall_time=elapsed)
219
+
220
+ if result["timed_out"]:
221
+ return Verdict(UNKNOWN, self.name, reason="timeout", wall_time=elapsed,
222
+ detail="twee did not finish within the time budget")
223
+
224
+ if status == "Unknown":
225
+ # No RESULT line although our timeout did not fire (the case above):
226
+ # Twee refused the problem or died -- its parse/usage error is on
227
+ # stderr, exit 1, with nothing on stdout (see the module docstring
228
+ # of atp.twee_entailment, shape 5; ``raw_output`` carries stderr).
229
+ # An error with Twee's own text, not "incomplete".
230
+ return Verdict(ERROR, self.name, reason="infra", wall_time=elapsed,
231
+ detail=_rejection_detail(
232
+ "twee", result.get("raw_output", ""),
233
+ "no RESULT line in its output"))
234
+
235
+ return Verdict(UNKNOWN, self.name, reason="incomplete", wall_time=elapsed,
236
+ detail=f"twee status: {status}")