kele 0.0.1a1__tar.gz → 0.0.1a2__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.
- {kele-0.0.1a1 → kele-0.0.1a2}/.pre-commit-config.yaml +9 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/.ruff.toml +2 -5
- {kele-0.0.1a1 → kele-0.0.1a2}/CONTRIBUTING.md +3 -2
- {kele-0.0.1a1 → kele-0.0.1a2}/PKG-INFO +13 -3
- {kele-0.0.1a1 → kele-0.0.1a2}/README.md +10 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/README.zh.md +10 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/__init__.py +8 -6
- kele-0.0.1a2/kele/_utils.py +23 -0
- kele-0.0.1a2/kele/_version.py +1 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/config.py +52 -14
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/__init__.py +9 -4
- kele-0.0.1a2/kele/control/builtin_hooks.py +119 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/callback.py +14 -4
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/grounding_selector/__init__.py +7 -1
- kele-0.0.1a2/kele/control/grounding_selector/_rule_strategies/README.md +37 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/grounding_selector/_rule_strategies/__init__.py +2 -2
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/grounding_selector/_rule_strategies/_sequential_strategy.py +5 -3
- kele-0.0.1a2/kele/control/grounding_selector/_rule_strategies/strategy_protocol.py +27 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/grounding_selector/_selector_utils.py +2 -10
- kele-0.0.1a2/kele/control/grounding_selector/_term_strategies/README.md +34 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/grounding_selector/_term_strategies/__init__.py +2 -2
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/grounding_selector/_term_strategies/_exhausted_strategy.py +5 -3
- kele-0.0.1a2/kele/control/grounding_selector/_term_strategies/strategy_protocol.py +26 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/grounding_selector/rule_selector.py +14 -5
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/grounding_selector/term_selector.py +16 -6
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/infer_path.py +9 -8
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/metrics.py +7 -8
- kele-0.0.1a2/kele/control/registry.py +112 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/status.py +190 -49
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/egg_equiv.pyi +3 -3
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/equality/_equiv_elem.py +2 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/equality/_utils.py +4 -2
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/equality/equivalence.py +8 -7
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/executer/executing.py +40 -24
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/__init__.py +2 -7
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/__init__.py +2 -2
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/__init__.py +4 -4
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/_assertion.py +27 -14
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/_conn.py +4 -2
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/_op.py +6 -3
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/_root.py +4 -4
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/_rule.py +5 -5
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/_term.py +11 -10
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/_tftable.py +1 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/_tupletable.py +62 -58
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/grounded_class.py +60 -17
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/grounded_ds_utils.py +3 -4
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/rule_check.py +6 -5
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounding.py +38 -36
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/builtin_base/builtin_facts.py +3 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/builtin_base/builtin_operators.py +1 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/builtin_base/builtin_rules.py +1 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/fact_base.py +37 -16
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/ontology_base.py +1 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/rule_base.py +53 -32
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/main.py +55 -37
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/__init__.py +12 -12
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/_cnf_converter.py +2 -2
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/_sat_solver.py +3 -3
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/base_classes.py +92 -20
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/dnf_converter.py +10 -5
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/external.py +2 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/sub_concept.py +5 -4
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/syntacticsugar.py +3 -4
- {kele-0.0.1a1 → kele-0.0.1a2}/mypy.ini +1 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/pyproject.toml +23 -3
- {kele-0.0.1a1 → kele-0.0.1a2}/uv.lock +108 -1
- kele-0.0.1a1/kele/_version.py +0 -1
- kele-0.0.1a1/kele/control/grounding_selector/_rule_strategies/README.md +0 -13
- kele-0.0.1a1/kele/control/grounding_selector/_rule_strategies/strategy_protocol.py +0 -51
- kele-0.0.1a1/kele/control/grounding_selector/_term_strategies/strategy_protocol.py +0 -50
- {kele-0.0.1a1 → kele-0.0.1a2}/.gitattributes +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/.github/dependabot.yml +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/.github/workflows/license_check.yml +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/.github/workflows/lint.yml +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/.github/workflows/release.yml +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/.github/workflows/test.yml +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/.gitignore +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/Cargo.lock +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/Cargo.toml +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/LICENSE +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/_scripts/ci/examples_static_comment.py +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/_scripts/ci/run_examples_static_ci.sh +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/hatch_build.py +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/control/README_metrics.md +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/equality/README.md +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/equality/__init__.py +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/equality/_egg_equiv/src/lib.rs +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/executer/__init__.py +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/README.md +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/grounder/grounded_rule_ds/_nodes/_typing_polars.py +1 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/README.md +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/__init__.py +1 -1
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/builtin_base/__init__.py +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/knowledge_bases/builtin_base/builtin_concepts.py +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/py.typed +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/CONCEPT_README.md +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/kele/syntax/connectives.py +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/licensecheck.json +0 -0
- {kele-0.0.1a1 → kele-0.0.1a2}/pytest.ini +0 -0
|
@@ -9,9 +9,7 @@ lint.select = [
|
|
|
9
9
|
"C4", # flake8-comprehensions
|
|
10
10
|
"C90", # mccabe
|
|
11
11
|
"COM", # flake8-commas
|
|
12
|
-
"
|
|
13
|
-
# TODO: 这里有个问题的,501用于提醒有raise命令无注释。我需要这个检查,但我不需要必须按docstring的格式解决这一问题,毕竟仓库用的是
|
|
14
|
-
# reStructuredText格式。但我没有找到可用的reStructuredText linter,所以暂时不行。ruff的#9003好像也不太一样
|
|
12
|
+
"D101", "D102", "D103", "D104", "D419",
|
|
15
13
|
"DTZ", # flake8-datetimez
|
|
16
14
|
"E", # pycodestyle
|
|
17
15
|
"ERA", # eradicate
|
|
@@ -60,10 +58,9 @@ lint.ignore = [
|
|
|
60
58
|
"COM812", # Do not force trailing commas
|
|
61
59
|
"Q000", # Using single quotes instead of double quotes
|
|
62
60
|
"TRY003", # Allow exception message with any length
|
|
63
|
-
"PTH123", # Allow builtin-open
|
|
64
61
|
]
|
|
65
62
|
|
|
66
|
-
exclude = ['docs/', '.git']
|
|
63
|
+
exclude = ['docs/', '.git', '.venv', '__pycache__', 'target']
|
|
67
64
|
|
|
68
65
|
[lint.per-file-ignores]
|
|
69
66
|
# 对 tests 文件夹中的所有 Python 文件忽略规则
|
|
@@ -14,8 +14,8 @@ If you have any questions, please use the GitHub discussions.
|
|
|
14
14
|
The code structure of KELE is following the standard Python package structure.
|
|
15
15
|
We organize the package code into the folder named `KELE`, the tests into the folder named `tests`,
|
|
16
16
|
and the documents into the folder named `docs`.
|
|
17
|
-
The file `pyproject.toml` is used to define the package metadata.
|
|
18
|
-
There are also some other files such as `.ruff.toml`, `mypy.ini`, `.pre-commit-config.yaml` used to format and lint the code.
|
|
17
|
+
The file `pyproject.toml` is used to define the package metadata and lint configuration.
|
|
18
|
+
There are also some other files such as `.ruff.toml`, `mypy.ini`, and `.pre-commit-config.yaml` used to format and lint the code.
|
|
19
19
|
|
|
20
20
|
## How to get involved
|
|
21
21
|
|
|
@@ -24,6 +24,7 @@ We use the git flow mode to merge the pull requests.
|
|
|
24
24
|
Please provide the essential information with proper formatting in the git commit message and the pull request description.
|
|
25
25
|
|
|
26
26
|
Please make sure that your code is properly formatted, linted and typed when you submit a pull request.
|
|
27
|
+
We lint with `ruff`, and we supplement its DOC-series docstring checks with `pydoclint` (via `flake8`) to support reST-style docstrings. Static typing is checked with `mypy`.
|
|
27
28
|
The comments in the code are expected to be enough for other developers to understand your code.
|
|
28
29
|
Please add docstrings to the code in reStructuredText style.
|
|
29
30
|
If necessary, please update documentations and add tests for your changes.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kele
|
|
3
|
-
Version: 0.0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.0.1a2
|
|
4
|
+
Summary: Knowledge Equations based Logic Engine, a forward chaining inference engine with Assertional Logic
|
|
5
5
|
Author: Bingqian Li, BoYang Zhang, Weiming Hong, Hao Zhang, Yi Zhou
|
|
6
6
|
Maintainer-email: Bingqian Li <libq2022@alumni.shanghaitech.edu.cn>, Yi Zhou <yi_zhou@ustc.edu.cn>
|
|
7
7
|
License: BSD-3-Clause
|
|
@@ -17,6 +17,7 @@ Requires-Dist: polars>=1.32
|
|
|
17
17
|
Requires-Dist: prometheus-client>=0.22
|
|
18
18
|
Requires-Dist: psutil>=7.0
|
|
19
19
|
Requires-Dist: pydantic<3.0,>=2.0.0
|
|
20
|
+
Requires-Dist: python-baseconv<2.0,>=1.0
|
|
20
21
|
Requires-Dist: python-sat<2.0,>=1.7.dev0
|
|
21
22
|
Requires-Dist: pyvis<0.4,>=0.3
|
|
22
23
|
Requires-Dist: pyyaml<7.0,>=6.0
|
|
@@ -51,6 +52,7 @@ It supports **term-level facts**, **nested terms**, **equivalence axioms**, and
|
|
|
51
52
|
- **Equivalence axioms**: convenient equivalence expressions with internal maintenance
|
|
52
53
|
- **Nested compound terms**: operators can nest to build complex structures
|
|
53
54
|
- **Implement functions for operators**: implement functions for operators (e.g., arithmetic, equation solving)
|
|
55
|
+
- **Built-in hook enabler**: enable built-in hooks for inspection/debugging via `BuiltinHookEnabler`
|
|
54
56
|
|
|
55
57
|
> Implement functions for operators ≈ Prolog meta-predicates / ASP HEX external predicates (not identical semantics, similar usage).
|
|
56
58
|
|
|
@@ -150,13 +152,21 @@ print(engine.infer_query(query))
|
|
|
150
152
|
|
|
151
153
|
* **Tutorial**: https://msg-bq.github.io/
|
|
152
154
|
|
|
155
|
+
### 🧩 Custom registries
|
|
156
|
+
|
|
157
|
+
KELE exposes a top-level `register` hub so you can customize internal strategies (such as term/rule selectors) to fit domain-specific needs.
|
|
158
|
+
|
|
159
|
+
* Built-in tasks: `register.rule_selector` and `register.term_selector`.
|
|
160
|
+
* Each task registry supports `register(name)` as a decorator plus `get(name)` helpers.
|
|
161
|
+
* Additional registries may be introduced in the future; today only rule/term selectors are supported.
|
|
162
|
+
|
|
153
163
|
### 🗺️ Roadmap
|
|
154
164
|
|
|
155
165
|
WIP
|
|
156
166
|
|
|
157
167
|
### 🤝 Contributing
|
|
158
168
|
|
|
159
|
-
Issues/PRs welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md), and consider enabling `ruff` and `
|
|
169
|
+
Issues/PRs welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md), and consider enabling `ruff`, `mypy`, and `pydoclint` (via `flake8`). Ruff's `DOC` rules are powered by `pydoclint`.
|
|
160
170
|
|
|
161
171
|
If you have any questions about using the engine—including usage, syntax/semantics, or theoretical foundations—please open an issue or contact us.
|
|
162
172
|
|
|
@@ -25,6 +25,7 @@ It supports **term-level facts**, **nested terms**, **equivalence axioms**, and
|
|
|
25
25
|
- **Equivalence axioms**: convenient equivalence expressions with internal maintenance
|
|
26
26
|
- **Nested compound terms**: operators can nest to build complex structures
|
|
27
27
|
- **Implement functions for operators**: implement functions for operators (e.g., arithmetic, equation solving)
|
|
28
|
+
- **Built-in hook enabler**: enable built-in hooks for inspection/debugging via `BuiltinHookEnabler`
|
|
28
29
|
|
|
29
30
|
> Implement functions for operators ≈ Prolog meta-predicates / ASP HEX external predicates (not identical semantics, similar usage).
|
|
30
31
|
|
|
@@ -124,13 +125,21 @@ print(engine.infer_query(query))
|
|
|
124
125
|
|
|
125
126
|
* **Tutorial**: https://msg-bq.github.io/
|
|
126
127
|
|
|
128
|
+
### 🧩 Custom registries
|
|
129
|
+
|
|
130
|
+
KELE exposes a top-level `register` hub so you can customize internal strategies (such as term/rule selectors) to fit domain-specific needs.
|
|
131
|
+
|
|
132
|
+
* Built-in tasks: `register.rule_selector` and `register.term_selector`.
|
|
133
|
+
* Each task registry supports `register(name)` as a decorator plus `get(name)` helpers.
|
|
134
|
+
* Additional registries may be introduced in the future; today only rule/term selectors are supported.
|
|
135
|
+
|
|
127
136
|
### 🗺️ Roadmap
|
|
128
137
|
|
|
129
138
|
WIP
|
|
130
139
|
|
|
131
140
|
### 🤝 Contributing
|
|
132
141
|
|
|
133
|
-
Issues/PRs welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md), and consider enabling `ruff` and `
|
|
142
|
+
Issues/PRs welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md), and consider enabling `ruff`, `mypy`, and `pydoclint` (via `flake8`). Ruff's `DOC` rules are powered by `pydoclint`.
|
|
134
143
|
|
|
135
144
|
If you have any questions about using the engine—including usage, syntax/semantics, or theoretical foundations—please open an issue or contact us.
|
|
136
145
|
|
|
@@ -25,6 +25,7 @@ KELE 是基于[断言逻辑](https://link.springer.com/chapter/10.1007/978-3-319
|
|
|
25
25
|
- **等词公理**:便捷表达等价关系,引擎内部自行维护
|
|
26
26
|
- **可嵌套复合项**:允许嵌套项,算子可互相嵌套构成更复杂的复合结构
|
|
27
27
|
- **算子的外部实现**:支持使用函数对算子进行自定义“实现”,如加法、解方程等
|
|
28
|
+
- **内置 hook 启用器**:通过 `BuiltinHookEnabler` 启用内置 hooks 用于检查/调试
|
|
28
29
|
|
|
29
30
|
> 外部实现 ≈ Prolog 元谓词 / ASP 中 HEX external predicate(语义不完全相同,但使用体验相近)。
|
|
30
31
|
|
|
@@ -118,13 +119,21 @@ print(engine.infer_query(query))
|
|
|
118
119
|
|
|
119
120
|
* **使用教程**:https://msg-bq.github.io/
|
|
120
121
|
|
|
122
|
+
### 🧩 自定义注册
|
|
123
|
+
|
|
124
|
+
KELE 暴露了顶层 `register` 入口,用于自定义内部策略(如 term 与 rule 的选择策略),以适应领域的细节需求。
|
|
125
|
+
|
|
126
|
+
* 内置任务:`register.rule_selector` 与 `register.term_selector`。
|
|
127
|
+
* 每个任务注册表支持 `register(name)` 装饰器与 `available()` 查看已注册策略。
|
|
128
|
+
* 目前仅支持规则/项选择器,后续可能会增加更多注册点。
|
|
129
|
+
|
|
121
130
|
### 🗺️ Roadmap
|
|
122
131
|
|
|
123
132
|
WIP
|
|
124
133
|
|
|
125
134
|
### 🤝 参与贡献
|
|
126
135
|
|
|
127
|
-
欢迎 Issue/PR!请先阅读 [CONTRIBUTING.md](CONTRIBUTING.md),遵循相关规范;建议启用 `ruff`、`mypy
|
|
136
|
+
欢迎 Issue/PR!请先阅读 [CONTRIBUTING.md](CONTRIBUTING.md),遵循相关规范;建议启用 `ruff`、`mypy`,以及 `pydoclint`(通过 `flake8` 运行)。`ruff` 的 `DOC` 系列规则由 `pydoclint` 支持。
|
|
128
137
|
|
|
129
138
|
如果对引擎的使用有问题,但不限于使用、语法语义、理论基础等任何方面的问题,都欢迎提 issue 或与我们联系。
|
|
130
139
|
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"""支持断言逻辑的推理引擎"""
|
|
2
|
-
from kele.main import EngineRunResult, InferenceEngine, QueryStructure
|
|
3
2
|
from kele.config import (
|
|
4
3
|
Config,
|
|
5
|
-
RunControlConfig,
|
|
6
|
-
InferenceStrategyConfig,
|
|
7
|
-
GrounderConfig,
|
|
8
4
|
ExecutorConfig,
|
|
9
|
-
|
|
5
|
+
GrounderConfig,
|
|
6
|
+
InferenceStrategyConfig,
|
|
10
7
|
KBConfig,
|
|
8
|
+
PathConfig,
|
|
9
|
+
RunControlConfig,
|
|
11
10
|
)
|
|
12
|
-
from kele.
|
|
11
|
+
from kele.control import register
|
|
12
|
+
from kele.main import EngineRunResult, InferenceEngine, QueryStructure
|
|
13
|
+
from kele.syntax.base_classes import Assertion, CompoundTerm, Concept, Constant, Formula, Operator, Rule, Variable
|
|
13
14
|
|
|
14
15
|
try:
|
|
15
16
|
from ._version import version as __version__
|
|
@@ -35,4 +36,5 @@ __all__ = [
|
|
|
35
36
|
'Rule',
|
|
36
37
|
'RunControlConfig',
|
|
37
38
|
'Variable',
|
|
39
|
+
'register',
|
|
38
40
|
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, TypeVar
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from collections.abc import Callable, Sequence
|
|
7
|
+
|
|
8
|
+
T = TypeVar("T")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def summarize_items(
|
|
12
|
+
items: Sequence[T],
|
|
13
|
+
*,
|
|
14
|
+
sample_size: int = 5,
|
|
15
|
+
formatter: Callable[[T], str] = str,
|
|
16
|
+
) -> dict[str, Any]:
|
|
17
|
+
"""Summarize a sequence for debug logging."""
|
|
18
|
+
total = len(items)
|
|
19
|
+
sample = [formatter(item) for item in items[:sample_size]]
|
|
20
|
+
return {
|
|
21
|
+
"rows": total,
|
|
22
|
+
"sample": sample,
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "0.0.1a2"
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# ruff: noqa: ERA001 # Commented parameters are either not implemented yet or depend on unfinished upstream/downstream modules.
|
|
2
|
-
import
|
|
3
|
-
from typing import Any, cast, Literal
|
|
4
|
-
|
|
2
|
+
import json
|
|
5
3
|
import logging
|
|
6
|
-
|
|
7
|
-
from
|
|
4
|
+
import warnings
|
|
5
|
+
from dataclasses import dataclass, field, fields
|
|
6
|
+
from datetime import UTC, datetime
|
|
8
7
|
from pathlib import Path
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
import tyro
|
|
12
|
-
from tyro.conf import OmitArgPrefixes
|
|
8
|
+
from typing import Any, Literal, cast
|
|
9
|
+
|
|
13
10
|
import dacite
|
|
11
|
+
import tyro
|
|
12
|
+
import yaml
|
|
14
13
|
from dacite.config import Config as daConfig
|
|
14
|
+
from tyro.conf import OmitArgPrefixes
|
|
15
15
|
|
|
16
16
|
RESULT_LEVEL = 25
|
|
17
17
|
logging.RESULT = RESULT_LEVEL # type: ignore[attr-defined] # This fails mypy; setattr fails ruff.
|
|
@@ -59,12 +59,50 @@ class InferenceStrategyConfig:
|
|
|
59
59
|
@dataclass
|
|
60
60
|
class GrounderConfig:
|
|
61
61
|
"""Grounder-related parameters."""
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
grounding_rules_per_step: int | Literal[-1] = -1
|
|
63
|
+
grounding_facts_per_rule: int | Literal[-1] = -1
|
|
64
|
+
grounding_rules_num_every_step: int | Literal[-1] | None = None
|
|
65
|
+
grounding_facts_num_for_each_rule: int | Literal[-1] | None = None
|
|
64
66
|
allow_unify_with_nested_term: bool = True # Allow Variables to be replaced by CompoundTerms.
|
|
65
67
|
conceptual_fuzzy_unification: bool = True # Use strict concept constraints to accelerate inference.
|
|
66
68
|
# This depends on correct concept subsumption and full constant.belong_concepts settings; beginners should use loose matching.
|
|
67
69
|
|
|
70
|
+
def __post_init__(self) -> None:
|
|
71
|
+
if self.grounding_rules_num_every_step is not None:
|
|
72
|
+
warnings.warn(
|
|
73
|
+
"grounding_rules_num_every_step is deprecated; use grounding_rules_per_step instead.",
|
|
74
|
+
DeprecationWarning,
|
|
75
|
+
stacklevel=2,
|
|
76
|
+
)
|
|
77
|
+
if self.grounding_rules_per_step == -1:
|
|
78
|
+
self.grounding_rules_per_step = self.grounding_rules_num_every_step
|
|
79
|
+
elif self.grounding_rules_per_step != self.grounding_rules_num_every_step:
|
|
80
|
+
warnings.warn(
|
|
81
|
+
"Both grounding_rules_per_step and grounding_rules_num_every_step are set; using grounding_rules_per_step.",
|
|
82
|
+
DeprecationWarning,
|
|
83
|
+
stacklevel=2,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if self.grounding_facts_num_for_each_rule is not None:
|
|
87
|
+
warnings.warn(
|
|
88
|
+
"grounding_facts_num_for_each_rule is deprecated; use grounding_facts_per_rule instead.",
|
|
89
|
+
DeprecationWarning,
|
|
90
|
+
stacklevel=2,
|
|
91
|
+
)
|
|
92
|
+
if self.grounding_facts_per_rule == -1:
|
|
93
|
+
self.grounding_facts_per_rule = self.grounding_facts_num_for_each_rule
|
|
94
|
+
elif self.grounding_facts_per_rule != self.grounding_facts_num_for_each_rule:
|
|
95
|
+
warnings.warn(
|
|
96
|
+
"Both grounding_facts_per_rule and grounding_facts_num_for_each_rule are set; using grounding_facts_per_rule.",
|
|
97
|
+
DeprecationWarning,
|
|
98
|
+
stacklevel=2,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if self.grounding_rules_num_every_step is None:
|
|
102
|
+
self.grounding_rules_num_every_step = self.grounding_rules_per_step
|
|
103
|
+
if self.grounding_facts_num_for_each_rule is None:
|
|
104
|
+
self.grounding_facts_num_for_each_rule = self.grounding_facts_per_rule
|
|
105
|
+
|
|
68
106
|
|
|
69
107
|
@dataclass
|
|
70
108
|
class ExecutorConfig:
|
|
@@ -103,7 +141,7 @@ class Config:
|
|
|
103
141
|
|
|
104
142
|
|
|
105
143
|
def _load_config_file(path: str) -> dict[str, Any]:
|
|
106
|
-
with open(
|
|
144
|
+
with Path(path).open(encoding="utf-8") as f:
|
|
107
145
|
if path.endswith(('.yaml', '.yml')):
|
|
108
146
|
data = yaml.safe_load(f)
|
|
109
147
|
elif path.endswith('.json'):
|
|
@@ -117,7 +155,7 @@ def _load_config_file(path: str) -> dict[str, Any]:
|
|
|
117
155
|
|
|
118
156
|
|
|
119
157
|
def _save_config(config: dict[str, Any], path: str) -> None:
|
|
120
|
-
with open(
|
|
158
|
+
with Path(path).open('w', encoding='utf8') as f:
|
|
121
159
|
yaml.dump(config, f, sort_keys=False)
|
|
122
160
|
|
|
123
161
|
|
|
@@ -197,7 +235,7 @@ def _build_config(user_config: Config | None = None,
|
|
|
197
235
|
|
|
198
236
|
:raises: ValueError: If `user_config` is used together with `config_file_path`
|
|
199
237
|
or when `user_config.config` is set.
|
|
200
|
-
"""
|
|
238
|
+
"""
|
|
201
239
|
if user_config and (user_config.config or config_file_path):
|
|
202
240
|
raise ValueError("default config instance and config file cannot be used together")
|
|
203
241
|
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"""用于callbacks和推理路径的记录"""
|
|
2
|
-
from .callback import
|
|
2
|
+
from .callback import Callback, CallbackManager, HookMixin
|
|
3
|
+
from .grounding_selector import GroundingRuleSelector
|
|
4
|
+
from .builtin_hooks import BuiltinHookEnabler, register_assertion_check_hook
|
|
5
|
+
from .infer_path import InferencePath
|
|
6
|
+
from .registry import register
|
|
3
7
|
from .status import (
|
|
4
8
|
InferenceStatus,
|
|
5
|
-
create_main_loop_manager,
|
|
6
9
|
create_executor_manager,
|
|
10
|
+
create_main_loop_manager,
|
|
7
11
|
)
|
|
8
|
-
from .grounding_selector import GroundingRuleSelector
|
|
9
|
-
from .infer_path import InferencePath
|
|
10
12
|
|
|
11
13
|
__all__ = [
|
|
14
|
+
'BuiltinHookEnabler',
|
|
12
15
|
'Callback',
|
|
13
16
|
'CallbackManager',
|
|
14
17
|
'GroundingRuleSelector',
|
|
@@ -17,4 +20,6 @@ __all__ = [
|
|
|
17
20
|
'InferenceStatus',
|
|
18
21
|
'create_executor_manager',
|
|
19
22
|
'create_main_loop_manager',
|
|
23
|
+
'register',
|
|
24
|
+
'register_assertion_check_hook',
|
|
20
25
|
]
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from collections.abc import Callable, Mapping
|
|
8
|
+
|
|
9
|
+
from kele.grounder import GroundedRule
|
|
10
|
+
from kele.grounder.grounded_rule_ds._nodes import _AssertionNode
|
|
11
|
+
from kele.syntax import CompoundTerm, Constant, Rule, Variable
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register_assertion_check_hook(
|
|
17
|
+
grounded_rule: GroundedRule,
|
|
18
|
+
*,
|
|
19
|
+
rule_name: str | None = None,
|
|
20
|
+
vars_filter: Mapping[str, str] | None = None,
|
|
21
|
+
on_match: Callable[[Rule, _AssertionNode, dict[Variable, Constant | CompoundTerm], bool], None] | None = None,
|
|
22
|
+
break_on_match: bool = False,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Register a built-in hook that observes assertion check results.
|
|
26
|
+
|
|
27
|
+
This is a user-facing inspection hook: it lets you capture whether a specific
|
|
28
|
+
assertion evaluation (for a given variable binding) is True/False, and optionally
|
|
29
|
+
stop on matches for deep debugging.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
def log_match(rule, assertion, combination, result):
|
|
33
|
+
print(rule.name, assertion.content, combination, result)
|
|
34
|
+
|
|
35
|
+
register_assertion_check_hook(
|
|
36
|
+
grounded_rule,
|
|
37
|
+
rule_name="rule_3",
|
|
38
|
+
vars_filter={"p1": "f", "p2": "a", "p13": "b", "p14": "c"},
|
|
39
|
+
on_match=log_match,
|
|
40
|
+
break_on_match=True,
|
|
41
|
+
)
|
|
42
|
+
"""
|
|
43
|
+
normalized_vars_filter = dict(vars_filter) if vars_filter is not None else None
|
|
44
|
+
|
|
45
|
+
def _hook(
|
|
46
|
+
*,
|
|
47
|
+
rule: Rule,
|
|
48
|
+
assertion: _AssertionNode,
|
|
49
|
+
combination: dict[Variable, Constant | CompoundTerm],
|
|
50
|
+
result: bool,
|
|
51
|
+
) -> None:
|
|
52
|
+
if rule_name and rule.name != rule_name:
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
combination_str = {str(k): str(v) for k, v in combination.items()}
|
|
56
|
+
if normalized_vars_filter:
|
|
57
|
+
for key, value in normalized_vars_filter.items():
|
|
58
|
+
if combination_str.get(key) != value:
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
if on_match is None:
|
|
62
|
+
logger.debug(
|
|
63
|
+
"Assertion check hook: rule=%s content=%s combination=%s result=%s",
|
|
64
|
+
rule,
|
|
65
|
+
assertion.content,
|
|
66
|
+
combination_str,
|
|
67
|
+
result,
|
|
68
|
+
)
|
|
69
|
+
else:
|
|
70
|
+
on_match(rule, assertion, combination, result)
|
|
71
|
+
|
|
72
|
+
if break_on_match:
|
|
73
|
+
breakpoint() # noqa: T100
|
|
74
|
+
|
|
75
|
+
grounded_rule.register_hook("assertion_check", _hook)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class BuiltinHookEnabler:
|
|
79
|
+
"""
|
|
80
|
+
Enabler for built-in hooks by name.
|
|
81
|
+
|
|
82
|
+
This class does not register hooks by itself. Create an instance and call
|
|
83
|
+
``enable`` to attach a built-in hook to a grounded rule.
|
|
84
|
+
|
|
85
|
+
Example:
|
|
86
|
+
hooks = BuiltinHookEnabler()
|
|
87
|
+
hooks.enable(
|
|
88
|
+
grounded_rule,
|
|
89
|
+
"assertion_check",
|
|
90
|
+
rule_name="rule_3",
|
|
91
|
+
vars_filter={"p1": "f"},
|
|
92
|
+
)
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def __init__(self) -> None:
|
|
96
|
+
self._hooks: dict[str, Callable[..., None]] = {
|
|
97
|
+
"assertion_check": register_assertion_check_hook,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
def available_hooks(self) -> list[str]:
|
|
101
|
+
"""
|
|
102
|
+
Return the names of available built-in hooks.
|
|
103
|
+
"""
|
|
104
|
+
return sorted(self._hooks)
|
|
105
|
+
|
|
106
|
+
def enable(self, grounded_rule: GroundedRule, name: str, **kwargs: object) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Enable a built-in hook by name.
|
|
109
|
+
"""
|
|
110
|
+
if name not in self._hooks:
|
|
111
|
+
raise KeyError(f"Unknown built-in hook: {name}")
|
|
112
|
+
self._hooks[name](grounded_rule, **kwargs)
|
|
113
|
+
|
|
114
|
+
def enable_many(self, grounded_rule: GroundedRule, names: list[str], **kwargs: object) -> None:
|
|
115
|
+
"""
|
|
116
|
+
Enable multiple built-in hooks by name.
|
|
117
|
+
"""
|
|
118
|
+
for hook_name in names:
|
|
119
|
+
self.enable(grounded_rule, hook_name, **kwargs)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections import defaultdict
|
|
4
|
-
from typing import
|
|
5
|
-
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
6
5
|
|
|
7
6
|
if TYPE_CHECKING:
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
|
|
8
9
|
from kele.equality import Equivalence
|
|
9
10
|
from kele.grounder import GroundedRule
|
|
10
11
|
from kele.knowledge_bases import FactBase, RuleBase
|
|
11
|
-
from kele.syntax import
|
|
12
|
-
from collections.abc import Callable
|
|
12
|
+
from kele.syntax import FACT_TYPE, CompoundTerm, Constant, Question, Rule, Variable
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class HookMixin:
|
|
@@ -41,6 +41,16 @@ class HookMixin:
|
|
|
41
41
|
for hook in self._hooks.get(event_name, []):
|
|
42
42
|
hook(*args, **kwargs)
|
|
43
43
|
|
|
44
|
+
def run_hooks(self, event_name: str, *args: Any, **kwargs: Any) -> None: # noqa: ANN401
|
|
45
|
+
"""
|
|
46
|
+
对外公开的钩子触发入口。
|
|
47
|
+
|
|
48
|
+
:param event_name: 事件名称。
|
|
49
|
+
:param args: 传递给钩子的所有位置参数。
|
|
50
|
+
:param kwargs: 传递给钩子的所有关键字参数。
|
|
51
|
+
"""
|
|
52
|
+
self._run_hooks(event_name, *args, **kwargs)
|
|
53
|
+
|
|
44
54
|
|
|
45
55
|
class Callback:
|
|
46
56
|
"""回调接口——在推理各阶段采集指标的Hook"""
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
"""grounding相关的选择器"""
|
|
2
|
+
from kele.control.registry import register
|
|
3
|
+
|
|
2
4
|
from .rule_selector import GroundingRuleSelector
|
|
3
5
|
from .term_selector import GroundingFlatTermWithWildCardSelector
|
|
4
6
|
|
|
5
|
-
__all__ = [
|
|
7
|
+
__all__ = [
|
|
8
|
+
"GroundingFlatTermWithWildCardSelector",
|
|
9
|
+
"GroundingRuleSelector",
|
|
10
|
+
"register",
|
|
11
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
## 默认strategy
|
|
2
|
+
|
|
3
|
+
### SequentialCyclic
|
|
4
|
+
按顺序逐个选择规则,每次选1条。
|
|
5
|
+
|
|
6
|
+
### SequentialCyclicWithPriority
|
|
7
|
+
根据规则的priority排序后,按顺序逐个选择规则,每次选1条。
|
|
8
|
+
|
|
9
|
+
## 创建自己的strategy
|
|
10
|
+
1. 创建一个py文件,命名要求为`_<name>_strategy.py`;
|
|
11
|
+
2. 继承RuleSelectionStrategy类,并至少声明此Protocol要求的函数;
|
|
12
|
+
3. 从`kele.control`导入并使用`@register.rule_selector('<name>')`注册你的策略类,后续即可通过`grounding_rule_strategy`使用策略;
|
|
13
|
+
4. 注意调整`grounding_rule_strategy`的类型标注(增加Literal的候选值)。
|
|
14
|
+
|
|
15
|
+
示例:
|
|
16
|
+
```python
|
|
17
|
+
from kele.control import register
|
|
18
|
+
from kele.control.grounding_selector._rule_strategies.strategy_protocol import RuleSelectionStrategy
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@register.rule_selector("MyRuleStrategy")
|
|
22
|
+
class MyRuleStrategy:
|
|
23
|
+
def __init__(self) -> None:
|
|
24
|
+
self._rules = []
|
|
25
|
+
|
|
26
|
+
def set_rules(self, rules):
|
|
27
|
+
self._rules = list(rules)
|
|
28
|
+
|
|
29
|
+
def reset(self) -> None:
|
|
30
|
+
self._rules = []
|
|
31
|
+
|
|
32
|
+
def select_next(self):
|
|
33
|
+
return self._rules[:1]
|
|
34
|
+
|
|
35
|
+
def on_feedback(self, feedback):
|
|
36
|
+
return None
|
|
37
|
+
```
|
|
@@ -3,7 +3,7 @@ import importlib
|
|
|
3
3
|
import logging
|
|
4
4
|
import pathlib
|
|
5
5
|
|
|
6
|
-
from .
|
|
6
|
+
from kele.control.registry import get_rule_strategy_class
|
|
7
7
|
|
|
8
8
|
current_dir = pathlib.Path(__file__).resolve().parent
|
|
9
9
|
package_name = __package__ or current_dir.name
|
|
@@ -21,4 +21,4 @@ for filename in current_dir.iterdir():
|
|
|
21
21
|
logger.exception('Failed to import %s', module_name)
|
|
22
22
|
continue
|
|
23
23
|
|
|
24
|
-
__all__ = ["
|
|
24
|
+
__all__ = ["get_rule_strategy_class"]
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from collections.abc import Sequence
|
|
2
2
|
|
|
3
|
-
from .
|
|
3
|
+
from kele.control.registry import register
|
|
4
4
|
from kele.syntax import Rule
|
|
5
5
|
|
|
6
|
+
from .strategy_protocol import Feedback, RuleSelectionStrategy
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
@register.rule_selector('SequentialCyclic')
|
|
8
10
|
class SequentialCyclicStrategy(RuleSelectionStrategy):
|
|
9
11
|
"""
|
|
10
12
|
按顺序循环遍历策略:
|
|
@@ -33,7 +35,7 @@ class SequentialCyclicStrategy(RuleSelectionStrategy):
|
|
|
33
35
|
return
|
|
34
36
|
|
|
35
37
|
|
|
36
|
-
@
|
|
38
|
+
@register.rule_selector("SequentialCyclicWithPriority")
|
|
37
39
|
class SequentialCyclicWithPriorityStrategy(SequentialCyclicStrategy):
|
|
38
40
|
"""将规则按优先级排序,优先级高的先取"""
|
|
39
41
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import TYPE_CHECKING, Protocol, runtime_checkable
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
|
|
9
|
+
from kele.syntax import Rule
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@runtime_checkable
|
|
13
|
+
class RuleSelectionStrategy(Protocol):
|
|
14
|
+
"""
|
|
15
|
+
选取策略的统一接口。允许根据需求返回任意规则。
|
|
16
|
+
"""
|
|
17
|
+
def __init__(self) -> None: ...
|
|
18
|
+
def set_rules(self, rules: Sequence[Rule]) -> None: ...
|
|
19
|
+
def reset(self) -> None: ...
|
|
20
|
+
def select_next(self) -> Sequence[Rule]: ...
|
|
21
|
+
def on_feedback(self, feedback: Feedback) -> None: ... # 给策略回传一次选择后的反馈
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class Feedback:
|
|
26
|
+
"""一次选择后的可选反馈信息;字段都可缺省,策略按需使用。"""
|
|
27
|
+
rule: Rule | None = None # 这次反馈关联到的规则;hack: 后面增加其他的相关信息,可能有facts等等
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import itertools
|
|
2
|
-
import warnings
|
|
3
2
|
from collections.abc import Sequence
|
|
3
|
+
from functools import singledispatch
|
|
4
4
|
|
|
5
5
|
from kele.knowledge_bases.builtin_base.builtin_concepts import FREEVARANY_CONCEPT
|
|
6
|
-
from kele.syntax import
|
|
7
|
-
Constant, Variable, ATOM_TYPE, Rule)
|
|
8
|
-
from functools import singledispatch
|
|
6
|
+
from kele.syntax import ATOM_TYPE, FACT_TYPE, TERM_TYPE, Assertion, CompoundTerm, Constant, Formula, Rule
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
@singledispatch
|
|
@@ -39,12 +37,6 @@ def _(fact: Constant) -> tuple[CompoundTerm | Constant, ...]:
|
|
|
39
37
|
return (fact, )
|
|
40
38
|
|
|
41
39
|
|
|
42
|
-
@_unify_all_terms.register(Variable)
|
|
43
|
-
def _(fact: Variable) -> tuple[CompoundTerm | Constant, ...]:
|
|
44
|
-
warnings.warn("Variable should not exist in fact", stacklevel=2)
|
|
45
|
-
return ()
|
|
46
|
-
|
|
47
|
-
|
|
48
40
|
class FREEVARANY(Constant):
|
|
49
41
|
"""
|
|
50
42
|
ANY标签,在free_variables用于占位,暂定为一种特殊的Constant。
|