ripple-down-rules 0.1.64__tar.gz → 0.1.66__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.
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/PKG-INFO +1 -1
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/pyproject.toml +1 -1
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/dataclasses.py +3 -3
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/experts.py +11 -110
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/rdr.py +141 -239
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/rules.py +27 -25
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/utils.py +48 -5
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules.egg-info/PKG-INFO +1 -1
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_rdr.py +8 -23
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_rdr_world.py +39 -33
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/LICENSE +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/README.md +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/setup.cfg +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/__init__.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datasets.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/__init__.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/callable_expression.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/case.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/enums.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/failures.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/helpers.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/prompt.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/rdr_decorators.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules.egg-info/SOURCES.txt +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules.egg-info/dependency_links.txt +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules.egg-info/top_level.txt +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_json_serialization.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_on_mutagenic.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_rdr_alchemy.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_relational_rdr.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_relational_rdr_alchemy.py +0 -0
- {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_sql_model.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ripple_down_rules
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.66
|
4
4
|
Summary: Implements the various versions of Ripple Down Rules (RDR) for knowledge representation and reasoning.
|
5
5
|
Author-email: Abdelrhman Bassiouny <abassiou@uni-bremen.de>
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
6
6
|
|
7
7
|
[project]
|
8
8
|
name = "ripple_down_rules"
|
9
|
-
version = "0.1.
|
9
|
+
version = "0.1.66"
|
10
10
|
description = "Implements the various versions of Ripple Down Rules (RDR) for knowledge representation and reasoning."
|
11
11
|
readme = "README.md"
|
12
12
|
authors = [{ name = "Abdelrhman Bassiouny", email = "abassiou@uni-bremen.de" }]
|
@@ -133,7 +133,7 @@ class CaseQuery:
|
|
133
133
|
if value is not None and not isinstance(value, (CallableExpression, str)):
|
134
134
|
raise ValueError("The target must be a CallableExpression or a string.")
|
135
135
|
self._target = value
|
136
|
-
self.
|
136
|
+
self.update_target_value()
|
137
137
|
|
138
138
|
@property
|
139
139
|
def target_value(self) -> Any:
|
@@ -141,10 +141,10 @@ class CaseQuery:
|
|
141
141
|
:return: The target value of the case query.
|
142
142
|
"""
|
143
143
|
if self._target_value is None:
|
144
|
-
self.
|
144
|
+
self.update_target_value()
|
145
145
|
return self._target_value
|
146
146
|
|
147
|
-
def
|
147
|
+
def update_target_value(self):
|
148
148
|
"""
|
149
149
|
Update the target value of the case query.
|
150
150
|
"""
|
@@ -32,10 +32,11 @@ class Expert(ABC):
|
|
32
32
|
"""
|
33
33
|
A flag to indicate if the expert should use loaded answers or not.
|
34
34
|
"""
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
|
36
|
+
def __init__(self, use_loaded_answers: bool = False, append: bool = False):
|
37
|
+
self.all_expert_answers = []
|
38
|
+
self.use_loaded_answers = use_loaded_answers
|
39
|
+
self.append = append
|
39
40
|
|
40
41
|
@abstractmethod
|
41
42
|
def ask_for_conditions(self, case_query: CaseQuery, last_evaluated_rule: Optional[Rule] = None) \
|
@@ -51,28 +52,6 @@ class Expert(ABC):
|
|
51
52
|
pass
|
52
53
|
|
53
54
|
@abstractmethod
|
54
|
-
def ask_for_extra_rules(self, case_query: CaseQuery) -> List[Dict[PromptFor, CallableExpression]]:
|
55
|
-
"""
|
56
|
-
Ask the expert to provide extra rules for a case by providing a pair of conclusion and conditions.
|
57
|
-
|
58
|
-
:param case_query: The case query containing the case to classify.
|
59
|
-
:return: The extra rules for the case as a list of dictionaries, where each dictionary contains the
|
60
|
-
conclusion and conditions for the rule.
|
61
|
-
"""
|
62
|
-
pass
|
63
|
-
|
64
|
-
@abstractmethod
|
65
|
-
def ask_if_conclusion_is_correct(self, case_query: CaseQuery, conclusion: Any,
|
66
|
-
current_conclusions: Any) -> bool:
|
67
|
-
"""
|
68
|
-
Ask the expert if the conclusion is correct.
|
69
|
-
|
70
|
-
:param case_query: The case query about which the expert should answer.
|
71
|
-
:param conclusion: The conclusion to check.
|
72
|
-
:param current_conclusions: The current conclusions for the case.
|
73
|
-
"""
|
74
|
-
pass
|
75
|
-
|
76
55
|
def ask_for_conclusion(self, case_query: CaseQuery) -> Optional[CallableExpression]:
|
77
56
|
"""
|
78
57
|
Ask the expert to provide a relational conclusion for the case.
|
@@ -87,18 +66,14 @@ class Human(Expert):
|
|
87
66
|
The Human Expert class, an expert that asks the human to provide differentiating features and conclusions.
|
88
67
|
"""
|
89
68
|
|
90
|
-
def
|
91
|
-
self.all_expert_answers = []
|
92
|
-
self.use_loaded_answers = use_loaded_answers
|
93
|
-
|
94
|
-
def save_answers(self, path: str, append: bool = False):
|
69
|
+
def save_answers(self, path: str):
|
95
70
|
"""
|
96
71
|
Save the expert answers to a file.
|
97
72
|
|
98
73
|
:param path: The path to save the answers to.
|
99
74
|
:param append: A flag to indicate if the answers should be appended to the file or not.
|
100
75
|
"""
|
101
|
-
if append:
|
76
|
+
if self.append:
|
102
77
|
# read the file and append the new answers
|
103
78
|
with open(path + '.json', "r") as f:
|
104
79
|
all_answers = json.load(f)
|
@@ -126,24 +101,6 @@ class Human(Expert):
|
|
126
101
|
last_evaluated_rule=last_evaluated_rule)
|
127
102
|
return self._get_conditions(case_query)
|
128
103
|
|
129
|
-
def ask_for_extra_rules(self, case_query: CaseQuery) -> List[Dict[PromptFor, CallableExpression]]:
|
130
|
-
"""
|
131
|
-
Ask the expert to provide extra rules for a case by providing a pair of conclusion and conditions.
|
132
|
-
|
133
|
-
:param case_query: The case query containing the case to classify.
|
134
|
-
:return: The extra rules for the case as a list of dictionaries, where each dictionary contains the
|
135
|
-
conclusion and conditions for the rule.
|
136
|
-
"""
|
137
|
-
rules = []
|
138
|
-
while True:
|
139
|
-
conclusion = self.ask_for_conclusion(case_query)
|
140
|
-
if conclusion is None:
|
141
|
-
break
|
142
|
-
conditions = self._get_conditions(case_query)
|
143
|
-
rules.append({PromptFor.Conclusion: conclusion,
|
144
|
-
PromptFor.Conditions: conditions})
|
145
|
-
return rules
|
146
|
-
|
147
104
|
def _get_conditions(self, case_query: CaseQuery) \
|
148
105
|
-> CallableExpression:
|
149
106
|
"""
|
@@ -154,6 +111,8 @@ class Human(Expert):
|
|
154
111
|
:return: The differentiating features as new rule conditions.
|
155
112
|
"""
|
156
113
|
user_input = None
|
114
|
+
if self.use_loaded_answers and len(self.all_expert_answers) == 0 and self.append:
|
115
|
+
self.use_loaded_answers = False
|
157
116
|
if self.use_loaded_answers:
|
158
117
|
user_input = self.all_expert_answers.pop(0)
|
159
118
|
if user_input:
|
@@ -173,6 +132,8 @@ class Human(Expert):
|
|
173
132
|
:return: The conclusion for the case as a callable expression.
|
174
133
|
"""
|
175
134
|
expression: Optional[CallableExpression] = None
|
135
|
+
if self.use_loaded_answers and len(self.all_expert_answers) == 0 and self.append:
|
136
|
+
self.use_loaded_answers = False
|
176
137
|
if self.use_loaded_answers:
|
177
138
|
expert_input = self.all_expert_answers.pop(0)
|
178
139
|
if expert_input is not None:
|
@@ -184,63 +145,3 @@ class Human(Expert):
|
|
184
145
|
self.all_expert_answers.append(expert_input)
|
185
146
|
case_query.target = expression
|
186
147
|
return expression
|
187
|
-
|
188
|
-
def get_category_type(self, cat_name: str) -> Optional[Type[CaseAttribute]]:
|
189
|
-
"""
|
190
|
-
Get the category type from the known categories.
|
191
|
-
|
192
|
-
:param cat_name: The name of the category.
|
193
|
-
:return: The category type.
|
194
|
-
"""
|
195
|
-
cat_name = cat_name.lower()
|
196
|
-
self.known_categories = get_all_subclasses(
|
197
|
-
CaseAttribute) if not self.known_categories else self.known_categories
|
198
|
-
self.known_categories.update(CaseAttribute.registry)
|
199
|
-
category_type = None
|
200
|
-
if cat_name in self.known_categories:
|
201
|
-
category_type = self.known_categories[cat_name]
|
202
|
-
return category_type
|
203
|
-
|
204
|
-
def ask_if_category_is_mutually_exclusive(self, category_name: str) -> bool:
|
205
|
-
"""
|
206
|
-
Ask the expert if the new category can have multiple values.
|
207
|
-
|
208
|
-
:param category_name: The name of the category to ask about.
|
209
|
-
"""
|
210
|
-
question = f"Can a case have multiple values of the new category {category_name}? (y/n):"
|
211
|
-
return not self.ask_for_affirmation(question)
|
212
|
-
|
213
|
-
def ask_if_conclusion_is_correct(self, case_query: CaseQuery, conclusion: Any,
|
214
|
-
current_conclusions: Any) -> bool:
|
215
|
-
"""
|
216
|
-
Ask the expert if the conclusion is correct.
|
217
|
-
|
218
|
-
:param case_query: The case query about which the expert should answer.
|
219
|
-
:param conclusion: The conclusion to check.
|
220
|
-
:param current_conclusions: The current conclusions for the case.
|
221
|
-
"""
|
222
|
-
if not self.use_loaded_answers:
|
223
|
-
print(f"Current conclusions: {current_conclusions}")
|
224
|
-
return self.ask_for_affirmation(case_query,
|
225
|
-
f"Is the conclusion {conclusion} correct for the case (True/False):")
|
226
|
-
|
227
|
-
def ask_for_affirmation(self, case_query: CaseQuery, question: str) -> bool:
|
228
|
-
"""
|
229
|
-
Ask the expert a yes or no question.
|
230
|
-
|
231
|
-
:param case_query: The case query about which the expert should answer.
|
232
|
-
:param question: The question to ask the expert.
|
233
|
-
:return: The answer to the question.
|
234
|
-
"""
|
235
|
-
while True:
|
236
|
-
if self.use_loaded_answers:
|
237
|
-
answer = self.all_expert_answers.pop(0)
|
238
|
-
else:
|
239
|
-
_, expression = prompt_user_for_expression(case_query, PromptFor.Affirmation, question)
|
240
|
-
answer = expression(case_query.case)
|
241
|
-
if answer:
|
242
|
-
self.all_expert_answers.append(True)
|
243
|
-
return True
|
244
|
-
else:
|
245
|
-
self.all_expert_answers.append(False)
|
246
|
-
return False
|