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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. unicode_logic_kit/__init__.py +385 -0
  2. unicode_logic_kit/__main__.py +520 -0
  3. unicode_logic_kit/_deadline.py +219 -0
  4. unicode_logic_kit/ace/__init__.py +126 -0
  5. unicode_logic_kit/ace/_align.py +135 -0
  6. unicode_logic_kit/ace/chem_lexicon.py +128 -0
  7. unicode_logic_kit/ace/drs_reader.py +570 -0
  8. unicode_logic_kit/ace/mapping.py +666 -0
  9. unicode_logic_kit/ace/reverse_modal.py +138 -0
  10. unicode_logic_kit/ace/runner.py +551 -0
  11. unicode_logic_kit/ace/translate.py +452 -0
  12. unicode_logic_kit/ace/verbalize.py +1070 -0
  13. unicode_logic_kit/api.py +1284 -0
  14. unicode_logic_kit/atp/__init__.py +177 -0
  15. unicode_logic_kit/atp/_ascii_names.py +113 -0
  16. unicode_logic_kit/atp/_html.py +72 -0
  17. unicode_logic_kit/atp/_substructural_input.py +228 -0
  18. unicode_logic_kit/atp/_tff_problem.py +715 -0
  19. unicode_logic_kit/atp/_tptp_problem.py +1111 -0
  20. unicode_logic_kit/atp/_writer_support.py +289 -0
  21. unicode_logic_kit/atp/clingo_backend.py +1180 -0
  22. unicode_logic_kit/atp/cvc5_backend.py +1385 -0
  23. unicode_logic_kit/atp/eprover_backend.py +732 -0
  24. unicode_logic_kit/atp/finite_domain.py +1055 -0
  25. unicode_logic_kit/atp/fitch.py +1547 -0
  26. unicode_logic_kit/atp/fitch_search.py +551 -0
  27. unicode_logic_kit/atp/hets_backend.py +339 -0
  28. unicode_logic_kit/atp/hybrid_down.py +120 -0
  29. unicode_logic_kit/atp/incremental.py +250 -0
  30. unicode_logic_kit/atp/kripke_enum.py +741 -0
  31. unicode_logic_kit/atp/lambek.py +436 -0
  32. unicode_logic_kit/atp/leo3_backend.py +332 -0
  33. unicode_logic_kit/atp/linear.py +738 -0
  34. unicode_logic_kit/atp/lj.py +705 -0
  35. unicode_logic_kit/atp/logic_backends.py +566 -0
  36. unicode_logic_kit/atp/ltl_tableau.py +1084 -0
  37. unicode_logic_kit/atp/minizinc_backend.py +1402 -0
  38. unicode_logic_kit/atp/modal_tableau.py +1382 -0
  39. unicode_logic_kit/atp/nanocop_backend.py +410 -0
  40. unicode_logic_kit/atp/portfolio.py +489 -0
  41. unicode_logic_kit/atp/protocol.py +1803 -0
  42. unicode_logic_kit/atp/prover9_entailment.py +1153 -0
  43. unicode_logic_kit/atp/resolution.py +1376 -0
  44. unicode_logic_kit/atp/resolution_check.py +1114 -0
  45. unicode_logic_kit/atp/sequent.py +1050 -0
  46. unicode_logic_kit/atp/tableau.py +921 -0
  47. unicode_logic_kit/atp/tableau_check.py +543 -0
  48. unicode_logic_kit/atp/tptp_ncl.py +811 -0
  49. unicode_logic_kit/atp/tptp_tff.py +1546 -0
  50. unicode_logic_kit/atp/tstp.py +1333 -0
  51. unicode_logic_kit/atp/tstp_check.py +1096 -0
  52. unicode_logic_kit/atp/twee_backend.py +236 -0
  53. unicode_logic_kit/atp/twee_check.py +711 -0
  54. unicode_logic_kit/atp/twee_entailment.py +953 -0
  55. unicode_logic_kit/atp/vampire_entailment.py +540 -0
  56. unicode_logic_kit/atp/z3_arith.py +470 -0
  57. unicode_logic_kit/atp/z3_equivalence.py +36 -0
  58. unicode_logic_kit/atp/z3_fuzzy.py +362 -0
  59. unicode_logic_kit/atp/z3_input.py +500 -0
  60. unicode_logic_kit/atp/z3_models.py +208 -0
  61. unicode_logic_kit/chem/__init__.py +88 -0
  62. unicode_logic_kit/chem/_naming.py +284 -0
  63. unicode_logic_kit/chem/cache.py +185 -0
  64. unicode_logic_kit/chem/interop.py +244 -0
  65. unicode_logic_kit/chem/mol.py +525 -0
  66. unicode_logic_kit/chem/signature.py +112 -0
  67. unicode_logic_kit/comorphism.py +497 -0
  68. unicode_logic_kit/dl/__init__.py +384 -0
  69. unicode_logic_kit/dl/classification.py +227 -0
  70. unicode_logic_kit/dl/concepts.py +632 -0
  71. unicode_logic_kit/dl/datatypes.py +818 -0
  72. unicode_logic_kit/dl/owl_functional.py +2433 -0
  73. unicode_logic_kit/dl/owl_manchester.py +1637 -0
  74. unicode_logic_kit/dl/owl_reasoner.py +790 -0
  75. unicode_logic_kit/dl/parser.py +391 -0
  76. unicode_logic_kit/dl/tableau.py +4048 -0
  77. unicode_logic_kit/dl/translate.py +2704 -0
  78. unicode_logic_kit/drt/__init__.py +94 -0
  79. unicode_logic_kit/drt/export.py +179 -0
  80. unicode_logic_kit/drt/nodes.py +506 -0
  81. unicode_logic_kit/drt/parser.py +965 -0
  82. unicode_logic_kit/drt/resolve.py +195 -0
  83. unicode_logic_kit/drt/reverse.py +175 -0
  84. unicode_logic_kit/eval/__init__.py +106 -0
  85. unicode_logic_kit/eval/batch.py +382 -0
  86. unicode_logic_kit/eval/canonical.py +663 -0
  87. unicode_logic_kit/eval/chem_batch.py +606 -0
  88. unicode_logic_kit/eval/converses.py +200 -0
  89. unicode_logic_kit/eval/datasets/__init__.py +136 -0
  90. unicode_logic_kit/eval/datasets/_base.py +263 -0
  91. unicode_logic_kit/eval/datasets/_proofwriter_proof.py +422 -0
  92. unicode_logic_kit/eval/datasets/c3po.py +678 -0
  93. unicode_logic_kit/eval/datasets/folio.py +158 -0
  94. unicode_logic_kit/eval/datasets/fracas.py +418 -0
  95. unicode_logic_kit/eval/datasets/groves.py +191 -0
  96. unicode_logic_kit/eval/datasets/logicbench.py +467 -0
  97. unicode_logic_kit/eval/datasets/logicnli.py +303 -0
  98. unicode_logic_kit/eval/datasets/malls.py +133 -0
  99. unicode_logic_kit/eval/datasets/pfolio.py +594 -0
  100. unicode_logic_kit/eval/datasets/pmb.py +242 -0
  101. unicode_logic_kit/eval/datasets/prontoqa.py +611 -0
  102. unicode_logic_kit/eval/datasets/proofwriter.py +1431 -0
  103. unicode_logic_kit/eval/datasets/proverqa.py +674 -0
  104. unicode_logic_kit/eval/datasets/willow.py +478 -0
  105. unicode_logic_kit/eval/equivalence.py +466 -0
  106. unicode_logic_kit/eval/exercise_gen.py +533 -0
  107. unicode_logic_kit/eval/explain.py +791 -0
  108. unicode_logic_kit/eval/generality.py +750 -0
  109. unicode_logic_kit/eval/metric_hf.py +458 -0
  110. unicode_logic_kit/eval/predicate_match.py +343 -0
  111. unicode_logic_kit/eval/theory_check.py +1170 -0
  112. unicode_logic_kit/eval/validate.py +306 -0
  113. unicode_logic_kit/fol/__init__.py +177 -0
  114. unicode_logic_kit/fol/_atom_keys.py +510 -0
  115. unicode_logic_kit/fol/_fol_nodes.py +3586 -0
  116. unicode_logic_kit/fol/_free_parameters.py +105 -0
  117. unicode_logic_kit/fol/_ho_nodes.py +448 -0
  118. unicode_logic_kit/fol/_hybrid_nodes.py +308 -0
  119. unicode_logic_kit/fol/_identifiers.py +1091 -0
  120. unicode_logic_kit/fol/_lambek_nodes.py +112 -0
  121. unicode_logic_kit/fol/_linear_nodes.py +352 -0
  122. unicode_logic_kit/fol/_modal_nodes.py +1467 -0
  123. unicode_logic_kit/fol/_msfl_nodes.py +2196 -0
  124. unicode_logic_kit/fol/_numeral_symbols.py +231 -0
  125. unicode_logic_kit/fol/_so_nodes.py +200 -0
  126. unicode_logic_kit/fol/_symbol_names.py +81 -0
  127. unicode_logic_kit/fol/_team_nodes.py +181 -0
  128. unicode_logic_kit/fol/_tptp_symbols.py +551 -0
  129. unicode_logic_kit/fol/_truth_constants.py +117 -0
  130. unicode_logic_kit/fol/casl_export.py +1135 -0
  131. unicode_logic_kit/fol/casl_import.py +929 -0
  132. unicode_logic_kit/fol/derivation.py +367 -0
  133. unicode_logic_kit/fol/dialect_detect.py +70 -0
  134. unicode_logic_kit/fol/dialect_repair.py +537 -0
  135. unicode_logic_kit/fol/frames.py +637 -0
  136. unicode_logic_kit/fol/grammars/terminals.lark +31 -0
  137. unicode_logic_kit/fol/lambda_tools.py +297 -0
  138. unicode_logic_kit/fol/latex_input.py +429 -0
  139. unicode_logic_kit/fol/modal_translation.py +944 -0
  140. unicode_logic_kit/fol/msflparser.py +1033 -0
  141. unicode_logic_kit/fol/naming.py +422 -0
  142. unicode_logic_kit/fol/nodes.py +241 -0
  143. unicode_logic_kit/fol/normalforms.py +492 -0
  144. unicode_logic_kit/fol/pal.py +287 -0
  145. unicode_logic_kit/fol/prolog_export.py +566 -0
  146. unicode_logic_kit/fol/prolog_input.py +505 -0
  147. unicode_logic_kit/fol/prover9_input.py +1325 -0
  148. unicode_logic_kit/fol/qml.py +1760 -0
  149. unicode_logic_kit/fol/qmltp_input.py +525 -0
  150. unicode_logic_kit/fol/sanitize.py +221 -0
  151. unicode_logic_kit/fol/serialize.py +79 -0
  152. unicode_logic_kit/fol/signature.py +1290 -0
  153. unicode_logic_kit/fol/simplify_check.py +544 -0
  154. unicode_logic_kit/fol/spans.py +594 -0
  155. unicode_logic_kit/fol/tptp_input.py +1503 -0
  156. unicode_logic_kit/fol/tptp_repair.py +941 -0
  157. unicode_logic_kit/fol/unification.py +157 -0
  158. unicode_logic_kit/fol/verbalize.py +263 -0
  159. unicode_logic_kit/hets/__init__.py +163 -0
  160. unicode_logic_kit/hets/bridge.py +142 -0
  161. unicode_logic_kit/hets/client.py +748 -0
  162. unicode_logic_kit/hets/docker.py +420 -0
  163. unicode_logic_kit/hets/dol.py +712 -0
  164. unicode_logic_kit/hets/haskell_json.py +355 -0
  165. unicode_logic_kit/hets/owl_backend.py +794 -0
  166. unicode_logic_kit/hets/owl_cli.py +598 -0
  167. unicode_logic_kit/hets/symbols.py +512 -0
  168. unicode_logic_kit/hol/__init__.py +140 -0
  169. unicode_logic_kit/hol/_ho_common.py +323 -0
  170. unicode_logic_kit/hol/_isabelle_binders.py +125 -0
  171. unicode_logic_kit/hol/classical.py +812 -0
  172. unicode_logic_kit/hol/deepshallow/__init__.py +45 -0
  173. unicode_logic_kit/hol/deepshallow/_common.py +177 -0
  174. unicode_logic_kit/hol/deepshallow/conditional.py +225 -0
  175. unicode_logic_kit/hol/deepshallow/intuitionistic.py +181 -0
  176. unicode_logic_kit/hol/deepshallow/modal.py +217 -0
  177. unicode_logic_kit/hol/deepshallow/qml.py +406 -0
  178. unicode_logic_kit/hol/deepshallow/relevant.py +206 -0
  179. unicode_logic_kit/hol/free.py +753 -0
  180. unicode_logic_kit/hol/goedel.py +336 -0
  181. unicode_logic_kit/hol/ho_modal.py +1743 -0
  182. unicode_logic_kit/hol/intuitionistic.py +403 -0
  183. unicode_logic_kit/hol/isabelle_conditional.py +593 -0
  184. unicode_logic_kit/hol/isabelle_modal.py +1908 -0
  185. unicode_logic_kit/hol/isabelle_relevant.py +412 -0
  186. unicode_logic_kit/hol/isabelle_runner.py +1147 -0
  187. unicode_logic_kit/hol/isabelle_substructural.py +884 -0
  188. unicode_logic_kit/hol/lean.py +1018 -0
  189. unicode_logic_kit/hol/manyvalued.py +921 -0
  190. unicode_logic_kit/hol/secondorder.py +687 -0
  191. unicode_logic_kit/hol/thf_modal.py +941 -0
  192. unicode_logic_kit/hol/thirdorder.py +397 -0
  193. unicode_logic_kit/ilp/__init__.py +89 -0
  194. unicode_logic_kit/ilp/readback.py +389 -0
  195. unicode_logic_kit/ilp/separation.py +153 -0
  196. unicode_logic_kit/ilp/task.py +730 -0
  197. unicode_logic_kit/logic.py +163 -0
  198. unicode_logic_kit/mcp/__init__.py +28 -0
  199. unicode_logic_kit/mcp/__main__.py +5 -0
  200. unicode_logic_kit/mcp/chem_tools.py +1031 -0
  201. unicode_logic_kit/mcp/server.py +2453 -0
  202. unicode_logic_kit/mcp/syntax_spec.py +681 -0
  203. unicode_logic_kit/prob/__init__.py +53 -0
  204. unicode_logic_kit/prob/_bdd.py +225 -0
  205. unicode_logic_kit/prob/_column_gen.py +668 -0
  206. unicode_logic_kit/prob/distribution.py +686 -0
  207. unicode_logic_kit/prob/nilsson.py +470 -0
  208. unicode_logic_kit/py.typed +0 -0
  209. unicode_logic_kit/semantics/__init__.py +137 -0
  210. unicode_logic_kit/semantics/_modal_reject.py +156 -0
  211. unicode_logic_kit/semantics/action_models.py +466 -0
  212. unicode_logic_kit/semantics/asp_models.py +1200 -0
  213. unicode_logic_kit/semantics/conditional.py +580 -0
  214. unicode_logic_kit/semantics/dynamic_epistemic.py +95 -0
  215. unicode_logic_kit/semantics/free_logic.py +913 -0
  216. unicode_logic_kit/semantics/fuzzy.py +384 -0
  217. unicode_logic_kit/semantics/fuzzy_kripke.py +442 -0
  218. unicode_logic_kit/semantics/intuitionistic.py +581 -0
  219. unicode_logic_kit/semantics/kripke.py +1139 -0
  220. unicode_logic_kit/semantics/manyvalued.py +580 -0
  221. unicode_logic_kit/semantics/matrix.py +342 -0
  222. unicode_logic_kit/semantics/model_eval.py +1135 -0
  223. unicode_logic_kit/semantics/modelfinder.py +1036 -0
  224. unicode_logic_kit/semantics/nonmonotonic.py +372 -0
  225. unicode_logic_kit/semantics/relevant.py +331 -0
  226. unicode_logic_kit/semantics/secondorder.py +657 -0
  227. unicode_logic_kit/semantics/structures.py +352 -0
  228. unicode_logic_kit/semantics/tarski.py +975 -0
  229. unicode_logic_kit/semantics/team.py +315 -0
  230. unicode_logic_kit/semantics/team_translation.py +416 -0
  231. unicode_logic_kit/semantics/thirdorder.py +358 -0
  232. unicode_logic_kit/semantics/tnorm.py +85 -0
  233. unicode_logic_kit/semantics/truthtable.py +201 -0
  234. unicode_logic_kit-0.31.0.dist-info/METADATA +333 -0
  235. unicode_logic_kit-0.31.0.dist-info/RECORD +237 -0
  236. unicode_logic_kit-0.31.0.dist-info/WHEEL +4 -0
  237. unicode_logic_kit-0.31.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,217 @@
1
+ r"""Deep + maximal-shallow + minimal-shallow embeddings of **propositional modal
2
+ logic** K, with machine-checked faithfulness proofs (the Benzmüller construction).
3
+
4
+ The emitted theory is self-contained and, with a local Isabelle/HOL, verifies end
5
+ to end: ``faithful1a/1b`` relate the deep and maximal-shallow embeddings,
6
+ ``faithful2/3`` relate them to the minimal-shallow embedding in the fixed model
7
+ ``(W := \<lambda>_. True, R := Racc, V := Vval)``, and ``sound_min`` records that the
8
+ minimal embedding is sound for deep validity. Each proof is a one-line
9
+ ``induct`` — see :func:`modal_faithfulness_theory`.
10
+
11
+ The accessibility relation ``R`` is left arbitrary, so faithfulness holds for the
12
+ base logic K (and hence, a fortiori, under any frame conditions). Deciding
13
+ validity *under a specific frame* is the job of the quantified minimal embedding in
14
+ :mod:`unicode_logic_kit.hol.isabelle_modal`; this module is about the three
15
+ embeddings and the faithful bridges between them.
16
+ """
17
+
18
+ from typing import Optional
19
+
20
+ from unicode_logic_kit.fol.nodes import (
21
+ Node, Not, And, Or, Implies, Iff, Box, Diamond,
22
+ )
23
+ from ._common import AtomConsts, encode_deep, wrap_theory, formula_section
24
+
25
+ # --------------------------------------------------------------------------- #
26
+ # The verified theory body (everything between ``begin`` and ``end``).
27
+ #
28
+ # This text is checked verbatim by the Isabelle-gated tests: exit 0 from
29
+ # ``check_theory`` means Isabelle's kernel discharged all five faithfulness
30
+ # theorems. Do not edit a clause without re-running that check — the ``induct``
31
+ # proofs depend on the exact operator definitions and the ``maxdefs`` / ``mindefs``
32
+ # simp bundles.
33
+ # --------------------------------------------------------------------------- #
34
+
35
+ _MODAL_BODY = r'''typedecl w \<comment> \<open>worlds\<close>
36
+ typedecl s \<comment> \<open>signature: propositional symbols (shared by all three embeddings)\<close>
37
+ type_synonym wset = "w \<Rightarrow> bool" \<comment> \<open>a set of worlds W\<close>
38
+ type_synonym acc = "w \<Rightarrow> w \<Rightarrow> bool" \<comment> \<open>accessibility relation R\<close>
39
+ type_synonym val = "s \<Rightarrow> w \<Rightarrow> bool" \<comment> \<open>valuation V\<close>
40
+
41
+ section \<open>Deep embedding: object syntax as a datatype + recursive truth\<close>
42
+
43
+ datatype pml =
44
+ Atm s | TopD | BotD
45
+ | NegD pml | AndD pml pml | OrD pml pml | ImpD pml pml | IffD pml pml
46
+ | BoxD pml | DiaD pml
47
+
48
+ primrec truthD :: "wset \<Rightarrow> acc \<Rightarrow> val \<Rightarrow> w \<Rightarrow> pml \<Rightarrow> bool" where
49
+ "truthD W R V x (Atm p) = V p x"
50
+ | "truthD W R V x TopD = True"
51
+ | "truthD W R V x BotD = False"
52
+ | "truthD W R V x (NegD f) = (\<not> truthD W R V x f)"
53
+ | "truthD W R V x (AndD f g) = (truthD W R V x f \<and> truthD W R V x g)"
54
+ | "truthD W R V x (OrD f g) = (truthD W R V x f \<or> truthD W R V x g)"
55
+ | "truthD W R V x (ImpD f g) = (truthD W R V x f \<longrightarrow> truthD W R V x g)"
56
+ | "truthD W R V x (IffD f g) = (truthD W R V x f = truthD W R V x g)"
57
+ | "truthD W R V x (BoxD f) = (\<forall>y. R x y \<longrightarrow> truthD W R V y f)"
58
+ | "truthD W R V x (DiaD f) = (\<exists>y. R x y \<and> truthD W R V y f)"
59
+
60
+ definition validD :: "pml \<Rightarrow> bool" where
61
+ "validD f \<equiv> \<forall>W R V. \<forall>x. W x \<longrightarrow> truthD W R V x f"
62
+
63
+ section \<open>Maximal (heavyweight) shallow embedding: every parameter explicit\<close>
64
+
65
+ type_synonym sigma = "wset \<Rightarrow> acc \<Rightarrow> val \<Rightarrow> w \<Rightarrow> bool"
66
+ definition AtmS :: "s \<Rightarrow> sigma" where "AtmS p \<equiv> \<lambda>W R V x. V p x"
67
+ definition TopS :: "sigma" where "TopS \<equiv> \<lambda>W R V x. True"
68
+ definition BotS :: "sigma" where "BotS \<equiv> \<lambda>W R V x. False"
69
+ definition NegS :: "sigma \<Rightarrow> sigma" where "NegS f \<equiv> \<lambda>W R V x. \<not> f W R V x"
70
+ definition AndS :: "sigma \<Rightarrow> sigma \<Rightarrow> sigma" where
71
+ "AndS f g \<equiv> \<lambda>W R V x. f W R V x \<and> g W R V x"
72
+ definition OrS :: "sigma \<Rightarrow> sigma \<Rightarrow> sigma" where
73
+ "OrS f g \<equiv> \<lambda>W R V x. f W R V x \<or> g W R V x"
74
+ definition ImpS :: "sigma \<Rightarrow> sigma \<Rightarrow> sigma" where
75
+ "ImpS f g \<equiv> \<lambda>W R V x. f W R V x \<longrightarrow> g W R V x"
76
+ definition IffS :: "sigma \<Rightarrow> sigma \<Rightarrow> sigma" where
77
+ "IffS f g \<equiv> \<lambda>W R V x. f W R V x = g W R V x"
78
+ definition BoxS :: "sigma \<Rightarrow> sigma" where
79
+ "BoxS f \<equiv> \<lambda>W R V x. \<forall>y. R x y \<longrightarrow> f W R V y"
80
+ definition DiaS :: "sigma \<Rightarrow> sigma" where
81
+ "DiaS f \<equiv> \<lambda>W R V x. \<exists>y. R x y \<and> f W R V y"
82
+ definition validS :: "sigma \<Rightarrow> bool" where
83
+ "validS f \<equiv> \<forall>W R V. \<forall>x. W x \<longrightarrow> f W R V x"
84
+
85
+ section \<open>Minimal (lightweight) shallow embedding: R, V fixed as metalogical consts\<close>
86
+
87
+ consts Racc :: "acc"
88
+ consts Vval :: "val"
89
+ type_synonym tau = "w \<Rightarrow> bool"
90
+ definition AtmM :: "s \<Rightarrow> tau" where "AtmM p \<equiv> \<lambda>x. Vval p x"
91
+ definition TopM :: "tau" where "TopM \<equiv> \<lambda>x. True"
92
+ definition BotM :: "tau" where "BotM \<equiv> \<lambda>x. False"
93
+ definition NegM :: "tau \<Rightarrow> tau" where "NegM f \<equiv> \<lambda>x. \<not> f x"
94
+ definition AndM :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "AndM f g \<equiv> \<lambda>x. f x \<and> g x"
95
+ definition OrM :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "OrM f g \<equiv> \<lambda>x. f x \<or> g x"
96
+ definition ImpM :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "ImpM f g \<equiv> \<lambda>x. f x \<longrightarrow> g x"
97
+ definition IffM :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "IffM f g \<equiv> \<lambda>x. f x = g x"
98
+ definition BoxM :: "tau \<Rightarrow> tau" where "BoxM f \<equiv> \<lambda>x. \<forall>y. Racc x y \<longrightarrow> f y"
99
+ definition DiaM :: "tau \<Rightarrow> tau" where "DiaM f \<equiv> \<lambda>x. \<exists>y. Racc x y \<and> f y"
100
+ definition validM :: "tau \<Rightarrow> bool" where "validM f \<equiv> \<forall>x. f x"
101
+
102
+ section \<open>Mappings between the embeddings\<close>
103
+
104
+ primrec dpToMax :: "pml \<Rightarrow> sigma" where
105
+ "dpToMax (Atm p) = AtmS p"
106
+ | "dpToMax TopD = TopS"
107
+ | "dpToMax BotD = BotS"
108
+ | "dpToMax (NegD f) = NegS (dpToMax f)"
109
+ | "dpToMax (AndD f g) = AndS (dpToMax f) (dpToMax g)"
110
+ | "dpToMax (OrD f g) = OrS (dpToMax f) (dpToMax g)"
111
+ | "dpToMax (ImpD f g) = ImpS (dpToMax f) (dpToMax g)"
112
+ | "dpToMax (IffD f g) = IffS (dpToMax f) (dpToMax g)"
113
+ | "dpToMax (BoxD f) = BoxS (dpToMax f)"
114
+ | "dpToMax (DiaD f) = DiaS (dpToMax f)"
115
+
116
+ primrec dpToMin :: "pml \<Rightarrow> tau" where
117
+ "dpToMin (Atm p) = AtmM p"
118
+ | "dpToMin TopD = TopM"
119
+ | "dpToMin BotD = BotM"
120
+ | "dpToMin (NegD f) = NegM (dpToMin f)"
121
+ | "dpToMin (AndD f g) = AndM (dpToMin f) (dpToMin g)"
122
+ | "dpToMin (OrD f g) = OrM (dpToMin f) (dpToMin g)"
123
+ | "dpToMin (ImpD f g) = ImpM (dpToMin f) (dpToMin g)"
124
+ | "dpToMin (IffD f g) = IffM (dpToMin f) (dpToMin g)"
125
+ | "dpToMin (BoxD f) = BoxM (dpToMin f)"
126
+ | "dpToMin (DiaD f) = DiaM (dpToMin f)"
127
+
128
+ section \<open>Faithfulness (machine-checked by Isabelle's kernel)\<close>
129
+
130
+ lemmas maxdefs = AtmS_def TopS_def BotS_def NegS_def AndS_def OrS_def
131
+ ImpS_def IffS_def BoxS_def DiaS_def
132
+ lemmas mindefs = AtmM_def TopM_def BotM_def NegM_def AndM_def OrM_def
133
+ ImpM_def IffM_def BoxM_def DiaM_def
134
+
135
+ text \<open>Deep truth coincides pointwise with maximal-shallow truth.\<close>
136
+ theorem faithful1a: "truthD W R V x f = dpToMax f W R V x"
137
+ by (induct f arbitrary: x) (simp_all add: maxdefs)
138
+
139
+ text \<open>Hence deep validity coincides with maximal-shallow validity.\<close>
140
+ theorem faithful1b: "validD f = validS (dpToMax f)"
141
+ by (simp add: validD_def validS_def faithful1a)
142
+
143
+ text \<open>Deep truth in the fixed model coincides with minimal-shallow truth.\<close>
144
+ theorem faithful2: "truthD (\<lambda>_. True) Racc Vval x f = dpToMin f x"
145
+ by (induct f arbitrary: x) (simp_all add: mindefs)
146
+
147
+ text \<open>Maximal- and minimal-shallow truth coincide in that fixed model.\<close>
148
+ theorem faithful3: "dpToMax f (\<lambda>_. True) Racc Vval x = dpToMin f x"
149
+ by (induct f arbitrary: x) (simp_all add: maxdefs mindefs)
150
+
151
+ text \<open>Soundness of the minimal embedding for deep validity.\<close>
152
+ theorem sound_min: "validD f \<Longrightarrow> validM (dpToMin f)"
153
+ proof -
154
+ assume *: "validD f"
155
+ have "truthD (\<lambda>_. True) Racc Vval x f" for x
156
+ using * by (simp add: validD_def)
157
+ then show "validM (dpToMin f)"
158
+ by (simp add: validM_def faithful2)
159
+ qed'''
160
+
161
+
162
+ # --------------------------------------------------------------------------- #
163
+ # Encoder: toolkit modal AST -> deep ``pml`` term.
164
+ # --------------------------------------------------------------------------- #
165
+
166
+ # Node type -> (deep constructor, arity). Xor desugars to NegD (IffD ...).
167
+ _CTORS = {
168
+ Not: ("NegD", 1), And: ("AndD", 2), Or: ("OrD", 2),
169
+ Implies: ("ImpD", 2), Iff: ("IffD", 2),
170
+ Box: ("BoxD", 1), Diamond: ("DiaD", 1),
171
+ }
172
+
173
+
174
+ def modal_to_deep(formula: Node, atoms: AtomConsts) -> str:
175
+ r"""Encode a **propositional** modal formula as a deep ``pml`` term.
176
+
177
+ Each distinct ground atom becomes a propositional symbol constant of type ``s``
178
+ (collected into ``atoms``); connectives map to the ``pml`` constructors and
179
+ ``Xor`` desugars to ``NegD (IffD ...)``. Raises :class:`NotImplementedError` if
180
+ the formula is genuinely first-order (contains a quantifier or a variable) — the
181
+ deep embedding is propositional; use :mod:`unicode_logic_kit.hol.isabelle_modal`
182
+ for the quantified fragment.
183
+ """
184
+ return encode_deep(formula, atoms, _CTORS, logic="modal_to_deep")
185
+
186
+
187
+ # --------------------------------------------------------------------------- #
188
+ # Public entry points.
189
+ # --------------------------------------------------------------------------- #
190
+
191
+ def modal_faithfulness_theory(
192
+ theory_name: str = "ModalFaithfulness",
193
+ formula: Optional[Node] = None,
194
+ ) -> str:
195
+ r"""Emit the self-contained modal deep/maximal/minimal + faithfulness theory.
196
+
197
+ The returned string is a full ``theory <theory_name> imports Main begin ... end``
198
+ containing the three embeddings and the five faithfulness theorems, each closed
199
+ by Isabelle. With a local Isabelle/HOL it is verified end to end by
200
+ :func:`unicode_logic_kit.hol.isabelle_runner.check_theory`.
201
+
202
+ Args:
203
+ theory_name: the Isabelle theory / file name (a legal identifier).
204
+ formula: an optional **propositional** modal formula. When given, its deep
205
+ encoding is appended as ``definition example :: pml`` (with ``consts`` for
206
+ its atoms), so the certificate is grounded in a concrete formula and the
207
+ faithfulness theorems specialise to it.
208
+
209
+ Returns:
210
+ The theory text (newline-terminated).
211
+ """
212
+ extra = ""
213
+ if formula is not None:
214
+ atoms = AtomConsts()
215
+ term = modal_to_deep(formula, atoms)
216
+ extra = formula_section(term, atoms, "pml")
217
+ return wrap_theory(theory_name, _MODAL_BODY, extra)
@@ -0,0 +1,406 @@
1
+ r"""Deep + maximal-shallow + minimal-shallow embeddings of **quantified** modal logic
2
+ (QML), Tier 2 — scoped to the base frame K, the CONSTANT domain regime only, and
3
+ the alethic ``□``/``◇`` modalities, with machine-checked faithfulness proofs.
4
+
5
+ This is the binder-carrying sibling of :mod:`unicode_logic_kit.hol.deepshallow.modal`:
6
+ where Tier 1 embeds *propositional* logics (no quantifiers, so induction over the
7
+ syntax datatype is the whole story), this module embeds a genuinely *quantified*
8
+ one. Object variables are represented **de Bruijn-indexed** (``obj = BVar nat |
9
+ FVar s``, ``FVar`` naming a rigid object CONSTANT) rather than by name, which is
10
+ what lets ``truthD`` be a plain ``primrec`` with no separate capture-avoiding
11
+ substitution: a bound variable is interpreted by looking up its index in an
12
+ explicit assignment stack ``env = nat ⇒ i``, and going under ``∀``/``∃`` simply
13
+ *prepends* one entry to that stack (``case_nat d e``, Isabelle's standard ``nat``
14
+ case-combinator). Every faithfulness theorem below is still a **one-line
15
+ ``induct``** — the "extra step" a binder-carrying structural induction needs,
16
+ beyond Tier 1's ``induct f arbitrary: x``, is generalizing the environment too
17
+ (``induct f arbitrary: e x``), so the induction hypothesis is available at the
18
+ *shifted* environment each quantifier clause recurses into.
19
+
20
+ The domain is a single set ``D :: i ⇒ bool`` shared by every world (the constant-
21
+ domain simplification) rather than a family ``D_w`` indexed by world — this is
22
+ what makes "K + constant domain" a fact about the **types**, not a runtime
23
+ frame/mode parameter to check and possibly reject: there is no way to *ask* this
24
+ module for a varying/increasing/decreasing domain or a T/S4/S5 frame, unlike
25
+ :mod:`unicode_logic_kit.hol.isabelle_modal` (which offers all four domain regimes,
26
+ every named frame, and the whole non-counterfactual modal family). ``R`` is left
27
+ completely arbitrary — as in :mod:`~unicode_logic_kit.hol.deepshallow.modal`, this
28
+ is what makes faithfulness hold for base K (and so, a fortiori, under any *stronger*
29
+ frame conditions one might separately assert on top of it — this module simply
30
+ never does).
31
+
32
+ Deliberately out of scope (raise :class:`NotImplementedError` **naming the
33
+ construct**, not approximated): equality/disequality (``=``/``≠``), function terms
34
+ (only object variables and 0-ary constants are terms here), and every operator
35
+ outside alethic ``□``/``◇`` — epistemic ``K_a``/doxastic ``B_a``/assertive/
36
+ bouletic, deontic ``Ⓞ``/``Ⓟ``, the whole temporal family, hybrid nominals/``@``,
37
+ and many-sorted ``SortedQuantifier``/``SortedConstant``. Use
38
+ :mod:`unicode_logic_kit.hol.isabelle_modal` / :mod:`unicode_logic_kit.hol.thf_modal`
39
+ for any of those — this module trades their breadth for a genuine, machine-checked
40
+ **meta-theorem** relating three embeddings of the fragment it does cover.
41
+
42
+ Public API: :func:`qml_to_deep`, :func:`qml_deep_faithfulness_theory`.
43
+ """
44
+
45
+ from typing import List, Optional
46
+
47
+ from unicode_logic_kit.fol.nodes import (
48
+ Node, Atom, Not, And, Or, Implies, Iff, Box, Diamond, Quantifier,
49
+ Variable, Constant,
50
+ )
51
+ from unicode_logic_kit.fol._truth_constants import refuse_truth_constants
52
+ from ._common import AtomConsts, wrap_theory, NO_CONSTANT_WHY
53
+
54
+ # --------------------------------------------------------------------------- #
55
+ # The verified theory body (everything between ``begin`` and ``end``).
56
+ #
57
+ # This text is checked verbatim by the Isabelle-gated tests: exit 0 from
58
+ # ``check_theory`` means Isabelle's kernel discharged all five faithfulness
59
+ # theorems. Do not edit a clause without re-running that check — the ``induct``
60
+ # proofs depend on the exact operator definitions and the ``maxdefs`` / ``mindefs``
61
+ # simp bundles, exactly as in ``modal.py``.
62
+ # --------------------------------------------------------------------------- #
63
+
64
+ _QML_BODY = r'''typedecl w \<comment> \<open>worlds\<close>
65
+ typedecl i \<comment> \<open>individuals: the ONE constant domain shared by every world\<close>
66
+ typedecl s \<comment> \<open>signature: predicate symbols and object-constant symbols\<close>
67
+ type_synonym wset = "w \<Rightarrow> bool" \<comment> \<open>a set of worlds W\<close>
68
+ type_synonym dom = "i \<Rightarrow> bool" \<comment> \<open>the constant domain D\<close>
69
+ type_synonym acc = "w \<Rightarrow> w \<Rightarrow> bool" \<comment> \<open>accessibility relation R\<close>
70
+ type_synonym val = "s \<Rightarrow> i list \<Rightarrow> w \<Rightarrow> bool" \<comment> \<open>valuation V\<close>
71
+ type_synonym cint = "s \<Rightarrow> i" \<comment> \<open>rigid interpretation of object constants\<close>
72
+ type_synonym env = "nat \<Rightarrow> i" \<comment> \<open>de Bruijn assignment stack\<close>
73
+
74
+ section \<open>Object terms: de Bruijn-indexed bound variables plus rigid constants\<close>
75
+
76
+ datatype obj = BVar nat | FVar s
77
+
78
+ primrec objD :: "env \<Rightarrow> cint \<Rightarrow> obj \<Rightarrow> i" where
79
+ "objD e c (BVar n) = e n"
80
+ | "objD e c (FVar a) = c a"
81
+
82
+ section \<open>Deep embedding: object syntax as a datatype + recursive truth\<close>
83
+
84
+ datatype qml =
85
+ Atm s "obj list" | TopD | BotD
86
+ | NegD qml | AndD qml qml | OrD qml qml | ImpD qml qml | IffD qml qml
87
+ | BoxD qml | DiaD qml
88
+ | AllD qml | ExD qml
89
+
90
+ primrec truthD :: "env \<Rightarrow> cint \<Rightarrow> wset \<Rightarrow> acc \<Rightarrow> dom \<Rightarrow> val \<Rightarrow> w \<Rightarrow> qml \<Rightarrow> bool" where
91
+ "truthD e c W R D V x (Atm p args) = V p (map (objD e c) args) x"
92
+ | "truthD e c W R D V x TopD = True"
93
+ | "truthD e c W R D V x BotD = False"
94
+ | "truthD e c W R D V x (NegD f) = (\<not> truthD e c W R D V x f)"
95
+ | "truthD e c W R D V x (AndD f g) = (truthD e c W R D V x f \<and> truthD e c W R D V x g)"
96
+ | "truthD e c W R D V x (OrD f g) = (truthD e c W R D V x f \<or> truthD e c W R D V x g)"
97
+ | "truthD e c W R D V x (ImpD f g) = (truthD e c W R D V x f \<longrightarrow> truthD e c W R D V x g)"
98
+ | "truthD e c W R D V x (IffD f g) = (truthD e c W R D V x f = truthD e c W R D V x g)"
99
+ | "truthD e c W R D V x (BoxD f) = (\<forall>y. R x y \<longrightarrow> truthD e c W R D V y f)"
100
+ | "truthD e c W R D V x (DiaD f) = (\<exists>y. R x y \<and> truthD e c W R D V y f)"
101
+ | "truthD e c W R D V x (AllD f) = (\<forall>d. D d \<longrightarrow> truthD (case_nat d e) c W R D V x f)"
102
+ | "truthD e c W R D V x (ExD f) = (\<exists>d. D d \<and> truthD (case_nat d e) c W R D V x f)"
103
+
104
+ definition validD :: "qml \<Rightarrow> bool" where
105
+ "validD f \<equiv> \<forall>e c W R D V x. W x \<longrightarrow> truthD e c W R D V x f"
106
+
107
+ section \<open>Maximal (heavyweight) shallow embedding: every parameter explicit\<close>
108
+
109
+ type_synonym sigma = "env \<Rightarrow> cint \<Rightarrow> wset \<Rightarrow> acc \<Rightarrow> dom \<Rightarrow> val \<Rightarrow> w \<Rightarrow> bool"
110
+
111
+ definition AtmS :: "s \<Rightarrow> obj list \<Rightarrow> sigma" where
112
+ "AtmS p args \<equiv> \<lambda>e c W R D V x. V p (map (objD e c) args) x"
113
+ definition TopS :: "sigma" where "TopS \<equiv> \<lambda>e c W R D V x. True"
114
+ definition BotS :: "sigma" where "BotS \<equiv> \<lambda>e c W R D V x. False"
115
+ definition NegS :: "sigma \<Rightarrow> sigma" where
116
+ "NegS f \<equiv> \<lambda>e c W R D V x. \<not> f e c W R D V x"
117
+ definition AndS :: "sigma \<Rightarrow> sigma \<Rightarrow> sigma" where
118
+ "AndS f g \<equiv> \<lambda>e c W R D V x. f e c W R D V x \<and> g e c W R D V x"
119
+ definition OrS :: "sigma \<Rightarrow> sigma \<Rightarrow> sigma" where
120
+ "OrS f g \<equiv> \<lambda>e c W R D V x. f e c W R D V x \<or> g e c W R D V x"
121
+ definition ImpS :: "sigma \<Rightarrow> sigma \<Rightarrow> sigma" where
122
+ "ImpS f g \<equiv> \<lambda>e c W R D V x. f e c W R D V x \<longrightarrow> g e c W R D V x"
123
+ definition IffS :: "sigma \<Rightarrow> sigma \<Rightarrow> sigma" where
124
+ "IffS f g \<equiv> \<lambda>e c W R D V x. f e c W R D V x = g e c W R D V x"
125
+ definition BoxS :: "sigma \<Rightarrow> sigma" where
126
+ "BoxS f \<equiv> \<lambda>e c W R D V x. \<forall>y. R x y \<longrightarrow> f e c W R D V y"
127
+ definition DiaS :: "sigma \<Rightarrow> sigma" where
128
+ "DiaS f \<equiv> \<lambda>e c W R D V x. \<exists>y. R x y \<and> f e c W R D V y"
129
+ definition AllS :: "sigma \<Rightarrow> sigma" where
130
+ "AllS f \<equiv> \<lambda>e c W R D V x. \<forall>d. D d \<longrightarrow> f (case_nat d e) c W R D V x"
131
+ definition ExS :: "sigma \<Rightarrow> sigma" where
132
+ "ExS f \<equiv> \<lambda>e c W R D V x. \<exists>d. D d \<and> f (case_nat d e) c W R D V x"
133
+ definition validS :: "sigma \<Rightarrow> bool" where
134
+ "validS f \<equiv> \<forall>e c W R D V x. W x \<longrightarrow> f e c W R D V x"
135
+
136
+ section \<open>Minimal (lightweight) shallow embedding: R, D, V, C fixed as metalogical consts\<close>
137
+
138
+ consts Racc :: "acc"
139
+ consts Dset :: "dom"
140
+ consts Vval :: "val"
141
+ consts Cint :: "cint"
142
+ type_synonym tau = "env \<Rightarrow> w \<Rightarrow> bool"
143
+
144
+ definition AtmM :: "s \<Rightarrow> obj list \<Rightarrow> tau" where
145
+ "AtmM p args \<equiv> \<lambda>e x. Vval p (map (objD e Cint) args) x"
146
+ definition TopM :: "tau" where "TopM \<equiv> \<lambda>e x. True"
147
+ definition BotM :: "tau" where "BotM \<equiv> \<lambda>e x. False"
148
+ definition NegM :: "tau \<Rightarrow> tau" where "NegM f \<equiv> \<lambda>e x. \<not> f e x"
149
+ definition AndM :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "AndM f g \<equiv> \<lambda>e x. f e x \<and> g e x"
150
+ definition OrM :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "OrM f g \<equiv> \<lambda>e x. f e x \<or> g e x"
151
+ definition ImpM :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "ImpM f g \<equiv> \<lambda>e x. f e x \<longrightarrow> g e x"
152
+ definition IffM :: "tau \<Rightarrow> tau \<Rightarrow> tau" where "IffM f g \<equiv> \<lambda>e x. f e x = g e x"
153
+ definition BoxM :: "tau \<Rightarrow> tau" where "BoxM f \<equiv> \<lambda>e x. \<forall>y. Racc x y \<longrightarrow> f e y"
154
+ definition DiaM :: "tau \<Rightarrow> tau" where "DiaM f \<equiv> \<lambda>e x. \<exists>y. Racc x y \<and> f e y"
155
+ definition AllM :: "tau \<Rightarrow> tau" where
156
+ "AllM f \<equiv> \<lambda>e x. \<forall>d. Dset d \<longrightarrow> f (case_nat d e) x"
157
+ definition ExM :: "tau \<Rightarrow> tau" where
158
+ "ExM f \<equiv> \<lambda>e x. \<exists>d. Dset d \<and> f (case_nat d e) x"
159
+ definition validM :: "tau \<Rightarrow> bool" where "validM f \<equiv> \<forall>e x. f e x"
160
+
161
+ section \<open>Mappings between the embeddings\<close>
162
+
163
+ primrec dpToMax :: "qml \<Rightarrow> sigma" where
164
+ "dpToMax (Atm p args) = AtmS p args"
165
+ | "dpToMax TopD = TopS"
166
+ | "dpToMax BotD = BotS"
167
+ | "dpToMax (NegD f) = NegS (dpToMax f)"
168
+ | "dpToMax (AndD f g) = AndS (dpToMax f) (dpToMax g)"
169
+ | "dpToMax (OrD f g) = OrS (dpToMax f) (dpToMax g)"
170
+ | "dpToMax (ImpD f g) = ImpS (dpToMax f) (dpToMax g)"
171
+ | "dpToMax (IffD f g) = IffS (dpToMax f) (dpToMax g)"
172
+ | "dpToMax (BoxD f) = BoxS (dpToMax f)"
173
+ | "dpToMax (DiaD f) = DiaS (dpToMax f)"
174
+ | "dpToMax (AllD f) = AllS (dpToMax f)"
175
+ | "dpToMax (ExD f) = ExS (dpToMax f)"
176
+
177
+ primrec dpToMin :: "qml \<Rightarrow> tau" where
178
+ "dpToMin (Atm p args) = AtmM p args"
179
+ | "dpToMin TopD = TopM"
180
+ | "dpToMin BotD = BotM"
181
+ | "dpToMin (NegD f) = NegM (dpToMin f)"
182
+ | "dpToMin (AndD f g) = AndM (dpToMin f) (dpToMin g)"
183
+ | "dpToMin (OrD f g) = OrM (dpToMin f) (dpToMin g)"
184
+ | "dpToMin (ImpD f g) = ImpM (dpToMin f) (dpToMin g)"
185
+ | "dpToMin (IffD f g) = IffM (dpToMin f) (dpToMin g)"
186
+ | "dpToMin (BoxD f) = BoxM (dpToMin f)"
187
+ | "dpToMin (DiaD f) = DiaM (dpToMin f)"
188
+ | "dpToMin (AllD f) = AllM (dpToMin f)"
189
+ | "dpToMin (ExD f) = ExM (dpToMin f)"
190
+
191
+ section \<open>Faithfulness (machine-checked by Isabelle's kernel)\<close>
192
+
193
+ lemmas maxdefs = AtmS_def TopS_def BotS_def NegS_def AndS_def OrS_def
194
+ ImpS_def IffS_def BoxS_def DiaS_def AllS_def ExS_def
195
+ lemmas mindefs = AtmM_def TopM_def BotM_def NegM_def AndM_def OrM_def
196
+ ImpM_def IffM_def BoxM_def DiaM_def AllM_def ExM_def
197
+
198
+ text \<open>Deep truth coincides pointwise with maximal-shallow truth. The extra
199
+ generalization beyond the propositional Tier 1 proofs (``arbitrary: e`` alongside
200
+ ``x``) is exactly the "binder-carrying structural induction" step: it makes the
201
+ induction hypothesis available at the SHIFTED environment ``case_nat d e`` each
202
+ ``AllD``/``ExD`` clause recurses into.\<close>
203
+ theorem faithful1a: "truthD e c W R D V x f = dpToMax f e c W R D V x"
204
+ by (induct f arbitrary: e x) (simp_all add: maxdefs)
205
+
206
+ text \<open>Hence deep validity coincides with maximal-shallow validity.\<close>
207
+ theorem faithful1b: "validD f = validS (dpToMax f)"
208
+ by (simp add: validD_def validS_def faithful1a)
209
+
210
+ text \<open>Deep truth in the fixed model coincides with minimal-shallow truth.\<close>
211
+ theorem faithful2: "truthD e Cint (\<lambda>_. True) Racc Dset Vval x f = dpToMin f e x"
212
+ by (induct f arbitrary: e x) (simp_all add: mindefs)
213
+
214
+ text \<open>Maximal- and minimal-shallow truth coincide in that fixed model.\<close>
215
+ theorem faithful3: "dpToMax f e Cint (\<lambda>_. True) Racc Dset Vval x = dpToMin f e x"
216
+ by (induct f arbitrary: e x) (simp_all add: maxdefs mindefs)
217
+
218
+ text \<open>Soundness of the minimal embedding for deep validity.\<close>
219
+ theorem sound_min: "validD f \<Longrightarrow> validM (dpToMin f)"
220
+ proof -
221
+ assume *: "validD f"
222
+ have "truthD e Cint (\<lambda>_. True) Racc Dset Vval x f" for e x
223
+ using * by (simp add: validD_def)
224
+ then show "validM (dpToMin f)"
225
+ by (simp add: validM_def faithful2)
226
+ qed'''
227
+
228
+
229
+ # --------------------------------------------------------------------------- #
230
+ # Encoder: toolkit QML AST -> deep ``qml`` term (de Bruijn-indexed).
231
+ # --------------------------------------------------------------------------- #
232
+
233
+ # Node type -> (deep constructor, arity 1 or 2). Quantifiers and Box/Diamond are
234
+ # handled separately below (they thread the bound-variable stack / recurse on
235
+ # ``.formula`` under a differently-named constructor).
236
+ _CONNECTIVES = {
237
+ Not: ("NegD", 1), And: ("AndD", 2), Or: ("OrD", 2),
238
+ Implies: ("ImpD", 2), Iff: ("IffD", 2),
239
+ }
240
+
241
+ _EQUALITY_PREDS = frozenset({"=", "≠"})
242
+
243
+ _UNSUPPORTED_HINT = (
244
+ "this deep embedding is scoped to K + constant domain + alethic □/◇ "
245
+ "only (Tier 2 of hol.deepshallow) — no epistemic/doxastic/assertive/"
246
+ "bouletic, deontic, temporal, hybrid or many-sorted operators, no equality, "
247
+ "no function terms. Use hol.isabelle_modal.to_isabelle_modal / "
248
+ "hol.thf_modal.to_thf_modal_full for the full modal family and the other "
249
+ "three domain regimes."
250
+ )
251
+
252
+
253
+ def _obj_to_deep(term: Node, bound: List[str], consts: AtomConsts) -> str:
254
+ """Encode an object TERM as a deep ``obj`` value: ``BVar`` (de Bruijn index
255
+ into ``bound``, innermost binder = index 0) or ``FVar`` (a rigid constant).
256
+
257
+ ``bound`` lists the quantifiers currently in scope, outermost first, so a
258
+ shadowed name resolves to the innermost (most recently pushed) binder —
259
+ exactly the de Bruijn convention ``truthD``'s ``AllD``/``ExD`` clauses
260
+ implement via ``case_nat``. A free (unbound) :class:`Variable` is refused:
261
+ this deep embedding requires a closed formula, every object variable bound
262
+ by some ``∀``/``∃`` in the formula itself.
263
+ """
264
+ if isinstance(term, Variable):
265
+ if term.name not in bound:
266
+ raise NotImplementedError(
267
+ f"qml_to_deep: free variable {term.name!r} is not bound by any "
268
+ "quantifier in the formula — the deep embedding requires a "
269
+ "closed formula (every object variable bound).")
270
+ idx = bound[::-1].index(term.name)
271
+ return f"(BVar {idx})"
272
+ if isinstance(term, Constant):
273
+ return f"(FVar {consts.name(term.name)})"
274
+ raise NotImplementedError(
275
+ f"qml_to_deep: unsupported term {type(term).__name__} — this "
276
+ "fragment has object variables and 0-ary constants only (no function "
277
+ f"terms, no Number literals). {_UNSUPPORTED_HINT}")
278
+
279
+
280
+ def _encode(node: Node, bound: List[str], atoms: AtomConsts, consts: AtomConsts) -> str:
281
+ """Encode a **K + constant-domain + alethic** QML formula as a deep ``qml`` term."""
282
+ if isinstance(node, Atom):
283
+ refuse_truth_constants([node], "qml_to_deep", NO_CONSTANT_WHY)
284
+ if node.predicate in _EQUALITY_PREDS:
285
+ raise NotImplementedError(
286
+ f"qml_to_deep: {node.predicate!r} (equality) is outside this "
287
+ f"fragment's scope, refused by name. {_UNSUPPORTED_HINT}")
288
+ objs = ", ".join(_obj_to_deep(a, bound, consts) for a in node.args)
289
+ return f"(Atm {atoms.name(node.predicate)} [{objs}])"
290
+ if isinstance(node, Box):
291
+ return f"(BoxD {_encode(node.formula, bound, atoms, consts)})"
292
+ if isinstance(node, Diamond):
293
+ return f"(DiaD {_encode(node.formula, bound, atoms, consts)})"
294
+ if isinstance(node, Quantifier):
295
+ inner = _encode(node.formula, bound + [node.variable.name], atoms, consts)
296
+ if node.type in ("∀", "forall"):
297
+ return f"(AllD {inner})"
298
+ if node.type in ("∃", "exists"):
299
+ return f"(ExD {inner})"
300
+ raise ValueError(f"qml_to_deep: unknown quantifier type {node.type!r}.")
301
+ spec = _CONNECTIVES.get(type(node))
302
+ if spec is not None:
303
+ name, arity = spec
304
+ if arity == 1:
305
+ return f"({name} {_encode(node.formula, bound, atoms, consts)})"
306
+ left = _encode(node.left, bound, atoms, consts)
307
+ right = _encode(node.right, bound, atoms, consts)
308
+ return f"({name} {left} {right})"
309
+ raise NotImplementedError(
310
+ f"qml_to_deep: unsupported node type {type(node).__name__}. "
311
+ f"{_UNSUPPORTED_HINT}")
312
+
313
+
314
+ def qml_to_deep(formula: Node, atoms: AtomConsts, consts: AtomConsts) -> str:
315
+ r"""Encode a **K + constant-domain + alethic □/◇** QML formula as a deep
316
+ ``qml`` term (de Bruijn-indexed bound variables, ``FVar`` for constants).
317
+
318
+ ``atoms`` collects PREDICATE-symbol constants, exactly like the Tier 1
319
+ encoders (:func:`~unicode_logic_kit.hol.deepshallow.modal.modal_to_deep` and
320
+ siblings). ``consts`` collects OBJECT-constant symbols and is a REQUIRED
321
+ argument, on purpose: a resolver this function created and the caller
322
+ never got back would be a resolver whose declarations a hand-assembled
323
+ theory can silently drop (an earlier version of this function made
324
+ exactly that mistake, defaulting ``consts=None`` and fabricating one
325
+ internally — a caller who then emitted only ``atoms.decls()`` produced an
326
+ ill-typed Isabelle theory with no error raised on the Python side). To
327
+ keep a predicate and a constant that sanitise to the same identifier from
328
+ colliding on the one Isabelle type ``s`` both use, share the
329
+ de-collision pool the way :func:`qml_deep_faithfulness_theory` itself
330
+ does::
331
+
332
+ atoms = AtomConsts()
333
+ consts = AtomConsts()
334
+ consts._used = atoms._used
335
+ term = qml_to_deep(formula, atoms, consts)
336
+
337
+ Any theory built from ``term`` — by hand, or via
338
+ :func:`qml_deep_faithfulness_theory` — must emit BOTH ``atoms.decls()``
339
+ and ``consts.decls()``; omitting either produces an ill-typed theory
340
+ (Isabelle rejects the undeclared name with "Extra variables on rhs").
341
+
342
+ Raises :class:`NotImplementedError` on equality/disequality, a function
343
+ term or a Number literal, a free (unbound) variable, or any operator
344
+ outside alethic ``□``/``◇`` (epistemic/doxastic/deontic/temporal/hybrid/
345
+ many-sorted) — every refusal names the offending construct. There is no
346
+ ``frame=``/``mode=`` parameter: this module structurally commits to K
347
+ (``R`` left arbitrary) and the constant domain (one shared ``D``); use
348
+ :mod:`unicode_logic_kit.hol.isabelle_modal` for the other frames/regimes.
349
+ """
350
+ return _encode(formula, [], atoms, consts)
351
+
352
+
353
+ # --------------------------------------------------------------------------- #
354
+ # Public entry points.
355
+ # --------------------------------------------------------------------------- #
356
+
357
+ def _qml_formula_section(term: str, atoms: AtomConsts, consts: AtomConsts) -> str:
358
+ """The ``consts`` + ``definition example`` block grounding a concrete formula.
359
+
360
+ Like :func:`unicode_logic_kit.hol.deepshallow._common.formula_section`, but
361
+ emitting TWO ``consts`` groups (predicate symbols, then object constants) —
362
+ ``qml_to_deep`` needs both namespaces, which ``_common.formula_section``'s
363
+ single-``AtomConsts`` signature cannot express.
364
+ """
365
+ lines = ["", "section \\<open>A concrete embedded formula\\<close>", ""]
366
+ lines += atoms.decls()
367
+ lines += consts.decls()
368
+ lines.append(f'definition example :: qml where "example = {term}"')
369
+ return "\n".join(lines)
370
+
371
+
372
+ def qml_deep_faithfulness_theory(
373
+ theory_name: str = "QmlFaithfulness",
374
+ formula: Optional[Node] = None,
375
+ ) -> str:
376
+ r"""Emit the self-contained QML deep/maximal/minimal + faithfulness theory
377
+ (Tier 2: K frame, constant domain, alethic □/◇ only).
378
+
379
+ The returned string is a full ``theory <theory_name> imports Main begin ... end``
380
+ containing the three embeddings and the five faithfulness theorems
381
+ (``faithful1a/1b/2/3``, ``sound_min``), each closed by Isabelle. With a local
382
+ Isabelle/HOL it is verified end to end by
383
+ :func:`unicode_logic_kit.hol.isabelle_runner.check_theory` — exit 0 means
384
+ Isabelle's kernel discharged every one; the theory text itself contains
385
+ neither ``sorry`` nor ``oops``.
386
+
387
+ Args:
388
+ theory_name: the Isabelle theory / file name (a legal identifier).
389
+ formula: an optional QML formula within this fragment. When given, its
390
+ deep encoding is appended as ``definition example :: qml`` (with
391
+ ``consts`` for its predicate and object-constant symbols), so the
392
+ certificate is grounded in a concrete formula. Raises
393
+ :class:`NotImplementedError` if ``formula`` uses a construct outside
394
+ K + constant domain + alethic □/◇ (see :func:`qml_to_deep`).
395
+
396
+ Returns:
397
+ The theory text (newline-terminated).
398
+ """
399
+ extra = ""
400
+ if formula is not None:
401
+ atoms = AtomConsts()
402
+ consts = AtomConsts()
403
+ consts._used = atoms._used
404
+ term = qml_to_deep(formula, atoms, consts)
405
+ extra = _qml_formula_section(term, atoms, consts)
406
+ return wrap_theory(theory_name, _QML_BODY, extra)