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,94 @@
|
|
|
1
|
+
"""The ``drt`` subpackage — Discourse Representation Theory (Kamp & Reyle).
|
|
2
|
+
|
|
3
|
+
Single-sentence FOL cannot express **cross-sentence anaphora** ("A farmer owns a donkey.
|
|
4
|
+
He beats it.") or **donkey sentences** ("Every farmer who owns a donkey beats it.") — the
|
|
5
|
+
pronoun's antecedent lives in a different sentence/clause than the pronoun, and the donkey
|
|
6
|
+
sentence's indefinite ("a donkey") gets a UNIVERSAL reading once it sits in a conditional's
|
|
7
|
+
antecedent. Discourse Representation Theory (Kamp & Reyle, *From Discourse to Logic*, 1993)
|
|
8
|
+
is the classical fix: represent a discourse as a **box** of referents + conditions, with a
|
|
9
|
+
structural ACCESSIBILITY relation deciding which referents a pronoun (or a later sentence)
|
|
10
|
+
can see, then give the whole box a first-order **standard translation** that gets the
|
|
11
|
+
donkey reading right for free.
|
|
12
|
+
|
|
13
|
+
This subpackage implements exactly that core, and nothing beyond it — see "Scope" below.
|
|
14
|
+
|
|
15
|
+
Modules
|
|
16
|
+
---------
|
|
17
|
+
* :mod:`unicode_logic_kit.drt.nodes` — the ``DRS`` data model (``referents``, ``conditions``)
|
|
18
|
+
and its condition variants — the five classical ones (``Pred``, ``Eq``, ``Neg``, ``Impl``, ``Or``) plus the 0.24.0 plural-DRT pair (``Card``, ``Part``) —
|
|
19
|
+
plus the accessibility checker :meth:`~unicode_logic_kit.drt.nodes.DRS.validate`.
|
|
20
|
+
* :mod:`unicode_logic_kit.drt.parser` — :func:`~unicode_logic_kit.drt.parser.parse_drs` for a
|
|
21
|
+
compact hand-written box notation, and
|
|
22
|
+
:func:`~unicode_logic_kit.drt.parser.parse_sbn` for a precisely documented SUBSET of the
|
|
23
|
+
Parallel Meaning Bank's Sequence Box Notation (SBN) — PMB is the natural "found data"
|
|
24
|
+
source of real DRSs, so SBN is this subpackage's interchange FROM format.
|
|
25
|
+
* :mod:`unicode_logic_kit.drt.resolve` — :func:`~unicode_logic_kit.drt.resolve.resolve_anaphora`,
|
|
26
|
+
accessibility-respecting pronoun resolution (right-to-left / most-recent preference; not
|
|
27
|
+
an NLP guesser — see that module's docstring).
|
|
28
|
+
* :mod:`unicode_logic_kit.drt.export` — :func:`~unicode_logic_kit.drt.export.drs_to_fol`, the
|
|
29
|
+
standard translation into the kit's own FOL AST
|
|
30
|
+
(:mod:`unicode_logic_kit.fol.nodes`), ready for ``unicode_logic_kit.api.prove`` /
|
|
31
|
+
``unicode_logic_kit.api.check``.
|
|
32
|
+
* :mod:`unicode_logic_kit.drt.reverse` — :func:`~unicode_logic_kit.drt.reverse.fol_to_drs`,
|
|
33
|
+
the standard translation run BACKWARDS: rebuilds the box structure of any
|
|
34
|
+
formula in the export's image and refuses everything outside it by name
|
|
35
|
+
(:class:`~unicode_logic_kit.drt.reverse.FolToDrsError`) — the bridge that
|
|
36
|
+
lets ``ace.formula_to_ace`` answer "is this formula expressible as ACE?".
|
|
37
|
+
|
|
38
|
+
Quick usage — the classic donkey sentence, entailed from its premises via Z3::
|
|
39
|
+
|
|
40
|
+
from unicode_logic_kit import drt, api
|
|
41
|
+
|
|
42
|
+
rule = drt.parse_drs(
|
|
43
|
+
"[x, y | Farmer(x), Donkey(y), Owns(x, y)] -> [ | Beats(x, y)]")
|
|
44
|
+
facts = drt.parse_drs("[ | Farmer(john), Donkey(daisy), Owns(john, daisy)]")
|
|
45
|
+
goal = drt.parse_drs("[ | Beats(john, daisy)]")
|
|
46
|
+
|
|
47
|
+
v = api.prove(drt.drs_to_fol(goal),
|
|
48
|
+
[drt.drs_to_fol(rule), drt.drs_to_fol(facts)])
|
|
49
|
+
assert v.status == "proved"
|
|
50
|
+
|
|
51
|
+
Scope (deliberately tight — this is a single kit subpackage, not a discourse-parsing system)
|
|
52
|
+
------------------------------------------------------------------------------------------------
|
|
53
|
+
IN scope: the classical propositional DRS core (five condition variants), box-notation and
|
|
54
|
+
SBN-subset parsing, accessibility-respecting explicit-marker pronoun resolution, and the
|
|
55
|
+
standard translation to FOL.
|
|
56
|
+
|
|
57
|
+
OUT of scope, refused loudly rather than silently approximated:
|
|
58
|
+
|
|
59
|
+
* multi-paragraph discourse machinery (discourse segmentation, rhetorical relations,
|
|
60
|
+
coreference chains spanning many sentences) — this subpackage parses and represents ONE
|
|
61
|
+
assembled DRS (one sentence, or a small hand-built discourse) per call;
|
|
62
|
+
* event semantics beyond plain predicates (no Davidsonian event variables are threaded
|
|
63
|
+
through automatically, no thematic-role ontology beyond "whatever role name the input
|
|
64
|
+
uses") — a ``Pred``'s arguments are exactly what the box notation or SBN input says;
|
|
65
|
+
* presupposition projection (definites, factives, "again", ...) — DRT's presupposition
|
|
66
|
+
extensions (van der Sandt's binding theory and successors) are a substantial theory of
|
|
67
|
+
their own and are not implemented here; a presupposition trigger in an SBN/box-notation
|
|
68
|
+
input is just an ordinary predicate as far as this subpackage is concerned, with no
|
|
69
|
+
special accommodation/binding behaviour.
|
|
70
|
+
|
|
71
|
+
See each module's docstring for the precise grammar/semantics decisions and their sources.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
from .nodes import (
|
|
75
|
+
DRS, Card, CARD_OPS, Condition, Pred, Eq, Neg, Impl, Or, Part,
|
|
76
|
+
is_referent, is_predicate_name, is_constant_name, walk_boxes,
|
|
77
|
+
)
|
|
78
|
+
from .parser import (
|
|
79
|
+
parse_drs, DRSSyntaxError,
|
|
80
|
+
parse_sbn, SBNSyntaxError, SBNMapping,
|
|
81
|
+
)
|
|
82
|
+
from .resolve import resolve_anaphora, Resolution, ResolutionReport, PRONOUN
|
|
83
|
+
from .export import drs_to_fol
|
|
84
|
+
from .reverse import fol_to_drs, FolToDrsError
|
|
85
|
+
|
|
86
|
+
__all__ = [
|
|
87
|
+
"DRS", "Condition", "Pred", "Eq", "Neg", "Impl", "Or", "Card", "Part",
|
|
88
|
+
"CARD_OPS",
|
|
89
|
+
"is_referent", "is_predicate_name", "is_constant_name", "walk_boxes",
|
|
90
|
+
"parse_drs", "DRSSyntaxError",
|
|
91
|
+
"parse_sbn", "SBNSyntaxError", "SBNMapping",
|
|
92
|
+
"resolve_anaphora", "Resolution", "ResolutionReport", "PRONOUN",
|
|
93
|
+
"drs_to_fol", "fol_to_drs", "FolToDrsError",
|
|
94
|
+
]
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""The standard translation of DRT into first-order logic (unicode_logic_kit.drt.export).
|
|
2
|
+
|
|
3
|
+
The standard translation (Kamp & Reyle, *From Discourse to Logic*, 1993) reads a box's
|
|
4
|
+
own referents as existential quantifiers over the conjunction of its conditions, with two
|
|
5
|
+
condition types contributing their own quantificational structure:
|
|
6
|
+
|
|
7
|
+
* ``Pred(name, args)`` ↦ ``name(args...)`` (an atom; each arg is a Variable if it's a
|
|
8
|
+
referent — :func:`~unicode_logic_kit.drt.nodes.is_referent` — else a Constant)
|
|
9
|
+
* ``Eq(a, b)`` ↦ ``a = b``
|
|
10
|
+
* ``Neg(D)`` ↦ ``¬τ(D)`` where ``τ(D)`` existentially closes D's own
|
|
11
|
+
referents — i.e. ``¬∃...`` : negation-as-failure-to-find-a-witness, matching the
|
|
12
|
+
accessibility rule that D's referents don't escape it (see ``nodes.py``).
|
|
13
|
+
* ``Or(D1, D2)`` ↦ ``τ(D1) ∨ τ(D2)`` — each disjunct closes its own referents
|
|
14
|
+
independently, again matching D1/D2's mutually inaccessible referents.
|
|
15
|
+
* ``Impl(A, B)`` ↦ ``∀(A's referents) (conj(A's conditions) → τ(B))`` — THE
|
|
16
|
+
donkey-sentence rule. Unlike every other condition, A's referents become UNIVERSAL
|
|
17
|
+
(not existential) quantifiers, and A's own conditions are conjoined DIRECTLY into the
|
|
18
|
+
antecedent (NOT re-wrapped in their own existential closure) — both together are what
|
|
19
|
+
make "Every farmer who owns a donkey beats it" come out as ``∀x∀y((Farmer(x) ∧
|
|
20
|
+
Donkey(y) ∧ Owns(x,y)) → Beats(x,y))`` rather than something existential-then-vacuous.
|
|
21
|
+
``τ(B)`` (B's OWN translation, i.e. its own referents existentially closed as usual) is
|
|
22
|
+
the consequent — B may introduce further referents of its own beyond what A shares with
|
|
23
|
+
it (accessible to B per the donkey accessibility rule, but not bound by A's ∀ unless
|
|
24
|
+
they ARE A's own referents).
|
|
25
|
+
|
|
26
|
+
A box with zero conditions translates to a reflexive-equality tautology (``c_tautology =
|
|
27
|
+
c_tautology`` — a constant the kit's own parser reads back) — the same "no constraint" idiom
|
|
28
|
+
:mod:`unicode_logic_kit.dl.translate` uses for an empty TBox/ABox — so an empty box never
|
|
29
|
+
silently vanishes into an ill-typed conjunction of zero formulas.
|
|
30
|
+
|
|
31
|
+
Closedness, and why :func:`drs_to_fol` always calls :meth:`~unicode_logic_kit.drt.nodes.DRS.validate`
|
|
32
|
+
-----------------------------------------------------------------------------------------------------
|
|
33
|
+
The classical Kamp/Reyle accessibility relation (see ``nodes.py``'s module docstring) is
|
|
34
|
+
EXACTLY the condition under which this translation binds every referent it uses: a
|
|
35
|
+
referent-shaped argument is accessible to the box it occurs in iff, walking the same
|
|
36
|
+
recursive structure this translation walks, some ∃/∀ introduced along the way would bind
|
|
37
|
+
it. So an accessibility VIOLATION (a referent used somewhere it isn't accessible)
|
|
38
|
+
translates to a genuinely FREE variable in the output formula — silently. To make that
|
|
39
|
+
impossible, :func:`drs_to_fol` calls ``drs.validate()`` before translating anything, so an
|
|
40
|
+
invalid DRS is refused loudly (``ValueError`` from ``validate()``) rather than handed back
|
|
41
|
+
as an FOL formula that fails ``unicode_logic_kit.api.check(...).ok`` for a reason the caller
|
|
42
|
+
would have to rediscover by re-deriving accessibility themselves.
|
|
43
|
+
|
|
44
|
+
Constants
|
|
45
|
+
-----------
|
|
46
|
+
By the time a DRS reaches this module, every constant-shaped ``Pred``/``Eq`` argument is
|
|
47
|
+
ALREADY a legal kit constant name — :mod:`unicode_logic_kit.drt.nodes` refuses anything else
|
|
48
|
+
at construction time, and :mod:`unicode_logic_kit.drt.parser` sanitizes quoted/irregular
|
|
49
|
+
constants (recording the mapping) before ever building a ``Pred``/``Eq``. So this module
|
|
50
|
+
does no sanitization of its own: a non-referent argument becomes
|
|
51
|
+
``unicode_logic_kit.fol.nodes.Constant(name)`` verbatim.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
from typing import List
|
|
55
|
+
|
|
56
|
+
from ..fol.nodes import (
|
|
57
|
+
Node, Variable, Constant, Atom, Count, Number,
|
|
58
|
+
Not as _FNot, And as _FAnd, Or as _FOr, Implies, Quantifier,
|
|
59
|
+
)
|
|
60
|
+
from .nodes import (
|
|
61
|
+
DRS, Card, Condition, Eq, Impl, Neg, Or, Part, Pred, is_referent,
|
|
62
|
+
walk_boxes,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
__all__ = ["drs_to_fol"]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class _FreshCounters:
|
|
69
|
+
"""Fresh counting variables for :class:`Card` translations.
|
|
70
|
+
|
|
71
|
+
``Card(g, ">=", 3)`` becomes ``∃≥3 p (Part_of(p, g))`` and the counting
|
|
72
|
+
variable ``p`` must collide with NOTHING the tree declares — a clash
|
|
73
|
+
would capture. Seeded once per :func:`drs_to_fol` call with every
|
|
74
|
+
declared referent, then hands out ``p1, p2, …`` skipping taken names.
|
|
75
|
+
(``Count`` binds its own variable, so two Cards may NOT share one name
|
|
76
|
+
if one ends up in the scope of the other's matrix — cheap to avoid by
|
|
77
|
+
never reusing any.)
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def __init__(self, drs: DRS):
|
|
81
|
+
self.taken = {r for box, _ in walk_boxes(drs) for r in box.referents}
|
|
82
|
+
self.i = 0
|
|
83
|
+
|
|
84
|
+
def next(self) -> str:
|
|
85
|
+
while True:
|
|
86
|
+
self.i += 1
|
|
87
|
+
candidate = f"p{self.i}"
|
|
88
|
+
if candidate not in self.taken:
|
|
89
|
+
self.taken.add(candidate)
|
|
90
|
+
return candidate
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
#: Card's kit-spelled ops onto Count's op codes; ``>``/``<`` shift the bound
|
|
94
|
+
#: (``> n`` ≡ ``≥ n+1``; ``< n`` ≡ ``≤ n-1``, and ``< 0`` is refused at
|
|
95
|
+
#: Card construction so the subtraction never goes negative).
|
|
96
|
+
_CARD_TO_COUNT = {"=": ("eq", 0), ">=": ("ge", 0), "<=": ("le", 0),
|
|
97
|
+
">": ("ge", +1), "<": ("le", -1)}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _term(name: str) -> Node:
|
|
101
|
+
"""A DRS argument (already validated legal by nodes.py) as a FOL term."""
|
|
102
|
+
return Variable(name) if is_referent(name) else Constant(name)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# The constant the empty-box tautology is built from. ``c_`` plus a word is the
|
|
106
|
+
# kit's CONSTANT terminal (fol._identifiers.constant_pattern), so the text this
|
|
107
|
+
# prints reads back through api.parse_any as the SAME formula. Until 0.30.0 it
|
|
108
|
+
# was Constant("_"), which printed `_ = _` -- text the kit's own parser rejects
|
|
109
|
+
# ("Unexpected character '_'"): drs_to_fol(DRS(referents=(), conditions=()))
|
|
110
|
+
# was a formula that could be computed but not handed back as text. The same
|
|
111
|
+
# fix, and the same name, as unicode_logic_kit.dl.translate's. `c = c` is valid
|
|
112
|
+
# whatever `c` denotes, so a DRS that happens to use a constant `c_tautology`
|
|
113
|
+
# is still rendered correctly.
|
|
114
|
+
_TAUTOLOGY_CONSTANT = Constant("c_tautology")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _tautology() -> Node:
|
|
118
|
+
"""The FOL image of "no constraint" — an empty box's condition list. Mirrors
|
|
119
|
+
unicode_logic_kit.dl.translate's empty-TBox/ABox idiom."""
|
|
120
|
+
return Atom("=", (_TAUTOLOGY_CONSTANT, _TAUTOLOGY_CONSTANT))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _conjoin(parts: List[Node]) -> Node:
|
|
124
|
+
"""Fold a (possibly empty) list of formulas into a single left-associated conjunction."""
|
|
125
|
+
if not parts:
|
|
126
|
+
return _tautology()
|
|
127
|
+
result = parts[0]
|
|
128
|
+
for p in parts[1:]:
|
|
129
|
+
result = _FAnd(result, p)
|
|
130
|
+
return result
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _translate_cond(cond: Condition, fresh: _FreshCounters) -> Node:
|
|
134
|
+
if isinstance(cond, Pred):
|
|
135
|
+
return Atom(cond.name, tuple(_term(a) for a in cond.args))
|
|
136
|
+
if isinstance(cond, Eq):
|
|
137
|
+
return Atom("=", (_term(cond.a), _term(cond.b)))
|
|
138
|
+
if isinstance(cond, Card):
|
|
139
|
+
op, shift = _CARD_TO_COUNT[cond.op]
|
|
140
|
+
counter = fresh.next()
|
|
141
|
+
return Count(op, Number(cond.n + shift), Variable(counter),
|
|
142
|
+
Atom("Part_of", (Variable(counter), _term(cond.ref))))
|
|
143
|
+
if isinstance(cond, Part):
|
|
144
|
+
return Atom("Part_of", (_term(cond.member), _term(cond.group)))
|
|
145
|
+
if isinstance(cond, Neg):
|
|
146
|
+
return _FNot(_translate_box(cond.drs, fresh))
|
|
147
|
+
if isinstance(cond, Impl):
|
|
148
|
+
antecedent = _conjoin([_translate_cond(c, fresh)
|
|
149
|
+
for c in cond.antecedent.conditions])
|
|
150
|
+
result: Node = Implies(antecedent, _translate_box(cond.consequent, fresh))
|
|
151
|
+
for r in reversed(cond.antecedent.referents):
|
|
152
|
+
result = Quantifier("∀", Variable(r), result)
|
|
153
|
+
return result
|
|
154
|
+
if isinstance(cond, Or):
|
|
155
|
+
return _FOr(_translate_box(cond.left, fresh),
|
|
156
|
+
_translate_box(cond.right, fresh))
|
|
157
|
+
raise TypeError(f"drs_to_fol: unsupported condition {type(cond).__name__}")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _translate_box(box: DRS, fresh: _FreshCounters) -> Node:
|
|
161
|
+
result: Node = _conjoin([_translate_cond(c, fresh) for c in box.conditions])
|
|
162
|
+
for r in reversed(box.referents):
|
|
163
|
+
result = Quantifier("∃", Variable(r), result)
|
|
164
|
+
return result
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def drs_to_fol(drs: DRS) -> Node:
|
|
168
|
+
"""The standard translation of ``drs`` into a kit FOL :class:`~unicode_logic_kit.fol.nodes.Node`
|
|
169
|
+
(see the module docstring for the per-condition rules and the donkey-sentence rule
|
|
170
|
+
for ``Impl``).
|
|
171
|
+
|
|
172
|
+
Calls ``drs.validate()`` first, so an accessibility violation is refused
|
|
173
|
+
(``ValueError``) here rather than silently producing a formula with a free variable
|
|
174
|
+
(see "Closedness" above). For a CLOSED, accessibility-valid ``drs`` the result is a
|
|
175
|
+
closed formula — ``unicode_logic_kit.api.check(drs_to_fol(drs)).ok`` holds — ready for
|
|
176
|
+
``unicode_logic_kit.api.prove``.
|
|
177
|
+
"""
|
|
178
|
+
drs.validate()
|
|
179
|
+
return _translate_box(drs, _FreshCounters(drs))
|