ripple-down-rules 0.6.24__tar.gz → 0.6.26__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 (153) hide show
  1. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/PKG-INFO +1 -1
  2. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/__init__.py +1 -1
  3. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/datastructures/callable_expression.py +3 -2
  4. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/datastructures/dataclasses.py +2 -2
  5. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/datastructures/enums.py +4 -1
  6. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/experts.py +2 -2
  7. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/helpers.py +28 -7
  8. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/rdr.py +68 -22
  9. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/rules.py +160 -53
  10. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/user_interface/prompt.py +6 -3
  11. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/utils.py +22 -19
  12. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules.egg-info/PKG-INFO +1 -1
  13. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_json_serialization.py +8 -3
  14. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_results/datasets_physical_object_is_a_robot/rdr_metadata/datasets_physical_object_is_a_robot.json +4 -4
  15. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/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 +2 -1
  16. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_user_interface/test_qt_gui_inline.py +3 -2
  17. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/.github/workflows/build_and_deploy_doc.yml +0 -0
  18. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/.github/workflows/ci.yml +0 -0
  19. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/.github/workflows/publish-to-test-pypi.yml +0 -0
  20. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/.gitignore +0 -0
  21. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/.idea/shelf/Uncommitted_changes_before_Checkout_at_2_4_25,_6_32_PM_[Changes]/shelved.patch +0 -0
  22. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/.idea/shelf/Uncommitted_changes_before_Checkout_at_2_4_25,_6_32_PM_[Changes]1/shelved.patch +0 -0
  23. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/LICENSE +0 -0
  24. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/README.md +0 -0
  25. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/doc/_config.yml +0 -0
  26. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/doc/_toc.yml +0 -0
  27. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/doc/bibliography.md +0 -0
  28. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/doc/intro.md +0 -0
  29. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/doc/references.bib +0 -0
  30. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/doc/requirements.txt +0 -0
  31. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/examples/__init__.py +0 -0
  32. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/examples/animal_species.py +0 -0
  33. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/examples/part_containment_rdr/__init__.py +0 -0
  34. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/examples/part_containment_rdr/rdr_metadata/part_containment_rdr.json +0 -0
  35. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/examples/part_containment_rdr/robot_contained_objects_mcrdr.py +0 -0
  36. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/examples/part_containment_rdr/robot_contained_objects_mcrdr_defs.py +0 -0
  37. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/examples/part_containment_rdr/robot_rdr.py +0 -0
  38. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/examples/relational_example.py +0 -0
  39. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/images/scrdr.dot +0 -0
  40. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/images/scrdr.png +0 -0
  41. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/images/thinking_pr2.jpg +0 -0
  42. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/pyproject.toml +0 -0
  43. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/pytest.ini +0 -0
  44. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/requirements-dev-ci.txt +0 -0
  45. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/requirements-dev.txt +0 -0
  46. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/requirements-gui.txt +0 -0
  47. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/requirements-viz.txt +0 -0
  48. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/requirements.txt +0 -0
  49. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_mcrdr_extra.dot +0 -0
  50. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_mcrdr_extra.png +0 -0
  51. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_mcrdr_stop_only.dot +0 -0
  52. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_mcrdr_stop_only.png +0 -0
  53. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_mcrdr_stop_plus_rule.dot +0 -0
  54. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_mcrdr_stop_plus_rule.png +0 -0
  55. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_scrdr.dot +0 -0
  56. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_scrdr.png +0 -0
  57. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_scrdr_2.dot +0 -0
  58. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_scrdr_2.png +0 -0
  59. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_scrdr_3.dot +0 -0
  60. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/complete_scrdr_3.png +0 -0
  61. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/grdr_Habitat.dot +0 -0
  62. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/grdr_Habitat.png +0 -0
  63. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/grdr_Species.dot +0 -0
  64. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/grdr_Species.png +0 -0
  65. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/mcrdr_extra.dot +0 -0
  66. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/mcrdr_extra.png +0 -0
  67. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/mcrdr_extra_classify.dot +0 -0
  68. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/mcrdr_extra_classify.png +0 -0
  69. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/mcrdr_stop_plus_rule_combined.dot +0 -0
  70. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/mcrdr_stop_plus_rule_combined.png +0 -0
  71. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/partial_mcrdr_extra.dot +0 -0
  72. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/partial_mcrdr_extra.png +0 -0
  73. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/relational_scrdr_classify.dot +0 -0
  74. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/results/relational_scrdr_classify.png +0 -0
  75. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/scripts/live_dot_server_client.py +0 -0
  76. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/setup.cfg +0 -0
  77. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/datastructures/__init__.py +0 -0
  78. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/datastructures/case.py +0 -0
  79. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/rdr_decorators.py +0 -0
  80. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/start-code-server.sh +0 -0
  81. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/user_interface/__init__.py +0 -0
  82. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/user_interface/gui.py +0 -0
  83. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/user_interface/ipython_custom_shell.py +0 -0
  84. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/user_interface/object_diagram.py +0 -0
  85. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules/user_interface/template_file_creator.py +0 -0
  86. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules.egg-info/SOURCES.txt +0 -0
  87. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules.egg-info/dependency_links.txt +0 -0
  88. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules.egg-info/requires.txt +0 -0
  89. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/src/ripple_down_rules.egg-info/top_level.txt +0 -0
  90. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/__init__.py +0 -0
  91. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/conf/__init__.py +0 -0
  92. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/conf/world/__init__.py +0 -0
  93. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/conf/world/base_config.py +0 -0
  94. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/conf/world/handles_and_containers.py +0 -0
  95. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/conftest.py +0 -0
  96. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/datasets.py +0 -0
  97. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/factories/__init__.py +0 -0
  98. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/factories/world/__init__.py +0 -0
  99. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/factories/world/handles_and_containers.py +0 -0
  100. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/correct_drawer_rdr_expert_answers_fit.json +0 -0
  101. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/drawer_cabinet_expert_answers_fit.json +0 -0
  102. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/grdr_expert_answers_classify.json +0 -0
  103. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/grdr_expert_answers_fit.json +0 -0
  104. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/grdr_expert_answers_fit_extra.json +0 -0
  105. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/grdr_expert_answers_fit_no_targets.json +0 -0
  106. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_expert_answers_classify.json +0 -0
  107. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_expert_answers_fit_no_targets.json +0 -0
  108. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_expert_answers_stop_only_fit.json +0 -0
  109. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_extra_expert_answers_classify.json +0 -0
  110. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_extra_expert_answers_fit.json +0 -0
  111. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_multi_line_expert_answers_fit.json +0 -0
  112. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_stop_only_answers_fit.json +0 -0
  113. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_stop_plus_rule_answers_fit.json +0 -0
  114. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_stop_plus_rule_combined_expert_answers_fit.json +0 -0
  115. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mcrdr_stop_plus_rule_expert_answers_fit.json +0 -0
  116. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/mutagenic_expert_answers.json +0 -0
  117. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/relational_scrdr_expert_answers_classify.json +0 -0
  118. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/scrdr_expert_answers_classify.json +0 -0
  119. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/scrdr_expert_answers_fit.json +0 -0
  120. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/scrdr_expert_answers_fit_no_targets.json +0 -0
  121. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/scrdr_multi_line_expert_answers_fit.json +0 -0
  122. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_expert_answers/scrdr_world_expert_answers_fit.json +0 -0
  123. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_generated_rdrs/__init__.py +0 -0
  124. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_helpers/__init__.py +0 -0
  125. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_helpers/helpers.py +0 -0
  126. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_helpers/object_diagram_case_query.png +0 -0
  127. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_helpers/object_diagram_person.png +0 -0
  128. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_object_diagram.py +0 -0
  129. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_on_mutagenic.py +0 -0
  130. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_rdr.py +0 -0
  131. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_rdr_alchemy.py +0 -0
  132. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_rdr_decorators.py +0 -0
  133. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_rdr_helpers_rdrs.py +0 -0
  134. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_rdr_world/__init__.py +0 -0
  135. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_rdr_world/conftest.py +0 -0
  136. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_rdr_world/test_rdr_world.py +0 -0
  137. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_relational_rdr.py +0 -0
  138. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_relational_rdr_alchemy.py +0 -0
  139. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_results/datasets_physical_object_is_a_robot/__init__.py +0 -0
  140. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_output__scrdr.py +1 -1
  141. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_output__scrdr_defs.py +1 -1
  142. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_rdr.py +1 -1
  143. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/__init__.py +0 -0
  144. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/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 +0 -0
  145. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/physical_object_select_objects_that_are_parts_of_robot_rdr.py +1 -1
  146. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/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 +0 -0
  147. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_sql_model.py +0 -0
  148. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_template_file_creator.py +0 -0
  149. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_user_interface/__init__.py +0 -0
  150. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_user_interface/test_ipython.py +0 -0
  151. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_user_interface/test_ipython_copilot.py +0 -0
  152. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_user_interface/test_prompt.py +0 -0
  153. {ripple_down_rules-0.6.24 → ripple_down_rules-0.6.26}/test/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.6.24
3
+ Version: 0.6.26
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
@@ -1,4 +1,4 @@
1
- __version__ = "0.6.24"
1
+ __version__ = "0.6.26"
2
2
 
3
3
  import logging
4
4
  logger = logging.Logger("rdr")
@@ -95,7 +95,7 @@ class CallableExpression(SubclassJSONSerializer):
95
95
  encapsulating_function_name: str = "_get_value"
96
96
 
97
97
  def __init__(self, user_input: Optional[str] = None,
98
- conclusion_type: Optional[Tuple[Type]] = None,
98
+ conclusion_type: Optional[Tuple[Type, ...]] = None,
99
99
  expression_tree: Optional[AST] = None,
100
100
  scope: Optional[Dict[str, Any]] = None,
101
101
  conclusion: Optional[Any] = None,
@@ -176,7 +176,8 @@ class CallableExpression(SubclassJSONSerializer):
176
176
  new_user_input = (f"{cond1_user_input}\n"
177
177
  f"{cond2_user_input}\n"
178
178
  f"return _cond1(case) and _cond2(case)")
179
- return CallableExpression(new_user_input, conclusion_type=self.conclusion_type)
179
+ return CallableExpression(new_user_input, conclusion_type=self.conclusion_type,
180
+ mutually_exclusive=self.mutually_exclusive)
180
181
 
181
182
  def update_user_input_from_file(self, file_path: str, function_name: str):
182
183
  """
@@ -31,7 +31,7 @@ class CaseQuery:
31
31
  """
32
32
  The name of the attribute.
33
33
  """
34
- _attribute_types: Tuple[Type]
34
+ _attribute_types: Tuple[Type, ...]
35
35
  """
36
36
  The type(s) of the attribute.
37
37
  """
@@ -139,7 +139,7 @@ class CaseQuery:
139
139
  attribute_types_str = f"Union[{', '.join([t.__name__ for t in self.core_attribute_type])}]"
140
140
  else:
141
141
  attribute_types_str = self.core_attribute_type[0].__name__
142
- if all(t in self.attribute_type for t in [list, set]) and len(self.core_attribute_type) > 2:
142
+ if not self.mutually_exclusive:
143
143
  return f"List[{attribute_types_str}]"
144
144
  else:
145
145
  return attribute_types_str
@@ -196,7 +196,10 @@ class RDREdge(Enum):
196
196
  """
197
197
  Next edge, the edge that represents the next rule to be evaluated.
198
198
  """
199
-
199
+ Filter = "filter if"
200
+ """
201
+ Filter edge, the edge that represents the filter condition.
202
+ """
200
203
 
201
204
  class ValueType(Enum):
202
205
  Unary = auto()
@@ -41,14 +41,14 @@ class Expert(ABC):
41
41
  A flag to indicate if the expert should use loaded answers or not.
42
42
  """
43
43
 
44
- def __init__(self, use_loaded_answers: bool = True,
44
+ def __init__(self, use_loaded_answers: bool = False,
45
45
  append: bool = False,
46
46
  answers_save_path: Optional[str] = None):
47
47
  self.all_expert_answers = []
48
48
  self.use_loaded_answers = use_loaded_answers
49
49
  self.append = append
50
50
  self.answers_save_path = answers_save_path
51
- if answers_save_path is not None:
51
+ if answers_save_path is not None and os.path.exists(answers_save_path + '.py'):
52
52
  if use_loaded_answers:
53
53
  self.load_answers(answers_save_path)
54
54
  else:
@@ -2,15 +2,14 @@ from __future__ import annotations
2
2
 
3
3
  import os
4
4
  from types import ModuleType
5
+ from typing import Tuple
5
6
 
6
- from ripple_down_rules.datastructures.dataclasses import CaseFactoryMetaData
7
-
8
- from .datastructures.case import create_case
9
- from .datastructures.dataclasses import CaseQuery
10
7
  from typing_extensions import Type, Optional, Callable, Any, Dict, TYPE_CHECKING, Union
11
8
 
12
- from .utils import get_func_rdr_model_name, copy_case, make_set, update_case
9
+ from .datastructures.case import create_case, Case
10
+ from .datastructures.dataclasses import CaseQuery
13
11
  from .utils import calculate_precision_and_recall
12
+ from .utils import get_func_rdr_model_name, copy_case, make_set, update_case
14
13
 
15
14
  if TYPE_CHECKING:
16
15
  from .rdr import RippleDownRules
@@ -55,12 +54,14 @@ def general_rdr_classify(classifiers_dict: Dict[str, Union[ModuleType, RippleDow
55
54
  if attribute_name in new_conclusions:
56
55
  temp_case_query = CaseQuery(case_cp, attribute_name, rdr.conclusion_type, rdr.mutually_exclusive)
57
56
  update_case(temp_case_query, new_conclusions)
58
- if len(new_conclusions) == 0 or len(classifiers_dict) == 1 and list(classifiers_dict.values())[0].mutually_exclusive:
57
+ if len(new_conclusions) == 0 or len(classifiers_dict) == 1 and list(classifiers_dict.values())[
58
+ 0].mutually_exclusive:
59
59
  break
60
60
  return conclusions
61
61
 
62
62
 
63
- def is_matching(classifier: Callable[[Any], Any], case_query: CaseQuery, pred_cat: Optional[Dict[str, Any]] = None) -> bool:
63
+ def is_matching(classifier: Callable[[Any], Any], case_query: CaseQuery,
64
+ pred_cat: Optional[Dict[str, Any]] = None) -> bool:
64
65
  """
65
66
  :param classifier: The RDR classifier to check the prediction of.
66
67
  :param case_query: The case query to check.
@@ -95,3 +96,23 @@ def load_or_create_func_rdr_model(func, model_dir: str, rdr_type: Type[RippleDow
95
96
  else:
96
97
  rdr = rdr_type(**rdr_kwargs)
97
98
  return rdr
99
+
100
+
101
+ def get_an_updated_case_copy(case: Case, conclusion: Callable, attribute_name: str, conclusion_type: Tuple[Type, ...],
102
+ mutually_exclusive: bool) -> Case:
103
+ """
104
+ :param case: The case to copy and update.
105
+ :param conclusion: The conclusion to add to the case.
106
+ :param attribute_name: The name of the attribute to update.
107
+ :param conclusion_type: The type of the conclusion to update.
108
+ :param mutually_exclusive: Whether the rule belongs to a mutually exclusive RDR.
109
+ :return: A copy of the case updated with the given conclusion.
110
+ """
111
+ case_cp = copy_case(case)
112
+ temp_case_query = CaseQuery(case_cp, attribute_name, conclusion_type,
113
+ mutually_exclusive=mutually_exclusive)
114
+ output = conclusion(case_cp)
115
+ if not isinstance(output, Dict):
116
+ output = {attribute_name: output}
117
+ update_case(temp_case_query, output)
118
+ return case_cp
@@ -1,12 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import importlib
4
+ import json
4
5
  import os
5
6
  from abc import ABC, abstractmethod
6
7
  from copy import copy
7
8
  from dataclasses import is_dataclass
8
9
  from types import NoneType
9
- import json
10
10
 
11
11
  from ripple_down_rules.datastructures.dataclasses import CaseFactoryMetaData
12
12
  from . import logger
@@ -29,16 +29,17 @@ from .datastructures.case import Case, CaseAttribute, create_case
29
29
  from .datastructures.dataclasses import CaseQuery
30
30
  from .datastructures.enums import MCRDRMode
31
31
  from .experts import Expert, Human
32
- from .helpers import is_matching, general_rdr_classify
33
- from .rules import Rule, SingleClassRule, MultiClassTopRule, MultiClassStopRule
32
+ from .helpers import is_matching, general_rdr_classify, get_an_updated_case_copy
33
+ from .rules import Rule, SingleClassRule, MultiClassTopRule, MultiClassStopRule, MultiClassRefinementRule, \
34
+ MultiClassFilterRule
34
35
 
35
36
  try:
36
37
  from .user_interface.gui import RDRCaseViewer
37
38
  except ImportError as e:
38
39
  RDRCaseViewer = None
39
40
  from .utils import draw_tree, make_set, SubclassJSONSerializer, make_list, get_type_from_string, \
40
- is_conflicting, extract_function_source, extract_imports, get_full_class_name, \
41
- is_iterable, str_to_snake_case, get_import_path_from_path, get_imports_from_types, render_tree, table_rows_as_str
41
+ is_value_conflicting, extract_function_source, extract_imports, get_full_class_name, \
42
+ is_iterable, str_to_snake_case, get_import_path_from_path, get_imports_from_types, render_tree
42
43
 
43
44
 
44
45
  class RippleDownRules(SubclassJSONSerializer, ABC):
@@ -500,25 +501,51 @@ class RDRWithCodeWriter(RippleDownRules, ABC):
500
501
  conclusion_func_names = [f'conclusion_{rid}' for rid in rules_dict.keys()
501
502
  if not isinstance(rules_dict[rid], MultiClassStopRule)]
502
503
  all_func_names = condition_func_names + conclusion_func_names
504
+ rule_tree_file_path = f"{model_dir}/{self.generated_python_file_name}.py"
503
505
  filepath = f"{model_dir}/{self.generated_python_defs_file_name}.py"
504
506
  cases_path = f"{model_dir}/{self.generated_python_cases_file_name}.py"
505
507
  cases_import_path = get_import_path_from_path(model_dir)
506
508
  cases_import_path = f"{cases_import_path}.{self.generated_python_cases_file_name}" if cases_import_path \
507
509
  else self.generated_python_cases_file_name
508
510
  functions_source = extract_function_source(filepath, all_func_names, include_signature=False)
511
+ python_rule_tree_source = ""
512
+ with open(rule_tree_file_path, "r") as rule_tree_source:
513
+ python_rule_tree_source = rule_tree_source.read()
509
514
  # get the scope from the imports in the file
510
515
  scope = extract_imports(filepath, package_name=package_name)
516
+ rules_not_found = set()
511
517
  for rule in [self.start_rule] + list(self.start_rule.descendants):
512
518
  if rule.conditions is not None:
513
- rule.conditions.user_input = functions_source[f"conditions_{rule.uid}"]
519
+ conditions_name = rule.generated_conditions_function_name
520
+ if conditions_name not in functions_source or conditions_name not in python_rule_tree_source:
521
+ rules_not_found.add(rule)
522
+ continue
523
+ rule.conditions.user_input = functions_source[conditions_name]
514
524
  rule.conditions.scope = scope
515
525
  if os.path.exists(cases_path):
516
526
  module = importlib.import_module(cases_import_path, package=package_name)
517
527
  importlib.reload(module)
518
528
  rule.corner_case_metadata = module.__dict__.get(f"corner_case_{rule.uid}", None)
519
- if rule.conclusion is not None and not isinstance(rule, MultiClassStopRule):
520
- rule.conclusion.user_input = functions_source[f"conclusion_{rule.uid}"]
529
+ if not isinstance(rule, MultiClassStopRule):
530
+ conclusion_name = rule.generated_conclusion_function_name
531
+ if conclusion_name not in functions_source or conclusion_name not in python_rule_tree_source:
532
+ rules_not_found.add(rule)
533
+ rule.conclusion.user_input = functions_source[conclusion_name]
521
534
  rule.conclusion.scope = scope
535
+ for rule in rules_not_found:
536
+ if isinstance(rule, MultiClassTopRule):
537
+ import pdb; pdb.set_trace()
538
+ rule.parent.set_immediate_alternative(rule.alternative)
539
+ if rule.refinement is not None:
540
+ ref_rules = [ref_rule for ref_rule in [rule.refinement] + list(rule.refinement.descendants)]
541
+ for ref_rule in ref_rules:
542
+ del ref_rule
543
+ else:
544
+ rule.parent.refinement = rule.alternative
545
+ if rule.alternative is not None:
546
+ rule.alternative = None
547
+ rule.parent = None
548
+ del rule
522
549
 
523
550
  @abstractmethod
524
551
  def write_rules_as_source_code_to_file(self, rule: Rule, file, parent_indent: str = "",
@@ -597,7 +624,7 @@ class RDRWithCodeWriter(RippleDownRules, ABC):
597
624
  """
598
625
  pass
599
626
 
600
- def _get_types_to_import(self) -> Tuple[Set[Type], Set[Type], Set[Type]]:
627
+ def _get_types_to_import(self) -> Tuple[Set[Union[Type, Callable]], Set[Type], Set[Type]]:
601
628
  """
602
629
  :return: The types of the main, defs, and corner cases files of the RDR classifier that will be imported.
603
630
  """
@@ -930,6 +957,9 @@ class MultiClassRDR(RDRWithCodeWriter):
930
957
  if rule.alternative:
931
958
  self.write_rules_as_source_code_to_file(rule.alternative, filename, parent_indent, defs_file=defs_file,
932
959
  cases_file=cases_file, package_name=package_name)
960
+ elif isinstance(rule, MultiClassTopRule):
961
+ with open(filename, "a") as file:
962
+ file.write(f"{parent_indent}return conclusions\n")
933
963
 
934
964
  @property
935
965
  def conclusion_type_hint(self) -> str:
@@ -939,8 +969,9 @@ class MultiClassRDR(RDRWithCodeWriter):
939
969
  else:
940
970
  return f"Set[Union[{', '.join(conclusion_types)}]]"
941
971
 
942
- def _get_types_to_import(self) -> Tuple[Set[Type], Set[Type], Set[Type]]:
972
+ def _get_types_to_import(self) -> Tuple[Set[Union[Type, Callable]], Set[Type], Set[Type]]:
943
973
  main_types, defs_types, cases_types = super()._get_types_to_import()
974
+ main_types.add(get_an_updated_case_copy)
944
975
  main_types.update({Set, make_set})
945
976
  defs_types.update({List, Set})
946
977
  return main_types, defs_types, cases_types
@@ -972,28 +1003,43 @@ class MultiClassRDR(RDRWithCodeWriter):
972
1003
  Stop a wrong conclusion by adding a stopping rule.
973
1004
  """
974
1005
  rule_conclusion = evaluated_rule.conclusion(case_query.case)
975
- if is_conflicting(rule_conclusion, case_query.target_value):
976
- self.stop_conclusion(case_query, expert, evaluated_rule)
977
- else:
1006
+ stop: bool = False
1007
+ add_filter_rule: bool = False
1008
+ if is_value_conflicting(rule_conclusion, case_query.target_value):
1009
+ if make_set(case_query.target_value).issubset(rule_conclusion):
1010
+ add_filter_rule = True
1011
+ else:
1012
+ stop = True
1013
+ elif make_set(case_query.core_attribute_type).issubset(make_set(evaluated_rule.conclusion.conclusion_type)):
1014
+ if make_set(case_query.target_value).issubset(rule_conclusion):
1015
+ add_filter_rule = True
1016
+
1017
+ if not stop:
978
1018
  self.add_conclusion(rule_conclusion)
1019
+ if stop or add_filter_rule:
1020
+ refinement_type = MultiClassStopRule if stop else MultiClassFilterRule
1021
+ self.stop_or_filter_conclusion(case_query, expert, evaluated_rule, refinement_type=refinement_type)
979
1022
 
980
- def stop_conclusion(self, case_query: CaseQuery,
981
- expert: Expert, evaluated_rule: MultiClassTopRule):
1023
+ def stop_or_filter_conclusion(self, case_query: CaseQuery,
1024
+ expert: Expert, evaluated_rule: MultiClassTopRule,
1025
+ refinement_type: Type[MultiClassRefinementRule] = MultiClassStopRule):
982
1026
  """
983
1027
  Stop a conclusion by adding a stopping rule.
984
1028
 
985
1029
  :param case_query: The case query to stop the conclusion for.
986
1030
  :param expert: The expert to ask for differentiating features as new rule conditions.
987
1031
  :param evaluated_rule: The evaluated rule to ask the expert about.
1032
+ :param refinement_type: The refinement type to use.
988
1033
  """
989
1034
  conditions = expert.ask_for_conditions(case_query, evaluated_rule)
990
- evaluated_rule.fit_rule(case_query)
991
- if self.mode == MCRDRMode.StopPlusRule:
992
- self.stop_rule_conditions = conditions
993
- if self.mode == MCRDRMode.StopPlusRuleCombined:
994
- new_top_rule_conditions = conditions.combine_with(evaluated_rule.conditions)
995
- case_query.conditions = new_top_rule_conditions
996
- self.add_top_rule(case_query)
1035
+ evaluated_rule.fit_rule(case_query, refinement_type=refinement_type)
1036
+ if refinement_type is MultiClassStopRule:
1037
+ if self.mode == MCRDRMode.StopPlusRule:
1038
+ self.stop_rule_conditions = conditions
1039
+ if self.mode == MCRDRMode.StopPlusRuleCombined:
1040
+ new_top_rule_conditions = conditions.combine_with(evaluated_rule.conditions)
1041
+ case_query.conditions = new_top_rule_conditions
1042
+ self.add_top_rule(case_query)
997
1043
 
998
1044
  def add_rule_for_case(self, case_query: CaseQuery, expert: Expert):
999
1045
  """