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,403 @@
|
|
|
1
|
+
"""Intuitionistic propositional logic → HOL, via the Gödel–McKinsey–Tarski (GMT)
|
|
2
|
+
box-translation into modal **S4** composed with the alethic shallow embedding.
|
|
3
|
+
|
|
4
|
+
Intuitionistic propositional logic (IPL) has no truth-functional semantics, but
|
|
5
|
+
Gödel (1933) and McKinsey–Tarski (1948) showed it embeds *faithfully* into the
|
|
6
|
+
modal logic **S4**: a propositional formula ``A`` is intuitionistically valid iff
|
|
7
|
+
its box-translation ``T(A)`` is S4-valid. The translation prefixes ``□`` exactly
|
|
8
|
+
where the intuitionistic clauses quantify over future worlds:
|
|
9
|
+
|
|
10
|
+
T(p) = □p (atoms are "stable" — forced henceforth)
|
|
11
|
+
T(¬A) = □¬T(A)
|
|
12
|
+
T(A ∧ B) = T(A) ∧ T(B)
|
|
13
|
+
T(A ∨ B) = T(A) ∨ T(B)
|
|
14
|
+
T(A → B) = □(T(A) → T(B))
|
|
15
|
+
|
|
16
|
+
(``A ↔ B`` and ``A ⊕ B`` are first expanded to their ∧/∨/→/¬ definitions —
|
|
17
|
+
matching the very clauses :meth:`IntKripkeModel.forces` uses — and then translated.)
|
|
18
|
+
|
|
19
|
+
FALSUM. The textbook GMT rule is ``T(⊥)=⊥`` with ``⊥`` a *genuine* logical constant,
|
|
20
|
+
and that is the rule here. The nullary atoms ``⊥`` and ``⊤`` (the reserved atom
|
|
21
|
+
``"⊥"`` of :data:`unicode_logic_kit.atp.fitch.FALSUM` among them) are the falsity and
|
|
22
|
+
truth constants, the same as ``$false`` and ``$true``: the intuitionistic Kripke
|
|
23
|
+
evaluator :func:`unicode_logic_kit.semantics.intuitionistic.int_valid` forces ``⊤`` at
|
|
24
|
+
every world and ``⊥`` at none, so ``⊥→p`` and ``¬⊥`` are valid and ``⊥`` alone and
|
|
25
|
+
``⊤→p`` are not. The box-translation keeps a constant as it is, ``T(⊥)=⊥`` and
|
|
26
|
+
``T(⊤)=⊤`` (a constant needs no box: it is the same at every world), and never
|
|
27
|
+
declares a symbol for one. See :func:`gmt_translate`.
|
|
28
|
+
|
|
29
|
+
The resulting S4 modal formula is handed to the existing alethic SSE
|
|
30
|
+
(:mod:`unicode_logic_kit.fol.qml`) with an **S4 frame** (reflexive + transitive),
|
|
31
|
+
so the emitted THF problem / Isabelle theory is a *Theorem* exactly when the
|
|
32
|
+
original formula is intuitionistically valid. The accessibility relation ``r`` of
|
|
33
|
+
S4 is precisely the intuitionistic "≥" pre-order, and the GMT box mirrors the
|
|
34
|
+
"for every later world" quantifier of the ``→``/``¬`` forcing clauses; this is why
|
|
35
|
+
``p ∨ ¬p``, ``¬¬p → p`` and Peirce's law come out **non-theorems**, while
|
|
36
|
+
``p → ¬¬p`` and the constructive tautologies are theorems.
|
|
37
|
+
|
|
38
|
+
EQUALITY IS REFUSED. ``a = b`` / ``a ≠ b`` are not propositional letters, and this
|
|
39
|
+
module is the PROPOSITIONAL one: its ground truth :func:`int_valid` keys an atom by
|
|
40
|
+
its rendered form (``"a = a"`` is just another variable, so ``a = a`` is not valid
|
|
41
|
+
there), while the S4 side of the GMT embedding goes through
|
|
42
|
+
:func:`unicode_logic_kit.fol.qml.qml_is_valid`, which reads ``=`` as RIGID identity
|
|
43
|
+
over the object domain (``a = a`` valid, ``a = b → □(a = b)`` valid). Fed an identity
|
|
44
|
+
atom the two sides of the module's own cross-check therefore answer different
|
|
45
|
+
questions and :func:`gmt_validity_matches_int_valid` reports a "mismatch" that is no
|
|
46
|
+
bug in either — and :func:`to_isabelle_intuitionistic` would emit a real proof
|
|
47
|
+
for ``a = a`` about an uninterpreted constant ``feq``, which Isabelle cannot check.
|
|
48
|
+
The two could be made to agree only by giving intuitionistic logic a term semantics
|
|
49
|
+
of its own (intuitionistic logic WITH equality — not what ``int_valid`` or the
|
|
50
|
+
G4ip prover decide, and not part of the GMT theorem, which is about propositional
|
|
51
|
+
formulas) or by reading identity as an uninterpreted relation on the S4 side (the
|
|
52
|
+
silent approximation the kit refuses, and against ``fol.qml``). So :func:`gmt_translate`
|
|
53
|
+
— every other public function goes through it — raises ``NotImplementedError``
|
|
54
|
+
naming the atom, with the shared
|
|
55
|
+
:func:`~unicode_logic_kit.semantics._modal_reject.reject_equality` the propositional
|
|
56
|
+
modal tableau and the Kripke evaluator use, scanning the WHOLE formula up front.
|
|
57
|
+
Other atoms with arguments (``P(a)``, ``a < b``) stay ordinary propositional letters
|
|
58
|
+
on both sides, exactly as before.
|
|
59
|
+
|
|
60
|
+
HONESTY. This module only *emits* a HOL problem/theory; it does not run Isabelle,
|
|
61
|
+
Leo-III, Satallax or Sledgehammer. IPL is decidable (finite model property —
|
|
62
|
+
which is what :func:`unicode_logic_kit.semantics.intuitionistic.int_valid` exploits),
|
|
63
|
+
and propositional S4 is decidable, so a HOL prover *can* discharge every emitted
|
|
64
|
+
conjecture; but the SSE target is full HOL, whose theorem-hood is only
|
|
65
|
+
semi-decidable, so an external prover may time out. The cross-checking function
|
|
66
|
+
:func:`gmt_validity_matches_int_valid` does not need an external prover: it compares
|
|
67
|
+
:func:`int_valid` against the toolkit's *own* S4-validity of the translation
|
|
68
|
+
(:func:`unicode_logic_kit.fol.qml.qml_is_valid` under an S4 frame, decided by Z3 — the
|
|
69
|
+
fragment is propositional, hence decidable), so the GMT correctness claim is verified
|
|
70
|
+
end-to-end inside the toolkit.
|
|
71
|
+
|
|
72
|
+
Public API: :func:`gmt_translate`, :func:`to_thf_intuitionistic`,
|
|
73
|
+
:func:`to_isabelle_intuitionistic`, :func:`gmt_is_s4_valid`,
|
|
74
|
+
:func:`gmt_validity_matches_int_valid`.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
from unicode_logic_kit.fol.nodes import (
|
|
78
|
+
Node, Atom, Not, And, Or, Xor, Implies, Iff,
|
|
79
|
+
Box, Quantifier, SortedQuantifier,
|
|
80
|
+
)
|
|
81
|
+
from unicode_logic_kit.fol._so_nodes import SecondOrderQuantifier
|
|
82
|
+
from unicode_logic_kit.fol.qml import to_thf_modal
|
|
83
|
+
from unicode_logic_kit.fol._truth_constants import truth_value
|
|
84
|
+
from unicode_logic_kit.semantics._modal_reject import reject_equality
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
#: How the GMT embedding reads an atom, and so why it cannot read identity: the
|
|
88
|
+
#: clause the shared equality refusal quotes, and the sentence that points elsewhere.
|
|
89
|
+
_EQUALITY_ROUTE = "the propositional Gödel–McKinsey–Tarski embedding"
|
|
90
|
+
_EQUALITY_ATOM_READING = ("an atom is a propositional letter keyed by its rendered "
|
|
91
|
+
"form, exactly as int_valid reads it")
|
|
92
|
+
_EQUALITY_INSTEAD = (
|
|
93
|
+
"The kit has no intuitionistic logic with equality, and the two sides of this "
|
|
94
|
+
"module's cross-check would answer different questions: int_valid reads the "
|
|
95
|
+
"atom as an uninterpreted proposition while the S4 side (fol.qml) reads '=' as "
|
|
96
|
+
"rigid identity. For identity under modal (classical) reasoning use "
|
|
97
|
+
"unicode_logic_kit.fol.qml.qml_is_valid or another first-order route, not here.")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _check_propositional(formula: Node) -> None:
|
|
101
|
+
"""Refuse ``formula`` if it is not propositional IPL.
|
|
102
|
+
|
|
103
|
+
Raises ``ValueError`` on a quantifier (out of scope) and ``NotImplementedError``
|
|
104
|
+
on an equality / disequality atom (``=`` / ``≠``, refused by name — see the
|
|
105
|
+
module docstring's "EQUALITY IS REFUSED"), scanning the WHOLE tree before any
|
|
106
|
+
translation or oracle call so no verdict is produced that never looked at it.
|
|
107
|
+
|
|
108
|
+
Mirrors :func:`unicode_logic_kit.semantics.intuitionistic._check_propositional`:
|
|
109
|
+
the GMT embedding here is for *propositional* IPL, whose decidability the
|
|
110
|
+
cross-check relies on. (Quantified IPL needs varying first-order domains.)
|
|
111
|
+
"""
|
|
112
|
+
for node in formula.walk():
|
|
113
|
+
if isinstance(node, (Quantifier, SortedQuantifier, SecondOrderQuantifier)):
|
|
114
|
+
raise ValueError(
|
|
115
|
+
"intuitionistic GMT: only propositional formulas are supported "
|
|
116
|
+
"(quantified intuitionistic logic needs varying domains, out of scope)."
|
|
117
|
+
)
|
|
118
|
+
reject_equality(node, "intuitionistic GMT", _EQUALITY_ROUTE,
|
|
119
|
+
atom_reading=_EQUALITY_ATOM_READING,
|
|
120
|
+
instead=_EQUALITY_INSTEAD)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def gmt_translate(formula: Node) -> Node:
|
|
124
|
+
"""Return the Gödel–McKinsey–Tarski box-translation ``T(formula)`` (a modal S4 Node).
|
|
125
|
+
|
|
126
|
+
The result is a classical modal formula built from :class:`Box`, the Boolean
|
|
127
|
+
connectives and the original atoms; it is S4-valid iff ``formula`` is
|
|
128
|
+
intuitionistically valid. ``↔`` and ``⊕`` are expanded to their ∧/∨/→/¬
|
|
129
|
+
definitions before translation, matching the intuitionistic forcing clauses.
|
|
130
|
+
The truth constants ``⊤`` / ``$true`` and ``⊥`` / ``$false`` are kept as they are
|
|
131
|
+
(``T(⊥)=⊥``), the reading :func:`int_valid` gives them; see the module docstring's
|
|
132
|
+
FALSUM note.
|
|
133
|
+
|
|
134
|
+
Raises ``ValueError`` on a quantifier and ``NotImplementedError`` on an equality
|
|
135
|
+
atom (``=`` / ``≠``) anywhere in ``formula`` — see the module docstring's
|
|
136
|
+
"EQUALITY IS REFUSED". Every other function of this module goes through here,
|
|
137
|
+
so they all refuse alike.
|
|
138
|
+
"""
|
|
139
|
+
_check_propositional(formula)
|
|
140
|
+
return _gmt(formula)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _gmt(f: Node) -> Node:
|
|
144
|
+
"""Core box-translation recursion (no validation; see :func:`gmt_translate`)."""
|
|
145
|
+
if isinstance(f, Atom):
|
|
146
|
+
if truth_value(f) is not None:
|
|
147
|
+
return f # T($true) = $true, T($false) = $false
|
|
148
|
+
return Box(f) # T(p) = □p
|
|
149
|
+
if isinstance(f, Not):
|
|
150
|
+
return Box(Not(_gmt(f.formula))) # T(¬A) = □¬T(A)
|
|
151
|
+
if isinstance(f, And):
|
|
152
|
+
return And(_gmt(f.left), _gmt(f.right)) # T(A∧B) = T(A)∧T(B)
|
|
153
|
+
if isinstance(f, Or):
|
|
154
|
+
return Or(_gmt(f.left), _gmt(f.right)) # T(A∨B) = T(A)∨T(B)
|
|
155
|
+
if isinstance(f, Implies):
|
|
156
|
+
return Box(Implies(_gmt(f.left), _gmt(f.right))) # T(A→B) = □(T(A)→T(B))
|
|
157
|
+
if isinstance(f, Iff):
|
|
158
|
+
# A↔B ≡ (A→B)∧(B→A) — exactly the intuitionistic forcing clause for ↔.
|
|
159
|
+
return _gmt(And(Implies(f.left, f.right), Implies(f.right, f.left)))
|
|
160
|
+
if isinstance(f, Xor):
|
|
161
|
+
# A⊕B ≡ (A∨B)∧¬(A∧B) — the intuitionistic forcing clause for ⊕.
|
|
162
|
+
a, b = f.left, f.right
|
|
163
|
+
return _gmt(And(Or(a, b), Not(And(a, b))))
|
|
164
|
+
raise NotImplementedError(
|
|
165
|
+
f"intuitionistic GMT: unsupported node {type(f).__name__} "
|
|
166
|
+
"(propositional ∧/∨/→/¬/↔/⊕/⊥ and atoms only)."
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def to_thf_intuitionistic(formula: Node) -> str:
|
|
171
|
+
"""Emit a Benzmüller-style TPTP **THF** problem whose theorem-hood ≡ IPL-validity.
|
|
172
|
+
|
|
173
|
+
Box-translates ``formula`` (GMT) into modal S4 and embeds the result with the
|
|
174
|
+
alethic shallow embedding under an S4 frame (reflexive + transitive). The
|
|
175
|
+
conjecture ``mvalid @ ⟨T(formula)⟩`` is a *Theorem* (dischargeable by a HOL ATP
|
|
176
|
+
such as Leo-III / Satallax) iff ``formula`` is intuitionistically valid.
|
|
177
|
+
|
|
178
|
+
The toolkit only *emits* the problem; it does not run the prover.
|
|
179
|
+
"""
|
|
180
|
+
return to_thf_modal(gmt_translate(formula), mode="constant", frame="S4")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# --- Isabelle/HOL rendering of the GMT-translated S4 modal formula -----------
|
|
184
|
+
#
|
|
185
|
+
# A complete, *loadable* theory (not the alethic-fragment skeleton in qml.py,
|
|
186
|
+
# which leaves the lemma inside a comment and defines only mnot/mbox/mvalid).
|
|
187
|
+
# Worlds are an opaque type ``i``; a modal proposition is ``i ⇒ bool``; the
|
|
188
|
+
# operators are the standard Benzmüller-style lifted abbreviations and the frame
|
|
189
|
+
# is fixed to S4 (``r`` reflexive + transitive) via a locale-free axiomatization
|
|
190
|
+
# discharged inside the lemma's assumptions, so the theory is self-contained and
|
|
191
|
+
# Sledgehammer/auto can attack the goal directly.
|
|
192
|
+
|
|
193
|
+
_ISA_PROP = "\\<Rightarrow>"
|
|
194
|
+
_ISA_NOT = "\\<^bold>\\<not>"
|
|
195
|
+
_ISA_AND = "\\<^bold>\\<and>"
|
|
196
|
+
_ISA_OR = "\\<^bold>\\<or>"
|
|
197
|
+
_ISA_IMP = "\\<^bold>\\<rightarrow>"
|
|
198
|
+
_ISA_BOX = "\\<^bold>\\<box>"
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# Aliases for reserved/symbolic atoms whose char-by-char sanitisation would otherwise
|
|
202
|
+
# collapse to the bare reserved token '_' (Isabelle's wildcard — a theory using it as a
|
|
203
|
+
# consts name will NOT load) and merge distinct atoms (⊥/⊤/=/≠ all → '_'). Each alias is
|
|
204
|
+
# a distinct, valid lowercase identifier. (The THF path aliases these separately.)
|
|
205
|
+
# ``=`` / ``≠`` are aliased only so this sanitiser stays total and injective for any
|
|
206
|
+
# atom NAME it is asked about: no public function reaches it with an identity atom,
|
|
207
|
+
# because gmt_translate refuses one by name (module docstring, "EQUALITY IS REFUSED").
|
|
208
|
+
_ISA_ATOM_ALIASES = {"⊥": "bottom", "⊤": "top", "=": "feq", "≠": "fneq"}
|
|
209
|
+
|
|
210
|
+
# Identifiers the emitted theory already uses structurally: the world type ``i``, the
|
|
211
|
+
# accessibility relation ``r`` and the free variables ``w``/``v``/``u`` of its frame
|
|
212
|
+
# axioms (``r_refl: "r w w"``, ``r_trans: "r w v ⟹ r v u ⟹ r w u"``), and the lifted
|
|
213
|
+
# operator names. An atom predicate that sanitised to one of these would emit a SECOND
|
|
214
|
+
# ``consts`` with that name (a duplicate-constant clash that Isabelle rejects — so the
|
|
215
|
+
# theory would not load even for a valid formula, e.g. the atom ``r`` in ``r → r``), or
|
|
216
|
+
# make the frame axioms ill-typed (an atom ``w`` shadowing the type-``i`` bound var).
|
|
217
|
+
# A colliding atom is de-collided with the ``p_`` prefix (a trailing ``_`` would be a
|
|
218
|
+
# *bad* Isabelle identifier).
|
|
219
|
+
_ISA_RESERVED = frozenset({
|
|
220
|
+
"i", "r", "w", "v", "u",
|
|
221
|
+
"mnot", "mand", "mor", "mimp", "mbox", "mvalid",
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _isa_atom_name(name: str) -> str:
|
|
226
|
+
"""A safe, *distinct* Isabelle constant name for an atom predicate.
|
|
227
|
+
|
|
228
|
+
Distinct source atoms must map to distinct legal identifiers. Reserved/symbolic
|
|
229
|
+
atoms (⊥, ⊤, =, ≠) are aliased to dedicated lowercase ids; everything else is
|
|
230
|
+
sanitised char-by-char (alnum/underscore), a ``p_`` prefix is prepended when the
|
|
231
|
+
result is empty, is the bare reserved ``_`` token, or starts with ``_`` (all of
|
|
232
|
+
which are illegal or reserved as a bare Isabelle constant name), and a name that
|
|
233
|
+
would collide with a structural identifier of the theory (the relation ``r``, an
|
|
234
|
+
axiom variable ``w``/``v``/``u``, the world type ``i``, a lifted operator) is
|
|
235
|
+
de-collided with the ``p_`` prefix (``r`` → ``p_r``).
|
|
236
|
+
"""
|
|
237
|
+
if name in _ISA_ATOM_ALIASES:
|
|
238
|
+
return _ISA_ATOM_ALIASES[name]
|
|
239
|
+
safe = "".join(c if (c.isalnum() or c == "_") else "_" for c in name)
|
|
240
|
+
if not safe or safe[0] == "_" or not safe[0].isalpha():
|
|
241
|
+
safe = "p_" + safe
|
|
242
|
+
if safe in _ISA_RESERVED:
|
|
243
|
+
safe = "p_" + safe # p_r / p_w / … (a trailing '_' is a bad Isabelle id)
|
|
244
|
+
return safe
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _isa_atoms(formula: Node):
|
|
248
|
+
"""Distinct atom predicate names in ``formula`` (each a propositional letter)."""
|
|
249
|
+
out, seen = [], set()
|
|
250
|
+
for n in formula.walk():
|
|
251
|
+
if (isinstance(n, Atom) and n.predicate not in seen
|
|
252
|
+
and truth_value(n) is None):
|
|
253
|
+
seen.add(n.predicate)
|
|
254
|
+
out.append(n.predicate)
|
|
255
|
+
return out
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _isa_render(node: Node) -> str:
|
|
259
|
+
"""Render a GMT-translated S4 modal Node in Isabelle bold-operator syntax."""
|
|
260
|
+
if isinstance(node, Atom):
|
|
261
|
+
if truth_value(node) is not None:
|
|
262
|
+
return "(\\<lambda>_. True)" if truth_value(node) else "(\\<lambda>_. False)"
|
|
263
|
+
return _isa_atom_name(node.predicate)
|
|
264
|
+
if isinstance(node, Not):
|
|
265
|
+
return f"({_ISA_NOT}{_isa_render(node.formula)})"
|
|
266
|
+
if isinstance(node, And):
|
|
267
|
+
return f"({_isa_render(node.left)} {_ISA_AND} {_isa_render(node.right)})"
|
|
268
|
+
if isinstance(node, Or):
|
|
269
|
+
return f"({_isa_render(node.left)} {_ISA_OR} {_isa_render(node.right)})"
|
|
270
|
+
if isinstance(node, Implies):
|
|
271
|
+
return f"({_isa_render(node.left)} {_ISA_IMP} {_isa_render(node.right)})"
|
|
272
|
+
if isinstance(node, Box):
|
|
273
|
+
return f"({_ISA_BOX}{_isa_render(node.formula)})"
|
|
274
|
+
# GMT output only ever contains Atom/Not/And/Or/Implies/Box.
|
|
275
|
+
raise NotImplementedError(
|
|
276
|
+
f"to_isabelle_intuitionistic: unexpected node {type(node).__name__} "
|
|
277
|
+
"in the S4 translation."
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def to_isabelle_intuitionistic(formula: Node, theory_name: str = "IPL_GMT") -> str:
|
|
282
|
+
"""Emit a complete, loadable **Isabelle/HOL** theory whose lemma ≡ IPL-validity.
|
|
283
|
+
|
|
284
|
+
Box-translates ``formula`` (GMT) into modal S4, then writes a self-contained
|
|
285
|
+
theory: worlds as a type ``i``; an accessibility relation ``r`` fixed to be
|
|
286
|
+
reflexive + transitive (the **S4** frame); the lifted modal operators as
|
|
287
|
+
abbreviations; the atoms as ``consts``; and the embedded formula as a genuine
|
|
288
|
+
``lemma`` (``\\<lfloor> T(formula) \\<rfloor>``). The lemma is a theorem iff
|
|
289
|
+
``formula`` is intuitionistically valid (Gödel–McKinsey–Tarski).
|
|
290
|
+
|
|
291
|
+
The proof is emitted **verdict-dependently** from the module's *decidable* S4
|
|
292
|
+
oracle :func:`gmt_is_s4_valid` (Z3 on the GMT→S4 translation, decisive on this
|
|
293
|
+
propositional fragment): when the formula is valid the theory carries a real,
|
|
294
|
+
Isabelle-checked proof (``using r_refl r_trans by (metis … | meson … | blast |
|
|
295
|
+
auto)`` — the S4 frame facts must be in scope, a bare ``axiomatization`` fact is
|
|
296
|
+
not in the default claset); when it is not valid the lemma is left ``oops`` (no
|
|
297
|
+
proof exists; see
|
|
298
|
+
:func:`~unicode_logic_kit.semantics.intuitionistic.int_countermodel`). The decision
|
|
299
|
+
deliberately does **not** use ``int_valid``'s default 3-world bound, which is
|
|
300
|
+
incomplete (IPL's finite-model bound grows with the formula).
|
|
301
|
+
|
|
302
|
+
Unlike :func:`unicode_logic_kit.fol.qml.to_isabelle_modal` (an alethic skeleton
|
|
303
|
+
that puts the lemma in a comment and defines only ``mnot``/``mbox``/``mvalid``),
|
|
304
|
+
this emits the full operator set and frame axioms, so the theory loads as-is.
|
|
305
|
+
The toolkit only *emits* the theory; it does not run Isabelle.
|
|
306
|
+
"""
|
|
307
|
+
s4 = gmt_translate(formula)
|
|
308
|
+
# Decide validity with the module's own DECIDABLE S4 oracle (Z3 on the GMT→S4
|
|
309
|
+
# translation), NOT int_valid's bounded Kripke search: int_valid defaults to a
|
|
310
|
+
# 3-world bound, but IPL's finite-model-property bound grows with the formula, so
|
|
311
|
+
# int_valid can wrongly call a non-theorem valid — e.g. (p→q)∨(q→r)∨(r→p) is
|
|
312
|
+
# IPL-INVALID but needs 4 worlds to refute — which would emit a real proof for a
|
|
313
|
+
# NON-theorem that then fails to build. gmt_is_s4_valid is decisive on this
|
|
314
|
+
# propositional S4 fragment, so the emitted proof is sound by construction.
|
|
315
|
+
valid = gmt_is_s4_valid(formula)
|
|
316
|
+
atoms = _isa_atoms(s4)
|
|
317
|
+
R = "\\<Rightarrow>"
|
|
318
|
+
lines = [
|
|
319
|
+
f"theory {theory_name}",
|
|
320
|
+
" imports Main",
|
|
321
|
+
"begin",
|
|
322
|
+
"",
|
|
323
|
+
"(* Goedel--McKinsey--Tarski embedding of intuitionistic propositional logic *)",
|
|
324
|
+
"(* into modal S4, then the Benzmueller shallow embedding into HOL. *)",
|
|
325
|
+
f"(* Original IPL formula: {formula.to_unicode_str()} *)",
|
|
326
|
+
"(* The lemma is a theorem iff the formula is intuitionistically valid. *)",
|
|
327
|
+
"",
|
|
328
|
+
"typedecl i \\<comment> \\<open>the type of worlds (Kripke stages)\\<close>",
|
|
329
|
+
"",
|
|
330
|
+
"consts r :: \"i \\<Rightarrow> i \\<Rightarrow> bool\" \\<comment> \\<open>accessibility (the intuitionistic \\<open>\\<le>\\<close>)\\<close>",
|
|
331
|
+
"",
|
|
332
|
+
"axiomatization where",
|
|
333
|
+
" r_refl: \"r w w\" and",
|
|
334
|
+
" r_trans: \"r w v \\<Longrightarrow> r v u \\<Longrightarrow> r w u\"",
|
|
335
|
+
"",
|
|
336
|
+
"type_synonym \\<sigma> = \"i \\<Rightarrow> bool\" \\<comment> \\<open>a modal proposition\\<close>",
|
|
337
|
+
"",
|
|
338
|
+
f"abbreviation mnot :: \"\\<sigma> {R} \\<sigma>\" (\"{_ISA_NOT}_\" [52] 53)",
|
|
339
|
+
" where \"" + _ISA_NOT + "\\<phi> \\<equiv> \\<lambda>w. \\<not> \\<phi> w\"",
|
|
340
|
+
f"abbreviation mand :: \"\\<sigma> {R} \\<sigma> {R} \\<sigma>\" (infixr \"{_ISA_AND}\" 51)",
|
|
341
|
+
" where \"\\<phi> " + _ISA_AND + " \\<psi> \\<equiv> \\<lambda>w. \\<phi> w \\<and> \\<psi> w\"",
|
|
342
|
+
f"abbreviation mor :: \"\\<sigma> {R} \\<sigma> {R} \\<sigma>\" (infixr \"{_ISA_OR}\" 50)",
|
|
343
|
+
" where \"\\<phi> " + _ISA_OR + " \\<psi> \\<equiv> \\<lambda>w. \\<phi> w \\<or> \\<psi> w\"",
|
|
344
|
+
f"abbreviation mimp :: \"\\<sigma> {R} \\<sigma> {R} \\<sigma>\" (infixr \"{_ISA_IMP}\" 49)",
|
|
345
|
+
" where \"\\<phi> " + _ISA_IMP + " \\<psi> \\<equiv> \\<lambda>w. \\<phi> w \\<longrightarrow> \\<psi> w\"",
|
|
346
|
+
f"abbreviation mbox :: \"\\<sigma> {R} \\<sigma>\" (\"{_ISA_BOX}_\" [52] 53)",
|
|
347
|
+
" where \"" + _ISA_BOX + "\\<phi> \\<equiv> \\<lambda>w. \\<forall>v. r w v \\<longrightarrow> \\<phi> v\"",
|
|
348
|
+
"abbreviation mvalid :: \"\\<sigma> \\<Rightarrow> bool\" (\"\\<lfloor>_\\<rfloor>\")",
|
|
349
|
+
" where \"\\<lfloor>\\<phi>\\<rfloor> \\<equiv> \\<forall>w. \\<phi> w\"",
|
|
350
|
+
"",
|
|
351
|
+
]
|
|
352
|
+
for a in atoms:
|
|
353
|
+
lines.append(f"consts {_isa_atom_name(a)} :: \"\\<sigma>\"")
|
|
354
|
+
lines.append("")
|
|
355
|
+
lines.append("lemma gmt_goal: \"\\<lfloor> " + _isa_render(s4) + " \\<rfloor>\"")
|
|
356
|
+
if valid:
|
|
357
|
+
# A real, Isabelle-checked proof. The S4 frame facts must be brought into
|
|
358
|
+
# scope (a bare `axiomatization` fact is not in the default claset), then a
|
|
359
|
+
# small method battery closes the GMT goal.
|
|
360
|
+
lines.append(" using r_refl r_trans")
|
|
361
|
+
lines.append(" by (metis r_refl r_trans | meson r_refl r_trans | blast | auto)")
|
|
362
|
+
else:
|
|
363
|
+
lines.append(" \\<comment> \\<open>NOT intuitionistically valid: no proof exists "
|
|
364
|
+
"(see int_countermodel for a Kripke counter-model)\\<close>")
|
|
365
|
+
lines.append(" oops")
|
|
366
|
+
lines.append("")
|
|
367
|
+
lines.append("end")
|
|
368
|
+
return "\n".join(lines) + "\n"
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def gmt_is_s4_valid(formula: Node, timeout: int = 10000) -> bool:
|
|
372
|
+
"""Return True iff the GMT translation ``T(formula)`` is **S4-valid**.
|
|
373
|
+
|
|
374
|
+
Decided *inside the toolkit* by handing the modal S4 translation to the alethic
|
|
375
|
+
shallow embedding under an S4 frame (reflexive + transitive) and discharging it
|
|
376
|
+
with Z3 (propositional S4 is decidable — there are no object quantifiers, so the
|
|
377
|
+
embedding is decidable here). By the GMT theorem this is True iff ``formula`` is
|
|
378
|
+
intuitionistically valid; :func:`gmt_validity_matches_int_valid` uses it as an
|
|
379
|
+
independent check of :func:`int_valid` that does not need an external HOL prover.
|
|
380
|
+
|
|
381
|
+
TIMEOUT CAVEAT: the problem class is decidable, but Z3 still runs under
|
|
382
|
+
``timeout`` (ms) — on a large/deeply-nested formula it can answer *unknown*,
|
|
383
|
+
which the Z3 validity oracle conservatively maps to False. So ``True`` is
|
|
384
|
+
always a proof, while ``False`` on a very large formula may mean "timed out",
|
|
385
|
+
not "refuted" — raise ``timeout`` for such inputs, or use
|
|
386
|
+
:func:`unicode_logic_kit.atp.lj.int_prove` (the G4ip proof search), which is a
|
|
387
|
+
terminating decision procedure with no solver timeout in play.
|
|
388
|
+
"""
|
|
389
|
+
from unicode_logic_kit.fol.qml import qml_is_valid
|
|
390
|
+
return qml_is_valid(gmt_translate(formula), mode="constant", frame="S4", timeout=timeout)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def gmt_validity_matches_int_valid(formula: Node, max_worlds: int = 3,
|
|
394
|
+
timeout: int = 10000) -> bool:
|
|
395
|
+
"""True iff the S4-validity of ``T(formula)`` agrees with :func:`int_valid`.
|
|
396
|
+
|
|
397
|
+
The GMT-correctness oracle: returns True when the GMT→S4 embedding pronounces
|
|
398
|
+
exactly the same verdict as the toolkit's native intuitionistic decision
|
|
399
|
+
procedure. (A green result is the faithfulness witness; it does not by itself
|
|
400
|
+
say whether ``formula`` is valid — call :func:`int_valid` for that.)
|
|
401
|
+
"""
|
|
402
|
+
from unicode_logic_kit.semantics.intuitionistic import int_valid
|
|
403
|
+
return gmt_is_s4_valid(formula, timeout=timeout) == int_valid(formula, max_worlds=max_worlds)
|