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