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,177 @@
1
+ from .z3_equivalence import formulas_are_equivalent
2
+ from .prover9_entailment import check_logical_entailment
3
+ from .vampire_entailment import check_logical_entailment_vampire
4
+ from .z3_models import is_satisfiable, is_valid, get_model
5
+ from .z3_fuzzy import (
6
+ fuzzy_is_satisfiable, fuzzy_is_valid, fuzzy_get_model, degree_expr,
7
+ )
8
+ from .z3_arith import (
9
+ to_z3_arith, is_satisfiable_arith, is_valid_arith, get_model_arith, ArithEnv,
10
+ )
11
+ from .resolution import to_clauses, refute, prove, is_valid_resolution
12
+ from .resolution_check import (
13
+ ResolutionStep, ResolutionDerivation, ResolutionCheckResult,
14
+ check_resolution_proof, verify_resolution_proof, render_resolution_proof,
15
+ )
16
+ from .fitch import (
17
+ Proof, Line, Subproof, Justification, ProofResult,
18
+ premise, assume, line, flag, FALSUM,
19
+ check_proof, verify_proof,
20
+ render_fitch, render_latex_fitch,
21
+ )
22
+ from .sequent import (
23
+ Sequent, Derivation, Comprehension, SequentResult,
24
+ sequent, derive, axiom,
25
+ check_sequent_proof, verify_sequent_proof, render_sequent_proof,
26
+ )
27
+ from .z3_input import from_z3, parse_smtlib, load_smtlib, to_smtlib
28
+ from .fitch_search import find_fitch_proof, fitch_prove, is_valid_fitch
29
+ from .tableau import (
30
+ tableau_closed, is_valid_tableau, prove_tableau, tableau_model,
31
+ prove_tableau_detailed, TableauProof, TableauStep, TableauClosure,
32
+ )
33
+ from .tableau_check import (
34
+ TableauCheckError, check_tableau_proof, check_entailment_tableau_detailed,
35
+ )
36
+ from .modal_tableau import (
37
+ modal_tableau_closed, is_modal_valid, modal_prove, modal_decide, modal_countermodel,
38
+ )
39
+ from .lj import check_lj_proof, verify_lj_proof, int_prove, int_decide
40
+ from .linear import (
41
+ ill_prove, ill_derivable, check_ill_proof, verify_ill_proof,
42
+ render_ill_proof, ILLSequent, ILLDerivation,
43
+ )
44
+ from .lambek import (
45
+ lambek_prove, lambek_derivable, check_lambek_proof, verify_lambek_proof,
46
+ render_lambek_proof, LambekSequent, LambekDerivation,
47
+ )
48
+ from .protocol import (
49
+ Verdict, BackendUnavailable, ProverBackend,
50
+ register_backend, get_backend, available_backends, default_chain,
51
+ run_backend,
52
+ z3_relevant_premises,
53
+ )
54
+ from .vampire_entailment import check_entailment_vampire_detailed
55
+ from .tstp import (
56
+ extract_szs_status, szs_to_verdict_fields,
57
+ TstpStep, TstpDerivation, parse_tstp_derivation,
58
+ relevant_premises_from_tstp,
59
+ to_tstp,
60
+ )
61
+ from .tstp_check import (
62
+ TstpStepResult, TstpCheckResult, check_tstp_derivation,
63
+ VAMPIRE_CLAUSIFICATION_RULES, VAMPIRE_CHECKED_RULES,
64
+ EPROVER_CLAUSIFICATION_RULES, EPROVER_CHECKED_RULES,
65
+ )
66
+ from .portfolio import portfolio_prove
67
+ from .cvc5_backend import Cvc5Backend
68
+ from .incremental import IncrementalSession
69
+ from .eprover_backend import (
70
+ EProverBackend, ZipperpositionBackend,
71
+ check_entailment_eprover_detailed,
72
+ eprover_available, zipperposition_available,
73
+ eprover_relevant_premises,
74
+ )
75
+ from .hets_backend import HetsBackend
76
+ from .nanocop_backend import NanocopBackend, to_nanocop, nanocop_available
77
+ from .twee_backend import TweeBackend
78
+ from .twee_entailment import twee_available, check_entailment_twee_detailed
79
+ from .twee_check import check_twee_proof, TweeCheckResult
80
+ from .kripke_enum import (
81
+ EnumSearchResult, modal_enum_search, modal_enum_countermodel,
82
+ kripke_model_to_dict, kripke_model_from_dict, KripkeEnumBackend,
83
+ )
84
+ from .hybrid_down import down_decide
85
+ from .tptp_ncl import to_tptp_ncl
86
+ from .leo3_backend import Leo3Backend
87
+ from .finite_domain import (
88
+ lower_msfol, FiniteDomainProblem, fragment_check, structure_from_solution, verify_model,
89
+ )
90
+ from .clingo_backend import ClingoBackend, clingo_available, to_asp
91
+ from .minizinc_backend import MinizincBackend, minizinc_available, to_minizinc
92
+ from .tptp_tff import generate_tff_problem, generate_tff_problem_with_mapping
93
+ from ._tff_problem import generate_tff_arith_problem
94
+ from ._tptp_problem import (
95
+ generate_tptp_problem, generate_tptp_problem_with_mapping,
96
+ TptpNameMap, apply_reverse_tptp,
97
+ )
98
+ from .ltl_tableau import (
99
+ LTLTrace, ltl_tableau_closed, ltl_valid, ltl_decide, ltl_countermodel,
100
+ ltl_trace_satisfies, LtlTableauBackend,
101
+ )
102
+ from .logic_backends import (
103
+ IntBackend, LambekBackend, IllBackend, RelevantBackend, HybridBackend,
104
+ )
105
+
106
+ __all__ = [
107
+ "formulas_are_equivalent",
108
+ "check_logical_entailment",
109
+ "check_logical_entailment_vampire",
110
+ "is_satisfiable", "is_valid", "get_model",
111
+ "fuzzy_is_satisfiable", "fuzzy_is_valid", "fuzzy_get_model", "degree_expr",
112
+ "to_z3_arith", "is_satisfiable_arith", "is_valid_arith", "get_model_arith", "ArithEnv",
113
+ "to_clauses", "refute", "prove", "is_valid_resolution",
114
+ "ResolutionStep", "ResolutionDerivation", "ResolutionCheckResult",
115
+ "check_resolution_proof", "verify_resolution_proof", "render_resolution_proof",
116
+ "Proof", "Line", "Subproof", "Justification", "ProofResult",
117
+ "premise", "assume", "line", "flag", "FALSUM",
118
+ "check_proof", "verify_proof",
119
+ "render_fitch", "render_latex_fitch",
120
+ "Sequent", "Derivation", "Comprehension", "SequentResult",
121
+ "sequent", "derive", "axiom",
122
+ "check_sequent_proof", "verify_sequent_proof", "render_sequent_proof",
123
+ "from_z3", "parse_smtlib", "load_smtlib", "to_smtlib",
124
+ "find_fitch_proof", "fitch_prove", "is_valid_fitch",
125
+ "tableau_closed", "is_valid_tableau", "prove_tableau", "tableau_model",
126
+ "prove_tableau_detailed", "TableauProof", "TableauStep", "TableauClosure",
127
+ "TableauCheckError", "check_tableau_proof",
128
+ "check_entailment_tableau_detailed",
129
+ "modal_tableau_closed", "is_modal_valid", "modal_prove", "modal_decide",
130
+ "modal_countermodel",
131
+ "check_lj_proof", "verify_lj_proof", "int_prove", "int_decide",
132
+ "ill_prove", "ill_derivable", "check_ill_proof", "verify_ill_proof",
133
+ "render_ill_proof", "ILLSequent", "ILLDerivation",
134
+ "lambek_prove", "lambek_derivable", "check_lambek_proof",
135
+ "verify_lambek_proof", "render_lambek_proof", "LambekSequent",
136
+ "LambekDerivation",
137
+ "Verdict", "BackendUnavailable", "ProverBackend",
138
+ "register_backend", "get_backend", "available_backends", "default_chain",
139
+ "run_backend",
140
+ "z3_relevant_premises",
141
+ "check_entailment_vampire_detailed",
142
+ "extract_szs_status", "szs_to_verdict_fields",
143
+ "TstpStep", "TstpDerivation", "parse_tstp_derivation",
144
+ "relevant_premises_from_tstp",
145
+ "to_tstp",
146
+ "TstpStepResult", "TstpCheckResult", "check_tstp_derivation",
147
+ "VAMPIRE_CLAUSIFICATION_RULES", "VAMPIRE_CHECKED_RULES",
148
+ "EPROVER_CLAUSIFICATION_RULES", "EPROVER_CHECKED_RULES",
149
+ "portfolio_prove",
150
+ "Cvc5Backend",
151
+ "IncrementalSession",
152
+ "EProverBackend", "ZipperpositionBackend",
153
+ "check_entailment_eprover_detailed",
154
+ "eprover_available", "zipperposition_available",
155
+ "eprover_relevant_premises",
156
+ "HetsBackend",
157
+ "NanocopBackend", "to_nanocop", "nanocop_available",
158
+ "TweeBackend", "twee_available", "check_entailment_twee_detailed",
159
+ "check_twee_proof", "TweeCheckResult",
160
+ "EnumSearchResult", "modal_enum_search", "modal_enum_countermodel",
161
+ "kripke_model_to_dict", "kripke_model_from_dict", "KripkeEnumBackend",
162
+ "down_decide",
163
+ "to_tptp_ncl",
164
+ "Leo3Backend",
165
+ "lower_msfol",
166
+ "FiniteDomainProblem", "fragment_check", "structure_from_solution", "verify_model",
167
+ "ClingoBackend", "clingo_available", "to_asp",
168
+ "MinizincBackend", "minizinc_available", "to_minizinc",
169
+ "generate_tff_problem", "generate_tff_problem_with_mapping",
170
+ "generate_tff_arith_problem",
171
+ "generate_tptp_problem", "generate_tptp_problem_with_mapping",
172
+ "TptpNameMap", "apply_reverse_tptp",
173
+ "LTLTrace", "ltl_tableau_closed", "ltl_valid", "ltl_decide",
174
+ "ltl_countermodel", "ltl_trace_satisfies", "LtlTableauBackend",
175
+ "IntBackend", "LambekBackend", "IllBackend", "RelevantBackend",
176
+ "HybridBackend",
177
+ ]
@@ -0,0 +1,113 @@
1
+ """Shared ASCII-identifier sanitisation for the ASCII-only export surfaces:
2
+ TPTP (:mod:`atp._tptp_problem`), Prover9 (:mod:`atp.prover9_entailment`), and
3
+ SMT-LIB2/cvc5 (:mod:`atp.cvc5_backend`).
4
+
5
+ WHY THIS IS NOT :mod:`fol.sanitize`
6
+ -------------------------------------
7
+ :mod:`fol.sanitize`'s :class:`~fol.sanitize.NameMapping` already solves
8
+ exactly this shape of problem — an injective, whole-problem-consistent
9
+ rewrite to legal tokens, with a reverse mapping back to the originals — but
10
+ its target legality is the kit's OWN ``MSFLParser`` grammar, not any of
11
+ these export formats'. The two disagree in a way that matters: a single-
12
+ letter constant such as ``a`` is not a legal bare ``NAME`` token in the
13
+ kit's own grammar (it would re-lex as a ``VARIABLE``), so
14
+ ``NameMapping.for_constant("a")`` rewrites it to ``c_a`` — but ``a`` is
15
+ already a perfectly legal TPTP ``lower_word`` / Prover9 ``NAME`` /
16
+ SMT-LIB2 simple symbol, and an exporter that "fixed" it anyway would
17
+ silently change the output of every formula using a short constant,
18
+ breaking the "already-legal names pass through byte-identical" guarantee
19
+ these export entry points make to their callers (see each of this module's
20
+ callers' own module docstrings). So each target format gets its OWN
21
+ legality test and its own synthesis rule for the names that fail it, built
22
+ from the primitives below — the same INJECTIVE / whole-problem-consistent
23
+ / reversible SHAPE :class:`~fol.sanitize.NameMapping` uses (a shared
24
+ reservation set, numeric-suffix de-collision, a flat reverse dict), just
25
+ parametrised per format instead of reusing that class's kit-specific
26
+ methods directly.
27
+
28
+ :func:`ascii_safe_base` is the one piece every target genuinely shares:
29
+ transliterating non-ASCII characters via
30
+ :func:`unicode_logic_kit.fol._fol_nodes.constant_name_to_ascii` (the same
31
+ Greek-letter-name / reversible ``uXXXX``-escape rule
32
+ :meth:`~fol.nodes.Constant.to_tptp` and :meth:`~fol.nodes.Constant.to_prover9`
33
+ already use) and guaranteeing the result does not start with a digit or come
34
+ out empty.
35
+ """
36
+
37
+ import re
38
+ from typing import Callable, Dict, Set
39
+
40
+ from ..fol._fol_nodes import constant_name_to_ascii
41
+
42
+ __all__ = ["ascii_safe_base", "reserve_rendered", "reverse_map_text"]
43
+
44
+
45
+ def ascii_safe_base(name: str, prefix: str) -> str:
46
+ """Transliterate ``name`` to ASCII and ensure a non-digit-leading result.
47
+
48
+ Reuses :func:`constant_name_to_ascii` (ASCII passes through, a Greek
49
+ letter becomes its spelled name, anything else non-ASCII becomes a
50
+ reversible ``uXXXX`` escape) — every one of those three outcomes starts
51
+ with a letter, so the ONLY way the result can still start with a digit
52
+ (or be empty) is if ``name`` itself was already plain ASCII and
53
+ digit-leading (transliteration is a no-op on it). ``prefix`` is
54
+ prepended in that case; it is also prepended to an empty transliteration
55
+ (``name`` was empty, or every character became... nothing — not reached
56
+ by any of :func:`constant_name_to_ascii`'s cases today, but kept as an
57
+ honest fallback rather than an assumption).
58
+ """
59
+ ascii_name = constant_name_to_ascii(name)
60
+ if not ascii_name or ascii_name[0].isdigit():
61
+ ascii_name = prefix + ascii_name
62
+ return ascii_name
63
+
64
+
65
+ def reserve_rendered(base: str, used: Set[str],
66
+ render: Callable[[str], str] = lambda s: s) -> str:
67
+ """Return a token starting from ``base`` whose ``render(...)`` form is not
68
+ yet in ``used``, reserving that rendered form; mirrors
69
+ :meth:`fol.sanitize.NameMapping._reserve`'s numeric-suffix scheme
70
+ (``base``, then ``base2``, ``base3``, ...) but de-collides on the
71
+ RENDERED form (what actually appears in the exported text — e.g. after
72
+ TPTP's first-letter fold) rather than on ``base`` itself, since two
73
+ different raw candidates can still render to the same text (``Foo2`` and
74
+ ``foo2`` both fold to ``foo2``). ``render`` defaults to the identity
75
+ (Prover9 and SMT-LIB2 render every accepted token verbatim; only TPTP
76
+ needs a non-identity ``render``).
77
+ """
78
+ candidate = base
79
+ i = 2
80
+ while render(candidate) in used:
81
+ candidate = f"{base}{i}"
82
+ i += 1
83
+ used.add(render(candidate))
84
+ return candidate
85
+
86
+
87
+ def reverse_map_text(text: str, *reverse_dicts: Dict[str, str]) -> str:
88
+ """Replace whole-token occurrences of a sanitised identifier in free
89
+ text with its original kit-level name.
90
+
91
+ Used for the free-text side of the Rückweg (R3's "Erklärungstexte") —
92
+ a prover's raw stdout excerpt, an error detail string, and similar —
93
+ where the identifiers of interest sit inside a larger human-readable
94
+ string rather than in a parsed :class:`~fol.nodes.Node`. Matching is by
95
+ whole token (regex word boundaries) so a sanitised name that happens to
96
+ be a substring of something else (another identifier, a longer word in
97
+ surrounding prose) is never partially rewritten; the first
98
+ ``reverse_dicts`` entry to contain a given token wins, and tokens are
99
+ tried longest-first so one sanitised name that is itself a prefix of
100
+ another is not matched short. Returns ``text`` unchanged if every dict
101
+ is empty (the common case: nothing needed sanitising, so nothing needs
102
+ reversing) or if ``text`` is empty.
103
+ """
104
+ combined: Dict[str, str] = {}
105
+ for d in reverse_dicts:
106
+ for token, original in d.items():
107
+ combined.setdefault(token, original)
108
+ if not combined or not text:
109
+ return text
110
+ pattern = re.compile(
111
+ r"\b(" + "|".join(re.escape(t) for t in sorted(combined, key=len, reverse=True)) + r")\b"
112
+ )
113
+ return pattern.sub(lambda m: combined[m.group(1)], text)
@@ -0,0 +1,72 @@
1
+ """Shared HTML-rendering primitives for the ``atp`` proof renderers.
2
+
3
+ :meth:`~unicode_logic_kit.atp.fitch.Proof.to_html` and
4
+ :meth:`~unicode_logic_kit.atp.sequent.Derivation.to_html` both render a
5
+ self-contained, theme-aware HTML page in the same idiom already established by
6
+ :meth:`unicode_logic_kit.fol.derivation.CCGDerivation.to_html` — a ``<!doctype
7
+ html>`` page, CSS custom properties themed via both
8
+ ``@media(prefers-color-scheme:dark)`` *and* a ``:root[data-theme=dark]``
9
+ override, and HTML-escaping of every user-supplied string (predicate/variable
10
+ names, surface text). This private module holds the pieces genuinely common
11
+ to the two ``atp`` renderers — escaping, a shared base colour palette, and the
12
+ page wrapper — so :mod:`~unicode_logic_kit.atp.fitch` and
13
+ :mod:`~unicode_logic_kit.atp.sequent` do not each reimplement them.
14
+
15
+ It deliberately does **not** import from :mod:`unicode_logic_kit.fol.derivation`
16
+ (nor the reverse): every ``unicode_logic_kit.atp`` module already imports
17
+ ``unicode_logic_kit.fol`` at module scope (``Node`` and friends), so ``atp`` →
18
+ ``fol`` is the established one-way dependency direction — ``fol`` only ever
19
+ reaches into ``atp`` from inside a function body (e.g. ``fol.qml``,
20
+ ``fol.modal_translation``, ``fol._fol_nodes``, all lazily importing
21
+ ``atp.z3_models``/``atp.z3_input`` to keep ``fol`` importable without ``z3``).
22
+ Having ``fol/derivation.py`` import this module at module scope would invert
23
+ that and risks a real import cycle (``fol/__init__.py`` imports
24
+ ``.derivation`` eagerly). The handful of lines duplicated below
25
+ (``esc_html``) are therefore an intentional, explicitly-permitted duplicate of
26
+ ``fol.derivation._esc_html`` rather than a cross-package import — see the C56
27
+ roadmap item.
28
+ """
29
+
30
+ __all__: list = [] # private helper module; nothing here is part of the public API
31
+
32
+
33
+ def esc_html(s: str) -> str:
34
+ """Escape ``&``, ``<``, ``>`` for safe inclusion in HTML text content.
35
+
36
+ Mirrors ``fol.derivation._esc_html`` exactly (a stable, three-line
37
+ function); duplicated here rather than imported, see the module docstring.
38
+ """
39
+ return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
40
+
41
+
42
+ # Shared colour tokens (page background / ink / muted text / rule lines /
43
+ # accent), following the exact idiom CCGDerivation.to_html() established:
44
+ # default (light) values live in :root, overridden both by the OS-level
45
+ # prefers-color-scheme media query and by an explicit :root[data-theme=...]
46
+ # attribute a host page can set to force one theme regardless of the OS.
47
+ _LIGHT_VARS = "--pg:#faf9f6;--ink:#23232a;--muted:#6b6b76;--bar:#3f3f47;--accent:#1c46b0"
48
+ _DARK_VARS = "--pg:#15151a;--ink:#e9e8e4;--muted:#a6a6b0;--bar:#c3c3cd;--accent:#84a6ff"
49
+
50
+ BASE_CSS = (
51
+ "\n:root{%s}"
52
+ "\n@media(prefers-color-scheme:dark){:root{%s}}"
53
+ "\n:root[data-theme=light]{%s}"
54
+ "\n:root[data-theme=dark]{%s}"
55
+ "\nbody{margin:0;background:var(--pg);color:var(--ink)}\n"
56
+ ) % (_LIGHT_VARS, _DARK_VARS, _LIGHT_VARS, _DARK_VARS)
57
+
58
+
59
+ def html_page(title: str, body_html: str, extra_css: str) -> str:
60
+ """Wrap ``body_html`` in a self-contained, theme-aware HTML page.
61
+
62
+ Same skeleton as ``CCGDerivation.to_html()``'s page wrapper: a
63
+ ``<!doctype html>`` document with a viewport meta tag and one inline
64
+ ``<style>`` combining the shared colour tokens (:data:`BASE_CSS`) with the
65
+ caller's ``extra_css``. ``title`` is HTML-escaped.
66
+ """
67
+ return (
68
+ "<!doctype html>\n<html><head><meta charset=\"utf-8\">\n"
69
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
70
+ "<title>%s</title>\n<style>%s%s</style></head>\n<body>\n%s\n</body></html>\n"
71
+ % (esc_html(title), BASE_CSS, extra_css, body_html)
72
+ )
@@ -0,0 +1,228 @@
1
+ """What the propositional substructural calculi read, and what they refuse.
2
+
3
+ Intuitionistic linear logic (:mod:`~unicode_logic_kit.atp.linear`) and the Lambek calculus
4
+ (:mod:`~unicode_logic_kit.atp.lambek`) decide derivability between formulas built from
5
+ CATEGORIES by the calculus' own connectives. "No derivation" is a statement about a sequent
6
+ the calculus can state, so each calculus reads exactly the node classes it has rules for, and
7
+ refuses every other node by name.
8
+
9
+ What each calculus reads (the two allow-lists, :data:`ILL` and :data:`LAMBEK`):
10
+
11
+ * intuitionistic linear logic: the connectives ``⊗`` (``Tensor``), ``&`` (``With``), ``⊕``
12
+ (``OPlus``), ``⊸`` (``LinearImplies``), ``!`` (``OfCourse``) and the units ``𝟙`` (``One``),
13
+ ``⊤`` (``Top``), ``𝟘`` (``Zero``), over atoms;
14
+ * the Lambek calculus: the connectives ``•`` (``Product``), ``\\`` (``Under``) and ``/``
15
+ (``Over``), over atoms.
16
+
17
+ These are the node classes the two grammars (``MSFLParser(linear=True)`` and
18
+ ``MSFLParser(lambek=True)``) produce, and the classes the proof checkers and the Isabelle export
19
+ of the two calculi have rules for; nothing either grammar can write is refused. An atom is read
20
+ with its terms (variables, constants, numerals and function terms) as written.
21
+
22
+ Both calculi are propositional: a sequent has no individuals to quantify over, no counting and
23
+ no identity. An atom over terms (``P(alpha)``, ``Loves(john, mary)``, ``Q(f(x))``, a free
24
+ variable included) is read as ONE category, identified by its predicate and its terms as
25
+ written. That reading is sound in both directions: a quantifier-free, equality-free sequent has
26
+ no rule that substitutes a term for another, so its first-order derivations and its
27
+ propositional derivations over those categories are the same derivations, and a sequent with no
28
+ derivation of the one kind has none of the other.
29
+
30
+ Every other node is refused, in three kinds.
31
+
32
+ * A quantifier, a counting or cardinality node, a sorted constant. Read as one more opaque
33
+ category they make a derivability verdict about ANOTHER formula: ``∀x P(x) ⊢ P(alpha)``
34
+ holds in first-order linear logic (instantiation) and has no derivation between the two
35
+ categories ``∀x P(x)`` and ``P(alpha)``. A sorted constant ``c:S`` asserts ``S(c)``, which the
36
+ category reading drops.
37
+ * An equality or disequality atom: ``⊢ alpha = alpha`` holds with identity and has no derivation
38
+ between categories.
39
+ * A node of any other logic: a classical connective (``And``, ``Or``, ``Not``, ``Implies``,
40
+ ``Iff``, ``Xor``), a modal, temporal, epistemic or hybrid operator, a connective of the other
41
+ calculus, a lambda, an application or a predicate in argument position (the lambda layer is
42
+ the one thing both grammars write besides their connectives and atoms: ``(λx. P(x))(a) ⊢ P(a)``
43
+ holds by beta reduction and has no derivation between the category of an application and the
44
+ category ``P(a)``). Neither calculus has a rule for it; ``And(A, B) ⊢ A`` holds classically
45
+ and has no derivation between the categories ``And(A, B)`` and ``A``. A term (a variable, a
46
+ constant, a numeral, a function term) where a formula stands is refused as well: it is not
47
+ an atom, and only an atom is a category.
48
+
49
+ :func:`refuse_unreadable_input` names such a node, its class and the calculus, lists the
50
+ connectives the calculus has, and says what to do instead.
51
+ """
52
+
53
+ from dataclasses import dataclass
54
+ from typing import Iterable, Optional, Tuple
55
+
56
+ from ..fol._linear_nodes import Top, Zero
57
+ from ..fol.nodes import (
58
+ Atom, Cardinality, Constant, Count, Function, LinearImplies, Node, Number, OfCourse, One,
59
+ OPlus, Over, Product, Quantifier, SecondOrderQuantifier, SlashedExists, SortedCardinality,
60
+ SortedConstant, SortedCount, SortedQuantifier, Tensor, Under, Variable, With,
61
+ )
62
+ from ..semantics._modal_reject import is_equality_atom
63
+
64
+ __all__ = ["Calculus", "ILL", "LAMBEK", "refuse_unreadable_input", "unreadable_reason"]
65
+
66
+
67
+ @dataclass(frozen=True)
68
+ class Calculus:
69
+ """A propositional substructural calculus, by what it has rules for.
70
+
71
+ Fields:
72
+
73
+ * ``name``: how a message calls the calculus.
74
+ * ``connectives``: the node classes the calculus has rules for (atoms are read besides).
75
+ * ``glyphs``: those connectives as the calculus' own grammar writes them.
76
+ """
77
+
78
+ name: str
79
+ connectives: Tuple[type, ...]
80
+ glyphs: str
81
+
82
+
83
+ #: Intuitionistic linear logic: the connectives of the ``linear`` grammar.
84
+ ILL = Calculus(
85
+ "intuitionistic linear logic",
86
+ (Tensor, With, OPlus, LinearImplies, OfCourse, One, Top, Zero),
87
+ "⊗ & ⊕ ⊸ ! 𝟙 ⊤ 𝟘")
88
+
89
+ #: The Lambek calculus: the connectives of the ``lambek`` grammar.
90
+ LAMBEK = Calculus("the Lambek calculus", (Product, Under, Over), "• \\ /")
91
+
92
+ #: The node classes of an atom's terms, read as written inside the category.
93
+ _TERMS: Tuple[type, ...] = (Variable, Constant, Number, Function)
94
+
95
+ #: The first-order node classes refused wherever they stand, with what each is called in a message.
96
+ _FIRST_ORDER: Tuple[Tuple[Tuple[type, ...], str], ...] = (
97
+ ((Quantifier, SortedQuantifier, SecondOrderQuantifier, SlashedExists), "quantifier"),
98
+ ((Count, SortedCount), "counting quantifier"),
99
+ ((Cardinality, SortedCardinality), "cardinality term"),
100
+ ((SortedConstant,), "sorted constant"),
101
+ )
102
+
103
+ #: The longest rendering of a refused node a message quotes.
104
+ _QUOTE_LIMIT = 100
105
+
106
+
107
+ def _first_order_label(node: Node) -> Optional[str]:
108
+ """What a first-order node is called, or ``None`` for any other node."""
109
+ for classes, label in _FIRST_ORDER:
110
+ if isinstance(node, classes):
111
+ return label
112
+ return None
113
+
114
+
115
+ def _quote(node: Node) -> str:
116
+ """The node's own rendering, shortened for a message."""
117
+ text = node.to_unicode_str()
118
+ return text if len(text) <= _QUOTE_LIMIT else text[:_QUOTE_LIMIT - 1] + "…"
119
+
120
+
121
+ def _outside(node: Node, calculus: Calculus, formula_position: bool = True) -> Optional[Node]:
122
+ """The first node, in pre-order, that is not read where it stands, or ``None``.
123
+
124
+ A formula is an atom or a connective of the calculus whose operands are formulas; the
125
+ arguments of an atom are terms (variables, constants, numerals and function terms over
126
+ terms). Any other node, and a term where a formula stands, is outside.
127
+ """
128
+ if formula_position:
129
+ if isinstance(node, Atom):
130
+ operands, operand_position = node._child_nodes(), False
131
+ elif isinstance(node, calculus.connectives):
132
+ operands, operand_position = node._child_nodes(), True
133
+ else:
134
+ return node
135
+ elif isinstance(node, _TERMS):
136
+ operands, operand_position = node._child_nodes(), False
137
+ else:
138
+ return node
139
+ for operand in operands:
140
+ found = _outside(operand, calculus, operand_position)
141
+ if found is not None:
142
+ return found
143
+ return None
144
+
145
+
146
+ #: The kinds of refusal, in the order they are looked for.
147
+ _FIRST_ORDER_KIND, _OUTSIDE_KIND, _IDENTITY_KIND = "first order", "outside", "identity"
148
+
149
+
150
+ def _first_refused(formulas: Tuple[Node, ...], calculus: Calculus) -> Optional[Tuple[Node, str, str]]:
151
+ """The first node ``calculus`` cannot read, what it is called, and the kind of refusal it gets.
152
+
153
+ The kinds, in the order they are looked for: first order (a quantifier, a count, a
154
+ cardinality, a sorted constant), outside (a node of another logic, or a term where a formula
155
+ stands), identity (an equality or disequality atom). An identity atom that merely holds a
156
+ refused term (``|{v : P(v)}| = 2``) is reported through that term, which says more than the
157
+ comparison around it, and a quantifier that holds a classical connective is reported as the
158
+ quantifier.
159
+ """
160
+ nodes = [node for formula in formulas for node in formula.walk()]
161
+ for node in nodes:
162
+ label = _first_order_label(node)
163
+ if label is not None:
164
+ return node, label, _FIRST_ORDER_KIND
165
+ for formula in formulas:
166
+ outside = _outside(formula, calculus)
167
+ if outside is not None:
168
+ label = "term where a formula stands" if isinstance(outside, _TERMS) else "node of another logic"
169
+ return outside, label, _OUTSIDE_KIND
170
+ for node in nodes:
171
+ if is_equality_atom(node):
172
+ return node, "equality atom" if node.predicate == "=" else "disequality atom", _IDENTITY_KIND
173
+ return None
174
+
175
+
176
+ def unreadable_reason(formulas: Iterable[Node], route: str, calculus: Calculus) -> Optional[str]:
177
+ """Why ``calculus`` cannot read ``formulas``, or ``None`` when it can.
178
+
179
+ The text :func:`refuse_unreadable_input` raises, for a caller that reports a refusal as an
180
+ answer instead of an exception (a backend, a proof checker).
181
+ """
182
+ found = _first_refused(tuple(formulas), calculus)
183
+ if found is None:
184
+ return None
185
+ node, what, kind = found
186
+ name = type(node).__name__
187
+ head = (f"{route}: the {what} {_quote(node)!r} ({name}) is refused by name — "
188
+ f"{calculus.name} has the connectives {calculus.glyphs} over categories")
189
+ if kind != _OUTSIDE_KIND:
190
+ return (
191
+ f"{head}, with no individuals, quantifiers, counting, sorts or identity, and reading "
192
+ "the node as one more opaque category would answer about another formula "
193
+ "(∀x P(x) ⊢ P(alpha) holds in every first-order reading and has no derivation "
194
+ "between the two categories). Decide it with a first-order route (z3, vampire, "
195
+ "eprover, tableau, resolution), or write the category as an atom over terms, "
196
+ "without the quantifier, count, sort or identity.")
197
+ if isinstance(node, _TERMS):
198
+ return (
199
+ f"{head}, and a term is not one of them: reading {name} as a category would answer "
200
+ "about another formula. Write the category as an atom, a predicate over terms.")
201
+ return (
202
+ f"{head}, and has no rule for {name}: it belongs to another logic (or to the lambda "
203
+ "layer every grammar shares), and "
204
+ "reading it as one more opaque category would answer about another formula "
205
+ "(And(A, B) ⊢ A holds classically and has no derivation between the categories "
206
+ "And(A, B) and A). Decide it with a route of the logic the node belongs to "
207
+ "(list_backends names them), or write it with the connectives "
208
+ f"{calculus.glyphs} of {calculus.name}.")
209
+
210
+
211
+ def refuse_unreadable_input(formulas: Iterable[Node], route: str, calculus: Calculus) -> None:
212
+ """Raise ``NotImplementedError`` naming the first node ``calculus`` cannot read, if any.
213
+
214
+ ``formulas`` are the antecedent formulas and the goal of one sequent. ``calculus`` reads the
215
+ node classes it has rules for (:data:`ILL`, :data:`LAMBEK`) and atoms over terms; a
216
+ quantifier (sorted, second-order or slashed), a counting or cardinality node, a sorted
217
+ constant, an equality or disequality atom and a node of any other logic are refused (see the
218
+ module docstring for the two allow-lists and for why an atom over terms is sound). ``route``
219
+ names the function or backend that refuses. The message quotes the node, names its class and
220
+ the calculus, lists the connectives the calculus has and says what to do instead. Returns
221
+ ``None`` when every formula is readable.
222
+
223
+ Raises:
224
+ NotImplementedError: a node of one of the refused kinds occurs in ``formulas``.
225
+ """
226
+ reason = unreadable_reason(formulas, route, calculus)
227
+ if reason is not None:
228
+ raise NotImplementedError(reason)