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.
- unicode_logic_kit/__init__.py +385 -0
- unicode_logic_kit/__main__.py +520 -0
- unicode_logic_kit/_deadline.py +219 -0
- unicode_logic_kit/ace/__init__.py +126 -0
- unicode_logic_kit/ace/_align.py +135 -0
- unicode_logic_kit/ace/chem_lexicon.py +128 -0
- unicode_logic_kit/ace/drs_reader.py +570 -0
- unicode_logic_kit/ace/mapping.py +666 -0
- unicode_logic_kit/ace/reverse_modal.py +138 -0
- unicode_logic_kit/ace/runner.py +551 -0
- unicode_logic_kit/ace/translate.py +452 -0
- unicode_logic_kit/ace/verbalize.py +1070 -0
- unicode_logic_kit/api.py +1284 -0
- unicode_logic_kit/atp/__init__.py +177 -0
- unicode_logic_kit/atp/_ascii_names.py +113 -0
- unicode_logic_kit/atp/_html.py +72 -0
- unicode_logic_kit/atp/_substructural_input.py +228 -0
- unicode_logic_kit/atp/_tff_problem.py +715 -0
- unicode_logic_kit/atp/_tptp_problem.py +1111 -0
- unicode_logic_kit/atp/_writer_support.py +289 -0
- unicode_logic_kit/atp/clingo_backend.py +1180 -0
- unicode_logic_kit/atp/cvc5_backend.py +1385 -0
- unicode_logic_kit/atp/eprover_backend.py +732 -0
- unicode_logic_kit/atp/finite_domain.py +1055 -0
- unicode_logic_kit/atp/fitch.py +1547 -0
- unicode_logic_kit/atp/fitch_search.py +551 -0
- unicode_logic_kit/atp/hets_backend.py +339 -0
- unicode_logic_kit/atp/hybrid_down.py +120 -0
- unicode_logic_kit/atp/incremental.py +250 -0
- unicode_logic_kit/atp/kripke_enum.py +741 -0
- unicode_logic_kit/atp/lambek.py +436 -0
- unicode_logic_kit/atp/leo3_backend.py +332 -0
- unicode_logic_kit/atp/linear.py +738 -0
- unicode_logic_kit/atp/lj.py +705 -0
- unicode_logic_kit/atp/logic_backends.py +566 -0
- unicode_logic_kit/atp/ltl_tableau.py +1084 -0
- unicode_logic_kit/atp/minizinc_backend.py +1402 -0
- unicode_logic_kit/atp/modal_tableau.py +1382 -0
- unicode_logic_kit/atp/nanocop_backend.py +410 -0
- unicode_logic_kit/atp/portfolio.py +489 -0
- unicode_logic_kit/atp/protocol.py +1803 -0
- unicode_logic_kit/atp/prover9_entailment.py +1153 -0
- unicode_logic_kit/atp/resolution.py +1376 -0
- unicode_logic_kit/atp/resolution_check.py +1114 -0
- unicode_logic_kit/atp/sequent.py +1050 -0
- unicode_logic_kit/atp/tableau.py +921 -0
- unicode_logic_kit/atp/tableau_check.py +543 -0
- unicode_logic_kit/atp/tptp_ncl.py +811 -0
- unicode_logic_kit/atp/tptp_tff.py +1546 -0
- unicode_logic_kit/atp/tstp.py +1333 -0
- unicode_logic_kit/atp/tstp_check.py +1096 -0
- unicode_logic_kit/atp/twee_backend.py +236 -0
- unicode_logic_kit/atp/twee_check.py +711 -0
- unicode_logic_kit/atp/twee_entailment.py +953 -0
- unicode_logic_kit/atp/vampire_entailment.py +540 -0
- unicode_logic_kit/atp/z3_arith.py +470 -0
- unicode_logic_kit/atp/z3_equivalence.py +36 -0
- unicode_logic_kit/atp/z3_fuzzy.py +362 -0
- unicode_logic_kit/atp/z3_input.py +500 -0
- unicode_logic_kit/atp/z3_models.py +208 -0
- unicode_logic_kit/chem/__init__.py +88 -0
- unicode_logic_kit/chem/_naming.py +284 -0
- unicode_logic_kit/chem/cache.py +185 -0
- unicode_logic_kit/chem/interop.py +244 -0
- unicode_logic_kit/chem/mol.py +525 -0
- unicode_logic_kit/chem/signature.py +112 -0
- unicode_logic_kit/comorphism.py +497 -0
- unicode_logic_kit/dl/__init__.py +384 -0
- unicode_logic_kit/dl/classification.py +227 -0
- unicode_logic_kit/dl/concepts.py +632 -0
- unicode_logic_kit/dl/datatypes.py +818 -0
- unicode_logic_kit/dl/owl_functional.py +2433 -0
- unicode_logic_kit/dl/owl_manchester.py +1637 -0
- unicode_logic_kit/dl/owl_reasoner.py +790 -0
- unicode_logic_kit/dl/parser.py +391 -0
- unicode_logic_kit/dl/tableau.py +4048 -0
- unicode_logic_kit/dl/translate.py +2704 -0
- unicode_logic_kit/drt/__init__.py +94 -0
- unicode_logic_kit/drt/export.py +179 -0
- unicode_logic_kit/drt/nodes.py +506 -0
- unicode_logic_kit/drt/parser.py +965 -0
- unicode_logic_kit/drt/resolve.py +195 -0
- unicode_logic_kit/drt/reverse.py +175 -0
- unicode_logic_kit/eval/__init__.py +106 -0
- unicode_logic_kit/eval/batch.py +382 -0
- unicode_logic_kit/eval/canonical.py +663 -0
- unicode_logic_kit/eval/chem_batch.py +606 -0
- unicode_logic_kit/eval/converses.py +200 -0
- unicode_logic_kit/eval/datasets/__init__.py +136 -0
- unicode_logic_kit/eval/datasets/_base.py +263 -0
- unicode_logic_kit/eval/datasets/_proofwriter_proof.py +422 -0
- unicode_logic_kit/eval/datasets/c3po.py +678 -0
- unicode_logic_kit/eval/datasets/folio.py +158 -0
- unicode_logic_kit/eval/datasets/fracas.py +418 -0
- unicode_logic_kit/eval/datasets/groves.py +191 -0
- unicode_logic_kit/eval/datasets/logicbench.py +467 -0
- unicode_logic_kit/eval/datasets/logicnli.py +303 -0
- unicode_logic_kit/eval/datasets/malls.py +133 -0
- unicode_logic_kit/eval/datasets/pfolio.py +594 -0
- unicode_logic_kit/eval/datasets/pmb.py +242 -0
- unicode_logic_kit/eval/datasets/prontoqa.py +611 -0
- unicode_logic_kit/eval/datasets/proofwriter.py +1431 -0
- unicode_logic_kit/eval/datasets/proverqa.py +674 -0
- unicode_logic_kit/eval/datasets/willow.py +478 -0
- unicode_logic_kit/eval/equivalence.py +466 -0
- unicode_logic_kit/eval/exercise_gen.py +533 -0
- unicode_logic_kit/eval/explain.py +791 -0
- unicode_logic_kit/eval/generality.py +750 -0
- unicode_logic_kit/eval/metric_hf.py +458 -0
- unicode_logic_kit/eval/predicate_match.py +343 -0
- unicode_logic_kit/eval/theory_check.py +1170 -0
- unicode_logic_kit/eval/validate.py +306 -0
- unicode_logic_kit/fol/__init__.py +177 -0
- unicode_logic_kit/fol/_atom_keys.py +510 -0
- unicode_logic_kit/fol/_fol_nodes.py +3586 -0
- unicode_logic_kit/fol/_free_parameters.py +105 -0
- unicode_logic_kit/fol/_ho_nodes.py +448 -0
- unicode_logic_kit/fol/_hybrid_nodes.py +308 -0
- unicode_logic_kit/fol/_identifiers.py +1091 -0
- unicode_logic_kit/fol/_lambek_nodes.py +112 -0
- unicode_logic_kit/fol/_linear_nodes.py +352 -0
- unicode_logic_kit/fol/_modal_nodes.py +1467 -0
- unicode_logic_kit/fol/_msfl_nodes.py +2196 -0
- unicode_logic_kit/fol/_numeral_symbols.py +231 -0
- unicode_logic_kit/fol/_so_nodes.py +200 -0
- unicode_logic_kit/fol/_symbol_names.py +81 -0
- unicode_logic_kit/fol/_team_nodes.py +181 -0
- unicode_logic_kit/fol/_tptp_symbols.py +551 -0
- unicode_logic_kit/fol/_truth_constants.py +117 -0
- unicode_logic_kit/fol/casl_export.py +1135 -0
- unicode_logic_kit/fol/casl_import.py +929 -0
- unicode_logic_kit/fol/derivation.py +367 -0
- unicode_logic_kit/fol/dialect_detect.py +70 -0
- unicode_logic_kit/fol/dialect_repair.py +537 -0
- unicode_logic_kit/fol/frames.py +637 -0
- unicode_logic_kit/fol/grammars/terminals.lark +31 -0
- unicode_logic_kit/fol/lambda_tools.py +297 -0
- unicode_logic_kit/fol/latex_input.py +429 -0
- unicode_logic_kit/fol/modal_translation.py +944 -0
- unicode_logic_kit/fol/msflparser.py +1033 -0
- unicode_logic_kit/fol/naming.py +422 -0
- unicode_logic_kit/fol/nodes.py +241 -0
- unicode_logic_kit/fol/normalforms.py +492 -0
- unicode_logic_kit/fol/pal.py +287 -0
- unicode_logic_kit/fol/prolog_export.py +566 -0
- unicode_logic_kit/fol/prolog_input.py +505 -0
- unicode_logic_kit/fol/prover9_input.py +1325 -0
- unicode_logic_kit/fol/qml.py +1760 -0
- unicode_logic_kit/fol/qmltp_input.py +525 -0
- unicode_logic_kit/fol/sanitize.py +221 -0
- unicode_logic_kit/fol/serialize.py +79 -0
- unicode_logic_kit/fol/signature.py +1290 -0
- unicode_logic_kit/fol/simplify_check.py +544 -0
- unicode_logic_kit/fol/spans.py +594 -0
- unicode_logic_kit/fol/tptp_input.py +1503 -0
- unicode_logic_kit/fol/tptp_repair.py +941 -0
- unicode_logic_kit/fol/unification.py +157 -0
- unicode_logic_kit/fol/verbalize.py +263 -0
- unicode_logic_kit/hets/__init__.py +163 -0
- unicode_logic_kit/hets/bridge.py +142 -0
- unicode_logic_kit/hets/client.py +748 -0
- unicode_logic_kit/hets/docker.py +420 -0
- unicode_logic_kit/hets/dol.py +712 -0
- unicode_logic_kit/hets/haskell_json.py +355 -0
- unicode_logic_kit/hets/owl_backend.py +794 -0
- unicode_logic_kit/hets/owl_cli.py +598 -0
- unicode_logic_kit/hets/symbols.py +512 -0
- unicode_logic_kit/hol/__init__.py +140 -0
- unicode_logic_kit/hol/_ho_common.py +323 -0
- unicode_logic_kit/hol/_isabelle_binders.py +125 -0
- unicode_logic_kit/hol/classical.py +812 -0
- unicode_logic_kit/hol/deepshallow/__init__.py +45 -0
- unicode_logic_kit/hol/deepshallow/_common.py +177 -0
- unicode_logic_kit/hol/deepshallow/conditional.py +225 -0
- unicode_logic_kit/hol/deepshallow/intuitionistic.py +181 -0
- unicode_logic_kit/hol/deepshallow/modal.py +217 -0
- unicode_logic_kit/hol/deepshallow/qml.py +406 -0
- unicode_logic_kit/hol/deepshallow/relevant.py +206 -0
- unicode_logic_kit/hol/free.py +753 -0
- unicode_logic_kit/hol/goedel.py +336 -0
- unicode_logic_kit/hol/ho_modal.py +1743 -0
- unicode_logic_kit/hol/intuitionistic.py +403 -0
- unicode_logic_kit/hol/isabelle_conditional.py +593 -0
- unicode_logic_kit/hol/isabelle_modal.py +1908 -0
- unicode_logic_kit/hol/isabelle_relevant.py +412 -0
- unicode_logic_kit/hol/isabelle_runner.py +1147 -0
- unicode_logic_kit/hol/isabelle_substructural.py +884 -0
- unicode_logic_kit/hol/lean.py +1018 -0
- unicode_logic_kit/hol/manyvalued.py +921 -0
- unicode_logic_kit/hol/secondorder.py +687 -0
- unicode_logic_kit/hol/thf_modal.py +941 -0
- unicode_logic_kit/hol/thirdorder.py +397 -0
- unicode_logic_kit/ilp/__init__.py +89 -0
- unicode_logic_kit/ilp/readback.py +389 -0
- unicode_logic_kit/ilp/separation.py +153 -0
- unicode_logic_kit/ilp/task.py +730 -0
- unicode_logic_kit/logic.py +163 -0
- unicode_logic_kit/mcp/__init__.py +28 -0
- unicode_logic_kit/mcp/__main__.py +5 -0
- unicode_logic_kit/mcp/chem_tools.py +1031 -0
- unicode_logic_kit/mcp/server.py +2453 -0
- unicode_logic_kit/mcp/syntax_spec.py +681 -0
- unicode_logic_kit/prob/__init__.py +53 -0
- unicode_logic_kit/prob/_bdd.py +225 -0
- unicode_logic_kit/prob/_column_gen.py +668 -0
- unicode_logic_kit/prob/distribution.py +686 -0
- unicode_logic_kit/prob/nilsson.py +470 -0
- unicode_logic_kit/py.typed +0 -0
- unicode_logic_kit/semantics/__init__.py +137 -0
- unicode_logic_kit/semantics/_modal_reject.py +156 -0
- unicode_logic_kit/semantics/action_models.py +466 -0
- unicode_logic_kit/semantics/asp_models.py +1200 -0
- unicode_logic_kit/semantics/conditional.py +580 -0
- unicode_logic_kit/semantics/dynamic_epistemic.py +95 -0
- unicode_logic_kit/semantics/free_logic.py +913 -0
- unicode_logic_kit/semantics/fuzzy.py +384 -0
- unicode_logic_kit/semantics/fuzzy_kripke.py +442 -0
- unicode_logic_kit/semantics/intuitionistic.py +581 -0
- unicode_logic_kit/semantics/kripke.py +1139 -0
- unicode_logic_kit/semantics/manyvalued.py +580 -0
- unicode_logic_kit/semantics/matrix.py +342 -0
- unicode_logic_kit/semantics/model_eval.py +1135 -0
- unicode_logic_kit/semantics/modelfinder.py +1036 -0
- unicode_logic_kit/semantics/nonmonotonic.py +372 -0
- unicode_logic_kit/semantics/relevant.py +331 -0
- unicode_logic_kit/semantics/secondorder.py +657 -0
- unicode_logic_kit/semantics/structures.py +352 -0
- unicode_logic_kit/semantics/tarski.py +975 -0
- unicode_logic_kit/semantics/team.py +315 -0
- unicode_logic_kit/semantics/team_translation.py +416 -0
- unicode_logic_kit/semantics/thirdorder.py +358 -0
- unicode_logic_kit/semantics/tnorm.py +85 -0
- unicode_logic_kit/semantics/truthtable.py +201 -0
- unicode_logic_kit-0.31.0.dist-info/METADATA +333 -0
- unicode_logic_kit-0.31.0.dist-info/RECORD +237 -0
- unicode_logic_kit-0.31.0.dist-info/WHEEL +4 -0
- 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}")
|