typedlogic 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. typedlogic-0.1.1/LICENSE +22 -0
  2. typedlogic-0.1.1/PKG-INFO +137 -0
  3. typedlogic-0.1.1/README.md +99 -0
  4. typedlogic-0.1.1/pyproject.toml +107 -0
  5. typedlogic-0.1.1/src/typedlogic/__init__.py +44 -0
  6. typedlogic-0.1.1/src/typedlogic/builtins.py +48 -0
  7. typedlogic-0.1.1/src/typedlogic/cli.py +76 -0
  8. typedlogic-0.1.1/src/typedlogic/compiler.py +123 -0
  9. typedlogic-0.1.1/src/typedlogic/compilers/__init__.py +0 -0
  10. typedlogic-0.1.1/src/typedlogic/compilers/fol_compiler.py +18 -0
  11. typedlogic-0.1.1/src/typedlogic/compilers/prolog_compiler.py +66 -0
  12. typedlogic-0.1.1/src/typedlogic/compilers/prover9_compiler.py +37 -0
  13. typedlogic-0.1.1/src/typedlogic/compilers/sexpr_compiler.py +99 -0
  14. typedlogic-0.1.1/src/typedlogic/compilers/tptp_compiler.py +29 -0
  15. typedlogic-0.1.1/src/typedlogic/compilers/yaml_compiler.py +76 -0
  16. typedlogic-0.1.1/src/typedlogic/datamodel.py +996 -0
  17. typedlogic-0.1.1/src/typedlogic/datamodels/__init__.py +0 -0
  18. typedlogic-0.1.1/src/typedlogic/datamodels/typesystem.py +155 -0
  19. typedlogic-0.1.1/src/typedlogic/decorators.py +149 -0
  20. typedlogic-0.1.1/src/typedlogic/evaluation.py +175 -0
  21. typedlogic-0.1.1/src/typedlogic/generators.py +94 -0
  22. typedlogic-0.1.1/src/typedlogic/integrations/__init__.py +0 -0
  23. typedlogic-0.1.1/src/typedlogic/integrations/data/__init__.py +0 -0
  24. typedlogic-0.1.1/src/typedlogic/integrations/data/dask/__init__.py +0 -0
  25. typedlogic-0.1.1/src/typedlogic/integrations/data/ibis/__init__.py +0 -0
  26. typedlogic-0.1.1/src/typedlogic/integrations/data/pandas/__init__.py +0 -0
  27. typedlogic-0.1.1/src/typedlogic/integrations/data/polars/__init__.py +0 -0
  28. typedlogic-0.1.1/src/typedlogic/integrations/data/sqlmodel/__init__.py +0 -0
  29. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/__init__.py +0 -0
  30. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/__init__.py +1 -0
  31. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/instance.py +164 -0
  32. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/loader.py +186 -0
  33. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/meta.py +78 -0
  34. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/meta_axioms.py +77 -0
  35. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/owldl/__init__.py +55 -0
  36. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/owldl/ontology_generators.py +0 -0
  37. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/owldl/owltop.py +2124 -0
  38. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/owldl/reasoner.py +206 -0
  39. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/pydantic/__init__.py +5 -0
  40. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/pydantic/pydantic_bridge.py +14 -0
  41. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/rdflib/__init__.py +3 -0
  42. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/rdflib/rdf.py +57 -0
  43. typedlogic-0.1.1/src/typedlogic/integrations/frameworks/rdflib/rdfs.py +80 -0
  44. typedlogic-0.1.1/src/typedlogic/integrations/solvers/__init__.py +0 -0
  45. typedlogic-0.1.1/src/typedlogic/integrations/solvers/clingo/__init__.py +5 -0
  46. typedlogic-0.1.1/src/typedlogic/integrations/solvers/clingo/clingo_solver.py +116 -0
  47. typedlogic-0.1.1/src/typedlogic/integrations/solvers/clorm/__init__.py +0 -0
  48. typedlogic-0.1.1/src/typedlogic/integrations/solvers/formulog/__init__.py +0 -0
  49. typedlogic-0.1.1/src/typedlogic/integrations/solvers/llm/__init__.py +0 -0
  50. typedlogic-0.1.1/src/typedlogic/integrations/solvers/llm/llm_solver.py +92 -0
  51. typedlogic-0.1.1/src/typedlogic/integrations/solvers/prover9/__init__.py +3 -0
  52. typedlogic-0.1.1/src/typedlogic/integrations/solvers/prover9/prover9_solver.py +81 -0
  53. typedlogic-0.1.1/src/typedlogic/integrations/solvers/pyprover/__init__.py +0 -0
  54. typedlogic-0.1.1/src/typedlogic/integrations/solvers/snakelog/__init__.py +3 -0
  55. typedlogic-0.1.1/src/typedlogic/integrations/solvers/snakelog/snakelog_solver.py +237 -0
  56. typedlogic-0.1.1/src/typedlogic/integrations/solvers/souffle/__init__.py +3 -0
  57. typedlogic-0.1.1/src/typedlogic/integrations/solvers/souffle/souffle_compiler.py +100 -0
  58. typedlogic-0.1.1/src/typedlogic/integrations/solvers/souffle/souffle_solver.py +119 -0
  59. typedlogic-0.1.1/src/typedlogic/integrations/solvers/z3/__init__.py +3 -0
  60. typedlogic-0.1.1/src/typedlogic/integrations/solvers/z3/z3_compiler.py +43 -0
  61. typedlogic-0.1.1/src/typedlogic/integrations/solvers/z3/z3_solver.py +335 -0
  62. typedlogic-0.1.1/src/typedlogic/integrations/solvers/z3/z3_utils.py +0 -0
  63. typedlogic-0.1.1/src/typedlogic/integrations/variadic_generics.py +18 -0
  64. typedlogic-0.1.1/src/typedlogic/parser.py +48 -0
  65. typedlogic-0.1.1/src/typedlogic/parsers/__init__.py +0 -0
  66. typedlogic-0.1.1/src/typedlogic/parsers/pyparser/__init__.py +5 -0
  67. typedlogic-0.1.1/src/typedlogic/parsers/pyparser/introspection.py +271 -0
  68. typedlogic-0.1.1/src/typedlogic/parsers/pyparser/python_ast_utils.py +376 -0
  69. typedlogic-0.1.1/src/typedlogic/parsers/pyparser/python_parser.py +94 -0
  70. typedlogic-0.1.1/src/typedlogic/parsers/yaml_parser.py +23 -0
  71. typedlogic-0.1.1/src/typedlogic/profiles.py +262 -0
  72. typedlogic-0.1.1/src/typedlogic/py.typed +0 -0
  73. typedlogic-0.1.1/src/typedlogic/pybridge.py +79 -0
  74. typedlogic-0.1.1/src/typedlogic/registry.py +118 -0
  75. typedlogic-0.1.1/src/typedlogic/solver.py +298 -0
  76. typedlogic-0.1.1/src/typedlogic/theories/__init__.py +0 -0
  77. typedlogic-0.1.1/src/typedlogic/theories/bfo/__init__.py +0 -0
  78. typedlogic-0.1.1/src/typedlogic/theories/jsonlog/__init__.py +0 -0
  79. typedlogic-0.1.1/src/typedlogic/theories/jsonlog/jsonlog.py +83 -0
  80. typedlogic-0.1.1/src/typedlogic/theories/jsonlog/jsonlog_axioms.py +28 -0
  81. typedlogic-0.1.1/src/typedlogic/theories/jsonlog/loader.py +58 -0
  82. typedlogic-0.1.1/src/typedlogic/transformations.py +1502 -0
  83. typedlogic-0.1.1/src/typedlogic/utils/__init__.py +0 -0
  84. typedlogic-0.1.1/src/typedlogic/utils/detect_stratified_negation.py +148 -0
  85. typedlogic-0.1.1/src/typedlogic/utils/graph_utils.py +70 -0
  86. typedlogic-0.1.1/src/typedlogic/utils/import_closure.py +49 -0
  87. typedlogic-0.1.1/src/typedlogic/utils/term_maker.py +27 -0
@@ -0,0 +1,22 @@
1
+
2
+ The MIT License (MIT)
3
+
4
+ Copyright (c) 2024 Monarch Initiative
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.1
2
+ Name: typedlogic
3
+ Version: 0.1.1
4
+ Summary: typedlogic
5
+ License: MIT
6
+ Author: Author 1
7
+ Author-email: author@org.org
8
+ Requires-Python: >=3.11,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Provides-Extra: clingo
14
+ Provides-Extra: clorm
15
+ Provides-Extra: llm
16
+ Provides-Extra: pydantic
17
+ Provides-Extra: pyprover
18
+ Provides-Extra: rdflib
19
+ Provides-Extra: snakelog
20
+ Provides-Extra: sympy
21
+ Provides-Extra: tests
22
+ Provides-Extra: z3
23
+ Requires-Dist: click
24
+ Requires-Dist: clingo ; extra == "clingo"
25
+ Requires-Dist: clorm ; extra == "clorm"
26
+ Requires-Dist: importlib-metadata (>=8.2.0)
27
+ Requires-Dist: llm ; extra == "llm"
28
+ Requires-Dist: pydantic ; extra == "pydantic"
29
+ Requires-Dist: pyprover ; extra == "pyprover"
30
+ Requires-Dist: pytest (>=8.3.2,<9.0.0)
31
+ Requires-Dist: rdflib ; extra == "rdflib"
32
+ Requires-Dist: snakelog ; extra == "snakelog"
33
+ Requires-Dist: sympy ; extra == "sympy"
34
+ Requires-Dist: typer (>=0.12.5,<0.13.0)
35
+ Requires-Dist: z3-solver ; extra == "z3"
36
+ Description-Content-Type: text/markdown
37
+
38
+ from typedlogic.registry import get_solver
39
+
40
+ # py-typedlogic: Pythonic logic for your data models.
41
+
42
+ Define logical predicates directly in Python as Pydantic, dataclasses, SQLModel, or plain python objects:
43
+
44
+ ```python
45
+ # links.py
46
+ from pydantic import BaseModel
47
+ from typedlogic import FactMixin, Term
48
+
49
+ ID = str
50
+
51
+ class Link(BaseModel, FactMixin):
52
+ """A link between two entities"""
53
+ source: ID
54
+ target: ID
55
+
56
+ class Path(BaseModel, FactMixin):
57
+ """An N-hop path between two entities, consisting of one or more links"""
58
+ source: ID
59
+ target: ID
60
+ hops: int
61
+ ```
62
+
63
+ This data model has two classes, `Link` and `Path`. These also correspond to *predicate signatures*
64
+ in a logical theory.
65
+
66
+ You can use this to create objects (ground terms, in logic terms) using normal Python code:
67
+
68
+ ```python
69
+ links = []
70
+ for source, target in [('CA', 'OR'), ('OR', 'WA')]:
71
+ links.append(link)
72
+ ```
73
+
74
+ Define logical *constraints* or *rules* using Python syntax:
75
+
76
+ ```python
77
+ from typedlogic.decorators import axiom
78
+
79
+ @axiom
80
+ def path_from_link(x: ID, y: ID):
81
+ """If there is a link from x to y, there is a path from x to y"""
82
+ if Link(source=x, target=y):
83
+ assert Path(source=x, target=y, hops=1)
84
+
85
+ @axiom
86
+ def transitivity(x: ID, y: ID, z: ID, d1: int, d2: int):
87
+ """Transitivity of paths, plus hop counting"""
88
+ if Path(source=x, target=y, hops=d1) and Path(source=y, target=z, hops=d2):
89
+ assert Path(source=x, target=z, hops=d1+d2)
90
+ ```
91
+
92
+ Use a solver to infer new facts:
93
+
94
+ ```python
95
+ from typedlogic.registry import get_solver
96
+ from links import Link
97
+
98
+ solver = get_solver("clingo")
99
+ solver.load(links)
100
+ links = [Link(source='CA', target='OR'), Link(source='OR', target='WA')]
101
+ for link in links:
102
+ solver.add(link)
103
+ model = solver.model()
104
+ for fact in model.iter_retrieve("Path"):
105
+ print(fact)
106
+ ```
107
+
108
+ prints:
109
+
110
+ ```
111
+ Path(source='CA', target='OR')
112
+ Path(source='OR', target='WA')
113
+ Path(source='CA', target='WA')
114
+ ```
115
+
116
+ ## Key Features
117
+
118
+ - Write logical axioms and rules using Python syntax (but can also be used independently of this)
119
+ - Benefit from strong typing and mypy validation
120
+ - Integration with multiple FOL solvers and logic programming engines
121
+ - Interconversion between multiple syntaxes for FOL, Rules, and logical models
122
+ - Integration with OWL-DL
123
+ - Integration with Python libraries like Pydantic
124
+ - Command Line and Python interfaces
125
+
126
+ ## Installation
127
+
128
+ Install TypedLogic using pip:
129
+
130
+ ```bash
131
+ pip install "typedlogic"
132
+ ```
133
+
134
+ ## Next Steps
135
+
136
+ - Consult the main docs
137
+
@@ -0,0 +1,99 @@
1
+ from typedlogic.registry import get_solver
2
+
3
+ # py-typedlogic: Pythonic logic for your data models.
4
+
5
+ Define logical predicates directly in Python as Pydantic, dataclasses, SQLModel, or plain python objects:
6
+
7
+ ```python
8
+ # links.py
9
+ from pydantic import BaseModel
10
+ from typedlogic import FactMixin, Term
11
+
12
+ ID = str
13
+
14
+ class Link(BaseModel, FactMixin):
15
+ """A link between two entities"""
16
+ source: ID
17
+ target: ID
18
+
19
+ class Path(BaseModel, FactMixin):
20
+ """An N-hop path between two entities, consisting of one or more links"""
21
+ source: ID
22
+ target: ID
23
+ hops: int
24
+ ```
25
+
26
+ This data model has two classes, `Link` and `Path`. These also correspond to *predicate signatures*
27
+ in a logical theory.
28
+
29
+ You can use this to create objects (ground terms, in logic terms) using normal Python code:
30
+
31
+ ```python
32
+ links = []
33
+ for source, target in [('CA', 'OR'), ('OR', 'WA')]:
34
+ links.append(link)
35
+ ```
36
+
37
+ Define logical *constraints* or *rules* using Python syntax:
38
+
39
+ ```python
40
+ from typedlogic.decorators import axiom
41
+
42
+ @axiom
43
+ def path_from_link(x: ID, y: ID):
44
+ """If there is a link from x to y, there is a path from x to y"""
45
+ if Link(source=x, target=y):
46
+ assert Path(source=x, target=y, hops=1)
47
+
48
+ @axiom
49
+ def transitivity(x: ID, y: ID, z: ID, d1: int, d2: int):
50
+ """Transitivity of paths, plus hop counting"""
51
+ if Path(source=x, target=y, hops=d1) and Path(source=y, target=z, hops=d2):
52
+ assert Path(source=x, target=z, hops=d1+d2)
53
+ ```
54
+
55
+ Use a solver to infer new facts:
56
+
57
+ ```python
58
+ from typedlogic.registry import get_solver
59
+ from links import Link
60
+
61
+ solver = get_solver("clingo")
62
+ solver.load(links)
63
+ links = [Link(source='CA', target='OR'), Link(source='OR', target='WA')]
64
+ for link in links:
65
+ solver.add(link)
66
+ model = solver.model()
67
+ for fact in model.iter_retrieve("Path"):
68
+ print(fact)
69
+ ```
70
+
71
+ prints:
72
+
73
+ ```
74
+ Path(source='CA', target='OR')
75
+ Path(source='OR', target='WA')
76
+ Path(source='CA', target='WA')
77
+ ```
78
+
79
+ ## Key Features
80
+
81
+ - Write logical axioms and rules using Python syntax (but can also be used independently of this)
82
+ - Benefit from strong typing and mypy validation
83
+ - Integration with multiple FOL solvers and logic programming engines
84
+ - Interconversion between multiple syntaxes for FOL, Rules, and logical models
85
+ - Integration with OWL-DL
86
+ - Integration with Python libraries like Pydantic
87
+ - Command Line and Python interfaces
88
+
89
+ ## Installation
90
+
91
+ Install TypedLogic using pip:
92
+
93
+ ```bash
94
+ pip install "typedlogic"
95
+ ```
96
+
97
+ ## Next Steps
98
+
99
+ - Consult the main docs
@@ -0,0 +1,107 @@
1
+ [tool.poetry]
2
+ name = "typedlogic"
3
+ version = "0.1.1"
4
+ description = "typedlogic"
5
+ authors = ["Author 1 <author@org.org>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+
9
+ [tool.poetry.dependencies]
10
+ python = "^3.11"
11
+ click = "*"
12
+ importlib-metadata = ">=8.2.0"
13
+ pydantic = { version="*" }
14
+ clingo = { version="*" }
15
+ z3-solver = { version="*" }
16
+ pyprover = { version="*" }
17
+ snakelog = { version="*" }
18
+ clorm = { version="*" }
19
+ rdflib = { version="*" }
20
+ sympy = { version="*" }
21
+ #py-horned-owldl = { version="*" }
22
+ llm = { version="*" }
23
+ pytest = "^8.3.2"
24
+ typer = "^0.12.5"
25
+
26
+ [tool.poetry.group.dev.dependencies]
27
+ pytest = {version = ">=8.3.2"}
28
+ tox = {version = ">=4.16.0"}
29
+ mypy = {version = "*"}
30
+ types-PyYAML = {version = "*"}
31
+ jupyter = {version = "*"}
32
+ papermill = {version = "*"}
33
+ nbdime = {version = "*"}
34
+ nbformat = {version = "*"}
35
+ pre-commit = {version = ">=3.3.3"}
36
+ mkdocs = "*"
37
+ mkdocs-mermaid2-plugin = "*"
38
+ mkdocstrings = {extras = ["crystal", "python"], version = "*"}
39
+ mknotebooks = "^0.8.0"
40
+ mkdocs-windmill = "*"
41
+ mkdocs-material = "*"
42
+
43
+
44
+ [tool.poetry.extras]
45
+ tests = ["black", "ruff"]
46
+ pydantic = ["pydantic"]
47
+ z3 = ["z3-solver"]
48
+ clingo = ["clingo"]
49
+ pyprover = ["pyprover"]
50
+ snakelog = ["snakelog"]
51
+ clorm = ["clorm"]
52
+ rdflib = ["rdflib"]
53
+ #owldl = ["py-horned-owldl"]
54
+ llm = ["llm"]
55
+ sympy = ["sympy"]
56
+
57
+
58
+ [tool.poetry.scripts]
59
+ typedlogic = "typedlogic.cli:app"
60
+
61
+ [tool.poetry-dynamic-versioning]
62
+ enable = false
63
+ vcs = "git"
64
+ style = "pep440"
65
+
66
+ [tool.black]
67
+ line-length = 120
68
+ target-version = ["py38", "py39", "py310"]
69
+
70
+ [tool.ruff]
71
+ lint.extend-ignore = [
72
+ "D211", # `no-blank-line-before-class`
73
+ "D212", # `multi-line-summary-first-line`
74
+ "D203", # `blank-line-before-docstring`
75
+ ]
76
+ line-length = 120
77
+
78
+ # Allow autofix for all enabled rules (when `--fix`) is provided.
79
+ lint.fixable = ["ALL"]
80
+
81
+ # Select or ignore from https://beta.ruff.rs/docs/rules/
82
+ lint.select = [
83
+ "B", # bugbear
84
+ "D", # pydocstyle
85
+ "E", # pycodestyle errors
86
+ "F", # Pyflakes
87
+ "I", # isort
88
+ "S", # flake8-bandit
89
+ "W", # Warning
90
+ ]
91
+
92
+ lint.unfixable = []
93
+ target-version = "py310"
94
+
95
+ [tool.ruff.lint.mccabe]
96
+ # Unlike Flake8, default to a complexity level of 10.
97
+ max-complexity = 10
98
+
99
+ [tool.codespell]
100
+ skip = "*.po,*.ts,.git,pyproject.toml"
101
+ count = ""
102
+ quiet-level = 3
103
+ # ignore-words-list = ""
104
+
105
+ [build-system]
106
+ requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"]
107
+ build-backend = "poetry_dynamic_versioning.backend"
@@ -0,0 +1,44 @@
1
+ """typedlogic package."""
2
+ from typedlogic.datamodel import (
3
+ BooleanSentence, And, Or, Not, Implies,
4
+ Forall, Exists, Term,
5
+ NegationAsFailure, not_provable, Xor, Implied, Iff, ExactlyOne,
6
+ Theory, Sentence,
7
+ PredicateDefinition, SentenceGroup,
8
+ Variable,
9
+ )
10
+ from typedlogic.pybridge import FactMixin, Fact
11
+ from typedlogic.generators import gen, gen1, gen2, gen3
12
+ from typedlogic.decorators import axiom, goal
13
+
14
+ __all__ = [
15
+ 'BooleanSentence',
16
+ 'And',
17
+ 'Or',
18
+ 'Not',
19
+ 'Implies',
20
+ 'Iff',
21
+ 'Forall',
22
+ 'Exists',
23
+ 'Term',
24
+ 'NegationAsFailure',
25
+ 'not_provable',
26
+ 'Xor',
27
+ 'ExactlyOne',
28
+ 'Implied',
29
+ 'Theory',
30
+ 'Sentence',
31
+ 'Variable',
32
+ 'PredicateDefinition',
33
+ 'SentenceGroup',
34
+
35
+ 'Fact',
36
+ 'FactMixin',
37
+
38
+ 'gen',
39
+ 'gen1',
40
+ 'gen2',
41
+ 'gen3',
42
+
43
+ ]
44
+
@@ -0,0 +1,48 @@
1
+ """
2
+ Mappings for builtin functions and datatypes.
3
+ """
4
+ import operator as op
5
+ from typing import Mapping, Callable
6
+
7
+ NUMERIC_BUILTINS: Mapping[str, Callable] = {
8
+ 'ge': op.ge,
9
+ 'gt': op.gt,
10
+ 'le': op.le,
11
+ 'lt': op.lt,
12
+ 'eq': op.eq,
13
+ 'ne': op.ne,
14
+ 'add': op.add,
15
+ 'sub': op.sub,
16
+ 'mul': op.mul,
17
+ 'truediv': op.truediv,
18
+ 'pow': op.pow,
19
+ 'xor': op.xor,
20
+ 'neg': op.neg,
21
+ }
22
+
23
+ NAME_TO_INFIX_OP: Mapping[str, str] = {
24
+ 'add': '+',
25
+ 'sub': '-',
26
+ 'mul': '*',
27
+ 'truediv': '/',
28
+ 'floordiv': '//',
29
+ 'mod': '%',
30
+ 'pow': '**',
31
+ 'lshift': '<<',
32
+ 'rshift': '>>',
33
+ 'or': '|',
34
+ 'xor': '^',
35
+ 'and': '&',
36
+ 'matmul': '@',
37
+ # Comparison operators
38
+ 'eq': '==',
39
+ 'ne': '!=',
40
+ 'lt': '<',
41
+ 'le': '<=',
42
+ 'gt': '>',
43
+ 'ge': '>=',
44
+ 'is': 'is',
45
+ 'is_not': 'is not',
46
+ 'in': 'in',
47
+ 'not_in': 'not in',
48
+ }
@@ -0,0 +1,76 @@
1
+ """
2
+ Command-line interface definitions using typer.
3
+ """
4
+ from pathlib import Path
5
+ from typing import List, Optional
6
+
7
+ import typer
8
+
9
+ from typedlogic.parsers.pyparser.python_parser import PythonParser
10
+ from typedlogic.registry import get_compiler, get_solver
11
+
12
+ app = typer.Typer()
13
+
14
+
15
+
16
+ @app.command()
17
+ def convert(
18
+ input_files: List[Path] = typer.Argument(..., exists=True, dir_okay=False, readable=True),
19
+ output_format: str = typer.Option(None, "--output-format", "-t", help="Output format"),
20
+ output_file: Optional[Path] = typer.Option(None, "--output-file", "-o", help="Output file path")
21
+ ):
22
+ """
23
+ Convert from one logic form to another.
24
+ """
25
+ parser = PythonParser()
26
+ theory = parser.parse(input_files[0])
27
+ if len(input_files) > 1:
28
+ for input_file in input_files[1:]:
29
+ facts_theory = parser.parse(input_file)
30
+ for s in facts_theory.sentences:
31
+ theory.add(s)
32
+
33
+ compiler = get_compiler(output_format or "z3sexpr")
34
+ result = compiler.compile(theory)
35
+
36
+ if output_file:
37
+ with open(output_file, 'w') as f:
38
+ f.write(result)
39
+ typer.echo(f"Conversion result written to {output_file}")
40
+ else:
41
+ typer.echo(result)
42
+
43
+
44
+ @app.command()
45
+ def solve(
46
+ input_file: Path = typer.Argument(..., exists=True, dir_okay=False, readable=True),
47
+ solver: str = typer.Option(None, help="Solver to use"),
48
+ output_file: Optional[Path] = typer.Option(None, "--output-file", "-o", help="Output file path for the solution")
49
+ ):
50
+ """
51
+ Solve using the specified solver.
52
+ """
53
+ parser = PythonParser()
54
+ theory = parser.parse(input_file)
55
+ solver_instance = get_solver(solver or "souffle")
56
+
57
+ solver_instance.add(theory)
58
+ solution = solver_instance.check()
59
+
60
+ result = f"Satisfiable: {solution.satisfiable}\n"
61
+ if solution.satisfiable:
62
+ model = solver_instance.model()
63
+ result += "Model:\n"
64
+ for fact in model.ground_terms:
65
+ result += f"{fact}\n"
66
+
67
+ if output_file:
68
+ with open(output_file, 'w') as f:
69
+ f.write(result)
70
+ typer.echo(f"Solution written to {output_file}")
71
+ else:
72
+ typer.echo(result)
73
+
74
+
75
+ if __name__ == "__main__":
76
+ app()
@@ -0,0 +1,123 @@
1
+ from abc import ABC, abstractmethod
2
+ from dataclasses import dataclass
3
+ from enum import Enum
4
+ from typing import ClassVar, Optional, Type, Union
5
+
6
+ from typedlogic import Sentence, Theory
7
+ from typedlogic.parser import Parser
8
+
9
+
10
+ class ModelSyntax(str, Enum):
11
+ UNKNOWN = "unknown"
12
+ SEXPR = "sexpr"
13
+ FUNCTIONAL = "functional"
14
+
15
+
16
+ @dataclass
17
+ class Compiler(ABC):
18
+ """
19
+ An engine for compiling from the internal logical model representation to an external format.
20
+
21
+ Note: one of the main use cases for compiling a theory is to generate an input for a solver.
22
+ For many use cases, it's possible to just use a Solver directly, and let the system
23
+ take care of compilation to an intermediate form.
24
+
25
+ You can use the registry `get_compiler` method to get a compiler for a particular syntax:
26
+
27
+ >>> from typedlogic.registry import get_compiler
28
+ >>> compiler = get_compiler("fol")
29
+
30
+ Next we will transpile from Python to FOL syntax. We will use a `Parser` object:
31
+
32
+ >>> from typedlogic.registry import get_parser
33
+ >>> parser = get_parser("python")
34
+ >>> theory = parser.parse_file("tests/theorems/animals.py")
35
+
36
+ Now we will compile the theory to FOL syntax:
37
+
38
+ >>> print(compiler.compile(theory))
39
+ Person('Fred')
40
+ Person('Jie')
41
+ Animal('corky', 'cat')
42
+ Animal('fido', 'dog')
43
+ ∀[x:Thing species:Thing]. Animal(x, species) → Likes(x, 'Fred')
44
+ ∀[x:Thing species:Thing]. Animal(x, 'cat') → Likes(x, 'Jie')
45
+ ∀[x:Thing species:Thing]. Animal(x, 'dog') → ¬Likes('Fred', x)
46
+
47
+ Another useful syntax is TPTP, which is accepted by many theorom provers:
48
+
49
+ >>> compiler = get_compiler("tptp")
50
+ >>> print(compiler.compile(theory))
51
+ % Problem: animals
52
+ fof(axiom1, axiom, person('Fred')).
53
+ fof(axiom2, axiom, person('Jie')).
54
+ fof(axiom3, axiom, animal('corky', 'cat')).
55
+ fof(axiom4, axiom, animal('fido', 'dog')).
56
+ fof(axiom5, axiom, ! [X, Species] : (animal(X, Species) => likes(X, 'Fred'))).
57
+ fof(axiom6, axiom, ! [X, Species] : (animal(X, 'cat') => likes(X, 'Jie'))).
58
+ fof(axiom7, axiom, ! [X, Species] : (animal(X, 'dog') => ~likes('Fred', X))).
59
+
60
+ Another common syntax is Prolog syntax, and its variants. These are often used by Datalog solvers:
61
+
62
+ >>> compiler = get_compiler("prolog")
63
+ >>> print(compiler.compile(theory))
64
+ %% Predicate Definitions
65
+ % Likes(subject: str, object: str)
66
+ % Person(name: str)
67
+ % Animal(name: str, species: str)
68
+ <BLANKLINE>
69
+ %% persons
70
+ <BLANKLINE>
71
+ person('Fred').
72
+ person('Jie').
73
+ <BLANKLINE>
74
+ %% animals
75
+ <BLANKLINE>
76
+ animal('corky', 'cat').
77
+ animal('fido', 'dog').
78
+ <BLANKLINE>
79
+ %% animal_preferences
80
+ <BLANKLINE>
81
+ likes(X, 'Fred') :- animal(X, Species).
82
+ likes(X, 'Jie') :- animal(X, 'cat').
83
+ <BLANKLINE>
84
+
85
+
86
+ """
87
+
88
+ default_suffix: ClassVar[str] = "txt"
89
+ parser_class: ClassVar[Optional[Type[Parser]]] = None
90
+ strict: Optional[bool] = None
91
+
92
+
93
+ @abstractmethod
94
+ def compile(self, theory: Theory, syntax: Optional[Union[str, ModelSyntax]] = None, **kwargs) -> str:
95
+ """
96
+ Compile a theory into an external representation.
97
+
98
+ :param theory:
99
+ :param syntax:
100
+ :param kwargs:
101
+ :return:
102
+ """
103
+ pass
104
+
105
+ def compile_sentence(self, sentence: Sentence, syntax: Optional[Union[str, ModelSyntax]] = None, **kwargs) -> str:
106
+ """
107
+ Compiles an individual sentence
108
+
109
+ :param sentence:
110
+ :param syntax:
111
+ :param kwargs:
112
+ :return:
113
+ """
114
+ theory = Theory()
115
+ theory.add(sentence)
116
+ return self.compile(theory, syntax=syntax, **kwargs)
117
+
118
+ @property
119
+ def suffix(self) -> str:
120
+ return self.default_suffix
121
+
122
+ def _add_untranslatable(self, sentence: Sentence):
123
+ pass
File without changes
@@ -0,0 +1,18 @@
1
+ from dataclasses import dataclass
2
+ from typing import ClassVar, Optional, Union
3
+
4
+ from typedlogic import Theory
5
+ from typedlogic.compiler import Compiler, ModelSyntax
6
+ from typedlogic.transformations import as_fol
7
+
8
+
9
+ @dataclass
10
+ class FOLCompiler(Compiler):
11
+
12
+ default_suffix: ClassVar[str] = "fol"
13
+
14
+ def compile(self, theory: Theory, syntax: Optional[Union[str, ModelSyntax]] = None, **kwargs) -> str:
15
+ lines = []
16
+ for s in theory.sentences:
17
+ lines.append(as_fol(s))
18
+ return "\n".join(lines)