ripple-down-rules 0.0.0__tar.gz → 0.0.1__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 (31) hide show
  1. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/PKG-INFO +1 -1
  2. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/pyproject.toml +1 -1
  3. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/datastructures/callable_expression.py +2 -2
  4. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/datastructures/table.py +8 -3
  5. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/rdr.py +9 -7
  6. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/rules.py +4 -0
  7. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/utils.py +19 -1
  8. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules.egg-info/PKG-INFO +1 -1
  9. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/test/test_json_serialization.py +11 -0
  10. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/README.md +0 -0
  11. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/setup.cfg +0 -0
  12. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/__init__.py +0 -0
  13. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/datasets.py +0 -0
  14. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/datastructures/__init__.py +0 -0
  15. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/datastructures/dataclasses.py +0 -0
  16. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/datastructures/enums.py +0 -0
  17. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/datastructures/generated/__init__.py +0 -0
  18. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/datastructures/generated/column/__init__.py +0 -0
  19. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/datastructures/generated/row/__init__.py +0 -0
  20. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/experts.py +0 -0
  21. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/failures.py +0 -0
  22. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules/prompt.py +0 -0
  23. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules.egg-info/SOURCES.txt +0 -0
  24. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules.egg-info/dependency_links.txt +0 -0
  25. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules.egg-info/requires.txt +0 -0
  26. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/src/ripple_down_rules.egg-info/top_level.txt +0 -0
  27. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/test/test_rdr.py +0 -0
  28. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/test/test_rdr_alchemy.py +0 -0
  29. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/test/test_relational_rdr.py +0 -0
  30. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/test/test_relational_rdr_alchemy.py +0 -0
  31. {ripple_down_rules-0.0.0 → ripple_down_rules-0.0.1}/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.0
3
+ Version: 0.0.1
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
  Project-URL: Homepage, https://github.com/AbdelrhmanBassiouny/ripple_down_rules
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "ripple_down_rules"
9
- version = "0.0.0"
9
+ version = "0.0.1"
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" }]
@@ -8,7 +8,7 @@ from sqlalchemy.orm import Session
8
8
  from typing_extensions import Type, Optional, Any, List, Union, Tuple, Dict, Set
9
9
 
10
10
  from .table import create_row, Row
11
- from ..utils import SubclassJSONSerializer, get_full_class_name
11
+ from ..utils import SubclassJSONSerializer, get_full_class_name, get_type_from_string
12
12
 
13
13
 
14
14
  class VariableVisitor(ast.NodeVisitor):
@@ -168,7 +168,7 @@ class CallableExpression(SubclassJSONSerializer):
168
168
 
169
169
  @classmethod
170
170
  def _from_json(cls, data: Dict[str, Any]) -> CallableExpression:
171
- return cls(user_input=data["user_input"], conclusion_type=data["conclusion_type"])
171
+ return cls(user_input=data["user_input"], conclusion_type=get_type_from_string(data["conclusion_type"]))
172
172
 
173
173
 
174
174
  def compile_expression_to_code(expression_tree: AST) -> Any:
@@ -4,6 +4,7 @@ import os
4
4
  import time
5
5
  from abc import ABC
6
6
  from collections import UserDict
7
+ from copy import deepcopy
7
8
  from dataclasses import dataclass
8
9
  from enum import Enum
9
10
 
@@ -77,6 +78,7 @@ class SubClassFactory:
77
78
  parent_class_alias = cls.__name__ + "_"
78
79
  imports = f"from {cls.__module__} import {cls.__name__} as {parent_class_alias}\n"
79
80
  class_code = f"class {name}({parent_class_alias}):\n"
81
+ class_attributes = deepcopy(class_attributes) if class_attributes else {}
80
82
  class_attributes.update({"_value_range": range_})
81
83
  for key, value in class_attributes.items():
82
84
  if value is not None:
@@ -245,12 +247,15 @@ class Row(UserDict, SubClassFactory, SubclassJSONSerializer):
245
247
  return isinstance(instance, (dict, UserDict, Row)) or super().__instancecheck__(instance)
246
248
 
247
249
  def to_json(self) -> Dict[str, Any]:
250
+ serializable = {k: v for k, v in self.items() if not k.startswith("_")}
251
+ serializable["_id"] = self.id
248
252
  return {**SubclassJSONSerializer.to_json(self),
249
- **{k: v.to_json() if isinstance(v, SubclassJSONSerializer) else v for k, v in self.items()}}
253
+ **{k: v.to_json() if isinstance(v, SubclassJSONSerializer) else v for k, v in serializable.items()}}
250
254
 
251
255
  @classmethod
252
256
  def _from_json(cls, data: Dict[str, Any]) -> Row:
253
- return cls(id_=data["id"], **data)
257
+ id_ = data.pop("_id")
258
+ return cls(id_=id_, **data)
254
259
 
255
260
 
256
261
  @dataclass
@@ -377,7 +382,7 @@ class Column(set, SubClassFactory, SubclassJSONSerializer):
377
382
 
378
383
  @classmethod
379
384
  def _from_json(cls, data: Dict[str, Any]) -> Column:
380
- return cls({ColumnValue(int(id_), v) for id_, v in data.items()})
385
+ return cls({ColumnValue.from_json(v) for id_, v in data.items()})
381
386
 
382
387
 
383
388
  def create_rows_from_dataframe(df: DataFrame, name: Optional[str] = None) -> List[Row]:
@@ -111,15 +111,17 @@ class RippleDownRules(ABC):
111
111
  if animate_tree and self.start_rule.size > num_rules:
112
112
  num_rules = self.start_rule.size
113
113
  self.update_figures()
114
- i += 1
115
- all_predicted = targets and all_pred == len(targets)
116
- num_iter_reached = n_iter and i >= n_iter
117
- stop_iterating = all_predicted or num_iter_reached
118
- if stop_iterating:
119
- break
114
+ i += 1
115
+ all_pred = [1 if p == t else 0
116
+ for case, target in zip(cases, targets) for p, t in zip(self.classify(case), target)]
117
+ all_predicted = targets and sum(all_pred) == len(targets)
118
+ num_iter_reached = n_iter and i >= n_iter
119
+ stop_iterating = all_predicted or num_iter_reached
120
+ if stop_iterating:
121
+ break
120
122
  print(f"Recall: {sum(all_recall) / len(all_recall)}")
121
123
  print(f"Precision: {sum(all_precision) / len(all_precision)}")
122
- print(f"Accuracy: {all_pred}/{n_iter}")
124
+ print(f"Accuracy: {all_pred}/{len(targets)}")
123
125
  print(f"Finished training in {i} iterations")
124
126
  if animate_tree:
125
127
  plt.ioff()
@@ -114,6 +114,8 @@ class HasAlternativeRule:
114
114
  Set the alternative rule of the rule. It is important that no rules should be retracted or changed,
115
115
  only new rules should be added.
116
116
  """
117
+ if new_rule is None:
118
+ return
117
119
  if self.furthest_alternative:
118
120
  self.furthest_alternative[-1].alternative = new_rule
119
121
  else:
@@ -139,6 +141,8 @@ class HasRefinementRule:
139
141
  Set the refinement rule of the rule. It is important that no rules should be retracted or changed,
140
142
  only new rules should be added.
141
143
  """
144
+ if new_rule is None:
145
+ return
142
146
  new_rule.top_rule = self
143
147
  if self.refinement:
144
148
  self.refinement.alternative = new_rule
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import importlib
3
4
  import logging
4
5
  from abc import abstractmethod
5
6
  from collections import UserDict
@@ -23,6 +24,17 @@ if TYPE_CHECKING:
23
24
  matplotlib.use("Qt5Agg") # or "Qt5Agg", depending on availability
24
25
 
25
26
 
27
+ def get_type_from_string(type_path: str):
28
+ """
29
+ Get a type from a string describing its path using the format "module_path.ClassName".
30
+
31
+ :param type_path: The path to the type.
32
+ """
33
+ module_path, class_name = type_path.rsplit(".", 1)
34
+ module = importlib.import_module(module_path)
35
+ return getattr(module, class_name)
36
+
37
+
26
38
  def get_full_class_name(cls):
27
39
  """
28
40
  Returns the full name of a class, including the module name.
@@ -75,9 +87,15 @@ class SubclassJSONSerializer:
75
87
  :param data: The json dict
76
88
  :return: The correct instance of the subclass
77
89
  """
90
+ if data is None:
91
+ return None
92
+ if get_full_class_name(cls) == data["_type"]:
93
+ return cls._from_json(data)
78
94
  for subclass in recursive_subclasses(SubclassJSONSerializer):
79
95
  if get_full_class_name(subclass) == data["_type"]:
80
- return subclass._from_json(data)
96
+ subclass_data = deepcopy(data)
97
+ subclass_data.pop("_type")
98
+ return subclass._from_json(subclass_data)
81
99
 
82
100
  raise ValueError("Unknown type {}".format(data["_type"]))
83
101
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.0.0
3
+ Version: 0.0.1
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
  Project-URL: Homepage, https://github.com/AbdelrhmanBassiouny/ripple_down_rules
@@ -26,6 +26,14 @@ class TestJSONSerialization(TestCase):
26
26
  with open(f"{self.cache_dir}/scrdr.json", "w") as f:
27
27
  json.dump(scrdr_json, f, indent=4)
28
28
 
29
+ # load the json from the file
30
+ with open(f"{self.cache_dir}/scrdr.json", "r") as f:
31
+ scrdr_json = json.load(f)
32
+ scrdr = SingleClassRDR.from_json(scrdr_json)
33
+ for case, target in zip(self.all_cases, self.targets):
34
+ cat = scrdr.classify(case)
35
+ self.assertEqual(cat, target)
36
+
29
37
  def get_fit_scrdr(self, draw_tree=False) -> SingleClassRDR:
30
38
  filename = self.expert_answers_dir + "/scrdr_expert_answers_fit"
31
39
  expert = Human(use_loaded_answers=True)
@@ -35,4 +43,7 @@ class TestJSONSerialization(TestCase):
35
43
  case_queries = [CaseQuery(case, target=target) for case, target in zip(self.all_cases, self.targets)]
36
44
  scrdr.fit(case_queries, expert=expert,
37
45
  animate_tree=draw_tree)
46
+ for case, target in zip(self.all_cases, self.targets):
47
+ cat = scrdr.classify(case)
48
+ self.assertEqual(cat, target)
38
49
  return scrdr