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,412 @@
|
|
|
1
|
+
r"""Isabelle/HOL export for relevant logic B (simplified Routley-Meyer semantics).
|
|
2
|
+
|
|
3
|
+
The modal exporter (:mod:`unicode_logic_kit.hol.isabelle_modal`) embeds a formula
|
|
4
|
+
over a single accessibility relation and reads truth as box/diamond over it. B's
|
|
5
|
+
``->`` is not that: it is the Priest-Sylvan **simplified** Routley-Meyer clause
|
|
6
|
+
implemented by :mod:`unicode_logic_kit.semantics.relevant` -- normal worlds get a
|
|
7
|
+
"material" reading (quantify over the WHOLE model), non-normal worlds route
|
|
8
|
+
through a ternary relation ``R`` -- so it needs its own embedding, which is what
|
|
9
|
+
this module emits.
|
|
10
|
+
|
|
11
|
+
Like :mod:`unicode_logic_kit.hol.isabelle_conditional`, the embedding is
|
|
12
|
+
*lightweight shallow*: a formula becomes a predicate on worlds (``tau = w =>
|
|
13
|
+
bool``) and each propositional atom is an uninterpreted ``w => bool`` constant.
|
|
14
|
+
The frame structure -- the normal-worlds predicate ``N``, the Routley star
|
|
15
|
+
``star`` and the ternary relation ``R`` -- are uninterpreted consts, and the
|
|
16
|
+
frame conditions :class:`~unicode_logic_kit.semantics.relevant.RelevantModel`
|
|
17
|
+
enforces in its ``__post_init__`` are bundled into a single ``wellformed``
|
|
18
|
+
proposition that is a **premise of the goal**, never an ``axiomatization``:
|
|
19
|
+
|
|
20
|
+
- ``N`` is nonempty (``relevant.py`` lines 121-122: ``if not normal: raise
|
|
21
|
+
ValueError``);
|
|
22
|
+
- ``star`` is a total involution on ``W`` (lines 126-135: ``star[star[w]] ==
|
|
23
|
+
w`` for every ``w``) -- totality of the ``w`` -> ``w`` map is free in HOL's
|
|
24
|
+
total function type, so only involution needs stating;
|
|
25
|
+
- ``R`` is sourced only at NON-normal worlds, i.e. ``R subseteq (W \ N) x W x
|
|
26
|
+
W`` (lines 142-145: ``if a in normal: raise ValueError``).
|
|
27
|
+
|
|
28
|
+
As a premise (mirroring ``nested Sel`` in ``isabelle_conditional``), nitpick
|
|
29
|
+
constructs ``N``/``star``/``R`` itself and can certify a countermodel as
|
|
30
|
+
*genuine* -- axiomatising them instead would downgrade nitpick's verdict to
|
|
31
|
+
``quasi_genuine`` and lose the refutation half of the decision procedure.
|
|
32
|
+
|
|
33
|
+
No hereditariness / persistence condition is encoded because
|
|
34
|
+
:class:`~unicode_logic_kit.semantics.relevant.RelevantModel` does not impose one:
|
|
35
|
+
its ``__post_init__`` places no monotonicity constraint on ``valuation``
|
|
36
|
+
(unlike, say, an intuitionistic Kripke model) -- this is exactly the
|
|
37
|
+
"simplified" in "simplified Routley-Meyer semantics" (Priest & Sylvan 1992),
|
|
38
|
+
which drops the compatibility/heredity apparatus of the original relational
|
|
39
|
+
semantics for B. So atoms are plain uninterpreted ``tau`` constants here, same
|
|
40
|
+
as in ``isabelle_conditional``.
|
|
41
|
+
|
|
42
|
+
``AndC``/``OrC``/``NegC``/``ImpC``/``IffC`` are the same truth conditions as
|
|
43
|
+
:func:`unicode_logic_kit.semantics.relevant.rel_satisfies`'s ``_sat`` clauses, so
|
|
44
|
+
what Isabelle certifies here is what the toolkit's own evaluator computes:
|
|
45
|
+
|
|
46
|
+
- ``w |= A /\ B`` / ``w |= A \/ B`` pointwise (``_sat`` And/Or clauses);
|
|
47
|
+
- ``w |= ~A`` iff ``w* |=/ A`` -- the Routley star (``_sat`` Not clause);
|
|
48
|
+
- ``w |= A -> B``, ``w`` normal, iff every ``A``-world of the WHOLE model is a
|
|
49
|
+
``B``-world (``_sat`` Implies clause, ``world in model.normal`` branch);
|
|
50
|
+
- ``w |= A -> B``, ``w`` non-normal, iff for every triple ``R(w, x, y)``,
|
|
51
|
+
``x |= A`` implies ``y |= B`` (``_sat`` Implies clause, ``else`` branch);
|
|
52
|
+
- ``w |= A <-> B`` iff ``w |= A -> B`` and ``w |= B -> A`` at the SAME world
|
|
53
|
+
(``_sat`` Iff clause: it recurses on ``Implies(left, right)`` /
|
|
54
|
+
``Implies(right, left)``, not a primitive biconditional clause) -- so
|
|
55
|
+
``IffC`` is defined via ``AndC``/``ImpC``, not as its own case split.
|
|
56
|
+
|
|
57
|
+
Only ``Not``/``And``/``Or``/``Implies``/``Iff`` over nullary atoms are accepted,
|
|
58
|
+
matching :func:`unicode_logic_kit.semantics.relevant._reject_non_propositional`
|
|
59
|
+
exactly (no quantifiers, modalities, lambda terms, ``Xor``, or non-nullary
|
|
60
|
+
atoms -- there is no B reading for them here either).
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
from typing import Optional, Sequence, Tuple
|
|
64
|
+
|
|
65
|
+
from ..fol.nodes import Node, Atom, Not, And, Or, Implies, Iff
|
|
66
|
+
from ..fol._msfl_nodes import key_text
|
|
67
|
+
from ..fol._truth_constants import refuse_truth_constants
|
|
68
|
+
from .deepshallow._common import AtomConsts, theory_name_ok
|
|
69
|
+
|
|
70
|
+
#: Why the B embeddings have no reading of ``$true`` / ``$false`` (the reason the
|
|
71
|
+
#: refusal names, the same one :mod:`unicode_logic_kit.semantics.relevant` gives).
|
|
72
|
+
_NO_CONSTANT_WHY = (
|
|
73
|
+
"relevant logic has two truths and two falsities, an additive pair and a "
|
|
74
|
+
"multiplicative pair, which differ in B, and TPTP's $true / $false names "
|
|
75
|
+
"neither pair")
|
|
76
|
+
from ._ho_common import ThfNames
|
|
77
|
+
|
|
78
|
+
#: The Isabelle type of an embedded formula: a predicate on worlds.
|
|
79
|
+
_TAU = r"w \<Rightarrow> bool"
|
|
80
|
+
|
|
81
|
+
#: Definitions the goal has to unfold before a proof method can see through it.
|
|
82
|
+
_DEFS = ("wellformed_def", "NegC_def", "AndC_def", "OrC_def", "ImpC_def", "IffC_def")
|
|
83
|
+
|
|
84
|
+
#: Proof methods tried in order, as a ``by (... | ...)`` battery. ``smt (verit)``
|
|
85
|
+
#: is tried first as a precaution, not a measured choice: house rules forbid
|
|
86
|
+
#: running ``isabelle build`` from this toolkit, so this ordering has not been
|
|
87
|
+
#: benchmarked. It mirrors ``isabelle_conditional.DEFAULT_METHODS``, whose
|
|
88
|
+
#: verit-first order *was* measured necessary there because ``blast`` diverges
|
|
89
|
+
#: on a goal that needs the sphere-nesting premise. ``ImpC`` here has an
|
|
90
|
+
#: analogous shape -- a case split on ``N x`` with a nested ``forall y z. R x y
|
|
91
|
+
#: z -> ...`` on one branch -- so the same defensive ordering is used rather
|
|
92
|
+
#: than assuming ``blast``-first is safe.
|
|
93
|
+
DEFAULT_METHODS: Tuple[str, ...] = ("smt (verit)", "blast", "force", "metis")
|
|
94
|
+
|
|
95
|
+
_PREAMBLE = r'''typedecl w \<comment> \<open>worlds\<close>
|
|
96
|
+
type_synonym tau = "w \<Rightarrow> bool"
|
|
97
|
+
|
|
98
|
+
consts N :: "w \<Rightarrow> bool" \<comment> \<open>N w: w is a NORMAL world\<close>
|
|
99
|
+
consts star :: "w \<Rightarrow> w" \<comment> \<open>the Routley star w |-> w*\<close>
|
|
100
|
+
consts R :: "w \<Rightarrow> w \<Rightarrow> w \<Rightarrow> bool" \<comment> \<open>the ternary relation R w x y\<close>
|
|
101
|
+
|
|
102
|
+
text \<open>The three well-formedness conditions RelevantModel.__post_init__ enforces
|
|
103
|
+
(semantics/relevant.py lines 121-145): N is nonempty, star is a total involution
|
|
104
|
+
on W (totality is free in HOL's total function type w => w, so only involution
|
|
105
|
+
is stated), and R is sourced only at NON-normal worlds. Bundled as a single
|
|
106
|
+
premise of the goal rather than baked into N/star/R by fiat, so nitpick builds
|
|
107
|
+
N/star/R itself and can certify a counter-model as genuine.\<close>
|
|
108
|
+
|
|
109
|
+
definition wellformed :: "bool" where
|
|
110
|
+
"wellformed \<equiv> (\<exists>x. N x) \<and> (\<forall>x. star (star x) = x)
|
|
111
|
+
\<and> (\<forall>x y z. R x y z \<longrightarrow> \<not> N x)"
|
|
112
|
+
|
|
113
|
+
definition NegC :: "tau \<Rightarrow> tau" where "NegC f \<equiv> \<lambda>x. \<not> f (star x)"
|
|
114
|
+
definition AndC :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "AndC f g \<equiv> \<lambda>x. f x \<and> g x"
|
|
115
|
+
definition OrC :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "OrC f g \<equiv> \<lambda>x. f x \<or> g x"
|
|
116
|
+
|
|
117
|
+
text \<open>A -> B at a NORMAL world w: every A-world of the WHOLE model is a B-world
|
|
118
|
+
(relevant.py _sat, the ``world in model.normal`` branch). At a NON-normal world:
|
|
119
|
+
for every R-triple R w x y, x |= A implies y |= B (the ``else`` branch).\<close>
|
|
120
|
+
|
|
121
|
+
definition ImpC :: "tau \<Rightarrow> tau \<Rightarrow> tau" where
|
|
122
|
+
"ImpC f g \<equiv> \<lambda>x.
|
|
123
|
+
(N x \<longrightarrow> (\<forall>y. f y \<longrightarrow> g y))
|
|
124
|
+
\<and> (\<not> N x \<longrightarrow> (\<forall>y z. R x y z \<longrightarrow> f y \<longrightarrow> g z))"
|
|
125
|
+
|
|
126
|
+
text \<open>A <-> B is (A -> B) /\ (B -> A) at the SAME world (relevant.py _sat's Iff
|
|
127
|
+
clause recurses on Implies(left,right)/Implies(right,left) -- not a primitive
|
|
128
|
+
biconditional clause), so IffC is built from ImpC/AndC rather than case-split
|
|
129
|
+
directly.\<close>
|
|
130
|
+
|
|
131
|
+
definition IffC :: "tau \<Rightarrow> tau \<Rightarrow> tau" where
|
|
132
|
+
"IffC f g \<equiv> AndC (ImpC f g) (ImpC g f)"
|
|
133
|
+
'''
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _encode(formula: Node, atoms: AtomConsts) -> str:
|
|
137
|
+
"""Recursive worker for :func:`to_isabelle_relevant`.
|
|
138
|
+
|
|
139
|
+
Mirrors :func:`unicode_logic_kit.semantics.relevant._reject_non_propositional`
|
|
140
|
+
exactly: only nullary :class:`Atom`\\ s and the connectives Not/And/Or/
|
|
141
|
+
Implies/Iff are accepted; everything else -- quantifiers, modalities, lambda
|
|
142
|
+
terms, ``Xor``, non-nullary atoms -- raises :class:`TypeError`, the same
|
|
143
|
+
exception type the oracle raises for the same inputs.
|
|
144
|
+
"""
|
|
145
|
+
if isinstance(formula, Atom):
|
|
146
|
+
refuse_truth_constants([formula], "to_isabelle_relevant", _NO_CONSTANT_WHY,
|
|
147
|
+
error=TypeError)
|
|
148
|
+
if formula.args:
|
|
149
|
+
raise TypeError(
|
|
150
|
+
"to_isabelle_relevant: only nullary propositional atoms are "
|
|
151
|
+
f"supported; got {formula.to_unicode_str()!r} with arguments -- "
|
|
152
|
+
"matching semantics.relevant._reject_non_propositional's "
|
|
153
|
+
"rejection of non-nullary atoms.")
|
|
154
|
+
return atoms.name(key_text(formula))
|
|
155
|
+
if isinstance(formula, And):
|
|
156
|
+
return f"(AndC {_encode(formula.left, atoms)} {_encode(formula.right, atoms)})"
|
|
157
|
+
if isinstance(formula, Or):
|
|
158
|
+
return f"(OrC {_encode(formula.left, atoms)} {_encode(formula.right, atoms)})"
|
|
159
|
+
if isinstance(formula, Not):
|
|
160
|
+
return f"(NegC {_encode(formula.formula, atoms)})"
|
|
161
|
+
if isinstance(formula, Implies):
|
|
162
|
+
return f"(ImpC {_encode(formula.left, atoms)} {_encode(formula.right, atoms)})"
|
|
163
|
+
if isinstance(formula, Iff):
|
|
164
|
+
return f"(IffC {_encode(formula.left, atoms)} {_encode(formula.right, atoms)})"
|
|
165
|
+
raise TypeError(
|
|
166
|
+
f"to_isabelle_relevant: unsupported node type {type(formula).__name__} "
|
|
167
|
+
f"in {formula.to_unicode_str()!r}. The B semantics "
|
|
168
|
+
"(semantics.relevant) interprets only the propositional connectives "
|
|
169
|
+
"not/and/or/implies/iff over nullary atoms -- no quantifiers, "
|
|
170
|
+
"modalities, lambda terms, or Xor; see "
|
|
171
|
+
"semantics.relevant._reject_non_propositional.")
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def battery_proof(methods: Sequence[str] = DEFAULT_METHODS) -> str:
|
|
175
|
+
"""An ``unfolding ...`` + ``by (m1 | m2 | ...)`` proof over the shallow definitions."""
|
|
176
|
+
if not methods:
|
|
177
|
+
raise ValueError("battery_proof: need at least one proof method.")
|
|
178
|
+
alts = " | ".join(methods)
|
|
179
|
+
return f" unfolding {' '.join(_DEFS)}\n by ({alts})"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def nitpick_proof(card: str = "1-3", timeout: int = 60) -> str:
|
|
183
|
+
"""A ``nitpick[expect = genuine]`` refutation attempt over the world type ``w``."""
|
|
184
|
+
return (f" nitpick[card w = {card}, timeout = {int(timeout)}, "
|
|
185
|
+
f"expect = genuine]\n oops")
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def to_isabelle_relevant(formula: Node, *,
|
|
189
|
+
theory_name: str = "RelDecide",
|
|
190
|
+
proof: Optional[str] = None,
|
|
191
|
+
lemma_name: str = "goal") -> str:
|
|
192
|
+
r"""Emit a self-contained theory asserting ``formula``'s validity in B.
|
|
193
|
+
|
|
194
|
+
The goal is ``wellformed \<Longrightarrow> \<forall>x. N x \<longrightarrow> phi x`` --
|
|
195
|
+
truth at every NORMAL world of every interpretation satisfying the frame
|
|
196
|
+
conditions bundled into ``wellformed`` (see the module docstring), matching
|
|
197
|
+
:func:`unicode_logic_kit.semantics.relevant.rel_valid`'s "true at every normal
|
|
198
|
+
world of every interpretation" contract. ``wellformed`` is a premise rather
|
|
199
|
+
than an axiom so that nitpick can build ``N``/``star``/``R`` itself and
|
|
200
|
+
certify a counter-model as genuine.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
formula: the AST node to decide -- the propositional connectives
|
|
204
|
+
``¬ ∧ ∨ → ↔`` over nullary atoms.
|
|
205
|
+
theory_name: the Isabelle theory identifier.
|
|
206
|
+
proof: the proof text under the lemma; defaults to :func:`battery_proof`.
|
|
207
|
+
Pass :func:`nitpick_proof` to emit the refutation theory instead.
|
|
208
|
+
lemma_name: the lemma identifier.
|
|
209
|
+
|
|
210
|
+
Raises:
|
|
211
|
+
ValueError: on an illegal theory name.
|
|
212
|
+
TypeError: propagated from :func:`_encode` -- a quantifier, modality,
|
|
213
|
+
lambda term, ``Xor``, or non-nullary atom, mirroring
|
|
214
|
+
:func:`unicode_logic_kit.semantics.relevant._reject_non_propositional`.
|
|
215
|
+
"""
|
|
216
|
+
if not theory_name_ok(theory_name):
|
|
217
|
+
raise ValueError(f"illegal theory name {theory_name!r}.")
|
|
218
|
+
atoms = AtomConsts()
|
|
219
|
+
term = _encode(formula, atoms)
|
|
220
|
+
body = [f"theory {theory_name}", " imports Main", "begin", "", _PREAMBLE]
|
|
221
|
+
decls = atoms.decls(_TAU)
|
|
222
|
+
if decls:
|
|
223
|
+
body.append("\n".join(decls))
|
|
224
|
+
body.append("")
|
|
225
|
+
body.append(
|
|
226
|
+
f'lemma {lemma_name}: "wellformed \\<Longrightarrow> '
|
|
227
|
+
f'\\<forall>x. N x \\<longrightarrow> ({term}) x"')
|
|
228
|
+
body.append(proof if proof is not None else battery_proof())
|
|
229
|
+
body.append("")
|
|
230
|
+
body.append("end")
|
|
231
|
+
return "\n".join(body) + "\n"
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# --------------------------------------------------------------------------
|
|
235
|
+
# THF
|
|
236
|
+
# --------------------------------------------------------------------------
|
|
237
|
+
#
|
|
238
|
+
# The THF sibling of the theory above: the same shallow embedding (a formula
|
|
239
|
+
# is true or false AT A WORLD; ``N``/``star``/``R`` uninterpreted; the frame
|
|
240
|
+
# conditions bundled into ``wellformed``), for a higher-order ATP (Leo-III,
|
|
241
|
+
# Vampire-THF, Satallax) instead of Isabelle. The conjecture is
|
|
242
|
+
# ``wellformed => ![X:w] : ((N @ X) => φ_at(X))``, matching the Isabelle goal's
|
|
243
|
+
# "true at every NORMAL world of every interpretation" contract exactly.
|
|
244
|
+
#
|
|
245
|
+
# UNLIKE the Isabelle encoding (and an earlier draft of this function), ``φ``
|
|
246
|
+
# is NOT built from separately-declared ``NegC``/``AndC``/``OrC``/``ImpC``/
|
|
247
|
+
# ``IffC`` *combinators* that :func:`_thf_encode` would apply to already-built
|
|
248
|
+
# ``tau``-typed subterms (``impc @ (andc @ p @ q) @ p``, mirroring the
|
|
249
|
+
# Isabelle term exactly). :func:`_thf_encode` instead THREADS the current
|
|
250
|
+
# world through the recursion and emits ``φ``, at that world, as one native
|
|
251
|
+
# THF formula (``&``/``|``/``~``/``=>``/``!``/``?`` applied to already-a-world
|
|
252
|
+
# atoms) -- the same "world-relativised connective, no free-standing
|
|
253
|
+
# constant" style :mod:`unicode_logic_kit.hol.ho_modal`'s box/diamond nesting
|
|
254
|
+
# uses. This is NOT a change of meaning: a combinator applied to arguments and
|
|
255
|
+
# the fully-inlined, world-threaded reading of the same formula are
|
|
256
|
+
# beta-equivalent term for term (only ``ImpC``'s two case-split branches are
|
|
257
|
+
# genuinely new content per node, and those are exactly the N/R clauses below,
|
|
258
|
+
# transcribed unchanged from ``_PREAMBLE``). It is a change of PROOF-SEARCH
|
|
259
|
+
# DIFFICULTY: measured by hand with a battery of THF micro-examples in the
|
|
260
|
+
# scratchpad, Vampire 5.0.1's default portfolio needs real higher-order
|
|
261
|
+
# UNIFICATION to match a combinator's parameter against another combinator's
|
|
262
|
+
# PARTIAL APPLICATION (``F := (andc @ p @ q)`` to unfold ``impc``'s body) and
|
|
263
|
+
# failed to close even ``(P∧Q)→P`` in 60s / a 150-strategy CASC sweep in 30s;
|
|
264
|
+
# feeding it the same formula already reduced to ordinary quantified
|
|
265
|
+
# first-order-shaped THF over ``w`` (no function-valued arguments passed
|
|
266
|
+
# between macros at all) closes in well under a second. ``wellformed`` stays a
|
|
267
|
+
# single named, ARGUMENT-FREE ``$o`` ``definition`` (unfolding a nullary
|
|
268
|
+
# biconditional needs no higher-order unification either way) and stays a
|
|
269
|
+
# PREMISE of the conjecture rather than an ``axiom``, for the reason given in
|
|
270
|
+
# the module docstring: a model finder run on this problem's negation should
|
|
271
|
+
# still be free to build its own N/star/R rather than trusting an axiomatised
|
|
272
|
+
# triple.
|
|
273
|
+
|
|
274
|
+
#: The embedding's own functors, pre-claimed so no user atom's THF stem can
|
|
275
|
+
#: collide with them (see hol._ho_common.ThfNames).
|
|
276
|
+
_THF_RESERVED = ("w", "n", "star", "r", "wellformed")
|
|
277
|
+
|
|
278
|
+
_THF_PRELUDE = [
|
|
279
|
+
"% Relevant logic B (simplified Routley-Meyer semantics) -> THF.",
|
|
280
|
+
"% Shallow embedding: a formula is true/false AT A WORLD; N/star/R are",
|
|
281
|
+
"% uninterpreted and their frame conditions are bundled into `wellformed`,",
|
|
282
|
+
"% a PREMISE of the conjecture (never an axiom) -- see isabelle_relevant.py's",
|
|
283
|
+
"% module docstring, _PREAMBLE, and the comment above _THF_PRELUDE for why",
|
|
284
|
+
"% the connectives below are inlined at each world rather than routed",
|
|
285
|
+
"% through separately-declared NegC/AndC/OrC/ImpC/IffC combinators.",
|
|
286
|
+
"thf(w_type, type, ( w : $tType )).",
|
|
287
|
+
"thf(n_type, type, ( n : w > $o )).",
|
|
288
|
+
"thf(star_type, type, ( star : w > w )).",
|
|
289
|
+
"thf(r_type, type, ( r : w > w > w > $o )).",
|
|
290
|
+
"thf(wellformed_type, type, ( wellformed : $o )).",
|
|
291
|
+
"thf(wellformed_def, definition, ( wellformed <=> "
|
|
292
|
+
"( ( ? [X: w] : ( n @ X ) ) "
|
|
293
|
+
"& ( ! [X: w] : ( ( star @ ( star @ X ) ) = X ) ) "
|
|
294
|
+
"& ( ! [X: w, Y: w, Z: w] : ( ( r @ X @ Y @ Z ) => ( ~ ( n @ X ) ) ) ) ) )).",
|
|
295
|
+
]
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _thf_implies_at(left: Node, right: Node, world: str,
|
|
299
|
+
names: ThfNames, depth: int) -> str:
|
|
300
|
+
"""The world-threaded rendering of ``left -> right`` at ``world``.
|
|
301
|
+
|
|
302
|
+
ImpC's own case split (:func:`_encode`'s ``ImpC`` clause, unchanged): at a
|
|
303
|
+
NORMAL world every ``left``-world of the WHOLE model is a ``right``-world;
|
|
304
|
+
at a non-normal world, every R-triple routes ``left`` to ``right``. ``Y``/
|
|
305
|
+
``Z`` are named from ``depth`` (not a running total) so that two SIBLING
|
|
306
|
+
``->`` nodes may freely reuse the same token -- each ``!`` binds only its
|
|
307
|
+
own subformula -- while a NESTED ``->`` (reached through ``left``/
|
|
308
|
+
``right``, always recursed at ``depth + 1``) never reuses an ancestor's.
|
|
309
|
+
|
|
310
|
+
This deliberately parallels :mod:`unicode_logic_kit.hol.ho_modal`'s OWN
|
|
311
|
+
Kripke-world binders (``f"W{depth}"`` in its ``_thf``/``_thf_arg``), not
|
|
312
|
+
:func:`~unicode_logic_kit.hol._ho_common.bound_token`: ``bound_token`` renames
|
|
313
|
+
a USER-level binder apart from other in-scope user binders of the SAME
|
|
314
|
+
source name (``thirdorder.py``/``ho_modal.py`` call it for the caller's own
|
|
315
|
+
``Quantifier``/``SecondOrderQuantifier``/``Lambda`` nodes), and no such node
|
|
316
|
+
ever reaches this encoder -- ``_thf_encode`` accepts only nullary atoms and
|
|
317
|
+
the propositional connectives, so there is no user binder to rename apart
|
|
318
|
+
from anything. ``Y{depth}``/``Z{depth}`` name this EMBEDDING's own frame
|
|
319
|
+
quantifiers instead, exactly the role ``ho_modal.py``'s plain ``W{depth}``
|
|
320
|
+
plays for its own world binders (see the comment above its ``_thf``).
|
|
321
|
+
"""
|
|
322
|
+
y, z = f"Y{depth}", f"Z{depth}"
|
|
323
|
+
left_at_y = _thf_encode(left, y, names, depth + 1)
|
|
324
|
+
right_at_y = _thf_encode(right, y, names, depth + 1)
|
|
325
|
+
right_at_z = _thf_encode(right, z, names, depth + 1)
|
|
326
|
+
return (f"( ( ( n @ {world} ) => ( ! [{y}: w] : "
|
|
327
|
+
f"( {left_at_y} => {right_at_y} ) ) ) "
|
|
328
|
+
f"& ( ( ~ ( n @ {world} ) ) => ( ! [{y}: w, {z}: w] : "
|
|
329
|
+
f"( ( r @ {world} @ {y} @ {z} ) => "
|
|
330
|
+
f"( {left_at_y} => {right_at_z} ) ) ) ) )")
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _thf_encode(formula: Node, world: str, names: ThfNames, depth: int = 0) -> str:
|
|
334
|
+
"""Recursive worker for :func:`to_thf_relevant`: ``formula`` rendered TRUE AT ``world``.
|
|
335
|
+
|
|
336
|
+
Structurally identical to :func:`_encode`'s own recursion -- only nullary
|
|
337
|
+
:class:`Atom`\\ s and Not/And/Or/Implies/Iff are accepted, everything else
|
|
338
|
+
raises :class:`TypeError`, the same refusal :func:`_encode` makes,
|
|
339
|
+
mirroring :func:`unicode_logic_kit.semantics.relevant._reject_non_propositional`
|
|
340
|
+
-- but threading ``world`` (a THF term, not a fixed variable: ``¬`` passes
|
|
341
|
+
down ``( star @ world )``) instead of building a free-standing ``tau``
|
|
342
|
+
term. See the comment above ``_THF_PRELUDE`` for why.
|
|
343
|
+
"""
|
|
344
|
+
if isinstance(formula, Atom):
|
|
345
|
+
refuse_truth_constants([formula], "to_thf_relevant", _NO_CONSTANT_WHY,
|
|
346
|
+
error=TypeError)
|
|
347
|
+
if formula.args:
|
|
348
|
+
raise TypeError(
|
|
349
|
+
"to_thf_relevant: only nullary propositional atoms are "
|
|
350
|
+
f"supported; got {formula.to_unicode_str()!r} with arguments -- "
|
|
351
|
+
"matching semantics.relevant._reject_non_propositional's "
|
|
352
|
+
"rejection of non-nullary atoms.")
|
|
353
|
+
functor = names.functor("predicate", key_text(formula))
|
|
354
|
+
return f"( {functor} @ {world} )"
|
|
355
|
+
if isinstance(formula, And):
|
|
356
|
+
return (f"( {_thf_encode(formula.left, world, names, depth)} & "
|
|
357
|
+
f"{_thf_encode(formula.right, world, names, depth)} )")
|
|
358
|
+
if isinstance(formula, Or):
|
|
359
|
+
return (f"( {_thf_encode(formula.left, world, names, depth)} | "
|
|
360
|
+
f"{_thf_encode(formula.right, world, names, depth)} )")
|
|
361
|
+
if isinstance(formula, Not):
|
|
362
|
+
return f"( ~ {_thf_encode(formula.formula, f'( star @ {world} )', names, depth)} )"
|
|
363
|
+
if isinstance(formula, Implies):
|
|
364
|
+
return _thf_implies_at(formula.left, formula.right, world, names, depth)
|
|
365
|
+
if isinstance(formula, Iff):
|
|
366
|
+
return (f"( {_thf_implies_at(formula.left, formula.right, world, names, depth)} "
|
|
367
|
+
f"& {_thf_implies_at(formula.right, formula.left, world, names, depth)} )")
|
|
368
|
+
raise TypeError(
|
|
369
|
+
f"to_thf_relevant: unsupported node type {type(formula).__name__} "
|
|
370
|
+
f"in {formula.to_unicode_str()!r}. The B semantics "
|
|
371
|
+
"(semantics.relevant) interprets only the propositional connectives "
|
|
372
|
+
"not/and/or/implies/iff over nullary atoms -- no quantifiers, "
|
|
373
|
+
"modalities, lambda terms, or Xor; see "
|
|
374
|
+
"semantics.relevant._reject_non_propositional.")
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def to_thf_relevant(formula: Node) -> str:
|
|
378
|
+
r"""Emit a self-contained THF (TH0) problem asserting ``formula``'s validity in B.
|
|
379
|
+
|
|
380
|
+
The THF sibling of :func:`to_isabelle_relevant`: the same shallow embedding
|
|
381
|
+
(a formula is true/false at a world; ``N``/``star``/``R`` uninterpreted;
|
|
382
|
+
the frame conditions bundled into ``wellformed``), for a higher-order ATP
|
|
383
|
+
(Leo-III, Vampire-THF, Satallax) instead of Isabelle. The conjecture is
|
|
384
|
+
``wellformed => ![X:w] : ((N @ X) => φ_at(X))`` -- truth at every NORMAL
|
|
385
|
+
world of every interpretation satisfying the frame conditions, matching
|
|
386
|
+
:func:`unicode_logic_kit.semantics.relevant.rel_valid`'s "true at every
|
|
387
|
+
normal world of every interpretation" contract, exactly as
|
|
388
|
+
:func:`to_isabelle_relevant`'s goal does (see the comment above
|
|
389
|
+
``_THF_PRELUDE`` for why ``φ_at(X)`` is rendered inline rather than as a
|
|
390
|
+
combinator applied to ``X``). As elsewhere in the toolkit, this function
|
|
391
|
+
only emits the problem; it does not run a prover.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
formula: the AST node to encode -- the propositional connectives
|
|
395
|
+
``¬ ∧ ∨ → ↔`` over nullary atoms.
|
|
396
|
+
|
|
397
|
+
Raises:
|
|
398
|
+
TypeError: propagated from :func:`_thf_encode` -- a quantifier,
|
|
399
|
+
modality, lambda term, ``Xor``, or non-nullary atom, mirroring
|
|
400
|
+
:func:`to_isabelle_relevant`'s own refusal and
|
|
401
|
+
:func:`unicode_logic_kit.semantics.relevant._reject_non_propositional`.
|
|
402
|
+
"""
|
|
403
|
+
names = ThfNames(reserved=_THF_RESERVED)
|
|
404
|
+
body = _thf_encode(formula, "X", names)
|
|
405
|
+
lines = list(_THF_PRELUDE)
|
|
406
|
+
for label in sorted({key_text(atom) for atom in formula.atoms()}):
|
|
407
|
+
functor = names.functor("predicate", label)
|
|
408
|
+
lines.append(f"thf({functor}_type, type, ( {functor} : w > $o )).")
|
|
409
|
+
lines.append(
|
|
410
|
+
"thf(goal, conjecture, ( wellformed => "
|
|
411
|
+
f"( ! [X: w] : ( ( n @ X ) => {body} ) ) )).")
|
|
412
|
+
return "\n".join(lines) + "\n"
|