unicode-logic-kit 0.31.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- unicode_logic_kit/__init__.py +385 -0
- unicode_logic_kit/__main__.py +520 -0
- unicode_logic_kit/_deadline.py +219 -0
- unicode_logic_kit/ace/__init__.py +126 -0
- unicode_logic_kit/ace/_align.py +135 -0
- unicode_logic_kit/ace/chem_lexicon.py +128 -0
- unicode_logic_kit/ace/drs_reader.py +570 -0
- unicode_logic_kit/ace/mapping.py +666 -0
- unicode_logic_kit/ace/reverse_modal.py +138 -0
- unicode_logic_kit/ace/runner.py +551 -0
- unicode_logic_kit/ace/translate.py +452 -0
- unicode_logic_kit/ace/verbalize.py +1070 -0
- unicode_logic_kit/api.py +1284 -0
- unicode_logic_kit/atp/__init__.py +177 -0
- unicode_logic_kit/atp/_ascii_names.py +113 -0
- unicode_logic_kit/atp/_html.py +72 -0
- unicode_logic_kit/atp/_substructural_input.py +228 -0
- unicode_logic_kit/atp/_tff_problem.py +715 -0
- unicode_logic_kit/atp/_tptp_problem.py +1111 -0
- unicode_logic_kit/atp/_writer_support.py +289 -0
- unicode_logic_kit/atp/clingo_backend.py +1180 -0
- unicode_logic_kit/atp/cvc5_backend.py +1385 -0
- unicode_logic_kit/atp/eprover_backend.py +732 -0
- unicode_logic_kit/atp/finite_domain.py +1055 -0
- unicode_logic_kit/atp/fitch.py +1547 -0
- unicode_logic_kit/atp/fitch_search.py +551 -0
- unicode_logic_kit/atp/hets_backend.py +339 -0
- unicode_logic_kit/atp/hybrid_down.py +120 -0
- unicode_logic_kit/atp/incremental.py +250 -0
- unicode_logic_kit/atp/kripke_enum.py +741 -0
- unicode_logic_kit/atp/lambek.py +436 -0
- unicode_logic_kit/atp/leo3_backend.py +332 -0
- unicode_logic_kit/atp/linear.py +738 -0
- unicode_logic_kit/atp/lj.py +705 -0
- unicode_logic_kit/atp/logic_backends.py +566 -0
- unicode_logic_kit/atp/ltl_tableau.py +1084 -0
- unicode_logic_kit/atp/minizinc_backend.py +1402 -0
- unicode_logic_kit/atp/modal_tableau.py +1382 -0
- unicode_logic_kit/atp/nanocop_backend.py +410 -0
- unicode_logic_kit/atp/portfolio.py +489 -0
- unicode_logic_kit/atp/protocol.py +1803 -0
- unicode_logic_kit/atp/prover9_entailment.py +1153 -0
- unicode_logic_kit/atp/resolution.py +1376 -0
- unicode_logic_kit/atp/resolution_check.py +1114 -0
- unicode_logic_kit/atp/sequent.py +1050 -0
- unicode_logic_kit/atp/tableau.py +921 -0
- unicode_logic_kit/atp/tableau_check.py +543 -0
- unicode_logic_kit/atp/tptp_ncl.py +811 -0
- unicode_logic_kit/atp/tptp_tff.py +1546 -0
- unicode_logic_kit/atp/tstp.py +1333 -0
- unicode_logic_kit/atp/tstp_check.py +1096 -0
- unicode_logic_kit/atp/twee_backend.py +236 -0
- unicode_logic_kit/atp/twee_check.py +711 -0
- unicode_logic_kit/atp/twee_entailment.py +953 -0
- unicode_logic_kit/atp/vampire_entailment.py +540 -0
- unicode_logic_kit/atp/z3_arith.py +470 -0
- unicode_logic_kit/atp/z3_equivalence.py +36 -0
- unicode_logic_kit/atp/z3_fuzzy.py +362 -0
- unicode_logic_kit/atp/z3_input.py +500 -0
- unicode_logic_kit/atp/z3_models.py +208 -0
- unicode_logic_kit/chem/__init__.py +88 -0
- unicode_logic_kit/chem/_naming.py +284 -0
- unicode_logic_kit/chem/cache.py +185 -0
- unicode_logic_kit/chem/interop.py +244 -0
- unicode_logic_kit/chem/mol.py +525 -0
- unicode_logic_kit/chem/signature.py +112 -0
- unicode_logic_kit/comorphism.py +497 -0
- unicode_logic_kit/dl/__init__.py +384 -0
- unicode_logic_kit/dl/classification.py +227 -0
- unicode_logic_kit/dl/concepts.py +632 -0
- unicode_logic_kit/dl/datatypes.py +818 -0
- unicode_logic_kit/dl/owl_functional.py +2433 -0
- unicode_logic_kit/dl/owl_manchester.py +1637 -0
- unicode_logic_kit/dl/owl_reasoner.py +790 -0
- unicode_logic_kit/dl/parser.py +391 -0
- unicode_logic_kit/dl/tableau.py +4048 -0
- unicode_logic_kit/dl/translate.py +2704 -0
- unicode_logic_kit/drt/__init__.py +94 -0
- unicode_logic_kit/drt/export.py +179 -0
- unicode_logic_kit/drt/nodes.py +506 -0
- unicode_logic_kit/drt/parser.py +965 -0
- unicode_logic_kit/drt/resolve.py +195 -0
- unicode_logic_kit/drt/reverse.py +175 -0
- unicode_logic_kit/eval/__init__.py +106 -0
- unicode_logic_kit/eval/batch.py +382 -0
- unicode_logic_kit/eval/canonical.py +663 -0
- unicode_logic_kit/eval/chem_batch.py +606 -0
- unicode_logic_kit/eval/converses.py +200 -0
- unicode_logic_kit/eval/datasets/__init__.py +136 -0
- unicode_logic_kit/eval/datasets/_base.py +263 -0
- unicode_logic_kit/eval/datasets/_proofwriter_proof.py +422 -0
- unicode_logic_kit/eval/datasets/c3po.py +678 -0
- unicode_logic_kit/eval/datasets/folio.py +158 -0
- unicode_logic_kit/eval/datasets/fracas.py +418 -0
- unicode_logic_kit/eval/datasets/groves.py +191 -0
- unicode_logic_kit/eval/datasets/logicbench.py +467 -0
- unicode_logic_kit/eval/datasets/logicnli.py +303 -0
- unicode_logic_kit/eval/datasets/malls.py +133 -0
- unicode_logic_kit/eval/datasets/pfolio.py +594 -0
- unicode_logic_kit/eval/datasets/pmb.py +242 -0
- unicode_logic_kit/eval/datasets/prontoqa.py +611 -0
- unicode_logic_kit/eval/datasets/proofwriter.py +1431 -0
- unicode_logic_kit/eval/datasets/proverqa.py +674 -0
- unicode_logic_kit/eval/datasets/willow.py +478 -0
- unicode_logic_kit/eval/equivalence.py +466 -0
- unicode_logic_kit/eval/exercise_gen.py +533 -0
- unicode_logic_kit/eval/explain.py +791 -0
- unicode_logic_kit/eval/generality.py +750 -0
- unicode_logic_kit/eval/metric_hf.py +458 -0
- unicode_logic_kit/eval/predicate_match.py +343 -0
- unicode_logic_kit/eval/theory_check.py +1170 -0
- unicode_logic_kit/eval/validate.py +306 -0
- unicode_logic_kit/fol/__init__.py +177 -0
- unicode_logic_kit/fol/_atom_keys.py +510 -0
- unicode_logic_kit/fol/_fol_nodes.py +3586 -0
- unicode_logic_kit/fol/_free_parameters.py +105 -0
- unicode_logic_kit/fol/_ho_nodes.py +448 -0
- unicode_logic_kit/fol/_hybrid_nodes.py +308 -0
- unicode_logic_kit/fol/_identifiers.py +1091 -0
- unicode_logic_kit/fol/_lambek_nodes.py +112 -0
- unicode_logic_kit/fol/_linear_nodes.py +352 -0
- unicode_logic_kit/fol/_modal_nodes.py +1467 -0
- unicode_logic_kit/fol/_msfl_nodes.py +2196 -0
- unicode_logic_kit/fol/_numeral_symbols.py +231 -0
- unicode_logic_kit/fol/_so_nodes.py +200 -0
- unicode_logic_kit/fol/_symbol_names.py +81 -0
- unicode_logic_kit/fol/_team_nodes.py +181 -0
- unicode_logic_kit/fol/_tptp_symbols.py +551 -0
- unicode_logic_kit/fol/_truth_constants.py +117 -0
- unicode_logic_kit/fol/casl_export.py +1135 -0
- unicode_logic_kit/fol/casl_import.py +929 -0
- unicode_logic_kit/fol/derivation.py +367 -0
- unicode_logic_kit/fol/dialect_detect.py +70 -0
- unicode_logic_kit/fol/dialect_repair.py +537 -0
- unicode_logic_kit/fol/frames.py +637 -0
- unicode_logic_kit/fol/grammars/terminals.lark +31 -0
- unicode_logic_kit/fol/lambda_tools.py +297 -0
- unicode_logic_kit/fol/latex_input.py +429 -0
- unicode_logic_kit/fol/modal_translation.py +944 -0
- unicode_logic_kit/fol/msflparser.py +1033 -0
- unicode_logic_kit/fol/naming.py +422 -0
- unicode_logic_kit/fol/nodes.py +241 -0
- unicode_logic_kit/fol/normalforms.py +492 -0
- unicode_logic_kit/fol/pal.py +287 -0
- unicode_logic_kit/fol/prolog_export.py +566 -0
- unicode_logic_kit/fol/prolog_input.py +505 -0
- unicode_logic_kit/fol/prover9_input.py +1325 -0
- unicode_logic_kit/fol/qml.py +1760 -0
- unicode_logic_kit/fol/qmltp_input.py +525 -0
- unicode_logic_kit/fol/sanitize.py +221 -0
- unicode_logic_kit/fol/serialize.py +79 -0
- unicode_logic_kit/fol/signature.py +1290 -0
- unicode_logic_kit/fol/simplify_check.py +544 -0
- unicode_logic_kit/fol/spans.py +594 -0
- unicode_logic_kit/fol/tptp_input.py +1503 -0
- unicode_logic_kit/fol/tptp_repair.py +941 -0
- unicode_logic_kit/fol/unification.py +157 -0
- unicode_logic_kit/fol/verbalize.py +263 -0
- unicode_logic_kit/hets/__init__.py +163 -0
- unicode_logic_kit/hets/bridge.py +142 -0
- unicode_logic_kit/hets/client.py +748 -0
- unicode_logic_kit/hets/docker.py +420 -0
- unicode_logic_kit/hets/dol.py +712 -0
- unicode_logic_kit/hets/haskell_json.py +355 -0
- unicode_logic_kit/hets/owl_backend.py +794 -0
- unicode_logic_kit/hets/owl_cli.py +598 -0
- unicode_logic_kit/hets/symbols.py +512 -0
- unicode_logic_kit/hol/__init__.py +140 -0
- unicode_logic_kit/hol/_ho_common.py +323 -0
- unicode_logic_kit/hol/_isabelle_binders.py +125 -0
- unicode_logic_kit/hol/classical.py +812 -0
- unicode_logic_kit/hol/deepshallow/__init__.py +45 -0
- unicode_logic_kit/hol/deepshallow/_common.py +177 -0
- unicode_logic_kit/hol/deepshallow/conditional.py +225 -0
- unicode_logic_kit/hol/deepshallow/intuitionistic.py +181 -0
- unicode_logic_kit/hol/deepshallow/modal.py +217 -0
- unicode_logic_kit/hol/deepshallow/qml.py +406 -0
- unicode_logic_kit/hol/deepshallow/relevant.py +206 -0
- unicode_logic_kit/hol/free.py +753 -0
- unicode_logic_kit/hol/goedel.py +336 -0
- unicode_logic_kit/hol/ho_modal.py +1743 -0
- unicode_logic_kit/hol/intuitionistic.py +403 -0
- unicode_logic_kit/hol/isabelle_conditional.py +593 -0
- unicode_logic_kit/hol/isabelle_modal.py +1908 -0
- unicode_logic_kit/hol/isabelle_relevant.py +412 -0
- unicode_logic_kit/hol/isabelle_runner.py +1147 -0
- unicode_logic_kit/hol/isabelle_substructural.py +884 -0
- unicode_logic_kit/hol/lean.py +1018 -0
- unicode_logic_kit/hol/manyvalued.py +921 -0
- unicode_logic_kit/hol/secondorder.py +687 -0
- unicode_logic_kit/hol/thf_modal.py +941 -0
- unicode_logic_kit/hol/thirdorder.py +397 -0
- unicode_logic_kit/ilp/__init__.py +89 -0
- unicode_logic_kit/ilp/readback.py +389 -0
- unicode_logic_kit/ilp/separation.py +153 -0
- unicode_logic_kit/ilp/task.py +730 -0
- unicode_logic_kit/logic.py +163 -0
- unicode_logic_kit/mcp/__init__.py +28 -0
- unicode_logic_kit/mcp/__main__.py +5 -0
- unicode_logic_kit/mcp/chem_tools.py +1031 -0
- unicode_logic_kit/mcp/server.py +2453 -0
- unicode_logic_kit/mcp/syntax_spec.py +681 -0
- unicode_logic_kit/prob/__init__.py +53 -0
- unicode_logic_kit/prob/_bdd.py +225 -0
- unicode_logic_kit/prob/_column_gen.py +668 -0
- unicode_logic_kit/prob/distribution.py +686 -0
- unicode_logic_kit/prob/nilsson.py +470 -0
- unicode_logic_kit/py.typed +0 -0
- unicode_logic_kit/semantics/__init__.py +137 -0
- unicode_logic_kit/semantics/_modal_reject.py +156 -0
- unicode_logic_kit/semantics/action_models.py +466 -0
- unicode_logic_kit/semantics/asp_models.py +1200 -0
- unicode_logic_kit/semantics/conditional.py +580 -0
- unicode_logic_kit/semantics/dynamic_epistemic.py +95 -0
- unicode_logic_kit/semantics/free_logic.py +913 -0
- unicode_logic_kit/semantics/fuzzy.py +384 -0
- unicode_logic_kit/semantics/fuzzy_kripke.py +442 -0
- unicode_logic_kit/semantics/intuitionistic.py +581 -0
- unicode_logic_kit/semantics/kripke.py +1139 -0
- unicode_logic_kit/semantics/manyvalued.py +580 -0
- unicode_logic_kit/semantics/matrix.py +342 -0
- unicode_logic_kit/semantics/model_eval.py +1135 -0
- unicode_logic_kit/semantics/modelfinder.py +1036 -0
- unicode_logic_kit/semantics/nonmonotonic.py +372 -0
- unicode_logic_kit/semantics/relevant.py +331 -0
- unicode_logic_kit/semantics/secondorder.py +657 -0
- unicode_logic_kit/semantics/structures.py +352 -0
- unicode_logic_kit/semantics/tarski.py +975 -0
- unicode_logic_kit/semantics/team.py +315 -0
- unicode_logic_kit/semantics/team_translation.py +416 -0
- unicode_logic_kit/semantics/thirdorder.py +358 -0
- unicode_logic_kit/semantics/tnorm.py +85 -0
- unicode_logic_kit/semantics/truthtable.py +201 -0
- unicode_logic_kit-0.31.0.dist-info/METADATA +333 -0
- unicode_logic_kit-0.31.0.dist-info/RECORD +237 -0
- unicode_logic_kit-0.31.0.dist-info/WHEEL +4 -0
- unicode_logic_kit-0.31.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
"""Export to TPTP's Non-Classical Logic dialect (NXF) for the mono-modal alethic fragment,
|
|
2
|
+
now including its native QUANTIFIED sub-fragment.
|
|
3
|
+
|
|
4
|
+
TPTP's *classical* ``fof``/``tff`` syntax (:meth:`Node.to_tptp`) has no way to say
|
|
5
|
+
"this problem is modal" — a non-classical prover needs a companion **logic
|
|
6
|
+
specification** naming the logic and its parameters, plus new connective syntax
|
|
7
|
+
for the modal operators themselves. That companion dialect is **NXF**
|
|
8
|
+
("Non-Classical TFF"), defined by Steen & Sutcliffe's TPTP-World infrastructure
|
|
9
|
+
for non-classical logics. This module renders one Unicode-kit modal formula as a
|
|
10
|
+
complete, self-contained NXF problem: a ``logic`` role statement, one type
|
|
11
|
+
declaration per sort/constant/predicate the formula actually uses, and a
|
|
12
|
+
``conjecture`` role statement.
|
|
13
|
+
|
|
14
|
+
Sources (verified against primary/gold material BEFORE writing a line of this
|
|
15
|
+
module — see the individual choices below for what each one settled):
|
|
16
|
+
|
|
17
|
+
* Steen & Sutcliffe, "TPTP World Infrastructure for Non-classical Logics"
|
|
18
|
+
(arXiv:2508.09318, fetched 2026-08-12, re-fetched and cross-checked against
|
|
19
|
+
real ``.p`` files 2026-09-18 — see the correction note below) — the
|
|
20
|
+
logic-specification shape ``tff(name, logic, $modal == [ $domains == ...,
|
|
21
|
+
$designation == ..., $terms == ..., $modalities == ... ] ).`` with those
|
|
22
|
+
four EXACT key names; the long-form connective application
|
|
23
|
+
``{connective_name} @ (arg1, ..., argn)`` (so ``{$box} @ (p)`` / ``{$dia} @
|
|
24
|
+
(p)``); the SHORT forms for the unparameterised unary modal connectives,
|
|
25
|
+
``[.]`` for box and ``<.>`` for diamond, used exactly like a classical
|
|
26
|
+
prefix connective; and Table 2's ``$modal_system_X`` literal-token list.
|
|
27
|
+
* ``github.com/TPTPWorld/NonClassicalLogic`` (cloned locally 2026-09-18 to
|
|
28
|
+
read full, real, prover-exercised ``.p`` files rather than a paper's
|
|
29
|
+
abbreviated excerpts — every claim below was checked against this clone,
|
|
30
|
+
not assumed from the paper alone):
|
|
31
|
+
- ``LogicSpecifications/CorrectSpecifications.p`` — confirms the four-key
|
|
32
|
+
logic-spec form is accepted verbatim (``$domains == $constant,
|
|
33
|
+
$designation == $rigid, $terms == $local/$global, $modalities ==
|
|
34
|
+
$modal_system_S5``), and that ``$modal_system_S5`` / ``$modal_axiom_K``
|
|
35
|
+
/ ``$modal_axiom_T`` / ``$modal_axiom_5`` are literal system/axiom
|
|
36
|
+
names.
|
|
37
|
+
- ``ProblemBuilding/Archive/ClaudiaNalon/IJCAR2022-TPTP/k45_branch_p/
|
|
38
|
+
k45_branch_p.0001.p`` (a real K45 benchmark, i.e. actually fed to
|
|
39
|
+
provers) — the model this module follows for the PROPOSITIONAL modal
|
|
40
|
+
fragment: ``tff(name,logic, $modal == [ $modalities ==
|
|
41
|
+
$modal_system_K45 ] ).`` (``$domains``/``$designation``/``$terms``
|
|
42
|
+
omitted — moot with no quantifiers/individual terms present), one
|
|
43
|
+
``tff(<p>_decl,type,<p>: $o).`` per propositional letter, and the
|
|
44
|
+
short-form connectives used as plain prefix operators (``[.] z100``,
|
|
45
|
+
``<.> [.] y100`` chained with no parens between them) — i.e.
|
|
46
|
+
``[.]``/``<.>`` sit in the grammar at exactly the same position ``~``
|
|
47
|
+
does (see :mod:`fol.tptp_input`'s ``?unary: "~" unary | ...`` rule).
|
|
48
|
+
- ``ProblemBuilding/QMLTP/7_QMLTPTP/SYM/SYM001_1.p`` — a GENUINE,
|
|
49
|
+
QMLTP-sourced NXF translation of the Barcan-scheme problem this
|
|
50
|
+
module's own test suite uses as a fixture, confirming the NATIVE
|
|
51
|
+
quantified syntax this release adds: ``! [X: $i] : ( {$box} @ (f(X)) )
|
|
52
|
+
=> ( {$box} @ (! [X: $i] : f(X)) )`` — a bound variable with NO
|
|
53
|
+
explicit sort defaults to TPTP's BUILT-IN ``$i`` (never a user-declared
|
|
54
|
+
``$tType``), and a non-nullary predicate gets its own
|
|
55
|
+
``tff(f_decl,type, f: $i > $o ).`` declaration, confirming NXF/NTF
|
|
56
|
+
stays a genuinely TYPED (TFF-based) dialect even for a
|
|
57
|
+
previously-untyped-looking QMLTP source.
|
|
58
|
+
- ``ProblemBuilding/QMLTP/7_QMLTPTP/APM/APM002_1.p`` — confirms (a) a
|
|
59
|
+
FREE constant of the default sort still needs its own explicit
|
|
60
|
+
declaration (``tff(a_decl,type, a: $i ).`` for a bare constant ``a``,
|
|
61
|
+
not merely left implicit), and (b) ``$modal_system_D`` is the literal
|
|
62
|
+
token for the serial (D/KD) system — the exact evidence this release's
|
|
63
|
+
``"D"`` addition (see below) is built on.
|
|
64
|
+
- ``Logics/LOG001_4.l`` — the corpus's OWN canonical modal-system-name
|
|
65
|
+
DEFINITIONS file (TPTP v9.0.0): ``tff(modal_system_T,definition, (
|
|
66
|
+
$modal_system_T == ( $modal_system_K & $modal_axiom_T ) ) ).`` --
|
|
67
|
+
confirming ``$modal_system_T`` (not ``$modal_system_M``) is the
|
|
68
|
+
correct, canonical token for the reflexive ("T") frame. No
|
|
69
|
+
``modal_system_M`` definition exists anywhere in this file or the rest
|
|
70
|
+
of the corpus (checked directly, see below) -- ``$modal_system_M``
|
|
71
|
+
appears only as a USAGE, and only inside
|
|
72
|
+
``ProblemBuilding/QMLTP/8_QMLTP``, which
|
|
73
|
+
``ProblemBuilding/QMLTP/README`` itself describes as "expanded
|
|
74
|
+
versions of 7_QMLTP with all combinations of the specification
|
|
75
|
+
parameters" (a derived/generated subtree, not the corpus's canonical
|
|
76
|
+
naming source) -- so those files reference a token this same corpus
|
|
77
|
+
never defines, almost certainly a generator artefact rather than a
|
|
78
|
+
legitimate alternate spelling. ``Tooling/generateSemantics.py`` (the
|
|
79
|
+
corpus's own canonical semantics-specification generator) confirms the
|
|
80
|
+
same thing independently: its ``all_modalities`` tuple is exactly
|
|
81
|
+
``("$modal_system_K", "$modal_system_T", "$modal_system_D",
|
|
82
|
+
"$modal_system_S4", "$modal_system_S5")`` -- five names, matching this
|
|
83
|
+
exporter's five supported frames one-to-one, with ``$modal_system_M``
|
|
84
|
+
absent. ``ProblemBuilding/QMLTP/SemanticSpecifications/t_*.p`` (all
|
|
85
|
+
eight ``t_<domain>_<designation>.p`` files) likewise all read
|
|
86
|
+
``$modalities == $modal_system_T``. A prior revision of this module
|
|
87
|
+
briefly "corrected" this token to ``$modal_system_M`` on the strength
|
|
88
|
+
of ``ProblemBuilding/Archive/.../kt_branch_p.0001.p`` and
|
|
89
|
+
``ProblemBuilding/QMLTP/8_QMLTP/SYM/SYM074_3.121.p`` alone, and a
|
|
90
|
+
docstring claim that a corpus-wide search for ``modal_system_T``
|
|
91
|
+
returned zero hits; that search was not actually re-run against the
|
|
92
|
+
real corpus before being written -- ``modal_system_T`` in fact appears
|
|
93
|
+
in dozens of files including the three canonical sources named above.
|
|
94
|
+
That revision was wrong and is reverted here (adversarial review); the
|
|
95
|
+
accompanying golden test is corrected back to match (see
|
|
96
|
+
``tests/test_tptp_ncl.py``).
|
|
97
|
+
- ``SampleProblems/PUZ087_1.p`` — a ``$epistemic_modal`` problem using the
|
|
98
|
+
INDEXED long form ``{$knows(#agent)} @ (...)``, confirming that a
|
|
99
|
+
future INDEXED multi-modal export (Knows/Believes/agent-indexed
|
|
100
|
+
alethic box(i)/dia(i)/... — still explicitly out of scope here, see
|
|
101
|
+
"Scope" below) would need the long, not short, connective form. Also
|
|
102
|
+
re-confirms the ``$tType``-declared-sort pattern
|
|
103
|
+
(``tff(agent_type,type,wiseman: $tType).``) this release's
|
|
104
|
+
:class:`~fol.nodes.SortedQuantifier`/:class:`~fol.nodes.SortedConstant`
|
|
105
|
+
support follows.
|
|
106
|
+
* ``fol/_modal_nodes.py`` — confirms ``Box``/``Diamond`` (and every other
|
|
107
|
+
modal-family node) reject the classical ``to_tptp()`` outright, so this
|
|
108
|
+
module cannot delegate to ``Node.to_tptp`` for a formula containing one and
|
|
109
|
+
must render the propositional connectives itself (mirroring their existing
|
|
110
|
+
``to_tptp`` shape exactly — see :func:`_render`).
|
|
111
|
+
* ``fol/tptp_input.py`` / ``fol/_fol_nodes.py`` — the kit's existing name
|
|
112
|
+
convention (predicate/constant/function names lower-cased on their first
|
|
113
|
+
letter only, a 0-ary atom is a bare lower-case identifier) is reused
|
|
114
|
+
verbatim via ``Node.to_tptp()`` for every propositional letter, term and
|
|
115
|
+
non-nullary atom, rather than re-implementing it here — this release's
|
|
116
|
+
quantified-fragment additions extend that same reuse to
|
|
117
|
+
:class:`~fol.nodes.Quantifier`/``SortedQuantifier``/``SortedConstant``
|
|
118
|
+
arguments (see :func:`_render` / :func:`_term_sort`).
|
|
119
|
+
|
|
120
|
+
Scope — deliberately narrow, and narrowed FURTHER than a "cover everything"
|
|
121
|
+
reading of the sources above once each fragment was checked against real,
|
|
122
|
+
prover-exercised files rather than guessed from the paper's grammar alone:
|
|
123
|
+
|
|
124
|
+
* Supported: :class:`~fol.nodes.Box`, :class:`~fol.nodes.Diamond`,
|
|
125
|
+
:class:`~fol.nodes.Not`, :class:`~fol.nodes.And`, :class:`~fol.nodes.Or`,
|
|
126
|
+
:class:`~fol.nodes.Implies`, :class:`~fol.nodes.Iff`, over an
|
|
127
|
+
:class:`~fol.nodes.Atom` of ANY arity (0-ary propositional letters, and
|
|
128
|
+
now non-nullary ``P(x, y, ...)`` atoms too, PLUS equality/disequality —
|
|
129
|
+
see below) whose arguments are :class:`~fol.nodes.Variable` (bound by a
|
|
130
|
+
:class:`~fol.nodes.Quantifier` / ``SortedQuantifier`` — this module
|
|
131
|
+
renders NATIVE NXF quantifiers, ``! [X: <sort>] : (...)`` / ``? [X:
|
|
132
|
+
<sort>] : (...)``, per ``SYM001_1.p``/PUZ087_1.p above), or
|
|
133
|
+
:class:`~fol.nodes.Constant` / :class:`~fol.nodes.SortedConstant` (each
|
|
134
|
+
free constant gets its own ``tff(<name>_decl,type, <name>: <sort> ).``,
|
|
135
|
+
per ``APM002_1.p`` above) — the mono-modal ALETHIC fragment (the frame
|
|
136
|
+
system is K/T/S4/S5/D; no other modal family). An equality/disequality
|
|
137
|
+
atom (``=``/``≠``) is accepted ONLY when both operands compute to the
|
|
138
|
+
SAME NXF sort token — see the next bullet for why.
|
|
139
|
+
* NOT supported, each raising :class:`NotImplementedError` with a message
|
|
140
|
+
naming the reason (never a silently weaker translation):
|
|
141
|
+
- A free (unbound) :class:`~fol.nodes.Variable` — an Atom/equality
|
|
142
|
+
argument naming a variable with no enclosing
|
|
143
|
+
:class:`~fol.nodes.Quantifier` / ``SortedQuantifier`` (found by
|
|
144
|
+
adversarial review) is refused rather than defaulted to ``$i``: TPTP
|
|
145
|
+
reads a free variable in a ``conjecture`` role as EXISTENTIALLY
|
|
146
|
+
quantified, not universally, so silently typing it would silently
|
|
147
|
+
change the meaning of the exported problem, not merely under-specify
|
|
148
|
+
its sort (see :data:`_UNSUPPORTED_FREE_VARIABLE`).
|
|
149
|
+
- :class:`~fol.nodes.Function` arguments (``P(f(x))``) — a genuine
|
|
150
|
+
function SYMBOL's own NXF type declaration
|
|
151
|
+
(``<name>: (<arg-sorts>) > <result-sort>``) was never found in any
|
|
152
|
+
real file of the cloned corpus (every QMLTP-derived problem checked
|
|
153
|
+
uses only 0-ary/N-ary PREDICATES and free CONSTANTS, never a compound
|
|
154
|
+
function term), so its exact shape is inferred-by-grammar-pattern
|
|
155
|
+
only, not confirmed — refused by name rather than emitted unverified,
|
|
156
|
+
pending a primary-source example.
|
|
157
|
+
- A cross-sort equality/disequality atom (found by adversarial review):
|
|
158
|
+
the kit's own SortedQuantifier/SortedConstant semantics is
|
|
159
|
+
guard-predicate based (one shared classical domain, a sort is just a
|
|
160
|
+
unary predicate over it — see ``fol._msfl_nodes.SortedQuantifier.
|
|
161
|
+
_relativize``), so a cross-sort equality is perfectly meaningful
|
|
162
|
+
there, but native TFF/NXF sorts are disjoint and TFF's polymorphic
|
|
163
|
+
``=`` requires both operands to share ONE declared type, with no
|
|
164
|
+
subtyping/coercion — emitting one anyway would be TYPE-INCORRECT NXF/
|
|
165
|
+
TFF text, not merely a false formula, so it is refused rather than
|
|
166
|
+
silently emitted (see :data:`_UNSUPPORTED_CROSS_SORT_EQUALITY`).
|
|
167
|
+
- An equality/disequality atom with a bare variable bound by an UNSORTED
|
|
168
|
+
quantifier, in a formula that also uses a user sort. Every operand pair
|
|
169
|
+
of such an atom can be well typed (two ``$i`` variables), but the types
|
|
170
|
+
are disjoint: the unsorted variable ranges over ``$i``, not over the
|
|
171
|
+
one universe the kit's sorts are subsets of, so ``∀x ∀y x = y`` bounds
|
|
172
|
+
``$i`` and says nothing about a user sort, and a prover would answer a
|
|
173
|
+
different question than the kit's other routes (``∀x ∀y x = y ⊢ ∀x:A
|
|
174
|
+
∀z:A x = z`` is valid in the kit and is not a theorem of the typed text).
|
|
175
|
+
The refusal is :class:`~unicode_logic_kit.atp.tptp_tff.Tf0Refusal` (also a
|
|
176
|
+
``NotImplementedError``), the same as the TF0 writer's, with the same
|
|
177
|
+
message; this exporter does not infer a sort for an unannotated constant
|
|
178
|
+
(each occurrence is typed on its own and a constant at two types is
|
|
179
|
+
refused), so that is the only one of the TF0 writer's two typed-reading
|
|
180
|
+
refusals it needs.
|
|
181
|
+
- The arithmetic comparison predicates (``<``/``>``/``≤``/``≥``) and a
|
|
182
|
+
bare :class:`~fol.nodes.Number` literal anywhere in the formula
|
|
183
|
+
(found by adversarial review) — both need one of TPTP's arithmetic
|
|
184
|
+
sorts (``$int``/``$rat``/``$real``), which this exporter never
|
|
185
|
+
declares; defaulting a ``Number`` to ``$i`` (the previous behaviour)
|
|
186
|
+
or applying ``$less``/``$greater``/... to ``$i``-typed operands would
|
|
187
|
+
likewise be type-incorrect NXF/TFF text. Mirrors
|
|
188
|
+
:mod:`atp.tptp_tff`'s identical TF0-only refusal of the same two
|
|
189
|
+
constructs (see that module's ``_ARITH_OUT_OF_SCOPE``) rather than
|
|
190
|
+
inventing a new policy here.
|
|
191
|
+
- Every other modal family (epistemic ``Knows``/``Believes``, doxastic,
|
|
192
|
+
temporal, deontic, counterfactual, PAL) and INDEXED multi-modal
|
|
193
|
+
(agent-/index-indexed box(i)/dia(i)) — each needs the INDEXED
|
|
194
|
+
long-form connective (PUZ087_1.p's ``{{$knows(#a)}} @ (...)``, or the
|
|
195
|
+
generic ``{{$box(#i)}} @ (...)`` form the arXiv paper's Section 2/5
|
|
196
|
+
describe for FOMML) and the corresponding multi-entry
|
|
197
|
+
``$modalities`` logic-spec list — real examples of the latter show at
|
|
198
|
+
least two non-equivalent accepted spellings for the per-index key
|
|
199
|
+
(``[#a] == system`` in ``CorrectSpecifications.p`` vs.
|
|
200
|
+
``{{$necessary(#a)}} == system`` in the same file), which is not
|
|
201
|
+
settled precisely enough to commit to one shape here; a follow-up, not
|
|
202
|
+
guessed.
|
|
203
|
+
- Any frame other than K/T/S4/S5/D (:class:`ValueError`, not
|
|
204
|
+
``NotImplementedError`` — this is a caller input error, not a missing
|
|
205
|
+
feature: these are exactly the frames the rest of this kit's modal
|
|
206
|
+
backends already know how to reason about, K/T/S4/S5 via
|
|
207
|
+
:func:`modal_prove` and D via :func:`~fol.qml.qml_is_valid`'s
|
|
208
|
+
``frame="D"``/``"KD"``).
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
from typing import Dict, List, Optional, Tuple
|
|
212
|
+
|
|
213
|
+
from ..fol.nodes import (
|
|
214
|
+
Atom, And, Box, Constant, Diamond, Function, Iff, Implies, Node, Not,
|
|
215
|
+
Number, Or, Quantifier, SortedConstant, SortedQuantifier, Variable,
|
|
216
|
+
)
|
|
217
|
+
from ..fol._fol_nodes import tptp_fold_first_letter
|
|
218
|
+
from ..fol._tptp_symbols import is_tptp_boolean_atom
|
|
219
|
+
from .tptp_tff import unsorted_equality_refusal
|
|
220
|
+
|
|
221
|
+
__all__ = ["to_tptp_ncl"]
|
|
222
|
+
|
|
223
|
+
# The frame names this kit's OWN modal routes already reason about (K/T/S4/S5
|
|
224
|
+
# via atp.modal_tableau, D via fol.qml.qml_is_valid(frame="D"/"KD")) map onto
|
|
225
|
+
# the literal $modal_system_<X> tokens — each individually confirmed against
|
|
226
|
+
# the corpus's OWN canonical sources (Logics/LOG001_4.l's definitions,
|
|
227
|
+
# Tooling/generateSemantics.py's all_modalities tuple, and
|
|
228
|
+
# ProblemBuilding/QMLTP/SemanticSpecifications/t_*.p), not merely some
|
|
229
|
+
# prover-exercised .p file from github.com/TPTPWorld/NonClassicalLogic (see
|
|
230
|
+
# the module docstring's "Sources" section for exactly which file proves
|
|
231
|
+
# which token).
|
|
232
|
+
_FRAME_TO_SYSTEM: Dict[str, str] = {
|
|
233
|
+
"K": "$modal_system_K",
|
|
234
|
+
"T": "$modal_system_T",
|
|
235
|
+
"S4": "$modal_system_S4",
|
|
236
|
+
"S5": "$modal_system_S5",
|
|
237
|
+
# D (serial K, a.k.a. KD) -- the alethic SERIALITY axiom ∀w∃v R(w,v),
|
|
238
|
+
# confirmed as $modal_system_D by APM002_1.p / kd_branch_p/*.p in the
|
|
239
|
+
# cloned corpus (see module docstring). NOT to be confused with
|
|
240
|
+
# fol.qml's *deontic* accessibility relation also spelled "D" (qml.py's
|
|
241
|
+
# _R_DEONTIC): that is a wholly different relation this exporter never
|
|
242
|
+
# touches -- this "D" names the ALETHIC frame's seriality condition,
|
|
243
|
+
# the same one fol.qml.qml_is_valid(frame="D") / frame="KD" already
|
|
244
|
+
# reasons about for □/◇.
|
|
245
|
+
"D": "$modal_system_D",
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
# $domains values, confirmed by CorrectSpecifications.p's $domains ==
|
|
249
|
+
# $constant / [$constant, plushie == $varying] examples and the arXiv
|
|
250
|
+
# infrastructure paper's Table 1 enumeration of
|
|
251
|
+
# $constant/$varying/$cumulative/$decreasing. Only the bare (non-per-type)
|
|
252
|
+
# form is exposed here — a per-type domain list is a further extension this
|
|
253
|
+
# module does not implement.
|
|
254
|
+
#
|
|
255
|
+
# What changing this value DOES and does NOT do to the emitted problem, now
|
|
256
|
+
# that native quantifiers exist (this release): NOTHING changes in how a
|
|
257
|
+
# Quantifier/SortedQuantifier is RENDERED -- every value renders the exact
|
|
258
|
+
# same native ``! [X: <sort>] : (...)`` / ``? [X: <sort>] : (...)`` form,
|
|
259
|
+
# with no kit-side existence-guard atom of any kind. That is deliberate, not
|
|
260
|
+
# an oversight: NXF's $domains property is read by the CONSUMING PROVER to
|
|
261
|
+
# constrain how per-world domains relate to each other (SYM001_1.p's own
|
|
262
|
+
# $domains == $constant is exactly what makes its Barcan-scheme conjecture a
|
|
263
|
+
# Theorem for that prover) -- it is declarative logic-specification
|
|
264
|
+
# metadata, not a term-level transformation this exporter would have to
|
|
265
|
+
# perform itself. This is why :func:`to_tptp_ncl` does NOT reuse
|
|
266
|
+
# :func:`fol.qml.qml_translate` (which DOES perform such a transformation,
|
|
267
|
+
# via an explicit existence predicate E(x,w), for its own DIFFERENT
|
|
268
|
+
# technique: a shallow embedding into CLASSICAL logic decided by Z3, not a
|
|
269
|
+
# native non-classical export at all) -- the two routes solve the domain
|
|
270
|
+
# regime in different places on purpose, and conflating them would either
|
|
271
|
+
# double-guard the quantifiers (wrong syntax for NXF, which expects native
|
|
272
|
+
# ``!``/``?``) or silently drop the qml.py guard machinery's own soundness
|
|
273
|
+
# story. So every one of the four values is equally "wired": each selects
|
|
274
|
+
# a distinct token in the emitted ``$domains == ...`` line, which is the
|
|
275
|
+
# ONLY place this parameter has any effect.
|
|
276
|
+
_DOMAIN_WORDS: Dict[str, str] = {
|
|
277
|
+
"constant": "$constant",
|
|
278
|
+
"varying": "$varying",
|
|
279
|
+
"cumulative": "$cumulative",
|
|
280
|
+
"decreasing": "$decreasing",
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
# TPTP's built-in "individual" type -- always available, never separately
|
|
284
|
+
# declared, and non-empty BY TPTP SEMANTICS (the TF0/TFF standard fixes $i to
|
|
285
|
+
# denote a single non-empty domain of individuals; see the TPTP syntax BNF
|
|
286
|
+
# cited in fol/tptp_input.py's own docstring). An untyped Quantifier / a bare
|
|
287
|
+
# Constant defaults to this sort -- confirmed by SYM001_1.p's ``! [X: $i]``
|
|
288
|
+
# and APM002_1.p's ``a: $i`` (see module docstring). A user-declared sort
|
|
289
|
+
# (SortedQuantifier / SortedConstant) instead gets its own
|
|
290
|
+
# ``tff(<name>_type,type, <name>: $tType ).`` declaration -- and a $tType
|
|
291
|
+
# declaration is ITSELF non-empty by the same TPTP semantics (a $tType is a
|
|
292
|
+
# non-empty domain by definition; TPTP has no notion of an empty type), so
|
|
293
|
+
# this exporter never needs -- and does not emit -- a separate
|
|
294
|
+
# "sort S is non-empty" axiom the way fol.qml.qml_axioms's
|
|
295
|
+
# nonempty_sort_axioms does for the classical/shallow-embedding routes: the
|
|
296
|
+
# TYPED DECLARATION ITSELF already carries that guarantee for any consumer
|
|
297
|
+
# that honours TF0/TFF semantics.
|
|
298
|
+
_DEFAULT_SORT = "$i"
|
|
299
|
+
|
|
300
|
+
_UNSUPPORTED_FUNCTION = (
|
|
301
|
+
"to_tptp_ncl: a compound function term {name!r}(...) is outside this "
|
|
302
|
+
"exporter's supported fragment -- a genuine NXF function-SYMBOL type "
|
|
303
|
+
"declaration (as opposed to a predicate's) was never found in any real "
|
|
304
|
+
"problem of the checked github.com/TPTPWorld/NonClassicalLogic corpus, "
|
|
305
|
+
"so its exact shape is not confirmed (see module docstring 'Scope'); "
|
|
306
|
+
"refusing rather than emitting an unverified declaration. Only "
|
|
307
|
+
"Variable/Constant/SortedConstant terms are supported as atom arguments "
|
|
308
|
+
"in this release."
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
_UNSUPPORTED_NUMBER = (
|
|
312
|
+
"to_tptp_ncl: a bare numeral literal ({value!r}) is outside this "
|
|
313
|
+
"exporter's supported fragment -- TPTP types a numeral intrinsically as "
|
|
314
|
+
"an arithmetic sort ($int/$rat/$real), never as the individual sort $i "
|
|
315
|
+
"(or a user sort) this exporter's quantifiers/constants use, and this "
|
|
316
|
+
"exporter never declares an arithmetic sort (mirrors atp.tptp_tff's "
|
|
317
|
+
"identical TF0-only refusal for a Number term -- see that module's "
|
|
318
|
+
"docstring 'Scope: TF0 only'); refusing rather than mistyping the "
|
|
319
|
+
"literal as $i. Only Variable/Constant/SortedConstant terms are "
|
|
320
|
+
"supported as atom arguments in this release."
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
_UNSUPPORTED_FREE_VARIABLE = (
|
|
324
|
+
"to_tptp_ncl: variable {name!r} is not bound by an enclosing Quantifier/"
|
|
325
|
+
"SortedQuantifier (found by adversarial review) -- refusing rather than "
|
|
326
|
+
"defaulting it to $i, because an emitted NXF conjecture with a genuinely "
|
|
327
|
+
"free variable is not equivalent to the source formula: TPTP treats a "
|
|
328
|
+
"free variable in a conjecture role as EXISTENTIALLY quantified, not "
|
|
329
|
+
"universally, which silently changes the meaning of the exported "
|
|
330
|
+
"problem rather than merely defaulting its sort. Bind every variable "
|
|
331
|
+
"with a Quantifier/SortedQuantifier before calling to_tptp_ncl."
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
_UNSUPPORTED_ARITHMETIC_PRED = (
|
|
335
|
+
"to_tptp_ncl: the arithmetic comparison {name!r} is outside this "
|
|
336
|
+
"exporter's supported fragment -- it needs TPTP's arithmetic sorts "
|
|
337
|
+
"($int/$rat/$real), which this exporter never declares (mirrors "
|
|
338
|
+
"atp.tptp_tff's identical TF0-only refusal of the same predicate -- see "
|
|
339
|
+
"that module's docstring 'Scope: TF0 only'); refusing rather than "
|
|
340
|
+
"emitting a $less/$greater/$lesseq/$greatereq atom whose operands are "
|
|
341
|
+
"typed $i (or a user sort) instead of an arithmetic sort."
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
_UNSUPPORTED_CROSS_SORT_EQUALITY = (
|
|
345
|
+
"to_tptp_ncl: an equality/disequality atom ({pred!r}) between an "
|
|
346
|
+
"operand of sort {left!r} and one of sort {right!r} is outside this "
|
|
347
|
+
"exporter's supported fragment -- the kit's own SortedQuantifier/"
|
|
348
|
+
"SortedConstant semantics is guard-predicate based (S(x) is a unary "
|
|
349
|
+
"predicate over one shared classical domain, so cross-sort equality is "
|
|
350
|
+
"meaningful there -- see fol._msfl_nodes.SortedQuantifier._relativize), "
|
|
351
|
+
"but native TFF/NXF types are disjoint and TFF's polymorphic '=' "
|
|
352
|
+
"requires both operands to share the SAME declared type, with no "
|
|
353
|
+
"subtyping/coercion; refusing rather than emitting a type-incorrect "
|
|
354
|
+
"NXF/TFF problem. Give both sides of the equality the same sort."
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
_UNSUPPORTED_NODE = (
|
|
358
|
+
"to_tptp_ncl: {name} is outside the supported mono-modal alethic "
|
|
359
|
+
"fragment (Box/Diamond/¬/∧/∨/→/↔ over atoms, with native ∀/∃ "
|
|
360
|
+
"quantifiers). Every other modal family (epistemic Knows/Believes, "
|
|
361
|
+
"doxastic, temporal, deontic, counterfactual, PAL), and INDEXED "
|
|
362
|
+
"multi-modal box(i)/dia(i), are documented, not-yet-implemented "
|
|
363
|
+
"extensions -- see module docstring 'Scope'."
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def _sort_token(sort_name: str) -> str:
|
|
368
|
+
"""The NXF identifier for a kit sort NAME (``SortedQuantifier.sort`` /
|
|
369
|
+
``SortedConstant.sort``) -- the same first-letter fold every other NXF
|
|
370
|
+
identifier in this module goes through (see :func:`_term_sort` /
|
|
371
|
+
:meth:`_NxfSymbols.note_predicate`), so a sort name follows the exact
|
|
372
|
+
same TPTP lower_word convention as everything else this exporter emits.
|
|
373
|
+
|
|
374
|
+
Raises:
|
|
375
|
+
NotImplementedError: ``sort_name`` starts with ``$``. Every such word is one of
|
|
376
|
+
TPTP's own (``$i`` the type of individuals, ``$o`` the booleans, ``$tType``
|
|
377
|
+
the type of types, ``$int`` / ``$rat`` / ``$real`` the numbers, ``$true``,
|
|
378
|
+
...), and this writer writes a sort name as it is, so the sort would be merged
|
|
379
|
+
with that word, or redeclare it as ``tff($i_type,type, $i: $tType )``. ``$i``
|
|
380
|
+
matters most: it is the sort this writer gives every UNSORTED quantifier and
|
|
381
|
+
constant, so a user sort of that name would be one with everything that has no
|
|
382
|
+
sort.
|
|
383
|
+
"""
|
|
384
|
+
if sort_name.startswith("$"):
|
|
385
|
+
raise NotImplementedError(
|
|
386
|
+
f"to_tptp_ncl: a sort named {sort_name!r} cannot be written: a name that starts "
|
|
387
|
+
"with '$' is one of TPTP's own words ($i is the type of individuals, which this "
|
|
388
|
+
"writer gives every unsorted quantifier and constant, $o the booleans, $tType the "
|
|
389
|
+
"type of types, $int/$rat/$real the numbers), so the sort would be merged with "
|
|
390
|
+
"that word or redeclare it. Rename the sort.")
|
|
391
|
+
return tptp_fold_first_letter(sort_name)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
class _NxfSymbols:
|
|
395
|
+
"""Collects every sort / constant / predicate this export's formula uses,
|
|
396
|
+
in first-occurrence order, while :func:`_render` walks the tree once --
|
|
397
|
+
and refuses (NotImplementedError), rather than silently aliasing, any
|
|
398
|
+
case where two DISTINCT kit symbols would render as the SAME NXF
|
|
399
|
+
identifier, or the same kit symbol would need two DIFFERENT NXF types.
|
|
400
|
+
Both are genuine soundness holes for an emitted problem: a duplicate
|
|
401
|
+
``type`` declaration for one name, or a real ambiguity a consuming
|
|
402
|
+
prover would resolve arbitrarily, silently changing what is being
|
|
403
|
+
proved. Mirrors the collision-refusal :func:`to_tptp_ncl` already
|
|
404
|
+
applied to 0-ary propositional letters before this release, generalised
|
|
405
|
+
to sorts/constants/predicates of any arity.
|
|
406
|
+
"""
|
|
407
|
+
|
|
408
|
+
def __init__(self):
|
|
409
|
+
self.sort_order: List[str] = []
|
|
410
|
+
self.sort_sig: Dict[str, str] = {} # token -> kit sort name
|
|
411
|
+
self.const_order: List[str] = []
|
|
412
|
+
self.const_sig: Dict[str, Tuple[str, str]] = {} # token -> (kit name, sort token)
|
|
413
|
+
self.pred_order: List[str] = []
|
|
414
|
+
self.pred_sig: Dict[str, Tuple[str, tuple]] = {} # token -> (kit name, arg sort tokens)
|
|
415
|
+
# The first equality / disequality atom, as text, that has a bare variable
|
|
416
|
+
# bound by an UNSORTED quantifier as one of its sides (see to_tptp_ncl).
|
|
417
|
+
self.unsorted_equality: Optional[str] = None
|
|
418
|
+
|
|
419
|
+
def note_sort(self, name: str, token: str) -> None:
|
|
420
|
+
"""Register one kit sort NAME (``SortedQuantifier.sort`` /
|
|
421
|
+
``SortedConstant.sort``) under its folded NXF ``token``, refusing
|
|
422
|
+
(NotImplementedError) rather than silently merging when two
|
|
423
|
+
DISTINCT kit sort names would fold to the SAME token -- mirrors
|
|
424
|
+
:meth:`note_constant`/:meth:`note_predicate` exactly (this is the
|
|
425
|
+
sort-level counterpart of both; before this check, two sorts like
|
|
426
|
+
``"Human"``/``"human"`` collapsed into one ``$tType`` declaration,
|
|
427
|
+
contradicting this class's own docstring)."""
|
|
428
|
+
if token in self.sort_sig:
|
|
429
|
+
prev_name = self.sort_sig[token]
|
|
430
|
+
if prev_name != name:
|
|
431
|
+
raise NotImplementedError(
|
|
432
|
+
f"to_tptp_ncl: distinct sorts {prev_name!r} and {name!r} "
|
|
433
|
+
f"would both render as the NXF identifier {token!r} "
|
|
434
|
+
"(TPTP lower-cases the first letter) -- refusing to "
|
|
435
|
+
"alias them; rename one of the sorts so the export "
|
|
436
|
+
"stays faithful.")
|
|
437
|
+
else:
|
|
438
|
+
self.sort_sig[token] = name
|
|
439
|
+
self.sort_order.append(token)
|
|
440
|
+
|
|
441
|
+
def note_constant(self, name: str, sort_token: str) -> None:
|
|
442
|
+
token = Constant(name).to_tptp()
|
|
443
|
+
if token in self.const_sig:
|
|
444
|
+
prev_name, prev_sort = self.const_sig[token]
|
|
445
|
+
if prev_name != name:
|
|
446
|
+
raise NotImplementedError(
|
|
447
|
+
f"to_tptp_ncl: distinct constants {prev_name!r} and {name!r} "
|
|
448
|
+
f"would both render as the NXF identifier {token!r} (TPTP "
|
|
449
|
+
"lower-cases the first letter) -- refusing to alias them; "
|
|
450
|
+
"rename one of the constants so the export stays faithful.")
|
|
451
|
+
if prev_sort != sort_token:
|
|
452
|
+
raise NotImplementedError(
|
|
453
|
+
f"to_tptp_ncl: the constant {name!r} is used with two "
|
|
454
|
+
f"different sorts ({prev_sort!r} and {sort_token!r}) in "
|
|
455
|
+
"this formula -- TPTP requires one fixed type per symbol; "
|
|
456
|
+
"give it a single, consistent sort throughout.")
|
|
457
|
+
else:
|
|
458
|
+
self.const_sig[token] = (name, sort_token)
|
|
459
|
+
self.const_order.append(token)
|
|
460
|
+
|
|
461
|
+
def note_predicate(self, name: str, arg_sorts: tuple) -> None:
|
|
462
|
+
token = tptp_fold_first_letter(name)
|
|
463
|
+
if token in self.pred_sig:
|
|
464
|
+
prev_name, prev_sorts = self.pred_sig[token]
|
|
465
|
+
if prev_name != name:
|
|
466
|
+
raise NotImplementedError(
|
|
467
|
+
f"to_tptp_ncl: distinct propositional/predicate letters "
|
|
468
|
+
f"{prev_name!r} and {name!r} would both render as the NXF "
|
|
469
|
+
f"identifier {token!r} (TPTP lower-cases the first "
|
|
470
|
+
"letter) -- refusing to alias them; rename one of the "
|
|
471
|
+
"atoms so the export stays faithful.")
|
|
472
|
+
if prev_sorts != arg_sorts:
|
|
473
|
+
raise NotImplementedError(
|
|
474
|
+
f"to_tptp_ncl: the predicate {name!r} is used at two "
|
|
475
|
+
f"different argument types/arities ({prev_sorts!r} and "
|
|
476
|
+
f"{arg_sorts!r}) in this formula -- TPTP requires one "
|
|
477
|
+
"fixed type per symbol; give it a single, consistent "
|
|
478
|
+
"signature throughout.")
|
|
479
|
+
else:
|
|
480
|
+
self.pred_sig[token] = (name, arg_sorts)
|
|
481
|
+
self.pred_order.append(token)
|
|
482
|
+
|
|
483
|
+
def check_no_cross_namespace_collision(self) -> None:
|
|
484
|
+
"""Refuse an NXF identifier used as more than one KIND of symbol
|
|
485
|
+
(e.g. a sort named the same as a predicate) -- TPTP identifiers are
|
|
486
|
+
a single flat namespace of ``lower_word`` tokens, so two DIFFERENT
|
|
487
|
+
kit symbols folding to the same token would collide even if neither
|
|
488
|
+
alone triggered :meth:`note_constant` / :meth:`note_predicate`.
|
|
489
|
+
|
|
490
|
+
This exporter returns bare text with no name map, so unlike the
|
|
491
|
+
``fof``/TF0/TFA problem writers (which rename the function/constant
|
|
492
|
+
side of such a clash and record it in a ``TptpNameMap``) it can only
|
|
493
|
+
refuse -- by name, naming both kit symbols and the writers to use."""
|
|
494
|
+
kinds: Dict[str, List[Tuple[str, str]]] = {}
|
|
495
|
+
for token in self.sort_order:
|
|
496
|
+
kinds.setdefault(token, []).append(("a sort", self.sort_sig[token]))
|
|
497
|
+
for token in self.const_order:
|
|
498
|
+
kinds.setdefault(token, []).append(("a constant", self.const_sig[token][0]))
|
|
499
|
+
for token in self.pred_order:
|
|
500
|
+
kinds.setdefault(token, []).append(("a predicate", self.pred_sig[token][0]))
|
|
501
|
+
for token, seen in kinds.items():
|
|
502
|
+
if len({kind for kind, _ in seen}) > 1:
|
|
503
|
+
described = " and ".join(f"{kind} ({name!r})" for kind, name in sorted(seen))
|
|
504
|
+
raise NotImplementedError(
|
|
505
|
+
f"to_tptp_ncl: the NXF identifier {token!r} would be "
|
|
506
|
+
f"declared as both {described} -- TPTP "
|
|
507
|
+
"identifiers share one flat namespace, and this exporter "
|
|
508
|
+
"has no name map to record a rename in; rename one of "
|
|
509
|
+
"the colliding kit symbols so the export stays faithful "
|
|
510
|
+
"(the classical writers generate_tptp_problem_with_mapping "
|
|
511
|
+
"and generate_tff_problem_with_mapping rename the "
|
|
512
|
+
"function/constant side of such a clash and return the "
|
|
513
|
+
"record).")
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
# Atom predicates TPTP renders as the genuinely INFIX built-in ('='/'!=') --
|
|
517
|
+
# never user-declared, so _render walks their arguments (for nested
|
|
518
|
+
# constants) without registering the predicate itself, but (unlike a plain
|
|
519
|
+
# user predicate) DOES require both operands to share one NXF sort token,
|
|
520
|
+
# since native TFF's polymorphic '=' has no subtyping/coercion (see
|
|
521
|
+
# _UNSUPPORTED_CROSS_SORT_EQUALITY). Reuses Atom's own table rather than
|
|
522
|
+
# re-listing it, so this set can never drift from what Atom.to_tptp()
|
|
523
|
+
# actually treats as infix.
|
|
524
|
+
_EQUALITY_PREDS = frozenset(Atom.INFIX_PREDS_TPTP)
|
|
525
|
+
|
|
526
|
+
# Arithmetic comparisons (TPTP's $less/$greater/$lesseq/$greatereq
|
|
527
|
+
# dollar-word PREFIX predicates) need TPTP's arithmetic sorts ($int/$rat/
|
|
528
|
+
# $real), which this exporter never declares -- refused by name rather than
|
|
529
|
+
# emitted over $i (or a user sort), mirroring atp.tptp_tff's identical
|
|
530
|
+
# TF0-only refusal of the same predicate set (see that module's
|
|
531
|
+
# _ARITH_OUT_OF_SCOPE). Reuses Atom's own table rather than re-listing it.
|
|
532
|
+
_ARITHMETIC_PREDS = frozenset(Atom.PREFIX_PREDS_TPTP)
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def _term_sort(term: Node, scope: Dict[str, str], symbols: _NxfSymbols) -> str:
|
|
536
|
+
"""The NXF sort token of one TERM occurrence, registering any
|
|
537
|
+
constant/sort it introduces into ``symbols`` as a side effect.
|
|
538
|
+
|
|
539
|
+
``scope`` maps a bound Variable's kit NAME to its NXF sort token (set by
|
|
540
|
+
the enclosing Quantifier/SortedQuantifier in :func:`_render`). A
|
|
541
|
+
Variable absent from ``scope`` is a genuinely FREE variable -- directly
|
|
542
|
+
reachable through the public entry point (:func:`to_tptp_ncl` starts
|
|
543
|
+
rendering with an empty scope, so any Atom/equality argument that is a
|
|
544
|
+
Variable with no enclosing Quantifier/SortedQuantifier hits this case,
|
|
545
|
+
found by adversarial review) -- and is refused rather than defaulted to
|
|
546
|
+
``$i``: TPTP reads a free variable in a conjecture role as EXISTENTIALLY
|
|
547
|
+
quantified, not universally, so silently defaulting its sort would
|
|
548
|
+
silently change the meaning of the exported problem, not merely under-
|
|
549
|
+
specify its type.
|
|
550
|
+
|
|
551
|
+
Raises:
|
|
552
|
+
NotImplementedError: ``term`` is a free (unbound) Variable, a
|
|
553
|
+
:class:`~fol.nodes.Function` (compound function term), or a
|
|
554
|
+
:class:`~fol.nodes.Number` -- see module docstring 'Scope'.
|
|
555
|
+
"""
|
|
556
|
+
if isinstance(term, Variable):
|
|
557
|
+
if term.name not in scope:
|
|
558
|
+
raise NotImplementedError(
|
|
559
|
+
_UNSUPPORTED_FREE_VARIABLE.format(name=term.name))
|
|
560
|
+
return scope[term.name]
|
|
561
|
+
if isinstance(term, SortedConstant):
|
|
562
|
+
token = _sort_token(term.sort)
|
|
563
|
+
symbols.note_sort(term.sort, token)
|
|
564
|
+
symbols.note_constant(term.name, token)
|
|
565
|
+
return token
|
|
566
|
+
if isinstance(term, Constant):
|
|
567
|
+
symbols.note_constant(term.name, _DEFAULT_SORT)
|
|
568
|
+
return _DEFAULT_SORT
|
|
569
|
+
if isinstance(term, Number):
|
|
570
|
+
# A bare numeral literal (e.g. "42") is TPTP's own built-in numeral
|
|
571
|
+
# syntax, but it is intrinsically typed to an ARITHMETIC sort
|
|
572
|
+
# ($int/$rat/$real) by the TPTP standard itself -- never to $i (the
|
|
573
|
+
# individual sort) or to any user-declared $tType. This exporter
|
|
574
|
+
# never declares an arithmetic sort (see _UNSUPPORTED_NUMBER /
|
|
575
|
+
# module docstring 'Scope'), so defaulting a Number to $i the way an
|
|
576
|
+
# untyped Constant/Quantifier does would emit a type-incorrect NXF/
|
|
577
|
+
# TFF problem (found by adversarial review; the previous version of
|
|
578
|
+
# this function did exactly that) -- refused instead, mirroring
|
|
579
|
+
# atp.tptp_tff's identical TF0-only refusal of a Number term.
|
|
580
|
+
raise NotImplementedError(_UNSUPPORTED_NUMBER.format(value=term.value))
|
|
581
|
+
if isinstance(term, Function):
|
|
582
|
+
raise NotImplementedError(_UNSUPPORTED_FUNCTION.format(name=term.name))
|
|
583
|
+
raise NotImplementedError(
|
|
584
|
+
f"to_tptp_ncl: unsupported term {type(term).__name__} in the "
|
|
585
|
+
"quantified fragment -- see module docstring 'Scope'.")
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def _quantifier_prefix(qtype: str, var_token: str, sort_token: str) -> str:
|
|
589
|
+
if qtype in ("∀", "forall"):
|
|
590
|
+
q = "!"
|
|
591
|
+
elif qtype in ("∃", "exists"):
|
|
592
|
+
q = "?"
|
|
593
|
+
else:
|
|
594
|
+
raise ValueError(f"to_tptp_ncl: unknown quantifier type {qtype!r}.")
|
|
595
|
+
return f"{q} [{var_token}: {sort_token}]"
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
def _render(node: Node, scope: Dict[str, str], symbols: _NxfSymbols) -> str:
|
|
599
|
+
"""Render one node of the supported fragment as an NXF formula string,
|
|
600
|
+
registering every sort/constant/predicate it introduces into ``symbols``.
|
|
601
|
+
|
|
602
|
+
Mirrors the shape :meth:`Node.to_tptp` already uses for the classical
|
|
603
|
+
connectives (``~(...)``, ``(l & r)``, ``(l | r)``, ``(l => r)``,
|
|
604
|
+
``(l <=> r)`` — see ``fol/_fol_nodes.py``), and extends it with the two
|
|
605
|
+
NXF short-form modal prefix connectives, ``[.]``/``<.>``, and NATIVE NXF
|
|
606
|
+
quantifiers ``! [X: <sort>] : (...)`` / ``? [X: <sort>] : (...)`` (see
|
|
607
|
+
module docstring). Every branch's own output is already a self-delimited
|
|
608
|
+
``unary`` production (a bare atom, a ``~(...)``-wrapped formula, a fully
|
|
609
|
+
parenthesised binary formula, ``[.]``/``<.>`` applied to one of those, or
|
|
610
|
+
a quantifier whose OWN body is parenthesised — ``! [X: S] : (unary)`` is
|
|
611
|
+
itself exactly the grammar's ``"!" "[" varlist "]" ":" unary`` alternative,
|
|
612
|
+
matching :mod:`fol.tptp_input`'s ``?unary: ... | "!" "[" varlist "]" ":"
|
|
613
|
+
unary | ...`` rule), so nesting one under another NEVER needs extra
|
|
614
|
+
wrapping parentheses.
|
|
615
|
+
|
|
616
|
+
Raises:
|
|
617
|
+
NotImplementedError: ``node`` (or a descendant) is outside the
|
|
618
|
+
supported fragment — a compound function-term, Number, or free
|
|
619
|
+
(unbound) Variable argument, an arithmetic comparison predicate,
|
|
620
|
+
a cross-sort equality, a quantifier of unknown type, or any
|
|
621
|
+
modal-family node other than Box/Diamond.
|
|
622
|
+
"""
|
|
623
|
+
if isinstance(node, Atom):
|
|
624
|
+
if node.predicate in _ARITHMETIC_PREDS:
|
|
625
|
+
raise NotImplementedError(
|
|
626
|
+
_UNSUPPORTED_ARITHMETIC_PRED.format(name=node.predicate))
|
|
627
|
+
if node.predicate in _EQUALITY_PREDS:
|
|
628
|
+
if len(node.args) != 2:
|
|
629
|
+
raise ValueError(
|
|
630
|
+
f"to_tptp_ncl: an equality/disequality atom "
|
|
631
|
+
f"({node.predicate!r}) must have exactly 2 arguments, "
|
|
632
|
+
f"got {len(node.args)}.")
|
|
633
|
+
left_sort = _term_sort(node.args[0], scope, symbols)
|
|
634
|
+
right_sort = _term_sort(node.args[1], scope, symbols)
|
|
635
|
+
if left_sort != right_sort:
|
|
636
|
+
raise NotImplementedError(_UNSUPPORTED_CROSS_SORT_EQUALITY.format(
|
|
637
|
+
pred=node.predicate, left=left_sort, right=right_sort))
|
|
638
|
+
if symbols.unsorted_equality is None and any(
|
|
639
|
+
isinstance(a, Variable) and scope[a.name] == _DEFAULT_SORT
|
|
640
|
+
for a in node.args):
|
|
641
|
+
symbols.unsorted_equality = node.to_unicode_str()
|
|
642
|
+
return node.to_tptp()
|
|
643
|
+
if node.predicate.startswith("$") or is_tptp_boolean_atom(node):
|
|
644
|
+
# TPTP's own words, and the truth constants under either spelling
|
|
645
|
+
# (``⊤`` / ``⊥`` are written ``$true`` / ``$false``): no symbol to declare.
|
|
646
|
+
for arg in node.args:
|
|
647
|
+
_term_sort(arg, scope, symbols)
|
|
648
|
+
return node.to_tptp()
|
|
649
|
+
arg_sorts = tuple(_term_sort(arg, scope, symbols) for arg in node.args)
|
|
650
|
+
symbols.note_predicate(node.predicate, arg_sorts)
|
|
651
|
+
return node.to_tptp()
|
|
652
|
+
if isinstance(node, Not):
|
|
653
|
+
return f"~({_render(node.formula, scope, symbols)})"
|
|
654
|
+
if isinstance(node, And):
|
|
655
|
+
return f"({_render(node.left, scope, symbols)} & {_render(node.right, scope, symbols)})"
|
|
656
|
+
if isinstance(node, Or):
|
|
657
|
+
return f"({_render(node.left, scope, symbols)} | {_render(node.right, scope, symbols)})"
|
|
658
|
+
if isinstance(node, Implies):
|
|
659
|
+
return f"({_render(node.left, scope, symbols)} => {_render(node.right, scope, symbols)})"
|
|
660
|
+
if isinstance(node, Iff):
|
|
661
|
+
return f"({_render(node.left, scope, symbols)} <=> {_render(node.right, scope, symbols)})"
|
|
662
|
+
if isinstance(node, Box):
|
|
663
|
+
return f"[.] {_render(node.formula, scope, symbols)}"
|
|
664
|
+
if isinstance(node, Diamond):
|
|
665
|
+
return f"<.> {_render(node.formula, scope, symbols)}"
|
|
666
|
+
if isinstance(node, (Quantifier, SortedQuantifier)):
|
|
667
|
+
sort = node.sort if isinstance(node, SortedQuantifier) else None
|
|
668
|
+
sort_token = _sort_token(sort) if sort is not None else _DEFAULT_SORT
|
|
669
|
+
if sort is not None:
|
|
670
|
+
symbols.note_sort(sort, sort_token)
|
|
671
|
+
var_token = Variable(node.variable.name).to_tptp()
|
|
672
|
+
new_scope = dict(scope)
|
|
673
|
+
new_scope[node.variable.name] = sort_token
|
|
674
|
+
body = _render(node.formula, new_scope, symbols)
|
|
675
|
+
prefix = _quantifier_prefix(node.type, var_token, sort_token)
|
|
676
|
+
return f"{prefix} : ({body})"
|
|
677
|
+
raise NotImplementedError(_UNSUPPORTED_NODE.format(name=type(node).__name__))
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
def to_tptp_ncl(formula: Node, *, frame: str = "K", domains: str = "constant",
|
|
681
|
+
conjecture_name: str = "c") -> str:
|
|
682
|
+
"""Render ``formula`` as a complete NXF (TPTP Non-Classical Logic) problem.
|
|
683
|
+
|
|
684
|
+
Covers the mono-modal ALETHIC fragment: Box/Diamond over
|
|
685
|
+
``¬``/``∧``/``∨``/``→``/``↔``, atoms of any arity, and native
|
|
686
|
+
``∀``/``∃`` quantifiers (:class:`~fol.nodes.Quantifier` /
|
|
687
|
+
:class:`~fol.nodes.SortedQuantifier`). See the module docstring for the
|
|
688
|
+
verified syntax sources and the exact scope boundary (compound function
|
|
689
|
+
terms, and non-alethic modal families, are documented, not-yet-
|
|
690
|
+
implemented extensions, not silently mistranslated).
|
|
691
|
+
|
|
692
|
+
The emitted problem is, in order:
|
|
693
|
+
|
|
694
|
+
1. A ``logic`` role statement fixing the four NXF modal parameters —
|
|
695
|
+
``$designation`` is fixed to ``$rigid`` and ``$terms`` to ``$global``
|
|
696
|
+
(the only combination the alethic fragment needs); ``$flexible``/
|
|
697
|
+
``$local`` are not exposed as they would only matter for a
|
|
698
|
+
flexible-designation extension this module does not attempt.
|
|
699
|
+
2. One ``tff(<sort>_type,type, <sort>: $tType ).`` per DISTINCT
|
|
700
|
+
user-declared sort the formula uses (``SortedQuantifier``/
|
|
701
|
+
``SortedConstant``), in first-occurrence order — TPTP's built-in
|
|
702
|
+
``$i`` (the default for every untyped Quantifier/Constant) needs no
|
|
703
|
+
such declaration and gets none (see :data:`_DEFAULT_SORT`).
|
|
704
|
+
3. One ``tff(<name>_decl,type, <name>: <sort> ).`` per DISTINCT free
|
|
705
|
+
constant the formula uses, in first-occurrence order.
|
|
706
|
+
4. One ``tff(<name>_decl,type, ...).`` per DISTINCT predicate the
|
|
707
|
+
formula uses, in first-occurrence order — ``<name>: $o`` for a 0-ary
|
|
708
|
+
(propositional) letter, ``<name>: <sort> > $o`` for one argument, or
|
|
709
|
+
``<name>: (<s1> * <s2> * ...) > $o`` for several — required because
|
|
710
|
+
NXF/NTF is a typed (TFF-based) dialect; an undeclared bare atom is
|
|
711
|
+
not accepted.
|
|
712
|
+
5. One ``conjecture`` role statement holding the translated ``formula``.
|
|
713
|
+
|
|
714
|
+
Args:
|
|
715
|
+
formula: a modal formula built from Box/Diamond/Not/And/Or/Implies/
|
|
716
|
+
Iff/Quantifier/SortedQuantifier over Atom nodes (the supported
|
|
717
|
+
fragment — see module docstring). Typically the result of
|
|
718
|
+
folding ``premises ⊨ conclusion`` into ``(∧premises) →
|
|
719
|
+
conclusion`` first (:func:`atp.leo3_backend`'s ``decide()`` does
|
|
720
|
+
this), since NXF has no separate premise list — one conjecture
|
|
721
|
+
is the whole problem.
|
|
722
|
+
frame: the alethic modal system — one of ``"K"``, ``"T"``, ``"S4"``,
|
|
723
|
+
``"S5"``, ``"D"`` (:class:`ValueError` listing the valid names
|
|
724
|
+
otherwise).
|
|
725
|
+
domains: the NXF ``$domains`` value — one of ``"constant"``,
|
|
726
|
+
``"varying"``, ``"cumulative"``, ``"decreasing"``
|
|
727
|
+
(:class:`ValueError` listing the valid names otherwise). Every
|
|
728
|
+
value selects a distinct ``$domains == ...`` token; NONE of them
|
|
729
|
+
changes how a quantifier is RENDERED (native ``!``/``?`` either
|
|
730
|
+
way) — see :data:`_DOMAIN_WORDS`'s docstring for exactly why
|
|
731
|
+
that is the correct, non-approximated behaviour rather than a
|
|
732
|
+
silent no-op.
|
|
733
|
+
conjecture_name: the TPTP statement name used for the ``conjecture``
|
|
734
|
+
role formula; the ``logic`` role statement is named
|
|
735
|
+
``<conjecture_name>_logic``.
|
|
736
|
+
|
|
737
|
+
Returns:
|
|
738
|
+
The complete NXF problem text, newline-terminated, ready to write to
|
|
739
|
+
a ``.p`` file for an NXF-aware prover (e.g. Leo-III via
|
|
740
|
+
:class:`atp.leo3_backend.Leo3Backend`).
|
|
741
|
+
|
|
742
|
+
Raises:
|
|
743
|
+
ValueError: ``frame`` or ``domains`` is not one of the recognised
|
|
744
|
+
values, or a Quantifier/SortedQuantifier has an unrecognised
|
|
745
|
+
``type``.
|
|
746
|
+
NotImplementedError: ``formula`` (or a descendant) is outside the
|
|
747
|
+
supported fragment, or two distinct kit symbols would collide
|
|
748
|
+
under NXF's identifier folding — see :func:`_render` /
|
|
749
|
+
:class:`_NxfSymbols`, or an equality over a variable bound by an
|
|
750
|
+
unsorted quantifier while a user sort occurs (a
|
|
751
|
+
:class:`~unicode_logic_kit.atp.tptp_tff.Tf0Refusal`, which is also
|
|
752
|
+
a ``ValueError``). That includes a predicate (or sort) and a
|
|
753
|
+
constant that fold to one word: this exporter returns bare text,
|
|
754
|
+
has no name map to record a rename in, and so refuses by name,
|
|
755
|
+
where :func:`~unicode_logic_kit.atp._tptp_problem
|
|
756
|
+
.generate_tptp_problem_with_mapping` renames the term side and
|
|
757
|
+
records it.
|
|
758
|
+
"""
|
|
759
|
+
if frame not in _FRAME_TO_SYSTEM:
|
|
760
|
+
raise ValueError(
|
|
761
|
+
f"to_tptp_ncl: unknown frame {frame!r} (use one of {sorted(_FRAME_TO_SYSTEM)})")
|
|
762
|
+
if domains not in _DOMAIN_WORDS:
|
|
763
|
+
raise ValueError(
|
|
764
|
+
f"to_tptp_ncl: unknown domains {domains!r} (use one of {sorted(_DOMAIN_WORDS)})")
|
|
765
|
+
|
|
766
|
+
# _render walks the WHOLE tree, collecting every sort/constant/predicate
|
|
767
|
+
# into `symbols` and raising before anything is emitted if any node (or
|
|
768
|
+
# term) is outside the supported fragment.
|
|
769
|
+
symbols = _NxfSymbols()
|
|
770
|
+
body = _render(formula, {}, symbols)
|
|
771
|
+
symbols.check_no_cross_namespace_collision()
|
|
772
|
+
if symbols.unsorted_equality is not None and symbols.sort_order:
|
|
773
|
+
# TFF's types are disjoint, so the unsorted variable of the equation ranges
|
|
774
|
+
# over $i, not over the universe a user sort is a subset of (the same
|
|
775
|
+
# refusal as the TF0 writer's; see unsorted_equality_refusal).
|
|
776
|
+
raise unsorted_equality_refusal(
|
|
777
|
+
"to_tptp_ncl", symbols.unsorted_equality,
|
|
778
|
+
[symbols.sort_sig[token] for token in symbols.sort_order], _DEFAULT_SORT)
|
|
779
|
+
|
|
780
|
+
lines = [
|
|
781
|
+
f"tff({conjecture_name}_logic,logic,",
|
|
782
|
+
" $modal ==",
|
|
783
|
+
f" [ $domains == {_DOMAIN_WORDS[domains]},",
|
|
784
|
+
" $designation == $rigid,",
|
|
785
|
+
" $terms == $global,",
|
|
786
|
+
f" $modalities == {_FRAME_TO_SYSTEM[frame]} ] ).",
|
|
787
|
+
"",
|
|
788
|
+
]
|
|
789
|
+
for token in symbols.sort_order:
|
|
790
|
+
lines.append(f"tff({token}_type,type,")
|
|
791
|
+
lines.append(f" {token}: $tType ).")
|
|
792
|
+
lines.append("")
|
|
793
|
+
for token in symbols.const_order:
|
|
794
|
+
_, sort_token = symbols.const_sig[token]
|
|
795
|
+
lines.append(f"tff({token}_decl,type,")
|
|
796
|
+
lines.append(f" {token}: {sort_token} ).")
|
|
797
|
+
lines.append("")
|
|
798
|
+
for token in symbols.pred_order:
|
|
799
|
+
_, arg_sorts = symbols.pred_sig[token]
|
|
800
|
+
lines.append(f"tff({token}_decl,type,")
|
|
801
|
+
if not arg_sorts:
|
|
802
|
+
lines.append(f" {token}: $o ).")
|
|
803
|
+
elif len(arg_sorts) == 1:
|
|
804
|
+
lines.append(f" {token}: {arg_sorts[0]} > $o ).")
|
|
805
|
+
else:
|
|
806
|
+
domain = " * ".join(arg_sorts)
|
|
807
|
+
lines.append(f" {token}: ({domain}) > $o ).")
|
|
808
|
+
lines.append("")
|
|
809
|
+
lines.append(f"tff({conjecture_name},conjecture,")
|
|
810
|
+
lines.append(f" {body} ).")
|
|
811
|
+
return "\n".join(lines) + "\n"
|