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,287 @@
|
|
|
1
|
+
"""Public Announcement Logic (PAL): syntactic reduction of announcements.
|
|
2
|
+
|
|
3
|
+
Public announcement logic extends static modal logic with an update operator: a
|
|
4
|
+
truthful public announcement of ``φ`` deletes every world where ``φ`` is false, and
|
|
5
|
+
``[φ!]ψ`` / ``⟨φ!⟩ψ`` (see :mod:`unicode_logic_kit.fol._modal_nodes`, classes
|
|
6
|
+
:class:`~unicode_logic_kit.fol._modal_nodes.Announce` /
|
|
7
|
+
:class:`~unicode_logic_kit.fol._modal_nodes.AnnounceDiamond`) say what holds *after*
|
|
8
|
+
that update. :func:`reduce_announcements` implements the standard PAL result that
|
|
9
|
+
every announcement is ELIMINABLE: PAL over the propositional-modal fragment
|
|
10
|
+
interpreted here is exactly as expressive as the announcement-free base logic, via
|
|
11
|
+
the reduction axioms below.
|
|
12
|
+
|
|
13
|
+
Public API: :func:`reduce_announcements`.
|
|
14
|
+
|
|
15
|
+
CORRECTNESS ARGUMENT
|
|
16
|
+
=====================
|
|
17
|
+
|
|
18
|
+
The whole reduction rests on one invariant, proved by induction on ψ:
|
|
19
|
+
|
|
20
|
+
(INV) M, w ⊨ ψ^φ IFF M|φ, w ⊨ ψ (for every w with M, w ⊨ φ)
|
|
21
|
+
|
|
22
|
+
— "ψ RELATIVIZED to φ, evaluated in the ORIGINAL model M, agrees with ψ evaluated
|
|
23
|
+
in the φ-RESTRICTED model M|φ" (:func:`unicode_logic_kit.semantics.dynamic_epistemic.announce`
|
|
24
|
+
builds M|φ: the submodel on the worlds satisfying φ, with every relation and the
|
|
25
|
+
valuation cut down to survivors). Given (INV), the announcement operators reduce
|
|
26
|
+
immediately from their own truth conditions
|
|
27
|
+
(:func:`unicode_logic_kit.semantics.kripke.satisfies_modal`'s Announce/AnnounceDiamond
|
|
28
|
+
cases, restated in :mod:`unicode_logic_kit.semantics.dynamic_epistemic`'s module
|
|
29
|
+
docstring)::
|
|
30
|
+
|
|
31
|
+
M, w ⊨ [φ!]ψ iff M,w⊨φ implies M|φ,w⊨ψ iff (INV) M,w⊨φ implies M,w⊨ψ^φ
|
|
32
|
+
iff M, w ⊨ (φ → ψ^φ)
|
|
33
|
+
|
|
34
|
+
M, w ⊨ ⟨φ!⟩ψ iff M,w⊨φ and M|φ,w⊨ψ iff (INV) M,w⊨φ and M,w⊨ψ^φ
|
|
35
|
+
iff M, w ⊨ (φ ∧ ψ^φ)
|
|
36
|
+
|
|
37
|
+
which are exactly the two clauses :func:`reduce_announcements` applies to a
|
|
38
|
+
top-level Announce/AnnounceDiamond node (with the inner announcement-free ψ, φ
|
|
39
|
+
already produced by pre-reducing everything below them — "innermost first").
|
|
40
|
+
|
|
41
|
+
Proof of (INV), by structural induction on ψ (each case implements the matching
|
|
42
|
+
standard PAL reduction axiom):
|
|
43
|
+
|
|
44
|
+
* ``ψ = p`` (atom): p^φ = p. p's truth value only depends on the valuation at w,
|
|
45
|
+
which M|φ COPIES verbatim from M for every survivor w — so M,w⊨p iff M|φ,w⊨p.
|
|
46
|
+
* ``ψ = ¬χ``, ``χ₁∘χ₂`` (∘ ∈ {∧,∨,→,↔,⊕}): the classical connectives commute with
|
|
47
|
+
restriction (M|φ's valuation at w is M's, unchanged) and with the induction
|
|
48
|
+
hypothesis applied to χ / χ₁ / χ₂ at the SAME world w, which — because w ⊨ φ
|
|
49
|
+
throughout this induction — is still a world of M|φ. So the classical clauses
|
|
50
|
+
relativize by simply relativizing their immediate subformulas: (¬χ)^φ=¬χ^φ,
|
|
51
|
+
(χ₁∘χ₂)^φ = χ₁^φ ∘ χ₂^φ.
|
|
52
|
+
* ``ψ = K_a χ`` (and identically B_a / Say_a / Want_a / □ / Ⓞ, every UNIVERSAL —
|
|
53
|
+
"box" — modality): M|φ,w ⊨ K_a χ iff χ holds at every "K:a"-successor of w that
|
|
54
|
+
SURVIVED the restriction (M|φ only keeps edges between survivors) — i.e. at
|
|
55
|
+
every successor v of w in M with v⊨φ. By the induction hypothesis (applicable
|
|
56
|
+
at each such v, since v⊨φ), that is M,v⊨χ^φ. So the whole condition is: for
|
|
57
|
+
every M-successor v of w, v⊨φ implies M,v⊨χ^φ — i.e. M,w ⊨ K_a(φ → χ^φ). Hence
|
|
58
|
+
(K_aχ)^φ = K_a(φ → χ^φ) (identically for B_a, Say_a, Want_a, □, Ⓞ, each over its
|
|
59
|
+
own relation).
|
|
60
|
+
* ``ψ = ◇χ`` (and identically Ⓟ, every EXISTENTIAL — "diamond" — modality): dual
|
|
61
|
+
reasoning — M|φ,w ⊨ ◇χ iff SOME surviving successor v (so v⊨φ) has M|φ,v⊨χ, iff
|
|
62
|
+
(by the induction hypothesis) M,v⊨χ^φ — i.e. some M-successor v has v⊨φ AND
|
|
63
|
+
M,v⊨χ^φ, i.e. M,w ⊨ ◇(φ ∧ χ^φ). Hence (◇χ)^φ = ◇(φ ∧ χ^φ) (identically Ⓟ).
|
|
64
|
+
* ``ψ = [χ!]ω`` (a NESTED announcement): reduced FIRST, entirely on its own —
|
|
65
|
+
``([χ!]ω)^φ`` is defined as ``ρ^φ`` where ``ρ = reduce_announcements([χ!]ω)`` is
|
|
66
|
+
the (announcement-free) result of reducing the inner announcement by itself.
|
|
67
|
+
This is sound because reduce_announcements is truth-preserving in M (it is
|
|
68
|
+
exactly this same theorem, applied one level down: M,v⊨[χ!]ω iff M,v⊨ρ, at
|
|
69
|
+
every world v, by structural induction on the announcement itself) — so
|
|
70
|
+
substituting ρ for [χ!]ω anywhere and THEN relativizing by φ computes the same
|
|
71
|
+
(INV) as relativizing [χ!]ω directly would, if the latter were defined. This
|
|
72
|
+
is the "innermost-first" rule: :func:`reduce_announcements` eliminates deeper
|
|
73
|
+
announcements before an enclosing one is relativized, so RELATIVIZE (the
|
|
74
|
+
induction above) is only ever asked to handle an announcement-free ψ.
|
|
75
|
+
|
|
76
|
+
Where the induction BREAKS — REJECTED, not silently mishandled:
|
|
77
|
+
|
|
78
|
+
* Temporal closure / one-step operators (Ⓖ Ⓕ Ⓝ Ⓤ ⒣ ⒫ ⒴ ⒮): the induction step for
|
|
79
|
+
a box/diamond modality above crucially used that M|φ's accessibility relation is
|
|
80
|
+
M's relation RESTRICTED to survivors — a ONE-STEP fact. Always/Eventually/Until
|
|
81
|
+
(and their past duals) quantify over the REFLEXIVE-TRANSITIVE CLOSURE of the
|
|
82
|
+
one-step relation; the closure of the RESTRICTED relation is in general a
|
|
83
|
+
STRICT SUBSET of the RESTRICTION of the closure (a path through M can visit a
|
|
84
|
+
¬φ-world and come back to φ-worlds; M|φ has no such path, since it never
|
|
85
|
+
contains the ¬φ-world at all, but M's closure "sees past" it) — "restriction of
|
|
86
|
+
a closure relation is not the closure of the restriction". So no box/diamond-style
|
|
87
|
+
axiom is sound for these operators under an announcement, including the
|
|
88
|
+
one-step Next: this module rejects it too, deliberately more conservative than
|
|
89
|
+
a operator-by-operator soundness argument might require, rather than risk
|
|
90
|
+
publishing an axiom that has not been verified.
|
|
91
|
+
* Would / Might (Lewis counterfactuals): interpreted over a similarity ordering
|
|
92
|
+
of worlds (Lewis spheres), not an accessibility relation — restriction has no
|
|
93
|
+
defined action on a sphere system in this codebase, so relativizing them is
|
|
94
|
+
undefined, not merely unproven.
|
|
95
|
+
* Nominal / At (hybrid H(@)): a nominal names EXACTLY ONE world; announcement
|
|
96
|
+
restriction can delete that very world (if it fails φ), after which the
|
|
97
|
+
nominal names nothing — undefined, not merely unproven.
|
|
98
|
+
* Quantifier / SortedQuantifier (first-order): :func:`satisfies_modal` interprets
|
|
99
|
+
these ACTUALISTICALLY over a per-world domain ``D_w``; :func:`announce`'s model
|
|
100
|
+
restriction never updates ``domains``, so relativizing a quantifier would be
|
|
101
|
+
reasoning about domains the restriction does not touch — out of scope here
|
|
102
|
+
(the propositional/ground modal fragment this reduction targets never needs
|
|
103
|
+
one anyway).
|
|
104
|
+
|
|
105
|
+
Any of the above found ANYWHERE inside the ψ (or φ) being relativized — however
|
|
106
|
+
deeply buried — raises :class:`NotImplementedError` identifying which family and
|
|
107
|
+
pointing at :func:`unicode_logic_kit.semantics.dynamic_epistemic.announce` /
|
|
108
|
+
:func:`unicode_logic_kit.semantics.kripke.satisfies_modal` for direct, MODEL-level
|
|
109
|
+
(rather than syntactic) evaluation, which handles Announce/AnnounceDiamond
|
|
110
|
+
directly and has no such restriction.
|
|
111
|
+
|
|
112
|
+
EXPORTS: :func:`reduce_announcements` is the sanctioned route from a PAL formula to
|
|
113
|
+
every classical modal back-end. Since Announce/AnnounceDiamond nodes themselves
|
|
114
|
+
reject to_z3/to_prover9/to_tptp (and the Isabelle/THF/Isabelle-Isabelle embeddings
|
|
115
|
+
in :mod:`unicode_logic_kit.hol.isabelle_modal` / :mod:`unicode_logic_kit.hol.thf_modal`
|
|
116
|
+
have no case for them either, so they raise the same generic "unsupported node
|
|
117
|
+
type" error every other out-of-scope construct does), a PAL formula bound for any
|
|
118
|
+
of those back-ends — or for :mod:`unicode_logic_kit.atp.modal_tableau` (which applies
|
|
119
|
+
this reduction itself, as a pre-pass, on every public entry point) — MUST be
|
|
120
|
+
reduced first: ``to_isabelle_modal(reduce_announcements(formula))``, etc.
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
from .nodes import (
|
|
124
|
+
Node,
|
|
125
|
+
Atom, Not, And, Or, Xor, Implies, Iff,
|
|
126
|
+
Box, Diamond, Knows, Believes, Says, Wants,
|
|
127
|
+
Always, Eventually, Next, Until,
|
|
128
|
+
Historically, Once, Previous, Since,
|
|
129
|
+
Obligatory, Permitted,
|
|
130
|
+
Would, Might,
|
|
131
|
+
Nominal, At,
|
|
132
|
+
Quantifier, SortedQuantifier,
|
|
133
|
+
)
|
|
134
|
+
from ._modal_nodes import Announce, AnnounceDiamond
|
|
135
|
+
|
|
136
|
+
__all__ = ["reduce_announcements"]
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# Node types with no sound relativization rule (see the module docstring's
|
|
140
|
+
# "Where the induction BREAKS" section) — grouped by WHY, so the raised message
|
|
141
|
+
# names the exact reason rather than a generic "unsupported".
|
|
142
|
+
_TEMPORAL_UNDER_ANNOUNCEMENT = (Always, Eventually, Next, Until,
|
|
143
|
+
Historically, Once, Previous, Since)
|
|
144
|
+
_TEMPORAL_MSG = (
|
|
145
|
+
"pal.reduce_announcements: {name} (a temporal operator) cannot be "
|
|
146
|
+
"relativized under an announcement: Always/Eventually/Until (and their past "
|
|
147
|
+
"duals Historically/Once/Since, and the one-step Next) quantify over the "
|
|
148
|
+
"REFLEXIVE-TRANSITIVE CLOSURE of the one-step temporal relation, and "
|
|
149
|
+
"restriction of a CLOSURE relation is not the closure of the restriction — "
|
|
150
|
+
"the box/diamond reduction axiom this module uses for K_a/B_a/□/Ⓞ/◇/Ⓟ is "
|
|
151
|
+
"UNSOUND here. Evaluate the announcement directly instead: "
|
|
152
|
+
"unicode_logic_kit.semantics.kripke.satisfies_modal (which interprets "
|
|
153
|
+
"Announce/AnnounceDiamond via the restricted-model semantics of "
|
|
154
|
+
"unicode_logic_kit.semantics.dynamic_epistemic.announce) has no such "
|
|
155
|
+
"restriction."
|
|
156
|
+
)
|
|
157
|
+
_COUNTERFACTUAL_MSG = (
|
|
158
|
+
"pal.reduce_announcements: {name} (a Lewis counterfactual, □→/◇→) cannot be "
|
|
159
|
+
"relativized under an announcement: it is evaluated over a similarity "
|
|
160
|
+
"ordering of worlds (Lewis spheres), not an accessibility relation, and "
|
|
161
|
+
"announcement restriction has no defined action on a sphere system in this "
|
|
162
|
+
"codebase. Evaluate the announcement directly with "
|
|
163
|
+
"unicode_logic_kit.semantics.kripke.satisfies_modal instead."
|
|
164
|
+
)
|
|
165
|
+
_HYBRID_MSG = (
|
|
166
|
+
"pal.reduce_announcements: {name} (a hybrid-logic construct, a nominal or "
|
|
167
|
+
"@) cannot be relativized under an announcement: a nominal names EXACTLY "
|
|
168
|
+
"ONE world, and announcement restriction can delete that very world (if it "
|
|
169
|
+
"fails the announcement), after which the nominal would name nothing. "
|
|
170
|
+
"Evaluate the announcement directly with "
|
|
171
|
+
"unicode_logic_kit.semantics.kripke.satisfies_modal instead."
|
|
172
|
+
)
|
|
173
|
+
_QUANTIFIER_MSG = (
|
|
174
|
+
"pal.reduce_announcements: {name} (a first-order quantifier) cannot be "
|
|
175
|
+
"relativized under an announcement: satisfies_modal interprets object "
|
|
176
|
+
"quantifiers actualistically over a per-world domain D_w, and "
|
|
177
|
+
"dynamic_epistemic.announce's model restriction never updates the domains "
|
|
178
|
+
"map, so there is no sound reduction axiom for a quantifier here. Evaluate "
|
|
179
|
+
"the announcement directly with unicode_logic_kit.semantics.kripke.satisfies_modal "
|
|
180
|
+
"instead (with domains= set on the KripkeModel)."
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _relativize(psi: Node, phi: Node) -> Node:
|
|
185
|
+
"""Compute ψ^φ (ψ relativized to the announced φ) — see the module docstring's
|
|
186
|
+
CORRECTNESS ARGUMENT for the invariant this implements and its proof.
|
|
187
|
+
|
|
188
|
+
Precondition: ψ is already announcement-free (the caller pre-reduces every
|
|
189
|
+
nested Announce/AnnounceDiamond bottom-up before relativizing), and φ is
|
|
190
|
+
likewise announcement-free.
|
|
191
|
+
"""
|
|
192
|
+
if isinstance(psi, Atom):
|
|
193
|
+
return psi
|
|
194
|
+
if isinstance(psi, Not):
|
|
195
|
+
return Not(_relativize(psi.formula, phi))
|
|
196
|
+
if isinstance(psi, And):
|
|
197
|
+
return And(_relativize(psi.left, phi), _relativize(psi.right, phi))
|
|
198
|
+
if isinstance(psi, Or):
|
|
199
|
+
return Or(_relativize(psi.left, phi), _relativize(psi.right, phi))
|
|
200
|
+
if isinstance(psi, Xor):
|
|
201
|
+
return Xor(_relativize(psi.left, phi), _relativize(psi.right, phi))
|
|
202
|
+
if isinstance(psi, Implies):
|
|
203
|
+
return Implies(_relativize(psi.left, phi), _relativize(psi.right, phi))
|
|
204
|
+
if isinstance(psi, Iff):
|
|
205
|
+
return Iff(_relativize(psi.left, phi), _relativize(psi.right, phi))
|
|
206
|
+
|
|
207
|
+
# --- box-wise (universal) modalities: (Xψ)^φ = X(φ → ψ^φ) ---
|
|
208
|
+
if isinstance(psi, Knows):
|
|
209
|
+
return Knows(psi.agent, Implies(phi, _relativize(psi.formula, phi)))
|
|
210
|
+
if isinstance(psi, Believes):
|
|
211
|
+
return Believes(psi.agent, Implies(phi, _relativize(psi.formula, phi)))
|
|
212
|
+
if isinstance(psi, Says):
|
|
213
|
+
return Says(psi.agent, Implies(phi, _relativize(psi.formula, phi)))
|
|
214
|
+
if isinstance(psi, Wants):
|
|
215
|
+
return Wants(psi.agent, Implies(phi, _relativize(psi.formula, phi)))
|
|
216
|
+
if isinstance(psi, Box):
|
|
217
|
+
return Box(Implies(phi, _relativize(psi.formula, phi)))
|
|
218
|
+
if isinstance(psi, Obligatory):
|
|
219
|
+
return Obligatory(Implies(phi, _relativize(psi.formula, phi)))
|
|
220
|
+
|
|
221
|
+
# --- diamond-wise (existential) modalities: (Xψ)^φ = X(φ ∧ ψ^φ) ---
|
|
222
|
+
if isinstance(psi, Diamond):
|
|
223
|
+
return Diamond(And(phi, _relativize(psi.formula, phi)))
|
|
224
|
+
if isinstance(psi, Permitted):
|
|
225
|
+
return Permitted(And(phi, _relativize(psi.formula, phi)))
|
|
226
|
+
|
|
227
|
+
# --- nested announcement: eliminate it FIRST (on its own), THEN relativize
|
|
228
|
+
# the announcement-free result — "innermost first" (module docstring). Only
|
|
229
|
+
# reachable if a caller invokes _relativize directly on un-pre-reduced input;
|
|
230
|
+
# reduce_announcements itself always pre-reduces, so this never fires there.
|
|
231
|
+
if isinstance(psi, (Announce, AnnounceDiamond)):
|
|
232
|
+
return _relativize(reduce_announcements(psi), phi)
|
|
233
|
+
|
|
234
|
+
# --- no sound rule: reject with a precise, family-specific explanation ---
|
|
235
|
+
if isinstance(psi, _TEMPORAL_UNDER_ANNOUNCEMENT):
|
|
236
|
+
raise NotImplementedError(_TEMPORAL_MSG.format(name=type(psi).__name__))
|
|
237
|
+
if isinstance(psi, (Would, Might)):
|
|
238
|
+
raise NotImplementedError(_COUNTERFACTUAL_MSG.format(name=type(psi).__name__))
|
|
239
|
+
if isinstance(psi, (Nominal, At)):
|
|
240
|
+
raise NotImplementedError(_HYBRID_MSG.format(name=type(psi).__name__))
|
|
241
|
+
if isinstance(psi, (Quantifier, SortedQuantifier)):
|
|
242
|
+
raise NotImplementedError(_QUANTIFIER_MSG.format(name=type(psi).__name__))
|
|
243
|
+
|
|
244
|
+
raise NotImplementedError(
|
|
245
|
+
f"pal.reduce_announcements: no relativization rule for "
|
|
246
|
+
f"{type(psi).__name__} under an announcement.")
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _reduce(node: Node) -> Node:
|
|
250
|
+
"""Bottom-up worker for :func:`reduce_announcements`: reduce every child
|
|
251
|
+
first (innermost first), then eliminate a top-level Announce/AnnounceDiamond.
|
|
252
|
+
"""
|
|
253
|
+
if isinstance(node, (Announce, AnnounceDiamond)):
|
|
254
|
+
phi = _reduce(node.announcement)
|
|
255
|
+
psi = _reduce(node.formula)
|
|
256
|
+
relativized = _relativize(psi, phi)
|
|
257
|
+
if isinstance(node, Announce):
|
|
258
|
+
return Implies(phi, relativized)
|
|
259
|
+
return And(phi, relativized)
|
|
260
|
+
# Not an announcement: recurse structurally into every Node-valued field
|
|
261
|
+
# (Node.map_children — the generic engine every other structural pass in
|
|
262
|
+
# this codebase uses), so an announcement buried under ANY other
|
|
263
|
+
# construct (∧, K_a, Ⓖ, ∀x, …) is still found and eliminated, as long as
|
|
264
|
+
# it does not itself end up inside a relativization that rejects it.
|
|
265
|
+
return node.map_children(_reduce)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def reduce_announcements(formula: Node) -> Node:
|
|
269
|
+
"""Eliminate every :class:`Announce` / :class:`AnnounceDiamond` in ``formula``,
|
|
270
|
+
returning an equivalent announcement-free modal formula.
|
|
271
|
+
|
|
272
|
+
Applies the standard PAL reduction axioms — ``[φ!]ψ ≡ φ → ψ^φ`` and
|
|
273
|
+
``⟨φ!⟩ψ ≡ φ ∧ ψ^φ`` — bottom-up, so a NESTED announcement (whether inside the
|
|
274
|
+
announcement or the post-condition of an outer one) is reduced before the
|
|
275
|
+
outer one is relativized. See the module docstring for the full correctness
|
|
276
|
+
argument (the relativization invariant ``M,w⊨ψ^φ iff M|φ,w⊨ψ`` and its proof)
|
|
277
|
+
and for exactly which constructs raise :class:`NotImplementedError` when they
|
|
278
|
+
occur under an announcement's scope (temporal closure/one-step operators,
|
|
279
|
+
Lewis counterfactuals, hybrid nominals/@, and first-order quantifiers) —
|
|
280
|
+
always because the reduction is UNSOUND or UNDEFINED there, never silently
|
|
281
|
+
approximated.
|
|
282
|
+
|
|
283
|
+
A formula with no announcement anywhere is returned as a structurally equal
|
|
284
|
+
(but freshly rebuilt) copy — a safe no-op pass. Idempotent: reducing an
|
|
285
|
+
already announcement-free formula returns an equal formula unchanged.
|
|
286
|
+
"""
|
|
287
|
+
return _reduce(formula)
|