kele 0.0.1a1__cp314-cp314-macosx_11_0_arm64.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.
Files changed (73) hide show
  1. kele/__init__.py +38 -0
  2. kele/_version.py +1 -0
  3. kele/config.py +243 -0
  4. kele/control/README_metrics.md +102 -0
  5. kele/control/__init__.py +20 -0
  6. kele/control/callback.py +255 -0
  7. kele/control/grounding_selector/__init__.py +5 -0
  8. kele/control/grounding_selector/_rule_strategies/README.md +13 -0
  9. kele/control/grounding_selector/_rule_strategies/__init__.py +24 -0
  10. kele/control/grounding_selector/_rule_strategies/_sequential_strategy.py +42 -0
  11. kele/control/grounding_selector/_rule_strategies/strategy_protocol.py +51 -0
  12. kele/control/grounding_selector/_selector_utils.py +123 -0
  13. kele/control/grounding_selector/_term_strategies/__init__.py +24 -0
  14. kele/control/grounding_selector/_term_strategies/_exhausted_strategy.py +34 -0
  15. kele/control/grounding_selector/_term_strategies/strategy_protocol.py +50 -0
  16. kele/control/grounding_selector/rule_selector.py +98 -0
  17. kele/control/grounding_selector/term_selector.py +89 -0
  18. kele/control/infer_path.py +306 -0
  19. kele/control/metrics.py +357 -0
  20. kele/control/status.py +286 -0
  21. kele/egg_equiv.pyi +11 -0
  22. kele/egg_equiv.so +0 -0
  23. kele/equality/README.md +8 -0
  24. kele/equality/__init__.py +4 -0
  25. kele/equality/_egg_equiv/src/lib.rs +267 -0
  26. kele/equality/_equiv_elem.py +67 -0
  27. kele/equality/_utils.py +36 -0
  28. kele/equality/equivalence.py +141 -0
  29. kele/executer/__init__.py +4 -0
  30. kele/executer/executing.py +139 -0
  31. kele/grounder/README.md +83 -0
  32. kele/grounder/__init__.py +17 -0
  33. kele/grounder/grounded_rule_ds/__init__.py +6 -0
  34. kele/grounder/grounded_rule_ds/_nodes/__init__.py +24 -0
  35. kele/grounder/grounded_rule_ds/_nodes/_assertion.py +353 -0
  36. kele/grounder/grounded_rule_ds/_nodes/_conn.py +116 -0
  37. kele/grounder/grounded_rule_ds/_nodes/_op.py +57 -0
  38. kele/grounder/grounded_rule_ds/_nodes/_root.py +71 -0
  39. kele/grounder/grounded_rule_ds/_nodes/_rule.py +119 -0
  40. kele/grounder/grounded_rule_ds/_nodes/_term.py +390 -0
  41. kele/grounder/grounded_rule_ds/_nodes/_tftable.py +15 -0
  42. kele/grounder/grounded_rule_ds/_nodes/_tupletable.py +444 -0
  43. kele/grounder/grounded_rule_ds/_nodes/_typing_polars.py +26 -0
  44. kele/grounder/grounded_rule_ds/grounded_class.py +461 -0
  45. kele/grounder/grounded_rule_ds/grounded_ds_utils.py +91 -0
  46. kele/grounder/grounded_rule_ds/rule_check.py +373 -0
  47. kele/grounder/grounding.py +118 -0
  48. kele/knowledge_bases/README.md +112 -0
  49. kele/knowledge_bases/__init__.py +6 -0
  50. kele/knowledge_bases/builtin_base/__init__.py +1 -0
  51. kele/knowledge_bases/builtin_base/builtin_concepts.py +13 -0
  52. kele/knowledge_bases/builtin_base/builtin_facts.py +43 -0
  53. kele/knowledge_bases/builtin_base/builtin_operators.py +105 -0
  54. kele/knowledge_bases/builtin_base/builtin_rules.py +14 -0
  55. kele/knowledge_bases/fact_base.py +158 -0
  56. kele/knowledge_bases/ontology_base.py +67 -0
  57. kele/knowledge_bases/rule_base.py +194 -0
  58. kele/main.py +464 -0
  59. kele/py.typed +0 -0
  60. kele/syntax/CONCEPT_README.md +117 -0
  61. kele/syntax/__init__.py +40 -0
  62. kele/syntax/_cnf_converter.py +161 -0
  63. kele/syntax/_sat_solver.py +116 -0
  64. kele/syntax/base_classes.py +1482 -0
  65. kele/syntax/connectives.py +20 -0
  66. kele/syntax/dnf_converter.py +145 -0
  67. kele/syntax/external.py +17 -0
  68. kele/syntax/sub_concept.py +87 -0
  69. kele/syntax/syntacticsugar.py +201 -0
  70. kele-0.0.1a1.dist-info/METADATA +165 -0
  71. kele-0.0.1a1.dist-info/RECORD +73 -0
  72. kele-0.0.1a1.dist-info/WHEEL +6 -0
  73. kele-0.0.1a1.dist-info/licenses/LICENSE +28 -0
@@ -0,0 +1,141 @@
1
+ from __future__ import annotations
2
+ import warnings
3
+ from typing import cast, overload, TYPE_CHECKING
4
+
5
+
6
+ from kele.egg_equiv import EggEquivalence
7
+ from kele.equality._utils import fact_validator # FIXME: 内部函数
8
+ from kele.syntax import Formula, Assertion, CompoundTerm, FACT_TYPE, Constant
9
+ from kele.grounder.grounded_rule_ds.grounded_ds_utils import split_all_terms
10
+
11
+ if TYPE_CHECKING:
12
+ from kele.config import Config
13
+ from kele.syntax.base_classes import TERM_TYPE, Variable, HashableAndStringable
14
+ from collections.abc import Sequence
15
+
16
+
17
+ class Equivalence:
18
+ """
19
+ 这个类是等价类的主要代码,用于实现维护等价类
20
+ 这个类主要的属性是father和length
21
+ """
22
+ def __init__(self, args: Config) -> None:
23
+ self._args = args
24
+ self.engine: EggEquivalence = EggEquivalence(trace=False) # HACK: 暂时不通过egraph获取等价关系解释
25
+ self._fact_validator = fact_validator
26
+
27
+ def get_related_item(self, input_item: TERM_TYPE) -> list[TERM_TYPE]:
28
+ # HACK: 此功能实际上应该由term_selector实现,或者调用egraph的相关函数来获取所有可能的等价形式
29
+ """
30
+ 获取与item相关的所有节点
31
+ 相关节点定义为:与item等价的所有节点,与term的某个复合子结构等价的所有节点,以及item本身
32
+
33
+ :param item: 要获取相关元素的元素
34
+ :returns: 返回与item相关的所有元素
35
+ """
36
+ if isinstance(input_item, CompoundTerm):
37
+ if TYPE_CHECKING:
38
+ input_item = cast("CompoundTerm[Constant | CompoundTerm[Constant | Variable | HashableAndStringable]]", input_item)
39
+ all_depth_terms = split_all_terms(input_item)
40
+ result_set = set()
41
+ for term in all_depth_terms:
42
+ result_set.update(self.engine.get_equiv_elem(term))
43
+ return list(result_set)
44
+ return self.get_equiv_item(input_item)
45
+
46
+ def get_equiv_item(self, input_item: TERM_TYPE) -> list[TERM_TYPE]:
47
+ """
48
+ 获取与item等价的所有节点
49
+ 如果item是与某个BOOL_CONCEPT等价,或者其本身是BOOL_CONCEPT,那么将*不会返回*和该BOOL_CONCEPT等价的元素
50
+
51
+ :param item: 要获取等价元素的元素
52
+ :returns: 返回与item等价的所有元素
53
+ """
54
+ return self.engine.get_equiv_elem(input_item)
55
+
56
+ def update_equiv_class(
57
+ self,
58
+ facts_or_equiv_rels: Sequence[FACT_TYPE],
59
+ ) -> None:
60
+ """更新等价类的对外接口"""
61
+ for item in facts_or_equiv_rels:
62
+ self._update_by_facts(item)
63
+
64
+ def get_represent_elem(self, input_item: Constant | CompoundTerm) -> Constant | CompoundTerm[Constant | CompoundTerm]:
65
+ """
66
+ 获取与item等价的代表元素
67
+
68
+ :param item: 要获取等价元素的元素
69
+ :returns: 返回与item等价的代表元素
70
+ """
71
+ return self.engine.get_represent_elem(input_item)
72
+
73
+ @overload
74
+ def query_equivalence(self, facts: Assertion) -> bool: ...
75
+
76
+ @overload
77
+ def query_equivalence(self, facts: Sequence[Assertion]) -> list[bool]: ...
78
+
79
+ def query_equivalence(
80
+ self,
81
+ facts: Sequence[Assertion] | Assertion,
82
+ ) -> bool | list[bool]:
83
+ """
84
+ 查询某个Assertion是否成立,即检查左右式是否匹配。
85
+
86
+ :param facts: 传入单个事实或者一组事实
87
+ :returns: 为每一个Assertion查询返回一个bool,对单个事实返回一个bool,对多个事实返回list[bool]
88
+
89
+ risk: 不确定设计是否合适,毕竟如果用并查集实现的话,本身也很难支持a=?的查询(先不考虑耗费O(n)时间能查询)
90
+ risk: 需要考虑是否区分unknown和false,此刻的方案不区分。
91
+ """
92
+ if isinstance(facts, Assertion):
93
+ return self._query_equivalence(facts)
94
+ result_list: list[bool] = [] # 这是用于储存匹配结果的,每个元素是一个bool,代表一个匹配结果
95
+ for assert_item in facts:
96
+ if self._query_equivalence(assert_item): # 调用函数执行查询,成功则加入True,失败则加入False
97
+ result_list.append(True)
98
+ else:
99
+ result_list.append(False)
100
+ return result_list
101
+
102
+ def clear(self) -> None:
103
+ """清空等价类"""
104
+ self._id_counter = 0
105
+ self.engine.clear()
106
+
107
+ def _update_by_facts(self, facts: FACT_TYPE | None) -> None:
108
+ """
109
+ 用于新事实对等价类模块的更新,一般出现在初始化KB、引擎
110
+
111
+ :param facts: 断言内的等号指示了等价关系。注意到Formula中,仅有and是可以直接拆分更新等价类的、or无法确定等价关系、not会删除等价类(暂不允许)、
112
+ imply先不管、equivalent也可以不管、forall现在的模式难以支持、exists无法确定等价关系
113
+ :returns: None
114
+ """
115
+ if isinstance(facts, Assertion) and self._fact_validator(facts):
116
+ if TYPE_CHECKING:
117
+ # Assertion中不可能含有Variable
118
+ facts.lhs = cast("CompoundTerm | Constant", facts.lhs)
119
+ facts.rhs = cast("CompoundTerm | Constant", facts.rhs)
120
+ self.engine.add_to_equiv(facts.lhs, facts.rhs)
121
+ elif isinstance(facts, Formula):
122
+ if facts.connective == 'AND':
123
+ self._update_by_facts(facts.formula_left)
124
+ self._update_by_facts(facts.formula_right)
125
+ else:
126
+ warnings.warn(f"Connective '{facts.connective}' cannot update equivalence classes.", stacklevel=2)
127
+ else:
128
+ warnings.warn(
129
+ f"Invalid fact type: {facts} has type {type(facts)} and cannot update equivalence classes.",
130
+ stacklevel=1,
131
+ )
132
+
133
+ def _query_equivalence(
134
+ self,
135
+ fact: Assertion,
136
+ ) -> bool:
137
+ if TYPE_CHECKING:
138
+ # Assertion中不可能含有Variable
139
+ fact.lhs = cast("CompoundTerm | Constant", fact.lhs)
140
+ fact.rhs = cast("CompoundTerm | Constant", fact.rhs)
141
+ return self.engine.query_equivalence(fact.lhs, fact.rhs)
@@ -0,0 +1,4 @@
1
+ """进行规则前件正确性的判断和执行"""
2
+ from .executing import Executor
3
+
4
+ __all__ = ['Executor']
@@ -0,0 +1,139 @@
1
+ import logging
2
+ from collections.abc import Sequence, Mapping
3
+
4
+ from kele.config import RunControlConfig
5
+ from kele.control import InferencePath
6
+ from kele.control.status import MainLoopManager, QuerySolutionManager
7
+ from kele.equality import Equivalence
8
+ from kele.knowledge_bases import FactBase
9
+ from kele.syntax import Question, FACT_TYPE, SankuManagementSystem, Variable, Constant, CompoundTerm
10
+ from kele.syntax import _QuestionRule
11
+ from kele.grounder import GroundedRule
12
+ from kele.control import InferenceStatus, create_executor_manager
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class Executor:
17
+ """执行器,负责对 grounded rules 执行 check 并更新事实库。"""
18
+ def __init__(self, # noqa: PLR0913
19
+ equivalence: Equivalence,
20
+ sk_system_handler: SankuManagementSystem,
21
+ fact_base: FactBase,
22
+ *,
23
+ main_loop_manager: MainLoopManager | None = None, # 仅用于更新主循环控制器。如在测试executor功能时可以为空
24
+ solution_manager: QuerySolutionManager,
25
+ inference_path: InferencePath | None = None, # 如在测试executor功能时可以为空
26
+ select_num: int = 5,
27
+ max_steps: int = 1000
28
+ ):
29
+ """:param select_num: 每轮最多执行的 grounded rules 数量,-1 表示不限制。"""
30
+ self.grounded_rules: Sequence[GroundedRule]
31
+ self.select_num = int(1e9) if select_num == -1 else select_num
32
+ # TODO: 此时的select num是从abstract rule层面进行选择的,但理想情况下能否进一步,对每个abstract rule选择其候选值。
33
+ # 不过也要考虑到的是,这里的选择和grounder结束时的选择是接近重复的
34
+ self.equivalence = equivalence
35
+ self.sk_system_handler = sk_system_handler
36
+
37
+ self.fact_base = fact_base # 仅用于更新全局事实,不用于推理
38
+
39
+ self.executor_manager = create_executor_manager(
40
+ equivalence, sk_system_handler,
41
+ solution_manager=solution_manager,
42
+ max_steps=max_steps
43
+ )
44
+
45
+ self.main_loop_manager = main_loop_manager
46
+
47
+ self.inference_path = inference_path if inference_path is not None else InferencePath(args=RunControlConfig(), equivalence=self.equivalence)
48
+ # FIXME: 只是为了本次PR改动不要太大的妥协,正常是executor要传一个args参的。另外这个参数None仅用于测试需求
49
+
50
+ def get_equivalence(self) -> Equivalence:
51
+ """获取等价关系处理器"""
52
+ return self.equivalence
53
+
54
+ def _sort_grounded_rules(self, question: Question) -> None:
55
+ """
56
+ 将 grounded rules 按优先级排序,使更有价值的规则先被执行。
57
+ """
58
+ self.grounded_rules = self.grounded_rules # TODO: 这里是要优化为更优策略的
59
+
60
+ def execute(self, grounded_rules: Sequence[GroundedRule], question: Question) -> InferenceStatus:
61
+ """
62
+ 执行 grounded rules 的 check 阶段,并更新事实库。
63
+
64
+ 会在每条规则执行后更新主循环状态,并在满足终止条件时返回。
65
+ """
66
+ logger.info("Starting execution for %s", question.description)
67
+
68
+ self.grounded_rules = grounded_rules
69
+ self._sort_grounded_rules(question)
70
+
71
+ try:
72
+ for i in range(min(self.select_num, len(self.grounded_rules))):
73
+ grounding_result = grounded_rules[i].check_grounding()
74
+
75
+ logger.info(
76
+ "Generate %s%i%s grounded rules from %s%s%s",
77
+ "\033[91m", len(grounding_result), "\033[0m", # \033[91m红色,\033[0m黑色
78
+ "\033[96m", grounded_rules[i].rule, "\033[0m" # \033[96m青绿色
79
+ )
80
+
81
+ if logger.isEnabledFor(logging.DEBUG):
82
+ logger.debug(
83
+ "all grounded rule text (unique rows: %s): %s",
84
+ grounded_rules[i].total_table_unique_height(),
85
+ grounded_rules[i].print_all_grounded_rules(),
86
+ )
87
+
88
+ added_facts = self._update_facts(grounding_result)
89
+ logger.info(
90
+ "%s%i%s new facts are derived from Rule %s%s%s",
91
+ "\033[91m", len(added_facts), "\033[0m", # \033[91m红色,\033[0m黑色
92
+ "\033[96m", grounded_rules[i].rule, "\033[0m" # \033[96m青绿色
93
+ )
94
+
95
+ if logger.isEnabledFor(logging.DEBUG):
96
+ logger.debug("new facts: %s", [str(f) for f in added_facts])
97
+
98
+ if self.main_loop_manager and not isinstance(grounded_rules[i].rule, _QuestionRule):
99
+ self.main_loop_manager.update_normal_rule_activation(new_facts=added_facts, used_rule=grounded_rules[i].rule)
100
+
101
+ solutions: list[Mapping[Variable, Constant | CompoundTerm]] = []
102
+ question_rule: _QuestionRule | None = None
103
+
104
+ if isinstance(grounded_rules[i].rule, _QuestionRule):
105
+ solutions, question_rule = grounded_rules[i].get_question_solutions()
106
+
107
+ # 检查执行器状态
108
+ status = self.executor_manager.check_status(
109
+ new_facts=added_facts,
110
+ question=question,
111
+ solutions=solutions,
112
+ question_rule=question_rule
113
+ )
114
+ logger.info("Step %d status: %s", self.executor_manager.step_num, status.log_message())
115
+ if not isinstance(grounded_rules[i].rule, _QuestionRule):
116
+ self.executor_manager.next_step()
117
+
118
+ if status.is_terminal_for_executor():
119
+ return status
120
+
121
+ except SystemExit:
122
+ logger.exception("Execution interrupted by SystemExit")
123
+ return InferenceStatus.EXTERNALLY_INTERRUPTED
124
+
125
+ return InferenceStatus.NO_MORE_RULES
126
+
127
+ def _update_facts(self, new_facts: list[FACT_TYPE]) -> list[FACT_TYPE]:
128
+ """
129
+ 更新事实库
130
+ :param new_facts : 这一轮实例化的结果
131
+ """
132
+ added_facts = self.fact_base.add_facts(facts=new_facts) # 更新事实库后就不需要单独更新等价类了
133
+ self.sk_system_handler.update_facts(new_facts)
134
+
135
+ return added_facts
136
+
137
+ def reset(self) -> None:
138
+ """当面向新问题推理时,对当前类进行reset"""
139
+ self.executor_manager.reset_for_new_inference()
@@ -0,0 +1,83 @@
1
+ # term-level grounding过程
2
+ 在grounder文件夹中,我们实现了term-level的实例化过程。
3
+ ## 各文件介绍
4
+
5
+ ```text
6
+ ├─ grouding.py: # 整个结构的对外接口,通过实例化其中的Grounder类,并调用grounding_process方法,可以启动grounding过程
7
+
8
+ ├─ grouded_rule_ds:
9
+ │ │
10
+ │ ├─ grounded_class.py: # 文件中储存了GroundedRule类和GroundedRuleDs类,其中GroundedRule是我们进行grounding的基本单位,承担了unify过程和execute过程的方法
11
+ │ │
12
+ │ ├─ rule_check.py: # 文件中有RuleCheckGraph类,这个类承担了构建图的方法
13
+
14
+ ├─ _grounded_ds_utils.py:# 包含将Term转化为FlatTerm的方法
15
+
16
+ └─ _nodes: # 文件夹中储存了构建图的节点
17
+ ├─_assertion.py: # 文件夹中储存了AssertionNode类
18
+ ├─_conn.py: # 文件夹中储存了ConnectiveNode类
19
+ ├─_op.py: # 文件夹中储存了OperatorNode类
20
+ ├─_root.py: # 文件夹中储存了RootNode类
21
+ ├─_rule.py: # 文件夹中储存了RuleNode类
22
+ ├─_term.py: # 文件夹中储存了TermNode类
23
+ ├─_tftable.py: # 储存用于传递index的结构
24
+ ├─_tupletable.py: # 储存用于记录Variable取值的结构
25
+ ```
26
+
27
+ ## Node节点介绍
28
+
29
+ 对于任意一个节点,它大致有如下的函数:
30
+ 1. add_child:自底向上的过程是张图或者树,所以需要连边;
31
+ 2. exec:每个节点有自己要执行的任务,比如Term要进行unify过程,比如Assertion要进行合并两个Term的变量替换候选值等。目前的名字是exec_*的格式;
32
+ 3. pass:每个节点要把exec后的信息传递给子节点或某个公共地址,目前的名字是pass_*的格式。
33
+ 4. _join: exec的一部分,用于合并两组变量替换。例如P(x) = Q(x)这个Assertion,P(x)可能匹配到的是x =1,2,3、Q(x)匹配到的是x = 2,3,那最终只能保留2, 3。如果规则是P(x) = Q(y),那就要从x=1,2,3和y=2,3合并为(1,2), (1,3), (2, 2)......
34
+
35
+ ## grounding流程介绍
36
+ grounding主要分为四个流程。
37
+ ### 图的构建
38
+ 首先,给定一个rule,我们会将其转化为一个图,用一个节点来表示一个term(FlatCompundTermNode),一个Assertion(AssertionNode)或者一个逻辑连接词(ConnectiveNode)
39
+
40
+ 具体地,构建图的流程如下:
41
+ 1. 将输入的规则body部分(常常是一个Formula)拆解为一系列的term,term对应的assertion,以及连接assertion的connective。
42
+ 2. 将term拆解为**FlatCompoundTerm**,FlatCompoundTerm是这样的term:它的arguments列表里面没有其他term。换句话说,FlatCompoundTerm是**最简单的Term**,不存在复合结构。同时,对于一些本身有复合结构的term,我们**用标记符$F来代替复合结构**,使得它成为FlatCompoundTerm,从而可以按照FlatCompoundTerm来处理,用*FlatCompoundTermNode*来记录这些FlatCompoundTerm
43
+ 3. FlatCompoundTermNode存在**其中一个是另外一个的子部分**的情况,这种时候,我们会**用一条边**来表示这种结构,这样就记录下了term的复合结构,在代码中,对于每个FlatCompoundTermNode,我们用一个列表记录它的所有子节点。对于最末尾的FlatCompoundTermNode,它会被连接到AssertionNode。
44
+ 4. 在存在connective的情况下,我们通过将AssertionNode连接到**ConnectiveNode**来记录这个结构
45
+ 5. 在图结构的末尾,我们连接**RuleNode**,用以表示匹配的终点
46
+
47
+ ### unify过程
48
+
49
+ 接下来,我们需要基于给定的Facts,确定Term中的Variable的可能取值。下面是详细的流程:
50
+ 1. 每个FlatCompoundTermNode保有一个**freevar_table**表格,用于记录它的variables的可能取值列表
51
+ 2. 我们类似前面的操作,将事实中出现的term拆解为FlatCompoundTerm(**即复合的term在标记后变成FlatCompoundTerm**),并且将这些FlatCompoundTerm基于OperatorNode的匹配,传入同一个Operator的FlatCompoundTermNode中。
52
+ 3. 这些FlatCompoundTerm会作为FlatCompoundTermNode的取值,如果满足下面三个条件
53
+ 1. Node对应位置为Variable,此时FlatCompoundTerm在相应位置的取值没有限制
54
+ 2. Node对应位置为$F,此时FlatCompoundTerm在相应位置的取值没有限制(Node也不会记录这个取值)
55
+ 3. Node对应位置为Constant,此时FlatCompoundTerm在相应位置的取值必须与FlatCompoundTermNode的取值相同
56
+ 4. 将上面符合条件的FlatCompoundTerm记录在freevar_table表格中,记录方式是记录Node中所有Variable在符合条件的FlatCompoundTerm中的取值。注意,这里的Variable**不包含**复合结构中的Variable(**即$F占位符代替的Term中Variable的取值不会被记录**)
57
+
58
+ ### pass与join过程
59
+
60
+ 上面的unify过程已使得每个Node记录了它自己的freevar_table表格,但是我们期望得到的是一个在这个规则层面的全局freevar_table表格,用于记录所有Node中的Variable的可能取值,并基于这个总表进行后续的检查
61
+
62
+ 于是我们有pass与join过程:
63
+
64
+ 1. 从根节点开始,每个节点将自己的freevar_table和其父节点传递来的freevar_table,一起传递给自己的子节点,由子节点将他们记录下来
65
+ 2. 上述过程在AssertionNode终止,接着单个AssertionNode合并得到自身的freevar_table,接着groundedrule将进一步计算所有AssertionNode的freevar_table的合并
66
+
67
+ 此过程主要的目的是**去除绑定不一致的结果**,即我们要求在此Rule中同一个Variable的取值必须是一致的(这个要求的合理性基于:Rule通过DNF转化和拆解后已经不再有OR结构)
68
+
69
+ ### check_grounding过程
70
+
71
+ 接下来变量的取值已经记录在AssertionNode中了,我们已经可以开始检查,并将检查结果向下传递到RuleNode了。
72
+
73
+ 具体地有以下步骤
74
+ 1. AssertionNode获取总freevar_table中的一部分(即涉及到当前AssertionNode使用的Variable的列)
75
+ 2. AssertionNode将它需要处理的Assertion中的Variable替换为Constant,然后对替换后的Assertion查询是否成立
76
+ 3. 将1中得到的table拆成TrueTable和FalseTable两部分,记录在TfTable结构中,并向下传递
77
+ 4. 接着将TfTables传递,每个ConnectiveNode需要依据自身的逻辑连接词(只处理AND, NOT两种,OR在DNF转化和规则拆解之后除去了)得到新的TfTable,
78
+
79
+ i. AND的情况下union两侧的TrueTable得到新的TrueTable,其他的组合(TF,FT,FF)两两union得到FalseTable,并继续向下传递
80
+
81
+ ii. NOT的情况下交换TrueTable和FalseTable,并继续向下传递
82
+
83
+ 5. 将最后的结果传递给RuleNode,RuleNode基于TfTable中的TrueTable来生成新的事实
@@ -0,0 +1,17 @@
1
+ """
2
+ 这是将规则转化为图的实现,之后基于得到的图,将在图上进行游走从而实现规则匹配
3
+ """
4
+ # 导入 grounding.py 中的grounder
5
+ from .grounding import Grounder
6
+
7
+ # 导入 grounded_class.py 中的推理过程结构
8
+ from .grounded_rule_ds import (
9
+ GroundedRule,
10
+ GroundedRuleDS,
11
+ GroundedProcess
12
+ )
13
+
14
+ __all__ = [
15
+ # grounded_rule_ds
16
+ "GroundedProcess", "GroundedRule", "GroundedRuleDS", "Grounder"
17
+ ]
@@ -0,0 +1,6 @@
1
+ """和grounding过程相关的一些类"""
2
+ from .grounded_class import GroundedRule, GroundedRuleDS, GroundedProcess
3
+ from .rule_check import RuleCheckGraph
4
+ from .grounded_ds_utils import flatten_arguments, unify_all_terms
5
+
6
+ __all__ = ['GroundedProcess', 'GroundedRule', 'GroundedRuleDS', 'RuleCheckGraph', 'flatten_arguments', 'unify_all_terms']
@@ -0,0 +1,24 @@
1
+ from ._op import _OperatorNode
2
+ from ._term import _BuildTerm, _FlatCompoundTermNode, _VariableNode, _TermNode, _ConstantNode
3
+ from ._assertion import _AssertionNode
4
+ from ._conn import _ConnectiveNode
5
+ from ._rule import _RuleNode, _QuestionRuleNode
6
+ from ._root import _RootNode
7
+ from ._tupletable import _TupleTable
8
+ from ._tftable import TfTables
9
+
10
+ __all__ = [
11
+ 'TfTables',
12
+ '_AssertionNode',
13
+ '_BuildTerm',
14
+ '_ConnectiveNode',
15
+ '_ConstantNode',
16
+ '_FlatCompoundTermNode',
17
+ '_OperatorNode',
18
+ '_QuestionRuleNode',
19
+ '_RootNode',
20
+ '_RuleNode',
21
+ '_TermNode',
22
+ '_TupleTable',
23
+ '_VariableNode',
24
+ ]