rustdl 0.3.16__tar.gz → 0.3.18__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 (209) hide show
  1. {rustdl-0.3.16 → rustdl-0.3.18}/Cargo.lock +10 -10
  2. {rustdl-0.3.16 → rustdl-0.3.18}/Cargo.toml +1 -1
  3. {rustdl-0.3.16 → rustdl-0.3.18}/PKG-INFO +1 -1
  4. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/README.md +9 -5
  5. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-datatypes/README.md +9 -5
  6. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/src/classify.rs +35 -13
  7. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/README.md +9 -5
  8. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/abox_saturation.rs +11 -0
  9. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/classify.rs +24 -0
  10. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/lib.rs +2 -2
  11. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/property_assertions.rs +75 -0
  12. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-saturation/README.md +9 -5
  13. rustdl-0.3.18/crates/owl-dl-tableau/README.md +161 -0
  14. {rustdl-0.3.16 → rustdl-0.3.18}/python/rustdl/__init__.py +29 -20
  15. {rustdl-0.3.16 → rustdl-0.3.18}/python/rustdl/__init__.pyi +18 -3
  16. rustdl-0.3.16/crates/owl-dl-tableau/README.md +0 -157
  17. {rustdl-0.3.16 → rustdl-0.3.18}/README.md +0 -0
  18. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/Cargo.toml +0 -0
  19. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/absorb.rs +0 -0
  20. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/approx_saturation.rs +0 -0
  21. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/clause.rs +0 -0
  22. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/convert.rs +0 -0
  23. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/convert_back.rs +0 -0
  24. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/data_axioms.rs +0 -0
  25. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/definitions.rs +0 -0
  26. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/disjunction_existential.rs +0 -0
  27. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/ir.rs +0 -0
  28. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/lib.rs +0 -0
  29. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/locality.rs +0 -0
  30. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/normalize.rs +0 -0
  31. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/ontology.rs +0 -0
  32. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/residual_trigger.rs +0 -0
  33. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/role_hierarchy.rs +0 -0
  34. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/told.rs +0 -0
  35. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/transform.rs +0 -0
  36. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/src/vocab.rs +0 -0
  37. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/tests/concept_pool_proptest.proptest-regressions +0 -0
  38. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/tests/concept_pool_proptest.rs +0 -0
  39. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/tests/convert_round_trip_proptest.rs +0 -0
  40. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-core/tests/role_hierarchy_proptest.rs +0 -0
  41. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-datatypes/Cargo.toml +0 -0
  42. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-datatypes/src/lib.rs +0 -0
  43. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/.gitignore +0 -0
  44. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/Cargo.toml +0 -0
  45. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/README.md +0 -0
  46. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/src/errors.rs +0 -0
  47. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/src/explain.rs +0 -0
  48. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/src/lib.rs +0 -0
  49. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/src/load.rs +0 -0
  50. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/src/materialize.rs +0 -0
  51. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/src/queries.rs +0 -0
  52. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/conftest.py +0 -0
  53. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_classify.py +0 -0
  54. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_examples.py +0 -0
  55. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_explain.py +0 -0
  56. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_manchester.py +0 -0
  57. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_materialize.py +0 -0
  58. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_queries.py +0 -0
  59. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_results.py +0 -0
  60. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_smoke.py +0 -0
  61. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_soundness.py +0 -0
  62. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_stubs.py +0 -0
  63. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-py/tests/python/test_tutorial.py +0 -0
  64. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/Cargo.toml +0 -0
  65. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/examples/embed_classify.rs +0 -0
  66. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/abox_check.rs +0 -0
  67. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/diagnose.rs +0 -0
  68. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/justify.rs +0 -0
  69. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/laconic.rs +0 -0
  70. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/model_cache.rs +0 -0
  71. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/realize.rs +0 -0
  72. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/repair.rs +0 -0
  73. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/src/union_find.rs +0 -0
  74. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/abox_consistency.rs +0 -0
  75. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/abox_sat_fp_probe.rs +0 -0
  76. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/abox_saturation.rs +0 -0
  77. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/adaptive_budget.rs +0 -0
  78. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/anon349_diagnostic.rs +0 -0
  79. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/approx_saturation_forced_disjunct.rs +0 -0
  80. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/blocked_disjunction_soundness.rs +0 -0
  81. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/blocked_disjunction_termination.rs +0 -0
  82. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/classify_concrete_domain.rs +0 -0
  83. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/classify_inverse_domain.rs +0 -0
  84. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/concrete_domain_clash.rs +0 -0
  85. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/data_properties.rs +0 -0
  86. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/data_property_assertions.rs +0 -0
  87. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/datatype_completeness.rs +0 -0
  88. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/datatype_inconsistency.rs +0 -0
  89. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/datatype_value_membership.rs +0 -0
  90. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/decide_pair_probe.rs +0 -0
  91. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/diagnose_partition.rs +0 -0
  92. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/disjunctive_existential_marker_fp.rs +0 -0
  93. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/domain_gci_completeness.rs +0 -0
  94. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/existential_successors.rs +0 -0
  95. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_direct_bot.ofn +0 -0
  96. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_no_bot.ofn +0 -0
  97. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_different_individuals.ofn +0 -0
  98. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_types.ofn +0 -0
  99. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa.ofn +0 -0
  100. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa_no_clash.ofn +0 -0
  101. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_consistent.ofn +0 -0
  102. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_inconsistent.ofn +0 -0
  103. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_different.ofn +0 -0
  104. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_without_different.ofn +0 -0
  105. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_diff.ofn +0 -0
  106. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_same_target.ofn +0 -0
  107. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric.ofn +0 -0
  108. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric_one_way.ofn +0 -0
  109. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive.ofn +0 -0
  110. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive_distinct.ofn +0 -0
  111. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_compatible.ofn +0 -0
  112. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_disjoint.ofn +0 -0
  113. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_cardinality_disjoint.ofn +0 -0
  114. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain-classified.owx +0 -0
  115. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain.ofn +0 -0
  116. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition-classified.owx +0 -0
  117. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition.ofn +0 -0
  118. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_facet.ofn +0 -0
  119. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/datatype/functional_data_property.ofn +0 -0
  120. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property-classified.owx +0 -0
  121. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property.ofn +0 -0
  122. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/functional-equiv-some-bug.ofn +0 -0
  123. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/named-pizza-country-bug.ofn +0 -0
  124. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-01.txt +0 -0
  125. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-02.txt +0 -0
  126. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-03.txt +0 -0
  127. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-04.txt +0 -0
  128. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-05.txt +0 -0
  129. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-06.txt +0 -0
  130. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-07.txt +0 -0
  131. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-08.txt +0 -0
  132. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.hermit.owx +0 -0
  133. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.ofn +0 -0
  134. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.owx +0 -0
  135. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.hermit.owx +0 -0
  136. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.ofn +0 -0
  137. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.owx +0 -0
  138. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.hermit.owx +0 -0
  139. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.ofn +0 -0
  140. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.owx +0 -0
  141. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.hermit.owx +0 -0
  142. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.ofn +0 -0
  143. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.owx +0 -0
  144. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.hermit.owx +0 -0
  145. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.ofn +0 -0
  146. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.owx +0 -0
  147. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.hermit.owx +0 -0
  148. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.ofn +0 -0
  149. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.owx +0 -0
  150. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.hermit.owx +0 -0
  151. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.ofn +0 -0
  152. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.owx +0 -0
  153. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.hermit.owx +0 -0
  154. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.ofn +0 -0
  155. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.owx +0 -0
  156. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/fixtures/phase2b/phase2b-verdicts.log +0 -0
  157. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/functional_enforcement.rs +0 -0
  158. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/inverse_cardinality_soundness.rs +0 -0
  159. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/inverse_symmetric_domain.rs +0 -0
  160. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/justification.rs +0 -0
  161. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/konclude_closure_diff.rs +0 -0
  162. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/label_heuristic_canary.rs +0 -0
  163. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/laconic_justification.rs +0 -0
  164. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/object_has_self_domain.rs +0 -0
  165. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/phase2c_pair_06_canary.rs +0 -0
  166. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/precompletion_probe_gate.rs +0 -0
  167. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/real_ontology_corpus.rs +0 -0
  168. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/repair_suggestions.rs +0 -0
  169. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/sat_lookahead_gate.rs +0 -0
  170. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/seed_probe_gate.rs +0 -0
  171. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/shadow_dep_gate.rs +0 -0
  172. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/snapshot_phase0_canary.rs +0 -0
  173. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/subproperty_axioms.rs +0 -0
  174. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/tautology_skip_canary.rs +0 -0
  175. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/value_type_disjoint_canary.rs +0 -0
  176. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/value_type_disjoint_probe.rs +0 -0
  177. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-reasoner/tests/wedge_consistency.rs +0 -0
  178. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-saturation/Cargo.toml +0 -0
  179. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-saturation/src/lib.rs +0 -0
  180. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-saturation/src/proof.rs +0 -0
  181. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-saturation/src/seed_sat.rs +0 -0
  182. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-saturation/tests/fixtures/phase2a_functional_role_canary.ofn +0 -0
  183. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-saturation/tests/fixtures/phase2b_compound_existential_canary.ofn +0 -0
  184. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/Cargo.toml +0 -0
  185. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/counters.rs +0 -0
  186. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/deps.rs +0 -0
  187. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/graph.rs +0 -0
  188. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/hyper.rs +0 -0
  189. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/lib.rs +0 -0
  190. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/replay.rs +0 -0
  191. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/rules.rs +0 -0
  192. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/saturate.rs +0 -0
  193. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/search.rs +0 -0
  194. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/shadow_measures.rs +0 -0
  195. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/snapshot.rs +0 -0
  196. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/src/trail.rs +0 -0
  197. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/tests/backprop_risk.rs +0 -0
  198. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/tests/replay_driver.rs +0 -0
  199. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/tests/replay_roundtrip.rs +0 -0
  200. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/tests/sat_lookahead_drop.rs +0 -0
  201. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/tests/shadow_dep_probe.rs +0 -0
  202. {rustdl-0.3.16 → rustdl-0.3.18}/crates/owl-dl-tableau/tests/snapshot_capture.rs +0 -0
  203. {rustdl-0.3.16 → rustdl-0.3.18}/pyproject.toml +0 -0
  204. {rustdl-0.3.16 → rustdl-0.3.18}/python/rustdl/_results.py +0 -0
  205. {rustdl-0.3.16 → rustdl-0.3.18}/python/rustdl/data/pizza.owl.gz +0 -0
  206. {rustdl-0.3.16 → rustdl-0.3.18}/python/rustdl/data/sio.owl.gz +0 -0
  207. {rustdl-0.3.16 → rustdl-0.3.18}/python/rustdl/data/sulo.owl.gz +0 -0
  208. {rustdl-0.3.16 → rustdl-0.3.18}/python/rustdl/examples.py +0 -0
  209. {rustdl-0.3.16 → rustdl-0.3.18}/python/rustdl/py.typed +0 -0
@@ -1018,7 +1018,7 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
1018
1018
 
1019
1019
  [[package]]
1020
1020
  name = "owl-dl-bench"
1021
- version = "0.3.16"
1021
+ version = "0.3.18"
1022
1022
  dependencies = [
1023
1023
  "anyhow",
1024
1024
  "clap",
@@ -1037,7 +1037,7 @@ dependencies = [
1037
1037
 
1038
1038
  [[package]]
1039
1039
  name = "owl-dl-cb"
1040
- version = "0.3.16"
1040
+ version = "0.3.18"
1041
1041
  dependencies = [
1042
1042
  "hashbrown 0.15.5",
1043
1043
  "owl-dl-core",
@@ -1045,7 +1045,7 @@ dependencies = [
1045
1045
 
1046
1046
  [[package]]
1047
1047
  name = "owl-dl-cli"
1048
- version = "0.3.16"
1048
+ version = "0.3.18"
1049
1049
  dependencies = [
1050
1050
  "anyhow",
1051
1051
  "clap",
@@ -1058,7 +1058,7 @@ dependencies = [
1058
1058
 
1059
1059
  [[package]]
1060
1060
  name = "owl-dl-core"
1061
- version = "0.3.16"
1061
+ version = "0.3.18"
1062
1062
  dependencies = [
1063
1063
  "bitvec",
1064
1064
  "bumpalo",
@@ -1072,7 +1072,7 @@ dependencies = [
1072
1072
 
1073
1073
  [[package]]
1074
1074
  name = "owl-dl-datatypes"
1075
- version = "0.3.16"
1075
+ version = "0.3.18"
1076
1076
  dependencies = [
1077
1077
  "owl-dl-core",
1078
1078
  "proptest",
@@ -1082,7 +1082,7 @@ dependencies = [
1082
1082
 
1083
1083
  [[package]]
1084
1084
  name = "owl-dl-py"
1085
- version = "0.3.16"
1085
+ version = "0.3.18"
1086
1086
  dependencies = [
1087
1087
  "horned-owl",
1088
1088
  "owl-dl-core",
@@ -1093,7 +1093,7 @@ dependencies = [
1093
1093
 
1094
1094
  [[package]]
1095
1095
  name = "owl-dl-reasoner"
1096
- version = "0.3.16"
1096
+ version = "0.3.18"
1097
1097
  dependencies = [
1098
1098
  "dashmap",
1099
1099
  "fixedbitset",
@@ -1110,7 +1110,7 @@ dependencies = [
1110
1110
 
1111
1111
  [[package]]
1112
1112
  name = "owl-dl-saturation"
1113
- version = "0.3.16"
1113
+ version = "0.3.18"
1114
1114
  dependencies = [
1115
1115
  "dashmap",
1116
1116
  "fixedbitset",
@@ -1126,7 +1126,7 @@ dependencies = [
1126
1126
 
1127
1127
  [[package]]
1128
1128
  name = "owl-dl-tableau"
1129
- version = "0.3.16"
1129
+ version = "0.3.18"
1130
1130
  dependencies = [
1131
1131
  "bitvec",
1132
1132
  "bumpalo",
@@ -2552,7 +2552,7 @@ dependencies = [
2552
2552
 
2553
2553
  [[package]]
2554
2554
  name = "xtask"
2555
- version = "0.3.16"
2555
+ version = "0.3.18"
2556
2556
  dependencies = [
2557
2557
  "anyhow",
2558
2558
  "clap",
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/owl-dl-core", "crates/owl-dl-saturation", "crates/owl-dl-tableau", "crates/owl-dl-datatypes", "crates/owl-dl-reasoner", "crates/owl-dl-py"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.3.16"
6
+ version = "0.3.18"
7
7
  edition = "2024"
8
8
  rust-version = "1.88"
9
9
  license = "Apache-2.0 OR MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rustdl
3
- Version: 0.3.16
3
+ Version: 0.3.18
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -6,7 +6,7 @@ consequence-based **saturation** engine handles the EL-ish fragment, a
6
6
  orchestrator picks per query. Parsing and the OWL model come from
7
7
  [`horned-owl`](https://github.com/phillord/horned-owl).
8
8
 
9
- ## Status (v0.3.12)
9
+ ## Status (v0.3.16)
10
10
 
11
11
  A working classifier, consistency checker, and instance reasoner for SROIQ(D)
12
12
  with first-class data properties. The defining property is **soundness**: every
@@ -17,10 +17,13 @@ reported subsumption is a genuine entailment.
17
17
  nothing that neither complete reasoner does.
18
18
  - **Fastest on EL.** rustdl's saturation kernel beats whelk-rs (1.4–1.9×) and ELK
19
19
  (4.5×) on galen/notgalen, deriving a sound *superset* of their closures.
20
- - **Competitive on DL, not the speed leader.** After recent work, most DL
21
- ontologies classify within ~10–50× of Konclude (the mature C++ tableau, which
22
- wins on speed); HermiT is slower still and itself DNFs on a hard tail.
23
- **wine** is rustdl's one DNF (combinatorial nominal+disjunction).
20
+ - **Competitive on DL, not the speed leader.** Most DL ontologies classify
21
+ within ~10–50× of Konclude (the mature C++ tableau, which wins on speed);
22
+ HermiT is slower still and itself DNFs on a hard tail. **wine — once rustdl's
23
+ one DNF (combinatorial nominal+disjunction) — now classifies soundly in ~1.6 s**
24
+ (a ~30× reduction from the coupled-saturation ∃-seed plus wedge search-ordering
25
+ work; see the [v0.3.16 snapshot](docs/perf-2026-06-27-bench-snapshot.md)). A
26
+ residual of ~9 idiosyncratic ORE-pilot ontologies stays hard.
24
27
  - Detects the **family** inconsistency (a consequence-based ABox-saturation
25
28
  pre-check) that the per-pair tableau alone misses.
26
29
  - **Explains *and* debugs — a full suite.** Built-in CLI commands turn rustdl into
@@ -150,6 +153,7 @@ license; no separate CLA.
150
153
 
151
154
  ## More
152
155
 
156
+ - Latest benchmark snapshot: [`docs/perf-2026-06-27-bench-snapshot.md`](docs/perf-2026-06-27-bench-snapshot.md)
153
157
  - Reasoner comparison: [`docs/reasoner-comparison-2026-06-21.md`](docs/reasoner-comparison-2026-06-21.md)
154
158
  - Perf vs Konclude/HermiT: [`docs/perf-2026-06-08-konclude-vs-rustdl.md`](docs/perf-2026-06-08-konclude-vs-rustdl.md)
155
159
  - Completeness envelope: [`docs/fragment-completeness.md`](docs/fragment-completeness.md)
@@ -6,7 +6,7 @@ consequence-based **saturation** engine handles the EL-ish fragment, a
6
6
  orchestrator picks per query. Parsing and the OWL model come from
7
7
  [`horned-owl`](https://github.com/phillord/horned-owl).
8
8
 
9
- ## Status (v0.3.12)
9
+ ## Status (v0.3.16)
10
10
 
11
11
  A working classifier, consistency checker, and instance reasoner for SROIQ(D)
12
12
  with first-class data properties. The defining property is **soundness**: every
@@ -17,10 +17,13 @@ reported subsumption is a genuine entailment.
17
17
  nothing that neither complete reasoner does.
18
18
  - **Fastest on EL.** rustdl's saturation kernel beats whelk-rs (1.4–1.9×) and ELK
19
19
  (4.5×) on galen/notgalen, deriving a sound *superset* of their closures.
20
- - **Competitive on DL, not the speed leader.** After recent work, most DL
21
- ontologies classify within ~10–50× of Konclude (the mature C++ tableau, which
22
- wins on speed); HermiT is slower still and itself DNFs on a hard tail.
23
- **wine** is rustdl's one DNF (combinatorial nominal+disjunction).
20
+ - **Competitive on DL, not the speed leader.** Most DL ontologies classify
21
+ within ~10–50× of Konclude (the mature C++ tableau, which wins on speed);
22
+ HermiT is slower still and itself DNFs on a hard tail. **wine — once rustdl's
23
+ one DNF (combinatorial nominal+disjunction) — now classifies soundly in ~1.6 s**
24
+ (a ~30× reduction from the coupled-saturation ∃-seed plus wedge search-ordering
25
+ work; see the [v0.3.16 snapshot](docs/perf-2026-06-27-bench-snapshot.md)). A
26
+ residual of ~9 idiosyncratic ORE-pilot ontologies stays hard.
24
27
  - Detects the **family** inconsistency (a consequence-based ABox-saturation
25
28
  pre-check) that the per-pair tableau alone misses.
26
29
  - **Explains *and* debugs — a full suite.** Built-in CLI commands turn rustdl into
@@ -150,6 +153,7 @@ license; no separate CLA.
150
153
 
151
154
  ## More
152
155
 
156
+ - Latest benchmark snapshot: [`docs/perf-2026-06-27-bench-snapshot.md`](docs/perf-2026-06-27-bench-snapshot.md)
153
157
  - Reasoner comparison: [`docs/reasoner-comparison-2026-06-21.md`](docs/reasoner-comparison-2026-06-21.md)
154
158
  - Perf vs Konclude/HermiT: [`docs/perf-2026-06-08-konclude-vs-rustdl.md`](docs/perf-2026-06-08-konclude-vs-rustdl.md)
155
159
  - Completeness envelope: [`docs/fragment-completeness.md`](docs/fragment-completeness.md)
@@ -1,7 +1,7 @@
1
1
  //! `classify` / `classify_bytes` top-level functions + the
2
2
  //! `Classification` `PyO3` class that wraps `owl_dl_reasoner::Classification`.
3
3
 
4
- use owl_dl_reasoner::{Classification as RsClassification, classify as rs_classify};
4
+ use owl_dl_reasoner::Classification as RsClassification;
5
5
  use pyo3::prelude::*;
6
6
 
7
7
  use crate::errors::reason_error_to_py;
@@ -51,7 +51,8 @@ impl PyClassification {
51
51
  /// True iff classification ran to completion — no pair hit the
52
52
  /// timeout. When `False`, the hierarchy may be missing real
53
53
  /// subsumptions (see `timed_out_pairs`); re-classify with
54
- /// `per_pair_timeout_ms=0` for the complete (unbounded) result.
54
+ /// `per_pair_timeout_ms=0, global_deadline_ms=0` for the complete
55
+ /// (unbounded) result.
55
56
  #[getter]
56
57
  fn complete(&self) -> bool {
57
58
  self.inner.stats().timed_out_pairs == 0
@@ -94,46 +95,67 @@ impl PyClassification {
94
95
  /// Format auto-detected from the file extension
95
96
  /// (`.ofn` | `.owx` | `.owl` | `.rdf` | `.omn`).
96
97
  #[pyfunction]
97
- #[pyo3(signature = (path, *, per_pair_timeout_ms=1000, saturation_only=false))]
98
+ #[pyo3(signature = (path, *, per_pair_timeout_ms=100, global_deadline_ms=60000, saturation_only=false))]
98
99
  pub(crate) fn classify(
99
100
  path: &str,
100
101
  per_pair_timeout_ms: Option<u64>,
102
+ global_deadline_ms: Option<u64>,
101
103
  saturation_only: bool,
102
104
  ) -> PyResult<PyClassification> {
103
105
  let ontology = load::load_path(path)?;
104
- do_classify(&ontology, per_pair_timeout_ms, saturation_only)
106
+ do_classify(
107
+ &ontology,
108
+ per_pair_timeout_ms,
109
+ global_deadline_ms,
110
+ saturation_only,
111
+ )
105
112
  }
106
113
 
107
114
  /// `rustdl.classify_bytes(data, format="ofn")` — same but from bytes.
108
115
  /// `format` is one of `"ofn"`, `"owx"`, `"rdf-xml"`, `"omn"`.
109
116
  #[pyfunction]
110
- #[pyo3(signature = (data, *, format, per_pair_timeout_ms=1000, saturation_only=false))]
117
+ #[pyo3(signature = (data, *, format, per_pair_timeout_ms=100, global_deadline_ms=60000, saturation_only=false))]
111
118
  pub(crate) fn classify_bytes(
112
119
  data: &[u8],
113
120
  format: &str,
114
121
  per_pair_timeout_ms: Option<u64>,
122
+ global_deadline_ms: Option<u64>,
115
123
  saturation_only: bool,
116
124
  ) -> PyResult<PyClassification> {
117
125
  let ontology = load::load_bytes(data, format)?;
118
- do_classify(&ontology, per_pair_timeout_ms, saturation_only)
126
+ do_classify(
127
+ &ontology,
128
+ per_pair_timeout_ms,
129
+ global_deadline_ms,
130
+ saturation_only,
131
+ )
119
132
  }
120
133
 
121
134
  fn do_classify(
122
135
  ontology: &horned_owl::ontology::set::SetOntology<horned_owl::model::RcStr>,
123
136
  per_pair_timeout_ms: Option<u64>,
137
+ global_deadline_ms: Option<u64>,
124
138
  saturation_only: bool,
125
139
  ) -> PyResult<PyClassification> {
126
140
  use std::time::Duration;
127
- // `None` or `0` unbounded (complete); any positive value bounds
128
- // each pair (sound under-approximation; check `.complete` after).
129
- let bounded = per_pair_timeout_ms.filter(|&ms| ms > 0);
141
+ // Two independent bounds (`0`/`None` disables that one): `per_pair`
142
+ // bounds any single `sub ⊓ ¬sup` pair; the global wall-budget bounds the
143
+ // TOTAL run so it can't grow with the pair count (the backstop against
144
+ // wine-class hangs). Each probe is cut at min(per_pair, remaining global).
145
+ // Cutting is a SOUND under-approximation — no false subsumptions; real
146
+ // ones may be missing (check `.complete` / `.timed_out_pairs`). Both
147
+ // disabled ⇒ unbounded/complete.
148
+ let per_pair = per_pair_timeout_ms
149
+ .filter(|&ms| ms > 0)
150
+ .map(Duration::from_millis);
151
+ let global = global_deadline_ms
152
+ .filter(|&ms| ms > 0)
153
+ .map(Duration::from_millis);
130
154
  let inner = if saturation_only {
131
155
  owl_dl_reasoner::classify_saturation_only(ontology).map_err(reason_error_to_py)?
132
- } else if let Some(ms) = bounded {
133
- owl_dl_reasoner::classify_top_down_with_timeout(ontology, Duration::from_millis(ms))
134
- .map_err(reason_error_to_py)?
135
156
  } else {
136
- rs_classify(ontology).map_err(reason_error_to_py)?
157
+ owl_dl_reasoner::classify_with_budget(ontology, per_pair, global)
158
+ .map_err(reason_error_to_py)?
137
159
  };
138
160
  Ok(PyClassification { inner })
139
161
  }
@@ -6,7 +6,7 @@ consequence-based **saturation** engine handles the EL-ish fragment, a
6
6
  orchestrator picks per query. Parsing and the OWL model come from
7
7
  [`horned-owl`](https://github.com/phillord/horned-owl).
8
8
 
9
- ## Status (v0.3.12)
9
+ ## Status (v0.3.16)
10
10
 
11
11
  A working classifier, consistency checker, and instance reasoner for SROIQ(D)
12
12
  with first-class data properties. The defining property is **soundness**: every
@@ -17,10 +17,13 @@ reported subsumption is a genuine entailment.
17
17
  nothing that neither complete reasoner does.
18
18
  - **Fastest on EL.** rustdl's saturation kernel beats whelk-rs (1.4–1.9×) and ELK
19
19
  (4.5×) on galen/notgalen, deriving a sound *superset* of their closures.
20
- - **Competitive on DL, not the speed leader.** After recent work, most DL
21
- ontologies classify within ~10–50× of Konclude (the mature C++ tableau, which
22
- wins on speed); HermiT is slower still and itself DNFs on a hard tail.
23
- **wine** is rustdl's one DNF (combinatorial nominal+disjunction).
20
+ - **Competitive on DL, not the speed leader.** Most DL ontologies classify
21
+ within ~10–50× of Konclude (the mature C++ tableau, which wins on speed);
22
+ HermiT is slower still and itself DNFs on a hard tail. **wine — once rustdl's
23
+ one DNF (combinatorial nominal+disjunction) — now classifies soundly in ~1.6 s**
24
+ (a ~30× reduction from the coupled-saturation ∃-seed plus wedge search-ordering
25
+ work; see the [v0.3.16 snapshot](docs/perf-2026-06-27-bench-snapshot.md)). A
26
+ residual of ~9 idiosyncratic ORE-pilot ontologies stays hard.
24
27
  - Detects the **family** inconsistency (a consequence-based ABox-saturation
25
28
  pre-check) that the per-pair tableau alone misses.
26
29
  - **Explains *and* debugs — a full suite.** Built-in CLI commands turn rustdl into
@@ -150,6 +153,7 @@ license; no separate CLA.
150
153
 
151
154
  ## More
152
155
 
156
+ - Latest benchmark snapshot: [`docs/perf-2026-06-27-bench-snapshot.md`](docs/perf-2026-06-27-bench-snapshot.md)
153
157
  - Reasoner comparison: [`docs/reasoner-comparison-2026-06-21.md`](docs/reasoner-comparison-2026-06-21.md)
154
158
  - Perf vs Konclude/HermiT: [`docs/perf-2026-06-08-konclude-vs-rustdl.md`](docs/perf-2026-06-08-konclude-vs-rustdl.md)
155
159
  - Completeness envelope: [`docs/fragment-completeness.md`](docs/fragment-completeness.md)
@@ -318,6 +318,17 @@ pub fn saturate_abox_consistency(internal: &InternalOntology) -> SaturationResul
318
318
  }
319
319
  }
320
320
  }
321
+ Axiom::TransitiveRole(r) => {
322
+ // Transitivity is the self-chain `R ∘ R ⊑ R`; registering it as a
323
+ // length-2 chain lets the Rule-4 fixpoint close the full transitive
324
+ // closure of `R`-edges — jointly with the role hierarchy, inverse
325
+ // materialization, and declared chains (a transitive edge can feed
326
+ // a sub-property/chain rule and vice-versa). The inverse of a
327
+ // transitive role is transitive too, and is covered by inverse
328
+ // materialization re-running over the closed forward edges.
329
+ let k = role_key(*r);
330
+ chains2.push((k, k, k));
331
+ }
321
332
  Axiom::ObjectPropertyDomain { role, domain } => {
322
333
  if let Some(d) = atomic_class(*domain) {
323
334
  domains.entry(role_key(*role)).or_default().push(d);
@@ -438,6 +438,30 @@ pub fn classify_with_global_deadline<A: ForIRI>(
438
438
  classify_top_down_internal(&internal, None, Some(deadline))
439
439
  }
440
440
 
441
+ /// Classify with BOTH a per-pair tableau deadline and a global wall-clock
442
+ /// budget — the recommended bounded entry point. Each probe is cut at
443
+ /// `min(per_pair, remaining global)` (see [`effective_deadline`]); `per_pair`
444
+ /// bounds any single pair, `global_budget` bounds the total wall so the run
445
+ /// can't grow with the pair count. Either may be `None` (that bound absent;
446
+ /// both `None` ⇒ the unbounded top-down classify).
447
+ ///
448
+ /// **Sound** at every setting: a cut probe defaults to "not subsumed"
449
+ /// (FP=0; the hierarchy may MISS a real subsumption — inspect
450
+ /// [`ClassificationStats`]`::complete` / `timed_out_pairs`).
451
+ ///
452
+ /// # Errors
453
+ ///
454
+ /// See [`ReasonError`].
455
+ pub fn classify_with_budget<A: ForIRI>(
456
+ ontology: &SetOntology<A>,
457
+ per_pair_timeout: Option<std::time::Duration>,
458
+ global_budget: Option<std::time::Duration>,
459
+ ) -> Result<Classification, ReasonError> {
460
+ let internal = convert_ontology(ontology)?;
461
+ let global_deadline = global_budget.map(|b| Instant::now() + b);
462
+ classify_top_down_internal(&internal, per_pair_timeout, global_deadline)
463
+ }
464
+
441
465
  /// Naive `n²` pair-sweep classifier. Kept for benchmarking and
442
466
  /// regression cross-checks against [`classify`]. On real workloads
443
467
  /// it is consistently 2× slower than the default top-down path; new
@@ -54,8 +54,8 @@ mod union_find;
54
54
  pub use classify::{
55
55
  Classification, ClassificationStats, FragmentClassification, analyze_fragment, classify,
56
56
  classify_internal, classify_n2, classify_n2_with_timeout, classify_saturation_only,
57
- classify_top_down, classify_top_down_with_timeout, classify_with_global_deadline,
58
- classify_with_timeout,
57
+ classify_top_down, classify_top_down_with_timeout, classify_with_budget,
58
+ classify_with_global_deadline, classify_with_timeout,
59
59
  };
60
60
  pub use diagnose::{DerivedClass, Diagnosis, diagnose};
61
61
  pub use laconic::{find_all_laconic_justifications, find_laconic_justification};
@@ -51,6 +51,81 @@ fn subproperty_entailed_assertions() {
51
51
  assert!(!got.contains(&triple("urn:a", "urn:hasAncestor", "urn:a")));
52
52
  }
53
53
 
54
+ /// Issue #26: a `TransitiveObjectProperty` must materialize the full transitive
55
+ /// closure of its asserted edges, not just the one-step edges.
56
+ #[test]
57
+ fn transitive_closure_materialized() {
58
+ let b = Build::new_rc();
59
+ let mut o = SetOntology::new();
60
+ o.insert(DeclareObjectProperty(b.object_property("urn:ancestorOf")));
61
+ o.insert(horned_owl::model::TransitiveObjectProperty(
62
+ ObjectPropertyExpression::ObjectProperty(b.object_property("urn:ancestorOf")),
63
+ ));
64
+ for i in ["urn:a", "urn:b", "urn:c", "urn:d"] {
65
+ o.insert(horned_owl::model::DeclareNamedIndividual(
66
+ b.named_individual(i),
67
+ ));
68
+ }
69
+ o.insert(opa(&b, "urn:ancestorOf", "urn:a", "urn:b"));
70
+ o.insert(opa(&b, "urn:ancestorOf", "urn:b", "urn:c"));
71
+ o.insert(opa(&b, "urn:ancestorOf", "urn:c", "urn:d"));
72
+
73
+ let got = materialize_object_property_assertions(&o).expect("materialize");
74
+ let t = |s: &str, x: &str| (s.to_string(), "urn:ancestorOf".to_string(), x.to_string());
75
+ // one-step (already worked)
76
+ assert!(got.contains(&t("urn:a", "urn:b")), "got: {got:?}");
77
+ assert!(got.contains(&t("urn:b", "urn:c")), "got: {got:?}");
78
+ assert!(got.contains(&t("urn:c", "urn:d")), "got: {got:?}");
79
+ // transitive closure (the regression)
80
+ assert!(got.contains(&t("urn:a", "urn:c")), "a⊑c missing: {got:?}");
81
+ assert!(got.contains(&t("urn:b", "urn:d")), "b⊑d missing: {got:?}");
82
+ assert!(got.contains(&t("urn:a", "urn:d")), "a⊑d missing: {got:?}");
83
+ }
84
+
85
+ /// Issue #26 larger case: sub-property + inverse + transitivity compose, so the
86
+ /// transitive edge through the sub-property/inverse rewrites is materialized.
87
+ #[test]
88
+ fn transitive_with_subproperty_and_inverse() {
89
+ let b = Build::new_rc();
90
+ let mut o = SetOntology::new();
91
+ for p in ["urn:hasParent", "urn:hasChild", "urn:hasAncestor"] {
92
+ o.insert(DeclareObjectProperty(b.object_property(p)));
93
+ }
94
+ for i in ["urn:alice", "urn:mary", "urn:john"] {
95
+ o.insert(horned_owl::model::DeclareNamedIndividual(
96
+ b.named_individual(i),
97
+ ));
98
+ }
99
+ // hasParent ⊑ hasAncestor ; hasAncestor transitive ; hasChild ≡ hasParent⁻
100
+ o.insert(SubObjectPropertyOf {
101
+ sub: SubObjectPropertyExpression::ObjectPropertyExpression(
102
+ ObjectPropertyExpression::ObjectProperty(b.object_property("urn:hasParent")),
103
+ ),
104
+ sup: ObjectPropertyExpression::ObjectProperty(b.object_property("urn:hasAncestor")),
105
+ });
106
+ o.insert(horned_owl::model::TransitiveObjectProperty(
107
+ ObjectPropertyExpression::ObjectProperty(b.object_property("urn:hasAncestor")),
108
+ ));
109
+ o.insert(horned_owl::model::InverseObjectProperties(
110
+ b.object_property("urn:hasChild"),
111
+ b.object_property("urn:hasParent"),
112
+ ));
113
+ o.insert(opa(&b, "urn:hasChild", "urn:mary", "urn:alice")); // mary hasChild alice
114
+ o.insert(opa(&b, "urn:hasParent", "urn:mary", "urn:john")); // mary hasParent john
115
+
116
+ let got = materialize_object_property_assertions(&o).expect("materialize");
117
+ let anc = |s: &str, x: &str| (s.to_string(), "urn:hasAncestor".to_string(), x.to_string());
118
+ // alice hasParent mary (inverse) ⟹ alice hasAncestor mary (sub-property)
119
+ assert!(got.contains(&anc("urn:alice", "urn:mary")), "got: {got:?}");
120
+ // mary hasAncestor john (sub-property)
121
+ assert!(got.contains(&anc("urn:mary", "urn:john")), "got: {got:?}");
122
+ // the composed edge (the regression): alice hasAncestor john
123
+ assert!(
124
+ got.contains(&anc("urn:alice", "urn:john")),
125
+ "composed alice⊑john missing: {got:?}"
126
+ );
127
+ }
128
+
54
129
  use owl_dl_reasoner::justify::{Entailment, entails};
55
130
 
56
131
  #[test]
@@ -6,7 +6,7 @@ consequence-based **saturation** engine handles the EL-ish fragment, a
6
6
  orchestrator picks per query. Parsing and the OWL model come from
7
7
  [`horned-owl`](https://github.com/phillord/horned-owl).
8
8
 
9
- ## Status (v0.3.12)
9
+ ## Status (v0.3.16)
10
10
 
11
11
  A working classifier, consistency checker, and instance reasoner for SROIQ(D)
12
12
  with first-class data properties. The defining property is **soundness**: every
@@ -17,10 +17,13 @@ reported subsumption is a genuine entailment.
17
17
  nothing that neither complete reasoner does.
18
18
  - **Fastest on EL.** rustdl's saturation kernel beats whelk-rs (1.4–1.9×) and ELK
19
19
  (4.5×) on galen/notgalen, deriving a sound *superset* of their closures.
20
- - **Competitive on DL, not the speed leader.** After recent work, most DL
21
- ontologies classify within ~10–50× of Konclude (the mature C++ tableau, which
22
- wins on speed); HermiT is slower still and itself DNFs on a hard tail.
23
- **wine** is rustdl's one DNF (combinatorial nominal+disjunction).
20
+ - **Competitive on DL, not the speed leader.** Most DL ontologies classify
21
+ within ~10–50× of Konclude (the mature C++ tableau, which wins on speed);
22
+ HermiT is slower still and itself DNFs on a hard tail. **wine — once rustdl's
23
+ one DNF (combinatorial nominal+disjunction) — now classifies soundly in ~1.6 s**
24
+ (a ~30× reduction from the coupled-saturation ∃-seed plus wedge search-ordering
25
+ work; see the [v0.3.16 snapshot](docs/perf-2026-06-27-bench-snapshot.md)). A
26
+ residual of ~9 idiosyncratic ORE-pilot ontologies stays hard.
24
27
  - Detects the **family** inconsistency (a consequence-based ABox-saturation
25
28
  pre-check) that the per-pair tableau alone misses.
26
29
  - **Explains *and* debugs — a full suite.** Built-in CLI commands turn rustdl into
@@ -150,6 +153,7 @@ license; no separate CLA.
150
153
 
151
154
  ## More
152
155
 
156
+ - Latest benchmark snapshot: [`docs/perf-2026-06-27-bench-snapshot.md`](docs/perf-2026-06-27-bench-snapshot.md)
153
157
  - Reasoner comparison: [`docs/reasoner-comparison-2026-06-21.md`](docs/reasoner-comparison-2026-06-21.md)
154
158
  - Perf vs Konclude/HermiT: [`docs/perf-2026-06-08-konclude-vs-rustdl.md`](docs/perf-2026-06-08-konclude-vs-rustdl.md)
155
159
  - Completeness envelope: [`docs/fragment-completeness.md`](docs/fragment-completeness.md)
@@ -0,0 +1,161 @@
1
+ # rustdl
2
+
3
+ A **sound** OWL 2 DL (SROIQ) reasoner in Rust. Konclude-style hybrid: a
4
+ consequence-based **saturation** engine handles the EL-ish fragment, a
5
+ **tableau** + hypertableau **wedge** handles the rest of SROIQ, and an
6
+ orchestrator picks per query. Parsing and the OWL model come from
7
+ [`horned-owl`](https://github.com/phillord/horned-owl).
8
+
9
+ ## Status (v0.3.16)
10
+
11
+ A working classifier, consistency checker, and instance reasoner for SROIQ(D)
12
+ with first-class data properties. The defining property is **soundness**: every
13
+ reported subsumption is a genuine entailment.
14
+
15
+ - **FP = 0 at scale.** Verified against the Konclude ∩ HermiT oracle across all
16
+ 201 diffed ORE-2015 pilot ontologies *and* the curated corpus — rustdl asserts
17
+ nothing that neither complete reasoner does.
18
+ - **Fastest on EL.** rustdl's saturation kernel beats whelk-rs (1.4–1.9×) and ELK
19
+ (4.5×) on galen/notgalen, deriving a sound *superset* of their closures.
20
+ - **Competitive on DL, not the speed leader.** Most DL ontologies classify
21
+ within ~10–50× of Konclude (the mature C++ tableau, which wins on speed);
22
+ HermiT is slower still and itself DNFs on a hard tail. **wine — once rustdl's
23
+ one DNF (combinatorial nominal+disjunction) — now classifies soundly in ~1.6 s**
24
+ (a ~30× reduction from the coupled-saturation ∃-seed plus wedge search-ordering
25
+ work; see the [v0.3.16 snapshot](docs/perf-2026-06-27-bench-snapshot.md)). A
26
+ residual of ~9 idiosyncratic ORE-pilot ontologies stays hard.
27
+ - Detects the **family** inconsistency (a consequence-based ABox-saturation
28
+ pre-check) that the per-pair tableau alone misses.
29
+ - **Explains *and* debugs — a full suite.** Built-in CLI commands turn rustdl into
30
+ an ontology-debugging tool, not just a classifier:
31
+ - `justify` — a minimal responsible-axiom set for any entailment (`--laconic`
32
+ weakens each axiom to its responsible *fragment*).
33
+ - `prove` — a step-level proof tree.
34
+ - `diagnose` — partitions unsatisfiable classes into **root** causes vs **derived**
35
+ collateral ("where to start fixing").
36
+ - `repair` — minimal axiom-removal sets to *break* an unwanted entailment, each
37
+ verified.
38
+ - `report` — a self-contained HTML debugging report combining all of the above.
39
+
40
+ Every result is **sound by construction** (justifications and repairs are verified
41
+ against the reasoner). **Konclude** (the DL speed leader) has **no built-in
42
+ justification or explanation facility** at all (its interface is classification /
43
+ consistency / realization / SPARQL only) — so the fastest reasoner tells you *that*
44
+ a subsumption holds but not *why*, or *how to fix* a broken ontology. rustdl does.
45
+
46
+ Full head-to-head (5 reasoners × 2 corpora):
47
+ [`docs/reasoner-comparison-2026-06-21.md`](docs/reasoner-comparison-2026-06-21.md).
48
+
49
+ **Completeness is partial** — the default classifier is empirically near-complete
50
+ across the measured corpus but not *provably* complete in general (it trusts the
51
+ wedge's `Sat` verdicts; see the soundness contract in `CLAUDE.md` and
52
+ [`docs/fragment-completeness.md`](docs/fragment-completeness.md)). The hard residual
53
+ is the engineering-maturity gap to Konclude's optimized tableau, not a missing
54
+ technique.
55
+
56
+ ## Coverage
57
+
58
+ **Supported (sound; complete on the fragment, oracle-validated):**
59
+
60
+ - SROIQ object-property reasoning — role hierarchies; transitive, symmetric,
61
+ asymmetric, irreflexive, functional, inverse-functional; inverse roles; role
62
+ chains (longer chains decomposed to 2-leg cascades).
63
+ - Class expressions — intersection, union, complement, nominals (`{a}`),
64
+ existential / universal restrictions, qualified cardinality (`≥n R.C`, `≤n R.C`).
65
+ - `DisjointClasses`, `EquivalentClasses`, `DisjointUnion`.
66
+ - ABox — `ClassAssertion`, `ObjectPropertyAssertion`,
67
+ `NegativeObjectPropertyAssertion`, `SameIndividual`, `DifferentIndividuals`;
68
+ consistency via an ABox-saturation pre-check + clash-pattern checks.
69
+ - **Data properties are first-class** (default-on) — data-property axioms lower to
70
+ the object fragment; concrete domains cover integer / float / decimal / date /
71
+ dateTime / string value-membership, faceted ranges, `DataOneOf`, and bounded
72
+ data cardinality.
73
+
74
+ **Sound under-approximation (silently dropped, never an error):** data ranges /
75
+ nested composites outside the recognized set; positives depending on them may be
76
+ missed, never falsely asserted.
77
+
78
+ **Unsupported (errors):** `HasKey`. SWRL rules are skipped (see `convert.rs`).
79
+
80
+ ## Crates
81
+
82
+ `owl-dl-core` (IR + normalization), `owl-dl-saturation` (EL closure),
83
+ `owl-dl-tableau` (SROIQ tableau + hypertableau wedge), `owl-dl-datatypes`
84
+ (concrete domains), `owl-dl-reasoner` (orchestrator + public API), `owl-dl-cli`
85
+ (`rustdl` binary), `owl-dl-bench` (corpus/benchmark harness), `owl-dl-py` (Python
86
+ bindings). `xtask` holds build automation.
87
+
88
+ ## Install
89
+
90
+ ```sh
91
+ cargo add owl-dl-reasoner # library
92
+ cargo install --git https://github.com/MaastrichtU-IDS/rustdl owl-dl-cli # CLI
93
+ pip install rustdl # Python 3.10+ (ABI3)
94
+ ```
95
+
96
+ ```python
97
+ import rustdl
98
+ result = rustdl.classify("ontology.ofn") # OFN / OWX / RDF-XML / Manchester (.omn) — auto-detected
99
+ print(f"{len(result.classes)} classes; {len(result.unsatisfiable)} unsat")
100
+ print(result.is_subclass("http://ex.org/Sub", "http://ex.org/Sup"))
101
+ ok = rustdl.is_consistent("ontology.ofn")
102
+ edges = rustdl.materialize_inferred_property_assertions("ontology.ofn") # inferred object property assertions
103
+ data_edges = rustdl.materialize_inferred_data_property_assertions("ontology.ofn") # inferred data property assertions
104
+ sub_obj = rustdl.materialize_inferred_subobjectproperty_axioms("ontology.ofn") # object property hierarchy
105
+ sub_dat = rustdl.materialize_inferred_subdataproperty_axioms("ontology.ofn") # data property hierarchy
106
+ succ = rustdl.materialize_existential_successors("ontology.ofn") # entailed exists-successors (blank-node witnesses)
107
+ report = rustdl.debug("ontology.ofn") # consistency + root/derived unsat + justifications + repairs
108
+ ```
109
+
110
+ New to the Python API? Walk through
111
+ [**Debugging an ontology with rustdl**](docs/python-ontology-qa.md) — an end-to-end
112
+ QA tutorial (classify → `debug()` → justify/repair → fix → read inferred facts).
113
+
114
+ ## Build & test
115
+
116
+ ```sh
117
+ cargo build --workspace --release # Rust 1.88+, edition 2024
118
+ cargo fmt --all -- --check
119
+ cargo clippy --workspace --all-targets --all-features -- -D warnings
120
+ cargo test --workspace
121
+ ```
122
+
123
+ ## CLI
124
+
125
+ ```sh
126
+ rustdl classify ontology.ofn # full class hierarchy (default)
127
+ rustdl consistent ontology.ofn
128
+ rustdl subclass ontology.ofn <sub> <sup>
129
+ rustdl instances ontology.ofn <class>
130
+ rustdl realize ontology.ofn [--properties] # per-individual types (+ inferred object & data property assertions)
131
+ rustdl justify ontology.ofn <query…> # minimal responsible-axiom set (why it holds)
132
+ rustdl justify --laconic ontology.ofn <query…> # pinpoint the responsible PART of each axiom
133
+ rustdl repair ontology.ofn <query…> # minimal axiom removals to break an entailment
134
+ rustdl prove ontology.ofn <sub> <sup> # step-level DL proof tree
135
+ rustdl diagnose ontology.ofn # root vs derived unsatisfiable classes (where to start fixing)
136
+ rustdl report ontology.ofn -o report.html # self-contained HTML debugging report
137
+ rustdl explain ontology.ofn <sub> <sup> # which engine answered (saturation vs tableau)
138
+ ```
139
+
140
+ Sound under-approximation modes (every reported subsumption still holds; positives
141
+ may be missed): `--saturation-only` (skip the tableau, EL-closure only) and
142
+ `--pair-timeout-ms N` (per-pair tableau deadline; cut pairs default to "not
143
+ subsumed" — robust on pathological SROIQ inputs). Diagnostics: `RUSTDL_TRACE=1`
144
+ (one stderr line per search/branch decision); `RUSTDL_COUNTERS=1` with
145
+ `--features counters` (per-rule call counts).
146
+
147
+ ## Licensing
148
+
149
+ Dual-licensed [Apache-2.0](LICENSE-APACHE) **OR** [MIT](LICENSE-MIT). `horned-owl`
150
+ is LGPL-3.0; binaries that statically link it inherit LGPL-3.0 obligations for that
151
+ portion (see [`NOTICE`](NOTICE)). Contributions are accepted under the same dual
152
+ license; no separate CLA.
153
+
154
+ ## More
155
+
156
+ - Latest benchmark snapshot: [`docs/perf-2026-06-27-bench-snapshot.md`](docs/perf-2026-06-27-bench-snapshot.md)
157
+ - Reasoner comparison: [`docs/reasoner-comparison-2026-06-21.md`](docs/reasoner-comparison-2026-06-21.md)
158
+ - Perf vs Konclude/HermiT: [`docs/perf-2026-06-08-konclude-vs-rustdl.md`](docs/perf-2026-06-08-konclude-vs-rustdl.md)
159
+ - Completeness envelope: [`docs/fragment-completeness.md`](docs/fragment-completeness.md)
160
+ - Strategy: [`docs/owl-dl-reasoner-rust-strategy-v2.md`](docs/owl-dl-reasoner-rust-strategy-v2.md)
161
+ - Engineering notes & soundness contract: [`CLAUDE.md`](CLAUDE.md)