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.
Files changed (32) hide show
  1. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/PKG-INFO +1 -1
  2. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/pyproject.toml +1 -1
  3. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/dataclasses.py +3 -3
  4. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/experts.py +11 -110
  5. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/rdr.py +141 -239
  6. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/rules.py +27 -25
  7. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/utils.py +48 -5
  8. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules.egg-info/PKG-INFO +1 -1
  9. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_rdr.py +8 -23
  10. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_rdr_world.py +39 -33
  11. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/LICENSE +0 -0
  12. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/README.md +0 -0
  13. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/setup.cfg +0 -0
  14. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/__init__.py +0 -0
  15. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datasets.py +0 -0
  16. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/__init__.py +0 -0
  17. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/callable_expression.py +0 -0
  18. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/case.py +0 -0
  19. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/datastructures/enums.py +0 -0
  20. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/failures.py +0 -0
  21. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/helpers.py +0 -0
  22. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/prompt.py +0 -0
  23. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules/rdr_decorators.py +0 -0
  24. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules.egg-info/SOURCES.txt +0 -0
  25. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules.egg-info/dependency_links.txt +0 -0
  26. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/src/ripple_down_rules.egg-info/top_level.txt +0 -0
  27. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_json_serialization.py +0 -0
  28. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_on_mutagenic.py +0 -0
  29. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_rdr_alchemy.py +0 -0
  30. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_relational_rdr.py +0 -0
  31. {ripple_down_rules-0.1.64 → ripple_down_rules-0.1.66}/test/test_relational_rdr_alchemy.py +0 -0
  32. {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.64
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.64"
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._update_target_value()
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._update_target_value()
144
+ self.update_target_value()
145
145
  return self._target_value
146
146
 
147
- def _update_target_value(self):
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
- known_categories: Optional[Dict[str, Type[CaseAttribute]]] = None
36
- """
37
- The known categories (i.e. Column types) to use.
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 __init__(self, use_loaded_answers: bool = False):
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