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,289 @@
1
+ """What the whole-problem TPTP writers share: premise names and the entry point's name.
2
+
3
+ Every whole-problem writer (the ``fof`` writer in :mod:`~unicode_logic_kit.atp._tptp_problem`,
4
+ the TF0 writer in :mod:`~unicode_logic_kit.atp.tptp_tff` and the TFA writer in
5
+ :mod:`~unicode_logic_kit.atp._tff_problem`) writes one ``axiom`` line per premise. By default
6
+ the lines are called ``premise_1``, ``premise_2``, ... and ``premise_names=`` lets a caller
7
+ name them, so that what a prover prints about its proof (the axioms it used) can be read
8
+ as the caller's own names: a TPTP library problem keeps the names of its axioms, and an
9
+ application that holds its premises under identifiers wants them back.
10
+
11
+ **What is written.** A name is a TPTP ``<name>``: a lower-case word
12
+ (``[a-z][A-Za-z0-9_]*``) or an unsigned integer without leading zeros is written as it
13
+ is, and anything else is a single-quoted word in which ``\\`` and ``'`` are escaped
14
+ (``it's`` is written ``'it\\'s'``). A name that no TPTP name can spell is refused: the
15
+ empty name, a name with a control character (a line break would end the statement, and the
16
+ TPTP grammar of a quoted word has no spelling for a character below the space), and a
17
+ string that cannot be encoded as UTF-8 (a lone surrogate). A non-ASCII letter is written
18
+ as it is: Vampire and E read UTF-8 and print it back unchanged.
19
+
20
+ **What is checked.** The names are pairwise distinct AS WRITTEN, and each is distinct from
21
+ every name the writer generates for the other lines of the problem (the conjecture
22
+ ``goal``, the non-emptiness line of a sort, the membership line of a sorted constant, the
23
+ type declarations). A clash is a ``ValueError`` that names both. A name that a prover's
24
+ OWN output uses for something else is refused too (:func:`prover_own_name`): Vampire prints
25
+ ``unknown`` for an axiom whose name it does not know and numbers its statements ``f1``,
26
+ ``f2``, ..., and E names the clauses it derives ``c_0_5`` and ``i_0_5``; a premise called
27
+ by one of these would be read back as another formula.
28
+
29
+ **What comes back.** The writer returns a
30
+ :class:`~unicode_logic_kit.atp._tptp_problem.TptpNameMap`, which records the premise names
31
+ in order (also the default ones) and the names and meaning of the background axioms the
32
+ writer added. :func:`axiom_leaf_label` and :func:`match_premise_label` read a prover's
33
+ printed axiom names against that record.
34
+
35
+ **What a prover prints.** Vampire echoes the name of an axiom only when asked
36
+ (``--output_axiom_names on``) and then in the second argument of the leaf's ``file(...)``
37
+ source; E prints the name as the statement name and in that argument too. Measured on
38
+ Vampire 5.0.1 and E 3.5.1: both print a quoted name back unchanged, except that E reads a
39
+ backslash followed by any character as one backslash, so an apostrophe in a name comes
40
+ back from E as a backslash (``it's`` is printed ``it\\s``). :func:`match_premise_label`
41
+ takes that into account when it is told the prover is E and refuses to choose between
42
+ two names that E would print alike.
43
+
44
+ **The entry point's name.** A refusal of a whole-problem writer starts with the name of the
45
+ function the caller called (:func:`refusals_speak_as`).
46
+ """
47
+
48
+ import contextlib
49
+ import re
50
+ from typing import Dict, Iterable, Iterator, List, Optional, Sequence, Tuple
51
+
52
+ __all__: List[str] = []
53
+
54
+ #: A TPTP lower word, which is a name as it stands.
55
+ _LOWER_WORD = re.compile(r"[a-z][A-Za-z0-9_]*")
56
+
57
+ #: An unsigned integer without leading zeros, which is a TPTP name as it stands.
58
+ _INTEGER = re.compile(r"0|[1-9][0-9]*")
59
+
60
+
61
+ def default_premise_names(count: int) -> Tuple[str, ...]:
62
+ """``premise_1`` ... ``premise_<count>``: the names every writer uses by default."""
63
+ return tuple(f"premise_{i}" for i in range(1, count + 1))
64
+
65
+
66
+ def names_kwargs(premise_names: Optional[Sequence[str]]) -> Dict[str, Sequence[str]]:
67
+ """``{"premise_names": premise_names}``, or ``{}`` when it is ``None``: a caller that
68
+ forwards the argument to a writer it did not write passes it only when it was given."""
69
+ return {} if premise_names is None else {"premise_names": premise_names}
70
+
71
+
72
+ def tptp_name_token(name: str) -> str:
73
+ """The TPTP spelling of ``name`` (see the module docstring): the name itself when it
74
+ is a lower word or an unsigned integer, otherwise a single-quoted word with ``\\`` and
75
+ ``'`` escaped. ``name`` must be a name :func:`normalise_premise_names` accepts."""
76
+ if _LOWER_WORD.fullmatch(name) or _INTEGER.fullmatch(name):
77
+ return name
78
+ return "'" + name.replace("\\", "\\\\").replace("'", "\\'") + "'"
79
+
80
+
81
+ def decode_tptp_name(token: str) -> str:
82
+ """The text a TPTP name token stands for: a single-quoted word without its quotes and
83
+ with ``\\\\`` read as ``\\`` and ``\\'`` as ``'``; any other token (a lower word, an
84
+ integer) as it is. A backslash before any other character is kept as it is."""
85
+ token = token.strip()
86
+ if len(token) >= 2 and token[0] == "'" and token[-1] == "'":
87
+ out: List[str] = []
88
+ body = token[1:-1]
89
+ i = 0
90
+ while i < len(body):
91
+ c = body[i]
92
+ if c == "\\" and i + 1 < len(body) and body[i + 1] in ("\\", "'"):
93
+ out.append(body[i + 1])
94
+ i += 2
95
+ else:
96
+ out.append(c)
97
+ i += 1
98
+ return "".join(out)
99
+ return token
100
+
101
+
102
+ #: Names a prover's output uses for something of its own, with what each is. Measured on
103
+ #: Vampire 5.0.1 and E 3.5.1: Vampire prints ``unknown`` as the name of an axiom it was not
104
+ #: told the name of, and names its statements ``f<k>`` (and the ``sat_conversion`` ones
105
+ #: ``s<k>``); E keeps the names of the problem's axioms and calls every clause it derives
106
+ #: ``c_<i>_<j>`` (``i_<i>_<j>`` in some of its strategies).
107
+ _PROVER_OWN_NAMES = (
108
+ (re.compile(r"unknown"), "the word Vampire prints for an axiom whose name it does not know"),
109
+ (re.compile(r"f[0-9]+"), "a name Vampire gives its own statements (f1, f2, ...)"),
110
+ (re.compile(r"[ci]_[0-9]+_[0-9]+"), "a name E gives the clauses it derives (c_0_5, i_0_5)"),
111
+ )
112
+
113
+
114
+ def prover_own_name(name: str) -> Optional[str]:
115
+ """What a prover uses ``name`` for in its own output (a sentence), or ``None`` when it is
116
+ not a name the provers use: the name of a premise must not be one, because the premise
117
+ that a proof's leaf is read as is decided by the name the prover prints for it."""
118
+ for pattern, what in _PROVER_OWN_NAMES:
119
+ if pattern.fullmatch(name):
120
+ return what
121
+ return None
122
+
123
+
124
+ def _unspellable(name: str) -> Optional[str]:
125
+ """Why no TPTP name spells ``name``, or ``None`` when one does."""
126
+ if name == "":
127
+ return "it is empty"
128
+ for ch in name:
129
+ if ord(ch) < 0x20 or ord(ch) == 0x7F:
130
+ return (f"it contains the control character U+{ord(ch):04X}, which a TPTP "
131
+ "quoted name cannot spell")
132
+ try:
133
+ name.encode("utf-8")
134
+ except UnicodeEncodeError:
135
+ return "it cannot be encoded as UTF-8 (it contains a lone surrogate)"
136
+ return None
137
+
138
+
139
+ def normalise_premise_names(premise_names: Optional[Sequence[str]], count: int,
140
+ *, where: str) -> Tuple[str, ...]:
141
+ """The names of ``count`` premises: ``premise_names`` checked, or the default ones.
142
+
143
+ Raises:
144
+ TypeError: ``premise_names`` is one string rather than a sequence of strings, or
145
+ one of its entries is not a string.
146
+ ValueError: it holds other than one name per premise, a name no TPTP name spells
147
+ (see the module docstring), a name a prover uses in its own output
148
+ (:func:`prover_own_name`), or two names that are the same as written.
149
+ """
150
+ if premise_names is None:
151
+ return default_premise_names(count)
152
+ if isinstance(premise_names, (str, bytes)):
153
+ raise TypeError(
154
+ f"{where}: premise_names is a sequence of strings, one per premise; got the "
155
+ f"single {type(premise_names).__name__} {premise_names!r}")
156
+ names = tuple(premise_names)
157
+ for i, name in enumerate(names):
158
+ if not isinstance(name, str):
159
+ raise TypeError(
160
+ f"{where}: premise_names[{i}] must be a string, got "
161
+ f"{type(name).__name__} {name!r}")
162
+ if len(names) != count:
163
+ raise ValueError(
164
+ f"{where}: premise_names must hold one name per premise, but there "
165
+ f"{'is' if count == 1 else 'are'} {count} premise{'' if count == 1 else 's'} "
166
+ f"and {len(names)} name{'' if len(names) == 1 else 's'}")
167
+ written: Dict[str, int] = {}
168
+ for i, name in enumerate(names):
169
+ why = _unspellable(name)
170
+ if why is not None:
171
+ raise ValueError(f"{where}: premise_names[{i}] = {name!r} is not a premise "
172
+ f"name: {why}")
173
+ own = prover_own_name(name)
174
+ if own is not None:
175
+ raise ValueError(
176
+ f"{where}: premise_names[{i}] = {name!r} is {own}, so a proof that uses this "
177
+ "premise could be read as using another; give the premise another name")
178
+ token = tptp_name_token(name)
179
+ if token in written:
180
+ raise ValueError(
181
+ f"{where}: premise_names[{written[token]}] and premise_names[{i}] are "
182
+ f"both {name!r}, which is written {token}; premise names must be pairwise "
183
+ "distinct as written")
184
+ written[token] = i
185
+ return names
186
+
187
+
188
+ def name_background_premises(premise_names: Sequence[str], given: int, total: int,
189
+ *, where: str) -> Tuple[str, ...]:
190
+ """``premise_names`` for ``given`` premises, extended by one name for each of the
191
+ ``total - given`` premises a caller's routine appended after them.
192
+
193
+ The sentences a signature declares (``api.prove(signature=...)``) and the side axioms
194
+ of a :class:`~unicode_logic_kit.logic.Sentence` follow the premises the caller passed.
195
+ The caller names the premises it passed; the others are background, named
196
+ ``background_<k>`` (``k`` from 1) by the writer, with ``_`` appended to a name that is
197
+ already one of the caller's, as written. ``premise_names`` is checked as every writer
198
+ checks it (:func:`normalise_premise_names`) against ``given``, and the message names
199
+ ``where``.
200
+
201
+ Raises:
202
+ TypeError: ``premise_names`` is one string rather than a sequence of strings, or
203
+ one of its entries is not a string.
204
+ ValueError: it holds other than ``given`` names, a name no TPTP name spells, a name a
205
+ prover uses in its own output (:func:`prover_own_name`), or two names that are the
206
+ same as written.
207
+ """
208
+ names = normalise_premise_names(premise_names, given, where=where)
209
+ taken = {tptp_name_token(name) for name in names}
210
+ extended = list(names)
211
+ for k in range(1, total - given + 1):
212
+ candidate = f"background_{k}"
213
+ while tptp_name_token(candidate) in taken:
214
+ candidate += "_"
215
+ taken.add(tptp_name_token(candidate))
216
+ extended.append(candidate)
217
+ return tuple(extended)
218
+
219
+
220
+ def check_against_generated(names: Sequence[str], generated: Iterable[Tuple[str, str]],
221
+ *, where: str) -> None:
222
+ """Refuse a premise name that is one of the names the writer gives its own lines.
223
+
224
+ ``generated`` holds ``(written name, what the writer uses it for)`` for every other
225
+ line of the problem. Raises ``ValueError`` naming the premise and the line."""
226
+ used = {tptp_name_token(name): i for i, name in enumerate(names)}
227
+ for written, what in generated:
228
+ i = used.get(written)
229
+ if i is not None:
230
+ raise ValueError(
231
+ f"{where}: premise_names[{i}] = {names[i]!r} is the name the writer gives "
232
+ f"{what} ({written}); give the premise another name")
233
+
234
+
235
+ def axiom_leaf_label(name_token: str, source_text: Optional[str]) -> str:
236
+ """The name under which the problem called an axiom leaf of a proof, as printed.
237
+
238
+ E names the statement after the axiom, and Vampire (asked for axiom names) puts the
239
+ name in the second argument of the ``file(path, name)`` source of a leaf whose own
240
+ name is its running number. A ``file(...)`` source that names nothing (Vampire without
241
+ the option prints the word ``unknown``) leaves the statement's own name."""
242
+ if source_text is not None and source_text.startswith("file(") and source_text.endswith(")"):
243
+ from .tstp import _split_top_level
244
+ fields = _split_top_level(source_text[len("file("):-1])
245
+ if len(fields) >= 2 and fields[1].strip() not in ("", "unknown"):
246
+ return decode_tptp_name(fields[1])
247
+ return decode_tptp_name(name_token)
248
+
249
+
250
+ def _as_eprover_prints(name: str) -> str:
251
+ """What E prints for the premise ``name``: it reads a backslash and the character after
252
+ it as one backslash, so every apostrophe of the written name (``\\'``) is a backslash."""
253
+ return name.replace("'", "\\")
254
+
255
+
256
+ def match_premise_label(label: str, names: Sequence[str],
257
+ *, eprover: bool = False) -> Optional[int]:
258
+ """The 0-based index of the premise a printed axiom ``label`` names, or ``None``.
259
+
260
+ ``label`` is the decoded name a prover printed (:func:`axiom_leaf_label`). With
261
+ ``eprover=True`` the premise names are compared as E prints them (see the module
262
+ docstring), and a label that two or more premises would be printed as is not matched
263
+ (``None``): the proof does not say which of them it used."""
264
+ if not eprover:
265
+ for i, name in enumerate(names):
266
+ if name == label:
267
+ return i
268
+ return None
269
+ hits = [i for i, name in enumerate(names) if _as_eprover_prints(name) == label]
270
+ return hits[0] if len(hits) == 1 else None
271
+
272
+
273
+ @contextlib.contextmanager
274
+ def refusals_speak_as(own: str, default: str) -> Iterator[None]:
275
+ """Word the refusals raised inside the block as coming from ``own``.
276
+
277
+ A writer's inner checks open their messages with the name of the writer function they
278
+ were written for (``default``); a caller of another entry point over the same checks
279
+ (``generate_tff_problem_with_mapping`` over the body of ``generate_tff_problem``) is
280
+ told its own name instead. Only a message that opens with ``default`` and a colon is
281
+ changed, so the message of a check of another layer (``Node.to_tptp: ...``) stays as
282
+ it is; the exception keeps its class, its other arguments and its traceback."""
283
+ try:
284
+ yield
285
+ except (NotImplementedError, ValueError) as exc:
286
+ prefix = default + ":"
287
+ if exc.args and isinstance(exc.args[0], str) and exc.args[0].startswith(prefix):
288
+ exc.args = (own + exc.args[0][len(default):],) + exc.args[1:]
289
+ raise