ripple-down-rules 0.0.12__tar.gz → 0.0.13__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 (28) hide show
  1. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/PKG-INFO +1 -1
  2. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/pyproject.toml +1 -1
  3. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/rdr.py +18 -12
  4. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/rules.py +11 -4
  5. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules.egg-info/PKG-INFO +1 -1
  6. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/test/test_json_serialization.py +11 -14
  7. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/test/test_rdr.py +5 -24
  8. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/LICENSE +0 -0
  9. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/README.md +0 -0
  10. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/setup.cfg +0 -0
  11. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/__init__.py +0 -0
  12. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/datasets.py +0 -0
  13. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/datastructures/__init__.py +0 -0
  14. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/datastructures/callable_expression.py +0 -0
  15. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/datastructures/case.py +0 -0
  16. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/datastructures/dataclasses.py +0 -0
  17. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/datastructures/enums.py +0 -0
  18. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/experts.py +0 -0
  19. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/failures.py +0 -0
  20. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/prompt.py +0 -0
  21. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules/utils.py +0 -0
  22. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules.egg-info/SOURCES.txt +0 -0
  23. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules.egg-info/dependency_links.txt +0 -0
  24. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/src/ripple_down_rules.egg-info/top_level.txt +0 -0
  25. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/test/test_rdr_alchemy.py +0 -0
  26. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/test/test_relational_rdr.py +0 -0
  27. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/test/test_relational_rdr_alchemy.py +0 -0
  28. {ripple_down_rules-0.0.12 → ripple_down_rules-0.0.13}/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.0.12
3
+ Version: 0.0.13
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.0.12"
9
+ version = "0.0.13"
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" }]
@@ -17,7 +17,7 @@ from .utils import draw_tree, make_set, get_attribute_by_type, copy_case, \
17
17
  get_hint_for_attribute, SubclassJSONSerializer, is_iterable, make_list
18
18
 
19
19
 
20
- class RippleDownRules(ABC):
20
+ class RippleDownRules(SubclassJSONSerializer, ABC):
21
21
  """
22
22
  The abstract base class for the ripple down rules classifiers.
23
23
  """
@@ -175,10 +175,7 @@ class RippleDownRules(ABC):
175
175
  return conclusion_type in case
176
176
 
177
177
 
178
- RDR = RippleDownRules
179
-
180
-
181
- class RDRWithCodeWriter(RDR, ABC):
178
+ class RDRWithCodeWriter(RippleDownRules, ABC):
182
179
 
183
180
  @abstractmethod
184
181
  def write_rules_as_source_code_to_file(self, rule: Rule, file, parent_indent: str = ""):
@@ -260,7 +257,7 @@ class RDRWithCodeWriter(RDR, ABC):
260
257
  return type(self.start_rule.conclusion)
261
258
 
262
259
 
263
- class SingleClassRDR(RDRWithCodeWriter, SubclassJSONSerializer):
260
+ class SingleClassRDR(RDRWithCodeWriter):
264
261
 
265
262
  def fit_case(self, case_query: CaseQuery, expert: Optional[Expert] = None, **kwargs) \
266
263
  -> Union[CaseAttribute, CallableExpression]:
@@ -353,17 +350,15 @@ class MultiClassRDR(RDRWithCodeWriter):
353
350
  The conditions of the stopping rule if needed.
354
351
  """
355
352
 
356
- def __init__(self, start_rules: Optional[List[Rule]] = None,
353
+ def __init__(self, start_rule: Optional[Rule] = None,
357
354
  mode: MCRDRMode = MCRDRMode.StopOnly, session: Optional[Session] = None):
358
355
  """
359
- :param start_rules: The starting rules for the classifier, these are the rules that are at the top of the tree
360
- and are always checked, in contrast to the refinement and alternative rules which are only checked if the
361
- starting rules fire or not.
356
+ :param start_rule: The starting rules for the classifier.
362
357
  :param mode: The mode of the classifier, either StopOnly or StopPlusRule, or StopPlusRuleCombined.
363
358
  :param session: The sqlalchemy orm session.
364
359
  """
365
- self.start_rules = [MultiClassTopRule()] if not start_rules else start_rules
366
- super(MultiClassRDR, self).__init__(self.start_rules[0], session=session)
360
+ start_rule = MultiClassTopRule() if not start_rule else start_rule
361
+ super(MultiClassRDR, self).__init__(start_rule, session=session)
367
362
  self.mode: MCRDRMode = mode
368
363
 
369
364
  def classify(self, case: Union[Case, SQLTable]) -> List[Any]:
@@ -614,6 +609,17 @@ class MultiClassRDR(RDRWithCodeWriter):
614
609
  """
615
610
  self.start_rule.alternative = MultiClassTopRule(conditions, conclusion, corner_case=corner_case)
616
611
 
612
+ def _to_json(self) -> Dict[str, Any]:
613
+ return {"start_rule": self.start_rule.to_json()}
614
+
615
+ @classmethod
616
+ def _from_json(cls, data: Dict[str, Any]) -> Self:
617
+ """
618
+ Create an instance of the class from a json
619
+ """
620
+ start_rule = SingleClassRule.from_json(data["start_rule"])
621
+ return cls(start_rule)
622
+
617
623
 
618
624
  class GeneralRDR(RippleDownRules):
619
625
  """
@@ -265,14 +265,17 @@ class MultiClassStopRule(Rule, HasAlternativeRule):
265
265
 
266
266
  def _to_json(self) -> Dict[str, Any]:
267
267
  self.json_serialization = {**Rule._to_json(self),
268
- "top_rule": self.top_rule.to_json(),
269
268
  "alternative": self.alternative.to_json() if self.alternative is not None else None}
270
269
  return self.json_serialization
271
270
 
272
271
  @classmethod
273
272
  def _from_json(cls, data: Dict[str, Any]) -> MultiClassStopRule:
274
- loaded_rule = Rule._from_json(data)
275
- loaded_rule.top_rule = MultiClassTopRule.from_json(data["top_rule"])
273
+ loaded_rule = super(MultiClassStopRule, cls)._from_json(data)
274
+ # The following is done to prevent re-initialization of the top rule,
275
+ # so the top rule that is already initialized is passed in the data instead of its json serialization.
276
+ loaded_rule.top_rule = data['top_rule']
277
+ if data['alternative'] is not None:
278
+ data['alternative']['top_rule'] = data['top_rule']
276
279
  loaded_rule.alternative = MultiClassStopRule.from_json(data["alternative"])
277
280
  return loaded_rule
278
281
 
@@ -312,7 +315,11 @@ class MultiClassTopRule(Rule, HasRefinementRule, HasAlternativeRule):
312
315
 
313
316
  @classmethod
314
317
  def _from_json(cls, data: Dict[str, Any]) -> MultiClassTopRule:
315
- loaded_rule = Rule._from_json(data)
318
+ loaded_rule = super(MultiClassTopRule, cls)._from_json(data)
319
+ # The following is done to prevent re-initialization of the top rule,
320
+ # so the top rule that is already initialized is passed in the data instead of its json serialization.
321
+ if data['refinement'] is not None:
322
+ data['refinement']['top_rule'] = loaded_rule
316
323
  loaded_rule.refinement = MultiClassStopRule.from_json(data["refinement"])
317
324
  loaded_rule.alternative = MultiClassTopRule.from_json(data["alternative"])
318
325
  return loaded_rule
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.0.12
3
+ Version: 0.0.13
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,9 @@ from typing_extensions import List
6
6
  from ripple_down_rules.datasets import load_zoo_dataset
7
7
  from ripple_down_rules.datastructures import CaseQuery, Case
8
8
  from ripple_down_rules.experts import Human
9
- from ripple_down_rules.rdr import SingleClassRDR
9
+ from ripple_down_rules.rdr import SingleClassRDR, MultiClassRDR
10
+ from ripple_down_rules.utils import make_set
11
+ from test_helpers.helpers import get_fit_mcrdr, get_fit_scrdr
10
12
 
11
13
 
12
14
  class TestJSONSerialization(TestCase):
@@ -20,7 +22,7 @@ class TestJSONSerialization(TestCase):
20
22
  cls.all_cases, cls.targets = load_zoo_dataset(cls.cache_dir + "/zoo_dataset.pkl")
21
23
 
22
24
  def test_scrdr_json_serialization(self):
23
- scrdr = self.get_fit_scrdr()
25
+ scrdr = get_fit_scrdr(self.all_cases, self.targets)
24
26
  filename = f"{self.cache_dir}/scrdr.json"
25
27
  scrdr.save(filename)
26
28
  scrdr = SingleClassRDR.load(filename)
@@ -28,16 +30,11 @@ class TestJSONSerialization(TestCase):
28
30
  cat = scrdr.classify(case)
29
31
  self.assertEqual(cat, target)
30
32
 
31
- def get_fit_scrdr(self, draw_tree=False) -> SingleClassRDR:
32
- filename = self.expert_answers_dir + "/scrdr_expert_answers_fit"
33
- expert = Human(use_loaded_answers=True)
34
- expert.load_answers(filename)
35
-
36
- scrdr = SingleClassRDR()
37
- case_queries = [CaseQuery(case, target=target) for case, target in zip(self.all_cases, self.targets)]
38
- scrdr.fit(case_queries, expert=expert,
39
- animate_tree=draw_tree)
33
+ def test_mcrdr_json_serialization(self):
34
+ mcrdr = get_fit_mcrdr(self.all_cases, self.targets)
35
+ filename = f"{self.cache_dir}/mcrdr.json"
36
+ mcrdr.save(filename)
37
+ mcrdr = MultiClassRDR.load(filename)
40
38
  for case, target in zip(self.all_cases, self.targets):
41
- cat = scrdr.classify(case)
42
- self.assertEqual(cat, target)
43
- return scrdr
39
+ cat = mcrdr.classify(case)
40
+ self.assertEqual(make_set(cat), make_set(target))
@@ -11,6 +11,7 @@ from ripple_down_rules.datastructures import Case, MCRDRMode, \
11
11
  from ripple_down_rules.experts import Human
12
12
  from ripple_down_rules.rdr import SingleClassRDR, MultiClassRDR, GeneralRDR
13
13
  from ripple_down_rules.utils import render_tree, get_all_subclasses, make_set
14
+ from test_helpers.helpers import get_fit_scrdr, get_fit_mcrdr
14
15
 
15
16
 
16
17
  class TestRDR(TestCase):
@@ -71,7 +72,7 @@ class TestRDR(TestCase):
71
72
  expert.save_answers(file)
72
73
 
73
74
  def test_write_scrdr_to_python_file(self):
74
- scrdr = self.get_fit_scrdr()
75
+ scrdr = get_fit_scrdr(self.all_cases,self.targets)
75
76
  scrdr.write_to_python_file(self.generated_rdrs_dir)
76
77
  classify_species_scrdr = scrdr.get_rdr_classifier_from_python_file(self.generated_rdrs_dir)
77
78
  for case, target in zip(self.all_cases, self.targets):
@@ -79,7 +80,7 @@ class TestRDR(TestCase):
79
80
  self.assertEqual(cat, target)
80
81
 
81
82
  def test_write_mcrdr_to_python_file(self):
82
- mcrdr = self.get_fit_mcrdr()
83
+ mcrdr = get_fit_mcrdr(self.all_cases, self.targets)
83
84
  mcrdr.write_to_python_file(self.generated_rdrs_dir)
84
85
  classify_species_mcrdr = mcrdr.get_rdr_classifier_from_python_file(self.generated_rdrs_dir)
85
86
  for case, target in zip(self.all_cases, self.targets):
@@ -258,7 +259,7 @@ class TestRDR(TestCase):
258
259
  if use_loaded_answers:
259
260
  expert.load_answers(filename)
260
261
 
261
- fit_scrdr = self.get_fit_scrdr(draw_tree=False)
262
+ fit_scrdr = get_fit_scrdr(self.all_cases, self.targets, draw_tree=False)
262
263
 
263
264
  grdr = GeneralRDR({type(fit_scrdr.start_rule.conclusion): fit_scrdr})
264
265
 
@@ -309,7 +310,7 @@ class TestRDR(TestCase):
309
310
  if use_loaded_answers:
310
311
  expert.load_answers(filename)
311
312
 
312
- fit_scrdr = self.get_fit_scrdr(draw_tree=False)
313
+ fit_scrdr = get_fit_scrdr(self.all_cases, self.targets, draw_tree=False)
313
314
 
314
315
  grdr = GeneralRDR({type(fit_scrdr.start_rule.conclusion): fit_scrdr})
315
316
 
@@ -326,23 +327,3 @@ class TestRDR(TestCase):
326
327
  cwd = os.getcwd()
327
328
  file = os.path.join(cwd, filename)
328
329
  expert.save_answers(file)
329
-
330
- def get_fit_scrdr(self, draw_tree=False) -> SingleClassRDR:
331
- filename = self.expert_answers_dir + "/scrdr_expert_answers_fit"
332
- expert = Human(use_loaded_answers=True)
333
- expert.load_answers(filename)
334
-
335
- scrdr = SingleClassRDR()
336
- case_queries = [CaseQuery(case, target=target) for case, target in zip(self.all_cases, self.targets)]
337
- scrdr.fit(case_queries, expert=expert,
338
- animate_tree=draw_tree)
339
- return scrdr
340
-
341
- def get_fit_mcrdr(self, draw_tree: bool = False):
342
- filename = self.expert_answers_dir + "/mcrdr_expert_answers_stop_only_fit"
343
- expert = Human(use_loaded_answers=True)
344
- expert.load_answers(filename)
345
- mcrdr = MultiClassRDR()
346
- case_queries = [CaseQuery(case, target=target) for case, target in zip(self.all_cases, self.targets)]
347
- mcrdr.fit(case_queries, expert=expert, animate_tree=draw_tree)
348
- return mcrdr