ripple-down-rules 0.5.1__tar.gz → 0.5.3__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 (139) hide show
  1. ripple_down_rules-0.5.3/.github/workflows/build_and_deploy_doc.yml +64 -0
  2. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/PKG-INFO +139 -14
  3. ripple_down_rules-0.5.3/README.md +188 -0
  4. ripple_down_rules-0.5.3/doc/_config.yml +54 -0
  5. ripple_down_rules-0.5.3/doc/_toc.yml +8 -0
  6. ripple_down_rules-0.5.3/doc/bibliography.md +4 -0
  7. ripple_down_rules-0.5.3/doc/intro.md +271 -0
  8. ripple_down_rules-0.5.3/doc/references.bib +18 -0
  9. ripple_down_rules-0.5.3/doc/requirements.txt +6 -0
  10. ripple_down_rules-0.5.3/examples/animal_species.py +50 -0
  11. ripple_down_rules-0.5.3/examples/part_containment_rdr/__init__.py +1 -0
  12. ripple_down_rules-0.5.3/examples/part_containment_rdr/rdr_metadata/part_containment_rdr.json +95 -0
  13. ripple_down_rules-0.5.3/examples/part_containment_rdr/robot_contained_objects_mcrdr.py +20 -0
  14. ripple_down_rules-0.5.3/examples/part_containment_rdr/robot_contained_objects_mcrdr_defs.py +23 -0
  15. ripple_down_rules-0.5.3/examples/part_containment_rdr/robot_rdr.py +15 -0
  16. ripple_down_rules-0.5.3/examples/relational_example.py +48 -0
  17. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/__init__.py +1 -1
  18. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/datastructures/callable_expression.py +2 -1
  19. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/experts.py +11 -44
  20. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/rdr.py +4 -2
  21. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/utils.py +1 -1
  22. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules.egg-info/PKG-INFO +139 -14
  23. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules.egg-info/SOURCES.txt +15 -2
  24. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_results/datasets_physical_object_is_a_robot/rdr_metadata/datasets_physical_object_is_a_robot.json +2 -2
  25. ripple_down_rules-0.5.3/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/__init__.py +1 -0
  26. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/rdr_metadata/datasets_physical_object_select_objects_that_are_parts_of_robot.json +6 -6
  27. ripple_down_rules-0.5.1/README.md +0 -63
  28. ripple_down_rules-0.5.1/examples/readme_example.py +0 -19
  29. ripple_down_rules-0.5.1/src/ripple_down_rules/failures.py +0 -10
  30. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/.github/workflows/ci.yml +0 -0
  31. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/.github/workflows/publish-to-test-pypi.yml +0 -0
  32. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/.idea/shelf/Uncommitted_changes_before_Checkout_at_2_4_25,_6_32_PM_[Changes]/shelved.patch +0 -0
  33. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/.idea/shelf/Uncommitted_changes_before_Checkout_at_2_4_25,_6_32_PM_[Changes]1/shelved.patch +0 -0
  34. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/LICENSE +0 -0
  35. {ripple_down_rules-0.5.1/test/test_results/datasets_physical_object_is_a_robot → ripple_down_rules-0.5.3/examples}/__init__.py +0 -0
  36. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/images/thinking_pr2.jpg +0 -0
  37. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/pyproject.toml +0 -0
  38. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/pytest.ini +0 -0
  39. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/requirements-dev-ci.txt +0 -0
  40. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/requirements-dev.txt +0 -0
  41. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/requirements-gui.txt +0 -0
  42. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/requirements-viz.txt +0 -0
  43. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/requirements.txt +0 -0
  44. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_mcrdr_extra.dot +0 -0
  45. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_mcrdr_extra.png +0 -0
  46. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_mcrdr_stop_only.dot +0 -0
  47. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_mcrdr_stop_only.png +0 -0
  48. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_mcrdr_stop_plus_rule.dot +0 -0
  49. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_mcrdr_stop_plus_rule.png +0 -0
  50. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_scrdr.dot +0 -0
  51. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_scrdr.png +0 -0
  52. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_scrdr_2.dot +0 -0
  53. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_scrdr_2.png +0 -0
  54. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_scrdr_3.dot +0 -0
  55. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/complete_scrdr_3.png +0 -0
  56. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/grdr_Habitat.dot +0 -0
  57. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/grdr_Habitat.png +0 -0
  58. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/grdr_Species.dot +0 -0
  59. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/grdr_Species.png +0 -0
  60. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/mcrdr_extra.dot +0 -0
  61. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/mcrdr_extra.png +0 -0
  62. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/mcrdr_extra_classify.dot +0 -0
  63. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/mcrdr_extra_classify.png +0 -0
  64. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/mcrdr_stop_plus_rule_combined.dot +0 -0
  65. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/mcrdr_stop_plus_rule_combined.png +0 -0
  66. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/partial_mcrdr_extra.dot +0 -0
  67. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/partial_mcrdr_extra.png +0 -0
  68. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/relational_scrdr_classify.dot +0 -0
  69. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/results/relational_scrdr_classify.png +0 -0
  70. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/setup.cfg +0 -0
  71. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/datastructures/__init__.py +0 -0
  72. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/datastructures/case.py +0 -0
  73. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/datastructures/dataclasses.py +0 -0
  74. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/datastructures/enums.py +0 -0
  75. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/helpers.py +0 -0
  76. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/rdr_decorators.py +0 -0
  77. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/rules.py +0 -0
  78. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/start-code-server.sh +0 -0
  79. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/user_interface/__init__.py +0 -0
  80. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/user_interface/gui.py +0 -0
  81. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/user_interface/ipython_custom_shell.py +0 -0
  82. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/user_interface/object_diagram.py +0 -0
  83. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/user_interface/prompt.py +0 -0
  84. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules/user_interface/template_file_creator.py +0 -0
  85. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules.egg-info/dependency_links.txt +0 -0
  86. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules.egg-info/requires.txt +0 -0
  87. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/src/ripple_down_rules.egg-info/top_level.txt +0 -0
  88. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/datasets.py +0 -0
  89. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/correct_drawer_rdr_expert_answers_fit.json +0 -0
  90. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/grdr_expert_answers_classify.json +0 -0
  91. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/grdr_expert_answers_fit.json +0 -0
  92. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/grdr_expert_answers_fit_extra.json +0 -0
  93. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/grdr_expert_answers_fit_no_targets.json +0 -0
  94. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_expert_answers_classify.json +0 -0
  95. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_expert_answers_fit_no_targets.json +0 -0
  96. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_expert_answers_stop_only_fit.json +0 -0
  97. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_extra_expert_answers_classify.json +0 -0
  98. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_extra_expert_answers_fit.json +0 -0
  99. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_multi_line_expert_answers_fit.json +0 -0
  100. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_stop_only_answers_fit.json +0 -0
  101. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_stop_plus_rule_answers_fit.json +0 -0
  102. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_stop_plus_rule_combined_expert_answers_fit.json +0 -0
  103. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mcrdr_stop_plus_rule_expert_answers_fit.json +0 -0
  104. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/mutagenic_expert_answers.json +0 -0
  105. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/relational_scrdr_expert_answers_classify.json +0 -0
  106. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/scrdr_expert_answers_classify.json +0 -0
  107. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/scrdr_expert_answers_fit.json +0 -0
  108. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/scrdr_expert_answers_fit_no_targets.json +0 -0
  109. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/scrdr_multi_line_expert_answers_fit.json +0 -0
  110. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/scrdr_world_expert_answers_fit.json +0 -0
  111. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_expert_answers/view_rdr_expert_answers_fit.json +0 -0
  112. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_generated_rdrs/__init__.py +0 -0
  113. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_helpers/__init__.py +0 -0
  114. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_helpers/helpers.py +0 -0
  115. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_helpers/object_diagram_case_query.png +0 -0
  116. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_helpers/object_diagram_person.png +0 -0
  117. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_json_serialization.py +0 -0
  118. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_object_diagram.py +0 -0
  119. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_on_mutagenic.py +0 -0
  120. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_rdr.py +0 -0
  121. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_rdr_alchemy.py +0 -0
  122. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_rdr_decorators.py +0 -0
  123. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_rdr_world.py +0 -0
  124. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_relational_rdr.py +0 -0
  125. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_relational_rdr_alchemy.py +0 -0
  126. {ripple_down_rules-0.5.1/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot → ripple_down_rules-0.5.3/test/test_results/datasets_physical_object_is_a_robot}/__init__.py +0 -0
  127. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_output__scrdr.py +0 -0
  128. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_output__scrdr_defs.py +1 -1
  129. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_rdr.py +0 -0
  130. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/physical_object_select_objects_that_are_parts_of_robot_output__mcrdr.py +0 -0
  131. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/physical_object_select_objects_that_are_parts_of_robot_output__mcrdr_defs.py +2 -2
  132. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/physical_object_select_objects_that_are_parts_of_robot_rdr.py +0 -0
  133. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_sql_model.py +0 -0
  134. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_template_file_creator.py +0 -0
  135. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_user_interface/__init__.py +0 -0
  136. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_user_interface/test_ipython.py +0 -0
  137. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_user_interface/test_ipython_copilot.py +0 -0
  138. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_user_interface/test_qt_gui_inline.py +0 -0
  139. {ripple_down_rules-0.5.1 → ripple_down_rules-0.5.3}/test/test_utils.py +0 -0
@@ -0,0 +1,64 @@
1
+ name: deploy-book
2
+
3
+ # Run this when the master or main branch changes
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+ # If your git repository has the Jupyter Book within some-subfolder next to
9
+ # unrelated files, you can make this run only if a file within that specific
10
+ # folder has been modified.
11
+ #
12
+ # paths:
13
+ # - some-subfolder/**
14
+
15
+ # This job installs dependencies, builds the book, and pushes it to `gh-pages`
16
+ jobs:
17
+ deploy-book:
18
+ runs-on: ubuntu-latest
19
+ environment:
20
+ name: github-pages
21
+ permissions:
22
+ pages: write
23
+ id-token: write
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+
27
+ # Install dependencies
28
+ - name: Set up Python 3.10
29
+ uses: actions/setup-python@v5
30
+ with:
31
+ python-version: '3.10'
32
+ cache: pip # Implicitly uses requirements.txt for cache key
33
+
34
+ - name: Install dependencies
35
+ run: |
36
+ sudo apt-get update
37
+ sudo apt install graphviz graphviz-dev
38
+ pip install -U pip && pip install -r requirements.txt && pip install . && pip install -r doc/requirements.txt
39
+
40
+ # (optional) Cache your executed notebooks between runs
41
+ # if you have config:
42
+ # execute:
43
+ # execute_notebooks: cache
44
+ - name: cache executed notebooks
45
+ uses: actions/cache@v4
46
+ with:
47
+ path: doc/_build/.jupyter_cache
48
+ key: jupyter-book-cache-${{ hashFiles('requirements.txt') }}
49
+
50
+ # Build the book
51
+ - name: Build the book
52
+ run: |
53
+ jupyter-book build doc
54
+
55
+ # Upload the book's HTML as an artifact
56
+ - name: Upload artifact
57
+ uses: actions/upload-pages-artifact@v3
58
+ with:
59
+ path: "doc/_build/html"
60
+
61
+ # Deploy the book's HTML to GitHub Pages
62
+ - name: Deploy to GitHub Pages
63
+ id: deployment
64
+ uses: actions/deploy-pages@v4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.5.1
3
+ Version: 0.5.3
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
@@ -725,36 +725,161 @@ For GUI support, also install:
725
725
  sudo apt-get install libxcb-cursor-dev
726
726
  ```
727
727
 
728
- ```bash
729
-
730
728
  ## Example Usage
731
729
 
732
- Fit the SCRDR to the data, then classify one of the data cases to check if its correct,
733
- and render the tree to a file:
730
+ ### Propositional Example
731
+
732
+ By propositional, I mean that each rule conclusion is a propositional logic statement with a constant value.
733
+
734
+ For this example, we will use the [UCI Zoo dataset](https://archive.ics.uci.edu/ml/datasets/zoo) to classify animals
735
+ into their species based on their features. The dataset contains 101 animals with 16 features, and the target is th
736
+ e species of the animal.
737
+
738
+ To install the dataset:
739
+ ```bash
740
+ pip install ucimlrepo
734
741
  ```
735
742
 
736
743
  ```python
744
+ from __future__ import annotations
737
745
  from ripple_down_rules.datastructures.dataclasses import CaseQuery
738
- from ripple_down_rules.rdr import SingleClassRDR
739
- from datasets import load_zoo_dataset
746
+ from ripple_down_rules.datastructures.case import create_cases_from_dataframe
747
+ from ripple_down_rules.rdr import GeneralRDR
740
748
  from ripple_down_rules.utils import render_tree
749
+ from ucimlrepo import fetch_ucirepo
750
+ from enum import Enum
741
751
 
742
- all_cases, targets = load_zoo_dataset()
752
+ class Species(str, Enum):
753
+ """Enum for the species of the animals in the UCI Zoo dataset."""
754
+ mammal = "mammal"
755
+ bird = "bird"
756
+ reptile = "reptile"
757
+ fish = "fish"
758
+ amphibian = "amphibian"
759
+ insect = "insect"
760
+ molusc = "molusc"
761
+
762
+ @classmethod
763
+ def from_str(cls, value: str) -> Species:
764
+ return getattr(cls, value)
743
765
 
744
- scrdr = SingleClassRDR()
766
+ # fetch dataset
767
+ zoo = fetch_ucirepo(id=111)
745
768
 
746
- # Fit the SCRDR to the data
769
+ # data (as pandas dataframes)
770
+ X = zoo.data.features
771
+ y = zoo.data.targets
772
+
773
+ # This is a utility that allows each row to be a Case instance,
774
+ # which simplifies access to column values using dot notation.
775
+ all_cases = create_cases_from_dataframe(X, name="Animal")
776
+
777
+ # The targets are the species of the animals
778
+ category_names = ["mammal", "bird", "reptile", "fish", "amphibian", "insect", "molusc"]
779
+ category_id_to_name = {i + 1: name for i, name in enumerate(category_names)}
780
+ targets = [Species.from_str(category_id_to_name[i]) for i in y.values.flatten()]
781
+
782
+ # Now that we are done with the data preparation, we can create and use the Ripple Down Rules classifier.
783
+ grdr = GeneralRDR()
784
+
785
+ # Fit the GRDR to the data
747
786
  case_queries = [CaseQuery(case, 'species', type(target), True, _target=target)
748
787
  for case, target in zip(all_cases[:10], targets[:10])]
749
- scrdr.fit(case_queries, animate_tree=True)
788
+ grdr.fit(case_queries, animate_tree=True)
750
789
 
751
790
  # Render the tree to a file
752
- render_tree(scrdr.start_rule, use_dot_exporter=True, filename="scrdr")
791
+ render_tree(grdr.start_rules[0], use_dot_exporter=True, filename="species_rdr")
753
792
 
754
- cat = scrdr.classify(all_cases[50])
793
+ # Classify a case
794
+ cat = grdr.classify(all_cases[50])['species']
755
795
  assert cat == targets[50]
756
796
  ```
757
797
 
798
+ ### Relational Example
799
+
800
+ By relational, I mean that each rule conclusion is not a constant value, but is related to the case being classified,
801
+ you can understand it better by the next example.
802
+
803
+ In this example, we will create a simple robot with parts and use Ripple Down Rules to find the contained objects inside
804
+ another object, in this case, a robot. You see, the result of such a rule will vary depending on the robot
805
+ and the parts it has.
806
+
807
+ ```python
808
+ from __future__ import annotations
809
+
810
+ import os.path
811
+ from dataclasses import dataclass, field
812
+
813
+ from typing_extensions import List, Optional
814
+
815
+ from ripple_down_rules.datastructures.dataclasses import CaseQuery
816
+ from ripple_down_rules.rdr import GeneralRDR
817
+
818
+
819
+ @dataclass(unsafe_hash=True)
820
+ class PhysicalObject:
821
+ """
822
+ A physical object is an object that can be contained in a container.
823
+ """
824
+ name: str
825
+ contained_objects: List[PhysicalObject] = field(default_factory=list, hash=False)
826
+
827
+ @dataclass(unsafe_hash=True)
828
+ class Part(PhysicalObject):
829
+ ...
830
+
831
+ @dataclass(unsafe_hash=True)
832
+ class Robot(PhysicalObject):
833
+ parts: List[Part] = field(default_factory=list, hash=False)
834
+
835
+
836
+ part_a = Part(name="A")
837
+ part_b = Part(name="B")
838
+ part_c = Part(name="C")
839
+ robot = Robot("pr2", parts=[part_a])
840
+ part_a.contained_objects = [part_b]
841
+ part_b.contained_objects = [part_c]
842
+
843
+ case_query = CaseQuery(robot, "contained_objects", (PhysicalObject,), False)
844
+
845
+ load = True # Set to True if you want to load an existing model, False if you want to create a new one.
846
+ if load and os.path.exists('./part_containment_rdr'):
847
+ grdr = GeneralRDR.load('./', model_name='part_containment_rdr')
848
+ grdr.ask_always = False # Set to True if you want to always ask the expert for a target value.
849
+ else:
850
+ grdr = GeneralRDR(save_dir='./', model_name='part_containment_rdr')
851
+
852
+ grdr.fit_case(case_query)
853
+
854
+ print(grdr.classify(robot)['contained_objects'])
855
+ assert grdr.classify(robot)['contained_objects'] == {part_b}
856
+ ```
857
+
858
+ When prompted to write a rule, I wrote the following inside the template function that the Ripple Down Rules created
859
+ for me, this function takes a `case` object as input:
860
+
861
+ ```python
862
+ contained_objects = []
863
+ for part in case.parts:
864
+ contained_objects.extend(part.contained_objects)
865
+ return contained_objects
866
+ ```
867
+
868
+ And then when asked for conditions, I wrote the following inside the template function that the Ripple Down Rules
869
+ created:
870
+
871
+ ```python
872
+ return len(case.parts) > 0
873
+ ```
874
+
875
+ This means that the rule will only be applied if the robot has parts.
876
+
877
+ If you notice, the result only contains part B, while one could say that part C is also contained in the robot, but,
878
+ the rule we wrote only returns the contained objects of the parts of the robot. To get part C, we would have to
879
+ add another rule that says that the contained objects of my contained objects are also contained in me, you can
880
+ try that yourself and see if it works!
881
+
882
+
758
883
  ## To Cite:
759
884
 
760
885
  ```bib
@@ -762,6 +887,6 @@ assert cat == targets[50]
762
887
  author = {Bassiouny, Abdelrhman},
763
888
  title = {Ripple-Down-Rules},
764
889
  url = {https://github.com/AbdelrhmanBassiouny/ripple_down_rules},
765
- version = {0.4.1},
890
+ version = {0.5.2},
766
891
  }
767
892
  ```
@@ -0,0 +1,188 @@
1
+ # Ripple Down Rules (RDR)
2
+
3
+ A python implementation of the various ripple down rules versions, including Single Classification (SCRDR),
4
+ Multi Classification (MCRDR), and Generalised Ripple Down Rules (GRDR).
5
+
6
+ SCRDR, MCRDR, and GRDR are rule-based classifiers that are built incrementally, and can be used to classify
7
+ data cases. The rules are refined as new data cases are classified.
8
+
9
+ SCRDR, MCRDR, and GRDR implementation were inspired from the book:
10
+ ["Ripple Down Rules: An Alternative to Machine Learning"](https://doi.org/10.1201/9781003126157) by Paul Compton, Byeong Ho Kang.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ sudo apt-get install graphviz graphviz-dev
16
+ pip install ripple_down_rules
17
+ ```
18
+ For GUI support, also install:
19
+
20
+ ```bash
21
+ sudo apt-get install libxcb-cursor-dev
22
+ ```
23
+
24
+ ## Example Usage
25
+
26
+ ### Propositional Example
27
+
28
+ By propositional, I mean that each rule conclusion is a propositional logic statement with a constant value.
29
+
30
+ For this example, we will use the [UCI Zoo dataset](https://archive.ics.uci.edu/ml/datasets/zoo) to classify animals
31
+ into their species based on their features. The dataset contains 101 animals with 16 features, and the target is th
32
+ e species of the animal.
33
+
34
+ To install the dataset:
35
+ ```bash
36
+ pip install ucimlrepo
37
+ ```
38
+
39
+ ```python
40
+ from __future__ import annotations
41
+ from ripple_down_rules.datastructures.dataclasses import CaseQuery
42
+ from ripple_down_rules.datastructures.case import create_cases_from_dataframe
43
+ from ripple_down_rules.rdr import GeneralRDR
44
+ from ripple_down_rules.utils import render_tree
45
+ from ucimlrepo import fetch_ucirepo
46
+ from enum import Enum
47
+
48
+ class Species(str, Enum):
49
+ """Enum for the species of the animals in the UCI Zoo dataset."""
50
+ mammal = "mammal"
51
+ bird = "bird"
52
+ reptile = "reptile"
53
+ fish = "fish"
54
+ amphibian = "amphibian"
55
+ insect = "insect"
56
+ molusc = "molusc"
57
+
58
+ @classmethod
59
+ def from_str(cls, value: str) -> Species:
60
+ return getattr(cls, value)
61
+
62
+ # fetch dataset
63
+ zoo = fetch_ucirepo(id=111)
64
+
65
+ # data (as pandas dataframes)
66
+ X = zoo.data.features
67
+ y = zoo.data.targets
68
+
69
+ # This is a utility that allows each row to be a Case instance,
70
+ # which simplifies access to column values using dot notation.
71
+ all_cases = create_cases_from_dataframe(X, name="Animal")
72
+
73
+ # The targets are the species of the animals
74
+ category_names = ["mammal", "bird", "reptile", "fish", "amphibian", "insect", "molusc"]
75
+ category_id_to_name = {i + 1: name for i, name in enumerate(category_names)}
76
+ targets = [Species.from_str(category_id_to_name[i]) for i in y.values.flatten()]
77
+
78
+ # Now that we are done with the data preparation, we can create and use the Ripple Down Rules classifier.
79
+ grdr = GeneralRDR()
80
+
81
+ # Fit the GRDR to the data
82
+ case_queries = [CaseQuery(case, 'species', type(target), True, _target=target)
83
+ for case, target in zip(all_cases[:10], targets[:10])]
84
+ grdr.fit(case_queries, animate_tree=True)
85
+
86
+ # Render the tree to a file
87
+ render_tree(grdr.start_rules[0], use_dot_exporter=True, filename="species_rdr")
88
+
89
+ # Classify a case
90
+ cat = grdr.classify(all_cases[50])['species']
91
+ assert cat == targets[50]
92
+ ```
93
+
94
+ ### Relational Example
95
+
96
+ By relational, I mean that each rule conclusion is not a constant value, but is related to the case being classified,
97
+ you can understand it better by the next example.
98
+
99
+ In this example, we will create a simple robot with parts and use Ripple Down Rules to find the contained objects inside
100
+ another object, in this case, a robot. You see, the result of such a rule will vary depending on the robot
101
+ and the parts it has.
102
+
103
+ ```python
104
+ from __future__ import annotations
105
+
106
+ import os.path
107
+ from dataclasses import dataclass, field
108
+
109
+ from typing_extensions import List, Optional
110
+
111
+ from ripple_down_rules.datastructures.dataclasses import CaseQuery
112
+ from ripple_down_rules.rdr import GeneralRDR
113
+
114
+
115
+ @dataclass(unsafe_hash=True)
116
+ class PhysicalObject:
117
+ """
118
+ A physical object is an object that can be contained in a container.
119
+ """
120
+ name: str
121
+ contained_objects: List[PhysicalObject] = field(default_factory=list, hash=False)
122
+
123
+ @dataclass(unsafe_hash=True)
124
+ class Part(PhysicalObject):
125
+ ...
126
+
127
+ @dataclass(unsafe_hash=True)
128
+ class Robot(PhysicalObject):
129
+ parts: List[Part] = field(default_factory=list, hash=False)
130
+
131
+
132
+ part_a = Part(name="A")
133
+ part_b = Part(name="B")
134
+ part_c = Part(name="C")
135
+ robot = Robot("pr2", parts=[part_a])
136
+ part_a.contained_objects = [part_b]
137
+ part_b.contained_objects = [part_c]
138
+
139
+ case_query = CaseQuery(robot, "contained_objects", (PhysicalObject,), False)
140
+
141
+ load = True # Set to True if you want to load an existing model, False if you want to create a new one.
142
+ if load and os.path.exists('./part_containment_rdr'):
143
+ grdr = GeneralRDR.load('./', model_name='part_containment_rdr')
144
+ grdr.ask_always = False # Set to True if you want to always ask the expert for a target value.
145
+ else:
146
+ grdr = GeneralRDR(save_dir='./', model_name='part_containment_rdr')
147
+
148
+ grdr.fit_case(case_query)
149
+
150
+ print(grdr.classify(robot)['contained_objects'])
151
+ assert grdr.classify(robot)['contained_objects'] == {part_b}
152
+ ```
153
+
154
+ When prompted to write a rule, I wrote the following inside the template function that the Ripple Down Rules created
155
+ for me, this function takes a `case` object as input:
156
+
157
+ ```python
158
+ contained_objects = []
159
+ for part in case.parts:
160
+ contained_objects.extend(part.contained_objects)
161
+ return contained_objects
162
+ ```
163
+
164
+ And then when asked for conditions, I wrote the following inside the template function that the Ripple Down Rules
165
+ created:
166
+
167
+ ```python
168
+ return len(case.parts) > 0
169
+ ```
170
+
171
+ This means that the rule will only be applied if the robot has parts.
172
+
173
+ If you notice, the result only contains part B, while one could say that part C is also contained in the robot, but,
174
+ the rule we wrote only returns the contained objects of the parts of the robot. To get part C, we would have to
175
+ add another rule that says that the contained objects of my contained objects are also contained in me, you can
176
+ try that yourself and see if it works!
177
+
178
+
179
+ ## To Cite:
180
+
181
+ ```bib
182
+ @software{bassiouny2025rdr,
183
+ author = {Bassiouny, Abdelrhman},
184
+ title = {Ripple-Down-Rules},
185
+ url = {https://github.com/AbdelrhmanBassiouny/ripple_down_rules},
186
+ version = {0.5.2},
187
+ }
188
+ ```
@@ -0,0 +1,54 @@
1
+ # Book settings
2
+ # Learn more at https://jupyterbook.org/customize/config.html
3
+
4
+ title: Ripple Down Rules
5
+ author: Abdelrhman Bassiouny
6
+ # logo: logo.png
7
+
8
+ # Force re-execution of notebooks on each build.
9
+ # See https://jupyterbook.org/content/execute.html
10
+ execute:
11
+ execute_notebooks: force
12
+
13
+ # Define the name of the latex output file for PDF builds
14
+ latex:
15
+ latex_documents:
16
+ targetname: book.tex
17
+
18
+ # Add a bibtex file so that we can create citations
19
+ bibtex_bibfiles:
20
+ - references.bib
21
+
22
+ sphinx:
23
+ extra_extensions:
24
+ - myst_nb
25
+ - sphinxcontrib.bibtex # Add the BibTeX extension
26
+ - autoapi.extension # Add the AutoAPI extension
27
+ - 'sphinx.ext.autodoc'
28
+ - sphinxcontrib.plantuml
29
+ config:
30
+ bibtex_bibfiles:
31
+ - references.bib
32
+ # AutoAPI configuration
33
+ autoapi_type: python
34
+ autoapi_dirs:
35
+ - ../src
36
+ autoapi_options:
37
+ - members
38
+ - undoc-members
39
+ - show-inheritance
40
+ - show-module-summary
41
+ autoapi_add_toctree_entry: True
42
+
43
+
44
+ # Information about where the book exists on the web
45
+ repository:
46
+ url: https://github.com/AbdelrhmanBassiouny/ripple_down_rules # Online location of your book
47
+ path_to_book: doc # Optional path to your book, relative to the repository root
48
+ branch: main # Which branch of the repository should be used when creating links (optional)
49
+
50
+ # Add GitHub buttons to your book
51
+ # See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository
52
+ html:
53
+ use_issues_button: true
54
+ use_repository_button: true
@@ -0,0 +1,8 @@
1
+ # Table of contents
2
+ # Learn more at https://jupyterbook.org/customize/toc.html
3
+
4
+ format: jb-book
5
+ root: intro
6
+ chapters:
7
+ - file: bibliography
8
+ - file: autoapi/index
@@ -0,0 +1,4 @@
1
+ # Bibliography
2
+
3
+ ```{bibliography}
4
+ ```