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.
- typedlogic-0.1.1/LICENSE +22 -0
- typedlogic-0.1.1/PKG-INFO +137 -0
- typedlogic-0.1.1/README.md +99 -0
- typedlogic-0.1.1/pyproject.toml +107 -0
- typedlogic-0.1.1/src/typedlogic/__init__.py +44 -0
- typedlogic-0.1.1/src/typedlogic/builtins.py +48 -0
- typedlogic-0.1.1/src/typedlogic/cli.py +76 -0
- typedlogic-0.1.1/src/typedlogic/compiler.py +123 -0
- typedlogic-0.1.1/src/typedlogic/compilers/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/compilers/fol_compiler.py +18 -0
- typedlogic-0.1.1/src/typedlogic/compilers/prolog_compiler.py +66 -0
- typedlogic-0.1.1/src/typedlogic/compilers/prover9_compiler.py +37 -0
- typedlogic-0.1.1/src/typedlogic/compilers/sexpr_compiler.py +99 -0
- typedlogic-0.1.1/src/typedlogic/compilers/tptp_compiler.py +29 -0
- typedlogic-0.1.1/src/typedlogic/compilers/yaml_compiler.py +76 -0
- typedlogic-0.1.1/src/typedlogic/datamodel.py +996 -0
- typedlogic-0.1.1/src/typedlogic/datamodels/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/datamodels/typesystem.py +155 -0
- typedlogic-0.1.1/src/typedlogic/decorators.py +149 -0
- typedlogic-0.1.1/src/typedlogic/evaluation.py +175 -0
- typedlogic-0.1.1/src/typedlogic/generators.py +94 -0
- typedlogic-0.1.1/src/typedlogic/integrations/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/data/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/data/dask/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/data/ibis/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/data/pandas/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/data/polars/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/data/sqlmodel/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/__init__.py +1 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/instance.py +164 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/loader.py +186 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/meta.py +78 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/linkml/meta_axioms.py +77 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/owldl/__init__.py +55 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/owldl/ontology_generators.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/owldl/owltop.py +2124 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/owldl/reasoner.py +206 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/pydantic/__init__.py +5 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/pydantic/pydantic_bridge.py +14 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/rdflib/__init__.py +3 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/rdflib/rdf.py +57 -0
- typedlogic-0.1.1/src/typedlogic/integrations/frameworks/rdflib/rdfs.py +80 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/clingo/__init__.py +5 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/clingo/clingo_solver.py +116 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/clorm/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/formulog/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/llm/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/llm/llm_solver.py +92 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/prover9/__init__.py +3 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/prover9/prover9_solver.py +81 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/pyprover/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/snakelog/__init__.py +3 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/snakelog/snakelog_solver.py +237 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/souffle/__init__.py +3 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/souffle/souffle_compiler.py +100 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/souffle/souffle_solver.py +119 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/z3/__init__.py +3 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/z3/z3_compiler.py +43 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/z3/z3_solver.py +335 -0
- typedlogic-0.1.1/src/typedlogic/integrations/solvers/z3/z3_utils.py +0 -0
- typedlogic-0.1.1/src/typedlogic/integrations/variadic_generics.py +18 -0
- typedlogic-0.1.1/src/typedlogic/parser.py +48 -0
- typedlogic-0.1.1/src/typedlogic/parsers/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/parsers/pyparser/__init__.py +5 -0
- typedlogic-0.1.1/src/typedlogic/parsers/pyparser/introspection.py +271 -0
- typedlogic-0.1.1/src/typedlogic/parsers/pyparser/python_ast_utils.py +376 -0
- typedlogic-0.1.1/src/typedlogic/parsers/pyparser/python_parser.py +94 -0
- typedlogic-0.1.1/src/typedlogic/parsers/yaml_parser.py +23 -0
- typedlogic-0.1.1/src/typedlogic/profiles.py +262 -0
- typedlogic-0.1.1/src/typedlogic/py.typed +0 -0
- typedlogic-0.1.1/src/typedlogic/pybridge.py +79 -0
- typedlogic-0.1.1/src/typedlogic/registry.py +118 -0
- typedlogic-0.1.1/src/typedlogic/solver.py +298 -0
- typedlogic-0.1.1/src/typedlogic/theories/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/theories/bfo/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/theories/jsonlog/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/theories/jsonlog/jsonlog.py +83 -0
- typedlogic-0.1.1/src/typedlogic/theories/jsonlog/jsonlog_axioms.py +28 -0
- typedlogic-0.1.1/src/typedlogic/theories/jsonlog/loader.py +58 -0
- typedlogic-0.1.1/src/typedlogic/transformations.py +1502 -0
- typedlogic-0.1.1/src/typedlogic/utils/__init__.py +0 -0
- typedlogic-0.1.1/src/typedlogic/utils/detect_stratified_negation.py +148 -0
- typedlogic-0.1.1/src/typedlogic/utils/graph_utils.py +70 -0
- typedlogic-0.1.1/src/typedlogic/utils/import_closure.py +49 -0
- typedlogic-0.1.1/src/typedlogic/utils/term_maker.py +27 -0
typedlogic-0.1.1/LICENSE
ADDED
|
@@ -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)
|