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,157 @@
|
|
|
1
|
+
"""Robinson first-order term unification (with occurs-check).
|
|
2
|
+
|
|
3
|
+
Computes a most-general unifier (MGU) of two terms, or of two atoms, over the
|
|
4
|
+
classical term language: Variable, Constant, Number, Function (and Atom for the
|
|
5
|
+
literal case). A substitution is a plain dict mapping a variable NAME (str) to a
|
|
6
|
+
term Node. The algorithm is functional: inputs are never mutated, and the input
|
|
7
|
+
substitution is copied before any binding is added.
|
|
8
|
+
|
|
9
|
+
Unification rules:
|
|
10
|
+
- A Variable unifies with any term t, binding its name to t, provided the
|
|
11
|
+
occurs-check passes (the variable does not occur in t under the current
|
|
12
|
+
substitution).
|
|
13
|
+
- Constant and Number unify iff they are equal (same value).
|
|
14
|
+
- Function unify iff they share name and arity and their arguments unify
|
|
15
|
+
pairwise.
|
|
16
|
+
- Atom unify iff they share predicate and arity and their arguments unify
|
|
17
|
+
pairwise.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from typing import Dict, Optional
|
|
21
|
+
|
|
22
|
+
from .nodes import Variable, Constant, Number, Function, Atom, Node, Measure
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def apply_subst(node: Node, subst: Dict[str, Node]) -> Node:
|
|
26
|
+
"""Apply substitution subst to node, returning a new node.
|
|
27
|
+
|
|
28
|
+
Recurses into Function/Atom arguments. A Variable is replaced by its bound
|
|
29
|
+
term when its name is a key of subst (the replacement is itself substituted
|
|
30
|
+
into, so chained bindings resolve fully); otherwise it is returned
|
|
31
|
+
unchanged. Constants and Numbers are returned unchanged. The input node is
|
|
32
|
+
never mutated.
|
|
33
|
+
"""
|
|
34
|
+
if isinstance(node, Variable):
|
|
35
|
+
if node.name in subst:
|
|
36
|
+
return apply_subst(subst[node.name], subst)
|
|
37
|
+
return node
|
|
38
|
+
if isinstance(node, (Constant, Number)):
|
|
39
|
+
return node
|
|
40
|
+
if isinstance(node, Function):
|
|
41
|
+
return Function(node.name, [apply_subst(a, subst) for a in node.args])
|
|
42
|
+
if isinstance(node, Measure):
|
|
43
|
+
# μ(entity, dimension) is an ordinary binary term (lowered to the
|
|
44
|
+
# function measure/2 by the exports): substitute into both slots.
|
|
45
|
+
return Measure(apply_subst(node.entity, subst),
|
|
46
|
+
apply_subst(node.dimension, subst))
|
|
47
|
+
if isinstance(node, Atom):
|
|
48
|
+
return Atom(node.predicate, [apply_subst(a, subst) for a in node.args])
|
|
49
|
+
raise TypeError(f"apply_subst: unsupported node type {type(node).__name__}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _occurs(name: str, term: Node, subst: Dict[str, Node]) -> bool:
|
|
53
|
+
"""Return True if the variable name occurs in term after applying subst.
|
|
54
|
+
|
|
55
|
+
Used by the occurs-check to reject bindings such as x ↦ f(x) that would
|
|
56
|
+
create an infinite (cyclic) term.
|
|
57
|
+
"""
|
|
58
|
+
term = apply_subst(term, subst)
|
|
59
|
+
if isinstance(term, Variable):
|
|
60
|
+
return term.name == name
|
|
61
|
+
if isinstance(term, (Function, Atom)):
|
|
62
|
+
return any(_occurs(name, a, subst) for a in term.args)
|
|
63
|
+
if isinstance(term, Measure):
|
|
64
|
+
return (_occurs(name, term.entity, subst)
|
|
65
|
+
or _occurs(name, term.dimension, subst))
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _bind(name: str, term: Node, subst: Dict[str, Node]) -> Optional[Dict[str, Node]]:
|
|
70
|
+
"""Extend subst with the binding name ↦ term, with occurs-check.
|
|
71
|
+
|
|
72
|
+
Returns a new substitution dict (the input is copied, never mutated), or
|
|
73
|
+
None if the occurs-check fails. Binding a variable to itself is a no-op that
|
|
74
|
+
leaves the substitution unchanged.
|
|
75
|
+
"""
|
|
76
|
+
if isinstance(term, Variable) and term.name == name:
|
|
77
|
+
return subst
|
|
78
|
+
if _occurs(name, term, subst):
|
|
79
|
+
return None
|
|
80
|
+
new_subst = dict(subst)
|
|
81
|
+
new_subst[name] = apply_subst(term, subst)
|
|
82
|
+
return new_subst
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def unify(t1: Node, t2: Node, subst: Optional[Dict[str, Node]] = None) -> Optional[Dict[str, Node]]:
|
|
86
|
+
"""Most-general unifier of t1 and t2, or None if they do not unify.
|
|
87
|
+
|
|
88
|
+
Robinson's algorithm with occurs-check. The result is a dict mapping
|
|
89
|
+
variable NAME -> term such that applying it to t1 and t2 (via apply_subst)
|
|
90
|
+
yields structurally equal nodes. An empty dict means the terms are already
|
|
91
|
+
equal / trivially unifiable.
|
|
92
|
+
|
|
93
|
+
Accepts Variable, Constant, Number, Function term nodes, or two Atoms (which
|
|
94
|
+
unify iff they share predicate and arity and their arguments unify
|
|
95
|
+
pairwise). The optional subst argument is treated as immutable: it is copied
|
|
96
|
+
before extension, never modified in place.
|
|
97
|
+
"""
|
|
98
|
+
if subst is None:
|
|
99
|
+
subst = {}
|
|
100
|
+
|
|
101
|
+
t1 = apply_subst(t1, subst)
|
|
102
|
+
t2 = apply_subst(t2, subst)
|
|
103
|
+
|
|
104
|
+
# Variable on either side: bind it (occurs-check inside _bind).
|
|
105
|
+
if isinstance(t1, Variable):
|
|
106
|
+
return _bind(t1.name, t2, subst)
|
|
107
|
+
if isinstance(t2, Variable):
|
|
108
|
+
return _bind(t2.name, t1, subst)
|
|
109
|
+
|
|
110
|
+
# Constants / Numbers: unify iff equal in value.
|
|
111
|
+
if isinstance(t1, (Constant, Number)) or isinstance(t2, (Constant, Number)):
|
|
112
|
+
if type(t1) is type(t2) and _leaf_value(t1) == _leaf_value(t2):
|
|
113
|
+
return subst
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
# Function applications: same name + arity, then unify arguments pairwise.
|
|
117
|
+
if isinstance(t1, Function) and isinstance(t2, Function):
|
|
118
|
+
if t1.name != t2.name or len(t1.args) != len(t2.args):
|
|
119
|
+
return None
|
|
120
|
+
return _unify_args(t1.args, t2.args, subst)
|
|
121
|
+
|
|
122
|
+
# Measure terms: a fixed binary function symbol — unify slot-wise. Purely
|
|
123
|
+
# syntactic: a Measure never unifies with a Function (even one literally
|
|
124
|
+
# named "measure"); the measure/2 spelling is an EXPORT convention, not an
|
|
125
|
+
# AST identity.
|
|
126
|
+
if isinstance(t1, Measure) and isinstance(t2, Measure):
|
|
127
|
+
return _unify_args((t1.entity, t1.dimension),
|
|
128
|
+
(t2.entity, t2.dimension), subst)
|
|
129
|
+
|
|
130
|
+
# Atoms (literal-level unification): same predicate + arity, then args.
|
|
131
|
+
if isinstance(t1, Atom) and isinstance(t2, Atom):
|
|
132
|
+
if t1.predicate != t2.predicate or len(t1.args) != len(t2.args):
|
|
133
|
+
return None
|
|
134
|
+
return _unify_args(t1.args, t2.args, subst)
|
|
135
|
+
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _leaf_value(node: Node):
|
|
140
|
+
"""Return the comparable payload of a leaf node (Constant name / Number value)."""
|
|
141
|
+
if isinstance(node, Constant):
|
|
142
|
+
return node.name
|
|
143
|
+
if isinstance(node, Number):
|
|
144
|
+
return node.value
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _unify_args(args1, args2, subst: Dict[str, Node]) -> Optional[Dict[str, Node]]:
|
|
149
|
+
"""Unify two equal-length argument lists left-to-right, threading the substitution.
|
|
150
|
+
|
|
151
|
+
Returns the accumulated substitution, or None as soon as any pair fails.
|
|
152
|
+
"""
|
|
153
|
+
for a, b in zip(args1, args2):
|
|
154
|
+
subst = unify(a, b, subst)
|
|
155
|
+
if subst is None:
|
|
156
|
+
return None
|
|
157
|
+
return subst
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""Verbalize a formula as an English sentence (a readability aid, not a parse inverse).
|
|
2
|
+
|
|
3
|
+
``to_english(node)`` renders a formula with structural English templates: ``∀x φ`` →
|
|
4
|
+
"for every x, …", ``A → B`` → "if A, then B", a unary atom ``Human(x)`` → "x is
|
|
5
|
+
human", an equality → "a is equal to b", and so on. It is deliberately predictable
|
|
6
|
+
rather than fluent, and — unlike ``to_unicode_str``/``parse`` — it is **not** an exact
|
|
7
|
+
round-trip: the English phrasing of nested connectives can be ambiguous. Use it to
|
|
8
|
+
explain a formula, not to re-parse one.
|
|
9
|
+
|
|
10
|
+
The two truth constants (the nullary atoms ``$true`` / ``⊤`` and ``$false`` / ``⊥``) are
|
|
11
|
+
not propositional letters and are not printed as one: ``⊤`` is read "truth" and ``⊥``
|
|
12
|
+
"falsity", so ``P → ⊥`` is "if P, then falsity" and ``¬⊥`` is "it is not the case that
|
|
13
|
+
falsity". A nullary atom of any other name is read as its name.
|
|
14
|
+
|
|
15
|
+
Public API: :func:`to_english`.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from ..fol.nodes import (
|
|
19
|
+
Node, Atom, Not, And, Or, Xor, Implies, Iff, Quantifier,
|
|
20
|
+
Variable, Constant, Number, Function,
|
|
21
|
+
SortedQuantifier, SortedConstant,
|
|
22
|
+
Count, Measure, Cardinality, Contrast,
|
|
23
|
+
SortedCount, SortedCardinality,
|
|
24
|
+
Nominal, At,
|
|
25
|
+
Dependence, SlashedExists,
|
|
26
|
+
Tensor, With, OPlus, LinearImplies, OfCourse, One,
|
|
27
|
+
Product, Under, Over,
|
|
28
|
+
Box, Diamond, Knows, Believes, Says, Wants, Obligatory, Permitted,
|
|
29
|
+
Always, Eventually, Next, Until,
|
|
30
|
+
Historically, Once, Previous, Since,
|
|
31
|
+
Would, Might,
|
|
32
|
+
WeakConjunction, WeakDisjunction, StrongConjunction, StrongDisjunction,
|
|
33
|
+
LukNegation, LukImplication, LukEquivalence,
|
|
34
|
+
)
|
|
35
|
+
from ._so_nodes import SecondOrderQuantifier
|
|
36
|
+
from ._modal_nodes import Announce, AnnounceDiamond
|
|
37
|
+
from ._truth_constants import truth_value
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Counting-quantifier op codes → English determiner phrases.
|
|
41
|
+
_COUNT_WORDS = {"ge": "at least", "le": "at most", "eq": "exactly"}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Comparison / equality predicates rendered with an English copula.
|
|
45
|
+
_COPULA = {
|
|
46
|
+
"=": ("is equal to", "is not equal to"),
|
|
47
|
+
"≠": ("is not equal to", "is equal to"),
|
|
48
|
+
"<": ("is less than", "is not less than"),
|
|
49
|
+
">": ("is greater than", "is not greater than"),
|
|
50
|
+
"≤": ("is at most", "is greater than"),
|
|
51
|
+
"≥": ("is at least", "is less than"),
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _term(node: Node) -> str:
|
|
56
|
+
"""Render a term in a readable form."""
|
|
57
|
+
if isinstance(node, (Variable, Constant, SortedConstant)):
|
|
58
|
+
return node.name
|
|
59
|
+
if isinstance(node, Number):
|
|
60
|
+
return str(node.value)
|
|
61
|
+
if isinstance(node, Function):
|
|
62
|
+
return f"{node.name}({', '.join(_term(a) for a in node.args)})"
|
|
63
|
+
if isinstance(node, Measure):
|
|
64
|
+
return f"the {_term(node.dimension)} of {_term(node.entity)}"
|
|
65
|
+
if isinstance(node, Cardinality):
|
|
66
|
+
return f"the number of {node.variable.name} such that {to_english(node.formula)}"
|
|
67
|
+
if isinstance(node, SortedCardinality):
|
|
68
|
+
return (f"the number of {node.variable.name} of sort {node.sort} such that "
|
|
69
|
+
f"{to_english(node.formula)}")
|
|
70
|
+
return node.to_unicode_str()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _atom(node: Atom, negated: bool = False) -> str:
|
|
74
|
+
"""Render an atom (optionally negated) in English."""
|
|
75
|
+
pred, args = node.predicate, node.args
|
|
76
|
+
if pred in _COPULA and len(args) == 2:
|
|
77
|
+
phrase = _COPULA[pred][1 if negated else 0]
|
|
78
|
+
return f"{_term(args[0])} {phrase} {_term(args[1])}"
|
|
79
|
+
if len(args) == 0:
|
|
80
|
+
constant = truth_value(node)
|
|
81
|
+
if constant is None:
|
|
82
|
+
body = pred
|
|
83
|
+
else:
|
|
84
|
+
body = "truth" if constant else "falsity" # the truth constants, not letters
|
|
85
|
+
return f"it is not the case that {body}" if negated else body
|
|
86
|
+
if len(args) == 1:
|
|
87
|
+
# "x is human" / "x is not human"
|
|
88
|
+
prop = pred.lower()
|
|
89
|
+
return f"{_term(args[0])} is {'not ' if negated else ''}{prop}"
|
|
90
|
+
call = f"{pred}({', '.join(_term(a) for a in args)})"
|
|
91
|
+
return f"it is not the case that {call}" if negated else call
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _needs_clause(node: Node) -> bool:
|
|
95
|
+
"""True if a sub-formula should be wrapped as a parenthetical clause for clarity."""
|
|
96
|
+
return isinstance(node, (And, Or, Xor, Implies, Iff))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _sub(node: Node) -> str:
|
|
100
|
+
"""Render a sub-formula, parenthesising a nested binary connective."""
|
|
101
|
+
text = to_english(node)
|
|
102
|
+
return f"({text})" if _needs_clause(node) else text
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def to_english(node: Node) -> str:
|
|
106
|
+
"""Return an English paraphrase of ``node`` (best-effort, not a parse inverse)."""
|
|
107
|
+
if isinstance(node, Atom):
|
|
108
|
+
return _atom(node)
|
|
109
|
+
|
|
110
|
+
if isinstance(node, Not):
|
|
111
|
+
inner = node.formula
|
|
112
|
+
if isinstance(inner, Atom):
|
|
113
|
+
return _atom(inner, negated=True)
|
|
114
|
+
return f"it is not the case that {_sub(inner)}"
|
|
115
|
+
|
|
116
|
+
if isinstance(node, And):
|
|
117
|
+
return f"{_sub(node.left)} and {_sub(node.right)}"
|
|
118
|
+
|
|
119
|
+
if isinstance(node, Or):
|
|
120
|
+
return f"{_sub(node.left)} or {_sub(node.right)}"
|
|
121
|
+
|
|
122
|
+
if isinstance(node, Xor):
|
|
123
|
+
return f"either {_sub(node.left)} or {_sub(node.right)}, but not both"
|
|
124
|
+
|
|
125
|
+
if isinstance(node, Contrast):
|
|
126
|
+
return f"{_sub(node.left)}, whereas {_sub(node.right)}"
|
|
127
|
+
|
|
128
|
+
if isinstance(node, Implies):
|
|
129
|
+
return f"if {_sub(node.left)}, then {_sub(node.right)}"
|
|
130
|
+
|
|
131
|
+
if isinstance(node, Iff):
|
|
132
|
+
return f"{_sub(node.left)} if and only if {_sub(node.right)}"
|
|
133
|
+
|
|
134
|
+
if isinstance(node, SortedQuantifier):
|
|
135
|
+
kind = "every" if node.type in ("∀", "forall") else "some"
|
|
136
|
+
return f"for {kind} {node.variable.name} of sort {node.sort}, {to_english(node.formula)}"
|
|
137
|
+
|
|
138
|
+
if isinstance(node, Quantifier):
|
|
139
|
+
if node.type in ("∀", "forall"):
|
|
140
|
+
return f"for every {node.variable.name}, {to_english(node.formula)}"
|
|
141
|
+
return f"for some {node.variable.name}, {to_english(node.formula)}"
|
|
142
|
+
|
|
143
|
+
if isinstance(node, Count):
|
|
144
|
+
return (f"there are {_COUNT_WORDS[node.op]} {node.n.value} {node.variable.name} "
|
|
145
|
+
f"such that {to_english(node.formula)}")
|
|
146
|
+
|
|
147
|
+
if isinstance(node, SortedCount):
|
|
148
|
+
return (f"there are {_COUNT_WORDS[node.op]} {node.n.value} {node.variable.name} "
|
|
149
|
+
f"of sort {node.sort} such that {to_english(node.formula)}")
|
|
150
|
+
|
|
151
|
+
if isinstance(node, SecondOrderQuantifier):
|
|
152
|
+
kind = "every" if node.type in ("∀", "forall") else "some"
|
|
153
|
+
return f"for {kind} {node.arity}-ary predicate {node.predicate}, {to_english(node.formula)}"
|
|
154
|
+
|
|
155
|
+
# --- modal / temporal / epistemic / doxastic / deontic ---
|
|
156
|
+
if isinstance(node, Box):
|
|
157
|
+
return f"necessarily, {_sub(node.formula)}"
|
|
158
|
+
if isinstance(node, Diamond):
|
|
159
|
+
return f"possibly, {_sub(node.formula)}"
|
|
160
|
+
if isinstance(node, Knows):
|
|
161
|
+
return f"agent {_term(node.agent)} knows that {_sub(node.formula)}"
|
|
162
|
+
if isinstance(node, Believes):
|
|
163
|
+
return f"agent {_term(node.agent)} believes that {_sub(node.formula)}"
|
|
164
|
+
if isinstance(node, Says):
|
|
165
|
+
return f"agent {_term(node.agent)} says that {_sub(node.formula)}"
|
|
166
|
+
if isinstance(node, Wants):
|
|
167
|
+
return f"agent {_term(node.agent)} wants it to be that {_sub(node.formula)}"
|
|
168
|
+
if isinstance(node, Obligatory):
|
|
169
|
+
return f"it is obligatory that {_sub(node.formula)}"
|
|
170
|
+
if isinstance(node, Permitted):
|
|
171
|
+
return f"it is permitted that {_sub(node.formula)}"
|
|
172
|
+
if isinstance(node, Always):
|
|
173
|
+
return f"it will always be the case that {_sub(node.formula)}"
|
|
174
|
+
if isinstance(node, Eventually):
|
|
175
|
+
return f"it will eventually be the case that {_sub(node.formula)}"
|
|
176
|
+
if isinstance(node, Next):
|
|
177
|
+
return f"at the next moment, {_sub(node.formula)}"
|
|
178
|
+
if isinstance(node, Until):
|
|
179
|
+
return f"{_sub(node.left)} until {_sub(node.right)}"
|
|
180
|
+
if isinstance(node, Historically):
|
|
181
|
+
return f"it has always been the case that {_sub(node.formula)}"
|
|
182
|
+
if isinstance(node, Once):
|
|
183
|
+
return f"it was once the case that {_sub(node.formula)}"
|
|
184
|
+
if isinstance(node, Previous):
|
|
185
|
+
return f"at the previous moment, {_sub(node.formula)}"
|
|
186
|
+
if isinstance(node, Since):
|
|
187
|
+
return f"{_sub(node.left)} since {_sub(node.right)}"
|
|
188
|
+
|
|
189
|
+
# --- public announcement logic (PAL) ---
|
|
190
|
+
if isinstance(node, Announce):
|
|
191
|
+
return (f"after it is truthfully announced that {to_english(node.announcement)}, "
|
|
192
|
+
f"{_sub(node.formula)}")
|
|
193
|
+
if isinstance(node, AnnounceDiamond):
|
|
194
|
+
return (f"{to_english(node.announcement)}, and after it is truthfully "
|
|
195
|
+
f"announced, {_sub(node.formula)}")
|
|
196
|
+
|
|
197
|
+
# --- counterfactual conditionals (subjunctive, not material) ---
|
|
198
|
+
if isinstance(node, Would):
|
|
199
|
+
return f"if {_sub(node.left)} were the case, {_sub(node.right)} would be"
|
|
200
|
+
if isinstance(node, Might):
|
|
201
|
+
return f"if {_sub(node.left)} were the case, {_sub(node.right)} might be"
|
|
202
|
+
|
|
203
|
+
# --- hybrid (nominals and @) ---
|
|
204
|
+
if isinstance(node, Nominal):
|
|
205
|
+
return f"this is world {node.name}"
|
|
206
|
+
if isinstance(node, At):
|
|
207
|
+
return f"at world {node.nominal.name}, {_sub(node.formula)}"
|
|
208
|
+
|
|
209
|
+
# --- dependence / IF (team semantics) ---
|
|
210
|
+
if isinstance(node, Dependence):
|
|
211
|
+
if len(node.args) == 1:
|
|
212
|
+
return f"the value of {_term(node.args[0])} is constant"
|
|
213
|
+
deps = ", ".join(_term(a) for a in node.args[:-1])
|
|
214
|
+
return (f"the value of {_term(node.args[-1])} is functionally "
|
|
215
|
+
f"determined by {deps}")
|
|
216
|
+
if isinstance(node, SlashedExists):
|
|
217
|
+
indep = ", ".join(node.slashed)
|
|
218
|
+
return (f"for some {node.variable.name} chosen independently of "
|
|
219
|
+
f"{indep}, {to_english(node.formula)}")
|
|
220
|
+
|
|
221
|
+
# --- linear logic (resource reading) ---
|
|
222
|
+
if isinstance(node, Tensor):
|
|
223
|
+
return f"{_sub(node.left)} together with {_sub(node.right)}"
|
|
224
|
+
if isinstance(node, With):
|
|
225
|
+
return f"a free choice between {_sub(node.left)} and {_sub(node.right)}"
|
|
226
|
+
if isinstance(node, OPlus):
|
|
227
|
+
return f"{_sub(node.left)} or else {_sub(node.right)}"
|
|
228
|
+
if isinstance(node, LinearImplies):
|
|
229
|
+
return f"consuming {_sub(node.left)} yields {_sub(node.right)}"
|
|
230
|
+
if isinstance(node, OfCourse):
|
|
231
|
+
return f"an unlimited supply of {_sub(node.formula)}"
|
|
232
|
+
if isinstance(node, One):
|
|
233
|
+
return "the empty resource"
|
|
234
|
+
|
|
235
|
+
# --- Lambek calculus (categorial reading) ---
|
|
236
|
+
if isinstance(node, Product):
|
|
237
|
+
return f"{_sub(node.left)} followed by {_sub(node.right)}"
|
|
238
|
+
if isinstance(node, Under):
|
|
239
|
+
return (f"something that combines with {_sub(node.left)} on its left "
|
|
240
|
+
f"to give {_sub(node.right)}")
|
|
241
|
+
if isinstance(node, Over):
|
|
242
|
+
return (f"something that combines with {_sub(node.right)} on its right "
|
|
243
|
+
f"to give {_sub(node.left)}")
|
|
244
|
+
|
|
245
|
+
# --- fuzzy (Łukasiewicz): name the strong/weak/Łukasiewicz operators so they do
|
|
246
|
+
# NOT read as their classical look-alikes ---
|
|
247
|
+
if isinstance(node, LukNegation):
|
|
248
|
+
return f"it is fuzzily not the case that {_sub(node.formula)}"
|
|
249
|
+
if isinstance(node, WeakConjunction):
|
|
250
|
+
return f"{_sub(node.left)} and weakly {_sub(node.right)}"
|
|
251
|
+
if isinstance(node, WeakDisjunction):
|
|
252
|
+
return f"{_sub(node.left)} or weakly {_sub(node.right)}"
|
|
253
|
+
if isinstance(node, StrongConjunction):
|
|
254
|
+
return f"{_sub(node.left)} and strongly {_sub(node.right)}"
|
|
255
|
+
if isinstance(node, StrongDisjunction):
|
|
256
|
+
return f"{_sub(node.left)} or strongly {_sub(node.right)}"
|
|
257
|
+
if isinstance(node, LukImplication):
|
|
258
|
+
return f"if {_sub(node.left)} then fuzzily {_sub(node.right)}"
|
|
259
|
+
if isinstance(node, LukEquivalence):
|
|
260
|
+
return f"{_sub(node.left)} is fuzzily equivalent to {_sub(node.right)}"
|
|
261
|
+
|
|
262
|
+
# Anything else (e.g. lambda) falls back to its glyph form.
|
|
263
|
+
return node.to_unicode_str()
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
r"""REST binding to a Dockerized HETS (Heterogeneous Tool Set) server.
|
|
2
|
+
|
|
3
|
+
`HETS <https://github.com/spechub/Hets>`_ is the reference heterogeneous
|
|
4
|
+
proof-management system for CASL and its extensions (and, via comorphisms,
|
|
5
|
+
many other logics): a development-graph manager over a network of theories
|
|
6
|
+
that dispatches proof obligations to external provers (SPASS, darwin,
|
|
7
|
+
Vampire, E, ...) through translations/comorphisms it selects. This subpackage
|
|
8
|
+
does not reimplement any of that — it is a thin client that lets the rest of
|
|
9
|
+
the kit drive a real HETS instance and read back its verdicts.
|
|
10
|
+
|
|
11
|
+
Architecture: process/network separation, not in-process linking
|
|
12
|
+
--------------------------------------------------------------------
|
|
13
|
+
HETS is GPL-licensed Haskell with a build realistically only reproducible via
|
|
14
|
+
its official Docker image. Two integration routes exist:
|
|
15
|
+
|
|
16
|
+
* **In-process bindings** — the ``hets``/``spechub`` Python API some
|
|
17
|
+
installs expose links this process directly against the GPL Haskell
|
|
18
|
+
library via its GHC-built shared objects, and is only buildable on Linux
|
|
19
|
+
with a working GHC toolchain. That is wrong for this kit on two independent
|
|
20
|
+
axes: it would pull a GPL dependency into an MIT-licensed process, and it
|
|
21
|
+
is not available on this kit's primary development platform (Windows) at
|
|
22
|
+
all. Documented here as the alternative that was considered and rejected,
|
|
23
|
+
not silently omitted.
|
|
24
|
+
* **REST against Docker** — the route this subpackage takes.
|
|
25
|
+
:mod:`~unicode_logic_kit.hets.docker` starts (or discovers) a
|
|
26
|
+
``spechub2/hets:latest`` container running HETS's own bundled HTTP server;
|
|
27
|
+
:mod:`~unicode_logic_kit.hets.client` speaks plain HTTP/JSON to it via
|
|
28
|
+
stdlib ``urllib`` (no ``requests`` dependency, matching this kit's other
|
|
29
|
+
external-tool adapters). This process and the HETS process share nothing
|
|
30
|
+
but a TCP socket — no linking, no shared address space, no GPL code ever
|
|
31
|
+
imported into this Python process. The boundary is enforced structurally,
|
|
32
|
+
not by a license header: :class:`~unicode_logic_kit.hets.client.HetsClient`
|
|
33
|
+
cannot reach HETS internals any way other than the documented REST API.
|
|
34
|
+
|
|
35
|
+
This mirrors the kit-wide convention for external provers that are
|
|
36
|
+
subprocess-spawned rather than linked (``atp.prover9_entailment``,
|
|
37
|
+
``atp.vampire_entailment``, ``hol.isabelle_runner``) — HETS just uses a
|
|
38
|
+
network boundary instead of a process boundary, because that is how its
|
|
39
|
+
official distribution ships (a server, not a CLI batch tool).
|
|
40
|
+
|
|
41
|
+
Modules
|
|
42
|
+
-------
|
|
43
|
+
* :mod:`~unicode_logic_kit.hets.docker` — :class:`~unicode_logic_kit.hets.docker.HetsContainer`
|
|
44
|
+
(start/stop/health-poll one container) and
|
|
45
|
+
:func:`~unicode_logic_kit.hets.docker.discover_hets_url` (the precedence
|
|
46
|
+
``$UFK_HETS_URL`` -> localhost -> optionally auto-start, never a silent
|
|
47
|
+
guess — raises :class:`~unicode_logic_kit.atp.protocol.BackendUnavailable`
|
|
48
|
+
with an actionable message otherwise). Also documents which reasoners in
|
|
49
|
+
the shipped image actually work.
|
|
50
|
+
* :mod:`~unicode_logic_kit.hets.client` — :class:`~unicode_logic_kit.hets.client.HetsClient`,
|
|
51
|
+
the REST binding itself (upload, development-graph inspection, prover /
|
|
52
|
+
translation listing, theory rendering/translation, prove,
|
|
53
|
+
consistency-check).
|
|
54
|
+
* :mod:`~unicode_logic_kit.hets.bridge` — the server's CASL comorphisms as
|
|
55
|
+
dynamic ``hets:<Name>`` edges in the kit's translation registry
|
|
56
|
+
(:func:`~unicode_logic_kit.hets.bridge.register_hets_comorphisms`).
|
|
57
|
+
* :mod:`~unicode_logic_kit.hets.dol` — DOL library EMISSION
|
|
58
|
+
(:func:`~unicode_logic_kit.hets.dol.to_dol_library`): multiple named CASL
|
|
59
|
+
specs, ``then``-extension structure and ``%implied`` goals in one
|
|
60
|
+
``library`` document a HETS server turns into a multi-node development
|
|
61
|
+
graph (no DOL *parsing* — same emission-only cut as the rest of the
|
|
62
|
+
CASL route; the importer for single basic specs is
|
|
63
|
+
:func:`unicode_logic_kit.fol.casl_import.parse_casl_spec`).
|
|
64
|
+
* :mod:`~unicode_logic_kit.hets.owl_backend` — a second, independent external
|
|
65
|
+
OWL 2 DL reasoner (FaCT++ via the server's ``Fact`` prover identifier),
|
|
66
|
+
over the ALCHQ + I + O fragment; mirrors
|
|
67
|
+
:mod:`~unicode_logic_kit.dl.owl_reasoner`'s function-per-namesake shape,
|
|
68
|
+
opt-in and never in a default chain.
|
|
69
|
+
* :mod:`~unicode_logic_kit.hets.haskell_json` —
|
|
70
|
+
:func:`~unicode_logic_kit.hets.haskell_json.repair_haskell_json`, which
|
|
71
|
+
recovers the Haskell ``show`` escapes HETS 0.108.0 leaks into its JSON
|
|
72
|
+
(``"Verdi\226\128\153s Requiem"`` for ``"Verdi’s Requiem"``). Without it
|
|
73
|
+
``GET /dg`` is unreadable for any library with one non-ASCII annotation,
|
|
74
|
+
and with it the real 8.3 MB OEO graph loads. Applied by
|
|
75
|
+
:meth:`~unicode_logic_kit.hets.client.HetsClient.dg` only on the failure
|
|
76
|
+
path, so a body ``json`` already accepts is never touched.
|
|
77
|
+
* :mod:`~unicode_logic_kit.hets.symbols` — the join between HETS' mangled TPTP
|
|
78
|
+
symbols and the OWL entities they came from
|
|
79
|
+
(:func:`~unicode_logic_kit.hets.symbols.hets_symbol_table`), plus the axioms
|
|
80
|
+
a translation silently dropped
|
|
81
|
+
(:func:`~unicode_logic_kit.hets.symbols.untranslated_axioms`). Pure
|
|
82
|
+
functions over a ``/dg`` dict and a TPTP string: no network, no Docker.
|
|
83
|
+
* :mod:`~unicode_logic_kit.hets.owl_cli` —
|
|
84
|
+
:func:`~unicode_logic_kit.hets.owl_cli.owl_to_tptp`, the COMMAND-LINE route
|
|
85
|
+
(``docker exec`` into a running container). It exists for exactly one
|
|
86
|
+
reason: ``hets-server``'s lossy ``-Y`` switch, which translates an
|
|
87
|
+
ontology whose sublogic a comorphism does not cover and which has no REST
|
|
88
|
+
equivalent. It runs the non-lossy translation first so the loss is always
|
|
89
|
+
reported, never silent.
|
|
90
|
+
|
|
91
|
+
The TPTP a HETS ``GET /theory`` returns is NOT a TPTP problem — HETS
|
|
92
|
+
prefixes it with a DOL ``logic TPTP.FOF`` line and a CASL ``%{ ... }%``
|
|
93
|
+
signature block. :func:`~unicode_logic_kit.hets.client.strip_hets_theory_header`
|
|
94
|
+
splits the two (and
|
|
95
|
+
:meth:`~unicode_logic_kit.hets.client.HetsClient.theory_tptp` does it for you);
|
|
96
|
+
:func:`unicode_logic_kit.fol.tptp_input.parse_tptp` refuses the unstripped text
|
|
97
|
+
BY NAME and points here, rather than learning a comment syntax that is not
|
|
98
|
+
TPTP's.
|
|
99
|
+
|
|
100
|
+
Kit formulas reach HETS through the Verdict layer:
|
|
101
|
+
:class:`unicode_logic_kit.atp.hets_backend.HetsBackend` (registry name
|
|
102
|
+
``"hets"``, never in a default chain) exports FOL/MSFOL problems to CASL
|
|
103
|
+
via :mod:`unicode_logic_kit.fol.casl_export` and maps the per-goal results
|
|
104
|
+
back onto the kit's :class:`~unicode_logic_kit.atp.protocol.Verdict`.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
from .bridge import HETS_EDGE_PREFIX, register_hets_comorphisms
|
|
108
|
+
from .client import (
|
|
109
|
+
HetsClient,
|
|
110
|
+
HetsNoTranslationsError,
|
|
111
|
+
HetsSublogicError,
|
|
112
|
+
strip_hets_theory_header,
|
|
113
|
+
)
|
|
114
|
+
from .docker import HETS_IMAGE, HetsContainer, discover_hets_url, hets_available
|
|
115
|
+
from .haskell_json import (
|
|
116
|
+
HaskellJsonRepair,
|
|
117
|
+
HaskellJsonRepairError,
|
|
118
|
+
repair_haskell_json,
|
|
119
|
+
)
|
|
120
|
+
from .owl_cli import (
|
|
121
|
+
HetsOwlNormalizationError,
|
|
122
|
+
OwlTptpResult,
|
|
123
|
+
SublogicMismatch,
|
|
124
|
+
owl_to_tptp,
|
|
125
|
+
)
|
|
126
|
+
from .symbols import (
|
|
127
|
+
HetsSymbol,
|
|
128
|
+
HetsSymbolCollisionError,
|
|
129
|
+
HetsSymbolTable,
|
|
130
|
+
UntranslatedAxiom,
|
|
131
|
+
hets_prefixes,
|
|
132
|
+
hets_symbol_table,
|
|
133
|
+
untranslated_axioms,
|
|
134
|
+
)
|
|
135
|
+
from .dol import DolSpec, to_dol_library, to_dol_library_from_modal, sanitize_modal_identifiers
|
|
136
|
+
from .owl_backend import (
|
|
137
|
+
hets_owl_available,
|
|
138
|
+
external_concept_satisfiable, external_concept_unsatisfiable,
|
|
139
|
+
external_subsumes, external_equivalent,
|
|
140
|
+
external_abox_consistent, external_instance_check, external_instance_retrieval,
|
|
141
|
+
external_realize, external_realize_all,
|
|
142
|
+
HetsOwlError,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
__all__ = [
|
|
146
|
+
"HetsClient",
|
|
147
|
+
"HetsNoTranslationsError", "HetsSublogicError", "strip_hets_theory_header",
|
|
148
|
+
"HaskellJsonRepair", "HaskellJsonRepairError", "repair_haskell_json",
|
|
149
|
+
"owl_to_tptp", "OwlTptpResult", "SublogicMismatch",
|
|
150
|
+
"HetsOwlNormalizationError",
|
|
151
|
+
"hets_symbol_table", "HetsSymbolTable", "HetsSymbol",
|
|
152
|
+
"HetsSymbolCollisionError",
|
|
153
|
+
"untranslated_axioms", "UntranslatedAxiom", "hets_prefixes",
|
|
154
|
+
"HETS_IMAGE", "HetsContainer", "discover_hets_url", "hets_available",
|
|
155
|
+
"HETS_EDGE_PREFIX", "register_hets_comorphisms",
|
|
156
|
+
"DolSpec", "to_dol_library", "to_dol_library_from_modal", "sanitize_modal_identifiers",
|
|
157
|
+
"hets_owl_available",
|
|
158
|
+
"external_concept_satisfiable", "external_concept_unsatisfiable",
|
|
159
|
+
"external_subsumes", "external_equivalent",
|
|
160
|
+
"external_abox_consistent", "external_instance_check", "external_instance_retrieval",
|
|
161
|
+
"external_realize", "external_realize_all",
|
|
162
|
+
"HetsOwlError",
|
|
163
|
+
]
|