rustdl 0.3.24__tar.gz → 0.3.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 (252) hide show
  1. {rustdl-0.3.24 → rustdl-0.3.26}/Cargo.lock +10 -10
  2. {rustdl-0.3.24 → rustdl-0.3.26}/Cargo.toml +1 -1
  3. {rustdl-0.3.24 → rustdl-0.3.26}/PKG-INFO +1 -1
  4. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/classify.rs +225 -10
  5. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/lib.rs +145 -0
  6. rustdl-0.3.26/crates/owl-dl-reasoner/tests/tbox_only_classify.rs +66 -0
  7. {rustdl-0.3.24 → rustdl-0.3.26}/README.md +0 -0
  8. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/Cargo.toml +0 -0
  9. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/README.md +0 -0
  10. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/absorb.rs +0 -0
  11. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/approx_saturation.rs +0 -0
  12. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/clause.rs +0 -0
  13. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/convert.rs +0 -0
  14. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/convert_back.rs +0 -0
  15. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/data_axioms.rs +0 -0
  16. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/definitions.rs +0 -0
  17. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/disjunction_existential.rs +0 -0
  18. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/disjunctive_antecedent.rs +0 -0
  19. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/ir.rs +0 -0
  20. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/lib.rs +0 -0
  21. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/locality.rs +0 -0
  22. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/normalize.rs +0 -0
  23. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/ontology.rs +0 -0
  24. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/residual_trigger.rs +0 -0
  25. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/role_hierarchy.rs +0 -0
  26. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/told.rs +0 -0
  27. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/transform.rs +0 -0
  28. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/vocab.rs +0 -0
  29. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/tests/concept_pool_proptest.proptest-regressions +0 -0
  30. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/tests/concept_pool_proptest.rs +0 -0
  31. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/tests/convert_round_trip_proptest.rs +0 -0
  32. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/tests/role_hierarchy_proptest.rs +0 -0
  33. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-datatypes/Cargo.toml +0 -0
  34. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-datatypes/README.md +0 -0
  35. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-datatypes/src/lib.rs +0 -0
  36. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/.gitignore +0 -0
  37. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/Cargo.toml +0 -0
  38. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/README.md +0 -0
  39. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/.gitignore +0 -0
  40. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/README.md +0 -0
  41. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/__init__.py +0 -0
  42. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/fixtures/recorded_replies_clash.json +0 -0
  43. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/fixtures/seed.ofn +0 -0
  44. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/gate.py +0 -0
  45. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/llm.py +0 -0
  46. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/loop.py +0 -0
  47. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/candidate.ofn +0 -0
  48. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/current.ofn +0 -0
  49. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/metrics.md +0 -0
  50. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/transcript.jsonl +0 -0
  51. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/candidate.ofn +0 -0
  52. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/current.ofn +0 -0
  53. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/metrics.md +0 -0
  54. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/transcript.jsonl +0 -0
  55. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/requirements.txt +0 -0
  56. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/run.py +0 -0
  57. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/__init__.py +0 -0
  58. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_gate.py +0 -0
  59. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_llm.py +0 -0
  60. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_loop.py +0 -0
  61. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_run.py +0 -0
  62. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_seed.py +0 -0
  63. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/classify.rs +0 -0
  64. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/errors.rs +0 -0
  65. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/explain.rs +0 -0
  66. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/lib.rs +0 -0
  67. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/load.rs +0 -0
  68. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/materialize.rs +0 -0
  69. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/queries.rs +0 -0
  70. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/conftest.py +0 -0
  71. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_classify.py +0 -0
  72. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_examples.py +0 -0
  73. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_explain.py +0 -0
  74. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_manchester.py +0 -0
  75. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_materialize.py +0 -0
  76. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_queries.py +0 -0
  77. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_results.py +0 -0
  78. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_smoke.py +0 -0
  79. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_soundness.py +0 -0
  80. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_stubs.py +0 -0
  81. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_tutorial.py +0 -0
  82. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/Cargo.toml +0 -0
  83. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/README.md +0 -0
  84. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/examples/embed_classify.rs +0 -0
  85. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/abox_check.rs +0 -0
  86. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/abox_saturation.rs +0 -0
  87. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/diagnose.rs +0 -0
  88. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/justify.rs +0 -0
  89. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/laconic.rs +0 -0
  90. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/model_cache.rs +0 -0
  91. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/oracle_diff.rs +0 -0
  92. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/realize.rs +0 -0
  93. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/repair.rs +0 -0
  94. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/union_find.rs +0 -0
  95. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/abox_consistency.rs +0 -0
  96. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/abox_sat_fp_probe.rs +0 -0
  97. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/abox_saturation.rs +0 -0
  98. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/adaptive_budget.rs +0 -0
  99. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/anon349_diagnostic.rs +0 -0
  100. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/anonymous_individuals_identity.rs +0 -0
  101. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/anonymous_individuals_reporting.rs +0 -0
  102. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/approx_saturation_forced_disjunct.rs +0 -0
  103. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/backfold.rs +0 -0
  104. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/backjump_precision_gate.rs +0 -0
  105. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/blocked_disjunction_soundness.rs +0 -0
  106. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/blocked_disjunction_termination.rs +0 -0
  107. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/cardinality_disjunct_atoms.rs +0 -0
  108. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/classify_concrete_domain.rs +0 -0
  109. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/classify_defined_sweep.rs +0 -0
  110. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/classify_inverse_domain.rs +0 -0
  111. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/completeness_contract.rs +0 -0
  112. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/concrete_domain_clash.rs +0 -0
  113. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/data_properties.rs +0 -0
  114. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/data_property_assertions.rs +0 -0
  115. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/datatype_completeness.rs +0 -0
  116. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/datatype_inconsistency.rs +0 -0
  117. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/datatype_value_membership.rs +0 -0
  118. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/decide_pair_probe.rs +0 -0
  119. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/diagnose_partition.rs +0 -0
  120. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/disjunctive_existential_marker_fp.rs +0 -0
  121. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/domain_gci_completeness.rs +0 -0
  122. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/existential_successors.rs +0 -0
  123. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/exists_top_filler.rs +0 -0
  124. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_direct_bot.ofn +0 -0
  125. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_no_bot.ofn +0 -0
  126. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_different_individuals.ofn +0 -0
  127. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_types.ofn +0 -0
  128. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa.ofn +0 -0
  129. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa_no_clash.ofn +0 -0
  130. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_consistent.ofn +0 -0
  131. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_inconsistent.ofn +0 -0
  132. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_different.ofn +0 -0
  133. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_without_different.ofn +0 -0
  134. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_diff.ofn +0 -0
  135. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_same_target.ofn +0 -0
  136. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric.ofn +0 -0
  137. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric_one_way.ofn +0 -0
  138. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive.ofn +0 -0
  139. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive_distinct.ofn +0 -0
  140. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_compatible.ofn +0 -0
  141. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_disjoint.ofn +0 -0
  142. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_cardinality_disjoint.ofn +0 -0
  143. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain-classified.owx +0 -0
  144. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain.ofn +0 -0
  145. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition-classified.owx +0 -0
  146. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition.ofn +0 -0
  147. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_facet.ofn +0 -0
  148. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/functional_data_property.ofn +0 -0
  149. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property-classified.owx +0 -0
  150. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property.ofn +0 -0
  151. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/functional-equiv-some-bug.ofn +0 -0
  152. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/materialize/rbox-materialized.owx +0 -0
  153. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/materialize/rbox.ofn +0 -0
  154. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/named-pizza-country-bug.ofn +0 -0
  155. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-01.txt +0 -0
  156. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-02.txt +0 -0
  157. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-03.txt +0 -0
  158. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-04.txt +0 -0
  159. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-05.txt +0 -0
  160. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-06.txt +0 -0
  161. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-07.txt +0 -0
  162. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-08.txt +0 -0
  163. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.hermit.owx +0 -0
  164. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.ofn +0 -0
  165. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.owx +0 -0
  166. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.hermit.owx +0 -0
  167. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.ofn +0 -0
  168. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.owx +0 -0
  169. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.hermit.owx +0 -0
  170. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.ofn +0 -0
  171. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.owx +0 -0
  172. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.hermit.owx +0 -0
  173. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.ofn +0 -0
  174. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.owx +0 -0
  175. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.hermit.owx +0 -0
  176. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.ofn +0 -0
  177. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.owx +0 -0
  178. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.hermit.owx +0 -0
  179. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.ofn +0 -0
  180. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.owx +0 -0
  181. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.hermit.owx +0 -0
  182. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.ofn +0 -0
  183. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.owx +0 -0
  184. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.hermit.owx +0 -0
  185. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.ofn +0 -0
  186. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.owx +0 -0
  187. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/phase2b-verdicts.log +0 -0
  188. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/funcmerge_inverse.rs +0 -0
  189. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/funcmerge_scaling.rs +0 -0
  190. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/functional_enforcement.rs +0 -0
  191. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/inverse_cardinality_soundness.rs +0 -0
  192. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/inverse_symmetric_domain.rs +0 -0
  193. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/justification.rs +0 -0
  194. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/konclude_closure_diff.rs +0 -0
  195. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/label_heuristic_canary.rs +0 -0
  196. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/laconic_justification.rs +0 -0
  197. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/materialize_oracle.rs +0 -0
  198. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/object_has_self_domain.rs +0 -0
  199. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/phase2c_pair_06_canary.rs +0 -0
  200. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/precompletion_probe_gate.rs +0 -0
  201. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/property_assertions.rs +0 -0
  202. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/real_ontology_corpus.rs +0 -0
  203. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/repair_suggestions.rs +0 -0
  204. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/sat_lookahead_gate.rs +0 -0
  205. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/saturator_disjointness.rs +0 -0
  206. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/seed_probe_gate.rs +0 -0
  207. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/shadow_dep_gate.rs +0 -0
  208. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/snapshot_phase0_canary.rs +0 -0
  209. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/sp2_nogood_gate.rs +0 -0
  210. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/subproperty_axioms.rs +0 -0
  211. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/tautology_skip_canary.rs +0 -0
  212. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/top_subsumes_all.rs +0 -0
  213. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/value_type_disjoint_canary.rs +0 -0
  214. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/value_type_disjoint_probe.rs +0 -0
  215. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/wedge_consistency.rs +0 -0
  216. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/Cargo.toml +0 -0
  217. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/README.md +0 -0
  218. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/src/lib.rs +0 -0
  219. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/src/proof.rs +0 -0
  220. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/src/seed_sat.rs +0 -0
  221. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/tests/fixtures/phase2a_functional_role_canary.ofn +0 -0
  222. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/tests/fixtures/phase2b_compound_existential_canary.ofn +0 -0
  223. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/Cargo.toml +0 -0
  224. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/README.md +0 -0
  225. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/counters.rs +0 -0
  226. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/deps.rs +0 -0
  227. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/graph.rs +0 -0
  228. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/hyper.rs +0 -0
  229. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/lib.rs +0 -0
  230. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/replay.rs +0 -0
  231. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/rules.rs +0 -0
  232. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/saturate.rs +0 -0
  233. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/search.rs +0 -0
  234. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/shadow_measures.rs +0 -0
  235. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/snapshot.rs +0 -0
  236. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/trail.rs +0 -0
  237. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/backprop_risk.rs +0 -0
  238. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/replay_driver.rs +0 -0
  239. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/replay_roundtrip.rs +0 -0
  240. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/sat_lookahead_drop.rs +0 -0
  241. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/semantic_branching.rs +0 -0
  242. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/shadow_dep_probe.rs +0 -0
  243. {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/snapshot_capture.rs +0 -0
  244. {rustdl-0.3.24 → rustdl-0.3.26}/pyproject.toml +0 -0
  245. {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/__init__.py +0 -0
  246. {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/__init__.pyi +0 -0
  247. {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/_results.py +0 -0
  248. {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/data/pizza.owl.gz +0 -0
  249. {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/data/sio.owl.gz +0 -0
  250. {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/data/sulo.owl.gz +0 -0
  251. {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/examples.py +0 -0
  252. {rustdl-0.3.24 → rustdl-0.3.26}/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.24"
1021
+ version = "0.3.26"
1022
1022
  dependencies = [
1023
1023
  "anyhow",
1024
1024
  "clap",
@@ -1038,7 +1038,7 @@ dependencies = [
1038
1038
 
1039
1039
  [[package]]
1040
1040
  name = "owl-dl-cb"
1041
- version = "0.3.24"
1041
+ version = "0.3.26"
1042
1042
  dependencies = [
1043
1043
  "hashbrown 0.15.5",
1044
1044
  "owl-dl-core",
@@ -1046,7 +1046,7 @@ dependencies = [
1046
1046
 
1047
1047
  [[package]]
1048
1048
  name = "owl-dl-cli"
1049
- version = "0.3.24"
1049
+ version = "0.3.26"
1050
1050
  dependencies = [
1051
1051
  "anyhow",
1052
1052
  "clap",
@@ -1059,7 +1059,7 @@ dependencies = [
1059
1059
 
1060
1060
  [[package]]
1061
1061
  name = "owl-dl-core"
1062
- version = "0.3.24"
1062
+ version = "0.3.26"
1063
1063
  dependencies = [
1064
1064
  "bitvec",
1065
1065
  "bumpalo",
@@ -1073,7 +1073,7 @@ dependencies = [
1073
1073
 
1074
1074
  [[package]]
1075
1075
  name = "owl-dl-datatypes"
1076
- version = "0.3.24"
1076
+ version = "0.3.26"
1077
1077
  dependencies = [
1078
1078
  "owl-dl-core",
1079
1079
  "proptest",
@@ -1083,7 +1083,7 @@ dependencies = [
1083
1083
 
1084
1084
  [[package]]
1085
1085
  name = "owl-dl-py"
1086
- version = "0.3.24"
1086
+ version = "0.3.26"
1087
1087
  dependencies = [
1088
1088
  "horned-owl",
1089
1089
  "owl-dl-core",
@@ -1094,7 +1094,7 @@ dependencies = [
1094
1094
 
1095
1095
  [[package]]
1096
1096
  name = "owl-dl-reasoner"
1097
- version = "0.3.24"
1097
+ version = "0.3.26"
1098
1098
  dependencies = [
1099
1099
  "anyhow",
1100
1100
  "dashmap",
@@ -1112,7 +1112,7 @@ dependencies = [
1112
1112
 
1113
1113
  [[package]]
1114
1114
  name = "owl-dl-saturation"
1115
- version = "0.3.24"
1115
+ version = "0.3.26"
1116
1116
  dependencies = [
1117
1117
  "dashmap",
1118
1118
  "fixedbitset",
@@ -1128,7 +1128,7 @@ dependencies = [
1128
1128
 
1129
1129
  [[package]]
1130
1130
  name = "owl-dl-tableau"
1131
- version = "0.3.24"
1131
+ version = "0.3.26"
1132
1132
  dependencies = [
1133
1133
  "bitvec",
1134
1134
  "bumpalo",
@@ -2554,7 +2554,7 @@ dependencies = [
2554
2554
 
2555
2555
  [[package]]
2556
2556
  name = "xtask"
2557
- version = "0.3.24"
2557
+ version = "0.3.26"
2558
2558
  dependencies = [
2559
2559
  "anyhow",
2560
2560
  "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.24"
6
+ version = "0.3.26"
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.24
3
+ Version: 0.3.26
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -638,7 +638,27 @@ pub(crate) fn classify_internal_with_timeout(
638
638
  // RUSTDL_HORN_SHORTCIRCUIT (default ON) for A/B isolation.
639
639
  if is_pure_el(internal)
640
640
  || (crate::horn_shortcircuit_enabled() && saturator_complete_fragment(internal))
641
+ || (crate::classify_tbox_fragment_enabled() && tbox_only_saturator_eligible(internal))
641
642
  {
643
+ // Lever 1 admits ABox-bearing ontologies to this fast path, so — like
644
+ // the top-down path — run the sound ABox-driven inconsistency pre-check
645
+ // first (nominal-free ABox is irrelevant to subsumption, but an
646
+ // inconsistent ABox still makes every class unsatisfiable). ABox-free
647
+ // inputs skip it (has_abox_axioms is a microsecond O(n) scan).
648
+ if crate::abox_check_enabled() && has_abox_axioms(internal) {
649
+ let prepared = PreparedOntology::from_internal(internal.clone())?;
650
+ if let crate::abox_check::AboxVerdict::Inconsistent { reason } = prepared.abox_verdict()
651
+ {
652
+ if std::env::var_os("RUSTDL_TRACE").is_some() {
653
+ eprintln!("abox_check: inconsistent — {reason:?}");
654
+ }
655
+ return Ok(classify_inconsistent(
656
+ classes,
657
+ index,
658
+ analyze_fragment(internal),
659
+ ));
660
+ }
661
+ }
642
662
  return Ok(classify_pure_el(internal, &classes, &index, &closure));
643
663
  }
644
664
 
@@ -674,11 +694,11 @@ pub(crate) fn classify_internal_with_timeout(
674
694
  // assuming sat here can never cause us to claim a
675
695
  // false subsumption later.
676
696
  let sat = prepared
677
- .decide_with_deadline(deadline, move |pool| pool.atomic(class_id))?
697
+ .decide_classify_with_deadline(deadline, move |pool| pool.atomic(class_id))?
678
698
  .unwrap_or(true);
679
699
  Ok((i, sat, false))
680
700
  } else {
681
- let sat = prepared.decide(move |pool| pool.atomic(class_id))?;
701
+ let sat = prepared.decide_classify(move |pool| pool.atomic(class_id))?;
682
702
  Ok((i, sat, false))
683
703
  }
684
704
  })
@@ -739,7 +759,7 @@ pub(crate) fn classify_internal_with_timeout(
739
759
  };
740
760
  match per_pair_timeout {
741
761
  None => {
742
- let sat = prepared.decide(build)?;
762
+ let sat = prepared.decide_classify(build)?;
743
763
  Ok((i, j, !sat, false, false))
744
764
  }
745
765
  Some(timeout) => {
@@ -749,7 +769,7 @@ pub(crate) fn classify_internal_with_timeout(
749
769
  // extra threads, no cancellation race — the rayon
750
770
  // worker stays bound to this single decide call.
751
771
  let deadline = Instant::now() + timeout;
752
- match prepared.decide_with_deadline(deadline, build)? {
772
+ match prepared.decide_classify_with_deadline(deadline, build)? {
753
773
  Some(sat) => Ok((i, j, !sat, false, false)),
754
774
  None => Ok((i, j, false, false, true)),
755
775
  }
@@ -893,12 +913,35 @@ fn classify_inconsistent(
893
913
  /// expand to cardinality, `ABox` assertions, ...) immediately returns
894
914
  /// `false`.
895
915
  pub(crate) fn is_pure_el(internal: &InternalOntology) -> bool {
916
+ is_pure_el_impl(internal, false)
917
+ }
918
+
919
+ /// Backing check for [`is_pure_el`]. `skip_abox` ⟹ ignore `ABox` assertion
920
+ /// axioms — Lever 1: a nominal-free `ABox` is irrelevant to class subsumption,
921
+ /// so an EL `TBox` carrying a big `ABox` is still classified completely by the
922
+ /// saturation fast path.
923
+ fn is_pure_el_impl(internal: &InternalOntology, skip_abox: bool) -> bool {
896
924
  internal
897
925
  .axioms
898
926
  .iter()
927
+ .filter(|ax| !(skip_abox && is_abox_axiom(ax)))
899
928
  .all(|ax| is_el_axiom(ax, &internal.concepts))
900
929
  }
901
930
 
931
+ /// True for the five `ABox` assertion axiom forms (individual-level). Used by
932
+ /// Lever 1 ([`tbox_only_saturator_eligible`]) to restrict the fragment gate to
933
+ /// the `TBox`. Kept in sync with [`has_abox_axioms`].
934
+ fn is_abox_axiom(ax: &Axiom) -> bool {
935
+ matches!(
936
+ ax,
937
+ Axiom::ClassAssertion { .. }
938
+ | Axiom::ObjectPropertyAssertion { .. }
939
+ | Axiom::NegativeObjectPropertyAssertion { .. }
940
+ | Axiom::SameIndividual(_)
941
+ | Axiom::DifferentIndividuals(_)
942
+ )
943
+ }
944
+
902
945
  fn is_el_axiom(ax: &Axiom, pool: &ConceptPool) -> bool {
903
946
  match ax {
904
947
  Axiom::SubClassOf { sub, sup } => is_el_concept(*sub, pool) && is_el_concept(*sup, pool),
@@ -935,7 +978,13 @@ fn is_el_axiom(ax: &Axiom, pool: &ConceptPool) -> bool {
935
978
 
936
979
  fn is_el_concept(c: ConceptId, pool: &ConceptPool) -> bool {
937
980
  match pool.get(c) {
938
- ConceptExpr::Top | ConceptExpr::Atomic(_) => true,
981
+ // Bot (Lever 1b): `⊥` is EL — `X ⊑ ⊥` (unsatisfiability) and `A⊓B ⊑ ⊥`
982
+ // (disjointness) are both reasoned over completely by the saturator's
983
+ // Bot/disjointness machinery. Sound here because `is_pure_el` admits NO
984
+ // functional role (is_el_axiom rejects FunctionalRole), so the
985
+ // disjoint×functional-merge interaction excluded from
986
+ // `saturator_complete_fragment` cannot arise on this arm.
987
+ ConceptExpr::Top | ConceptExpr::Atomic(_) | ConceptExpr::Bot => true,
939
988
  ConceptExpr::And(ops) => ops.iter().all(|op| is_el_concept(*op, pool)),
940
989
  ConceptExpr::Some(role, body) => !role.is_inverse() && is_el_concept(*body, pool),
941
990
  _ => false,
@@ -967,6 +1016,15 @@ fn is_el_concept(c: ConceptId, pool: &ConceptPool) -> bool {
967
1016
  /// chains>2, no inverse) stay on the fast path — verified by
968
1017
  /// `galen_notgalen_in_saturator_fragment` + the corpus FP/MISSED gate.
969
1018
  pub(crate) fn saturator_complete_fragment(internal: &InternalOntology) -> bool {
1019
+ saturator_complete_fragment_impl(internal, false)
1020
+ }
1021
+
1022
+ /// Backing check for [`saturator_complete_fragment`]. `skip_abox` ⟹ evaluate the
1023
+ /// fragment allowlist over the `TBox` only (Lever 1). The functional-role /
1024
+ /// disjoint-gating prelude is computed over ALL axioms (harmless — `ABox`
1025
+ /// assertions declare no role characteristics), so only the final per-axiom
1026
+ /// allowlist walk is `TBox`-restricted.
1027
+ fn saturator_complete_fragment_impl(internal: &InternalOntology, skip_abox: bool) -> bool {
970
1028
  // The set of roles for which conversion emitted a derived `∃R.⊤ ⊑ ≤1 R`
971
1029
  // GCI: `FunctionalRole(r) → r` (FORWARD only — `derive_functional_max_
972
1030
  // cardinality` does not emit for inverse-functional).
@@ -1007,9 +1065,26 @@ pub(crate) fn saturator_complete_fragment(internal: &InternalOntology) -> bool {
1007
1065
  internal
1008
1066
  .axioms
1009
1067
  .iter()
1068
+ .filter(|ax| !(skip_abox && is_abox_axiom(ax)))
1010
1069
  .all(|ax| is_saturator_axiom(ax, &internal.concepts, &functional_roles, disjoint_ok))
1011
1070
  }
1012
1071
 
1072
+ /// Lever 1 eligibility: the ontology has an `ABox`, uses NO nominals, and its
1073
+ /// `TBox` (all non-`ABox` axioms) lies in the saturator's complete fragment
1074
+ /// (pure-EL, or the EL+functional/hierarchy/chains fragment). When true, the
1075
+ /// nominal-free `ABox` is provably irrelevant to class subsumption, so the
1076
+ /// ontology can take the saturation-only fast path instead of the O(n²)
1077
+ /// per-pair hybrid loop. **Sound by construction** — see
1078
+ /// [`crate::classify_tbox_fragment_enabled`]. Env gating is the caller's job
1079
+ /// (mirrors [`saturator_complete_fragment`], a pure predicate).
1080
+ pub(crate) fn tbox_only_saturator_eligible(internal: &InternalOntology) -> bool {
1081
+ has_abox_axioms(internal)
1082
+ && !crate::ontology_uses_nominals(internal)
1083
+ && (is_pure_el_impl(internal, true)
1084
+ || (crate::horn_shortcircuit_enabled()
1085
+ && saturator_complete_fragment_impl(internal, true)))
1086
+ }
1087
+
1013
1088
  /// True iff `c` is exactly the derived functional-enforcement consequent
1014
1089
  /// `≤1 role.⊤` (`Max(1, role, Top)` unqualified) AND `role` carries a matching
1015
1090
  /// functional axiom (so the saturator's bitset enforces it). Used to accept
@@ -1055,6 +1130,17 @@ fn is_saturator_axiom(
1055
1130
  {
1056
1131
  true
1057
1132
  }
1133
+ // Lower-`⊥` GCI (Lever 1b): `X ⊑ ⊥`. A CONJUNCTIVE LHS (`A⊓B ⊑ ⊥`) is a
1134
+ // disjointness assertion — gate on `disjoint_ok` exactly like a native
1135
+ // `DisjointClasses` (the disjoint×functional-merge interaction is
1136
+ // unproven, so it must fall back when a functional role is present). A
1137
+ // non-conjunctive `A ⊑ ⊥` is a plain single-class unsatisfiability with
1138
+ // no such interaction ⇒ always in-fragment. The LHS below `⊥` must still
1139
+ // be a saturator concept.
1140
+ Axiom::SubClassOf { sub, sup } if matches!(pool.get(*sup), ConceptExpr::Bot) => {
1141
+ is_saturator_concept(*sub, pool)
1142
+ && (disjoint_ok || !matches!(pool.get(*sub), ConceptExpr::And(_)))
1143
+ }
1058
1144
  Axiom::SubClassOf { sub, sup } => {
1059
1145
  is_saturator_concept(*sub, pool) && is_saturator_concept(*sup, pool)
1060
1146
  }
@@ -1174,7 +1260,7 @@ pub fn classify_top_down_with_timeout<A: ForIRI>(
1174
1260
 
1175
1261
  /// Returns true iff the ontology contains any `ABox` axiom. Cheap
1176
1262
  /// scan over `internal.axioms` used to skip the `ABox` consistency
1177
- /// pre-check entirely on TBox-only inputs (e.g. GALEN), where
1263
+ /// pre-check entirely on `TBox`-only inputs (e.g. GALEN), where
1178
1264
  /// building `PreparedOntology` solely to consult `abox_verdict()`
1179
1265
  /// is wasted work — the check would early-return `Unknown` on
1180
1266
  /// empty `individuals` anyway. Microseconds even on the largest
@@ -1294,6 +1380,7 @@ pub(crate) fn classify_top_down_internal(
1294
1380
  // RUSTDL_HORN_SHORTCIRCUIT.
1295
1381
  if is_pure_el(internal)
1296
1382
  || (crate::horn_shortcircuit_enabled() && saturator_complete_fragment(internal))
1383
+ || (crate::classify_tbox_fragment_enabled() && tbox_only_saturator_eligible(internal))
1297
1384
  {
1298
1385
  // Skip the ABox check entirely on ABox-free inputs — building
1299
1386
  // PreparedOntology costs ~1.5 s on GALEN-sized TBoxes (NNF +
@@ -1455,7 +1542,7 @@ pub(crate) fn classify_top_down_internal(
1455
1542
  // sound under-approximation. Crashing classify on a
1456
1543
  // single oversized class is worse.
1457
1544
  let sat = match prepared
1458
- .decide_with_deadline(deadline, move |pool| pool.atomic(class_id))
1545
+ .decide_classify_with_deadline(deadline, move |pool| pool.atomic(class_id))
1459
1546
  {
1460
1547
  Ok(Some(s)) => s,
1461
1548
  Ok(None) | Err(crate::ReasonError::NoVerdict) => true,
@@ -1463,7 +1550,7 @@ pub(crate) fn classify_top_down_internal(
1463
1550
  };
1464
1551
  Ok((i, sat, false))
1465
1552
  } else {
1466
- let sat = prepared.decide(move |pool| pool.atomic(class_id))?;
1553
+ let sat = prepared.decide_classify(move |pool| pool.atomic(class_id))?;
1467
1554
  Ok((i, sat, false))
1468
1555
  }
1469
1556
  })
@@ -2464,7 +2551,7 @@ fn subsumes_via_tableau(
2464
2551
  // tableau probe even when per_pair_timeout is None (global-only mode).
2465
2552
  match effective_deadline(global_deadline, per_pair_timeout) {
2466
2553
  None => {
2467
- let sat = prepared.decide(build)?;
2554
+ let sat = prepared.decide_classify(build)?;
2468
2555
  stats.tableau_subsumption_calls += 1;
2469
2556
  let subsumed = !sat;
2470
2557
  if was_fast_refuted && subsumed {
@@ -2483,7 +2570,7 @@ fn subsumes_via_tableau(
2483
2570
  // (sound under-approximation), counted in `timed_out_pairs`.
2484
2571
  // Crashing classify on a single oversized pair is worse
2485
2572
  // than under-reporting the subsumption.
2486
- match prepared.decide_with_deadline(deadline, build) {
2573
+ match prepared.decide_classify_with_deadline(deadline, build) {
2487
2574
  Ok(Some(sat)) => {
2488
2575
  stats.tableau_subsumption_calls += 1;
2489
2576
  let subsumed = !sat;
@@ -3686,6 +3773,134 @@ Ontology(<http://rustdl.test/test>\n\
3686
3773
  );
3687
3774
  }
3688
3775
 
3776
+ #[test]
3777
+ fn tbox_fragment_accepts_el_tbox_with_abox() {
3778
+ // Lever 1: an EL TBox (A ⊑ B) carrying a nominal-free ABox must be
3779
+ // eligible for the saturation fast path — the ABox is irrelevant to
3780
+ // class subsumption. Without Lever 1 the ClassAssertion kicks it to the
3781
+ // O(n²) hybrid loop (the ORE ore_ont_1043 DNF shape).
3782
+ let i = internal_of(
3783
+ " Declaration(Class(:A))\n\
3784
+ Declaration(Class(:B))\n\
3785
+ Declaration(NamedIndividual(:x))\n\
3786
+ SubClassOf(:A :B)\n\
3787
+ ClassAssertion(:A :x)\n",
3788
+ );
3789
+ assert!(
3790
+ !is_pure_el(&i),
3791
+ "sanity: the full-axiom gate rejects it (ABox present)"
3792
+ );
3793
+ assert!(
3794
+ tbox_only_saturator_eligible(&i),
3795
+ "EL TBox + nominal-free ABox must be Lever-1 fast-path eligible"
3796
+ );
3797
+ }
3798
+
3799
+ #[test]
3800
+ fn tbox_fragment_rejects_nominal_abox() {
3801
+ // A nominal in the TBox (ObjectHasValue → ConceptExpr::Nominal) makes
3802
+ // the ABox subsumption-relevant, so Lever 1 must NOT fire.
3803
+ let i = internal_of(
3804
+ " Declaration(Class(:A))\n\
3805
+ Declaration(Class(:B))\n\
3806
+ Declaration(ObjectProperty(:r))\n\
3807
+ Declaration(NamedIndividual(:x))\n\
3808
+ SubClassOf(:A ObjectHasValue(:r :x))\n\
3809
+ ClassAssertion(:A :x)\n",
3810
+ );
3811
+ assert!(
3812
+ !tbox_only_saturator_eligible(&i),
3813
+ "an ontology using nominals must be excluded from Lever 1"
3814
+ );
3815
+ }
3816
+
3817
+ #[test]
3818
+ fn tbox_fragment_rejects_forall_tbox() {
3819
+ // Out-of-fragment TBox (∀) must reject even with the ABox stripped —
3820
+ // the D10 unsound-completeness guard carries into the TBox-only view.
3821
+ let i = internal_of(
3822
+ " Declaration(Class(:A))\n\
3823
+ Declaration(Class(:B))\n\
3824
+ Declaration(ObjectProperty(:r))\n\
3825
+ Declaration(NamedIndividual(:x))\n\
3826
+ SubClassOf(:A ObjectAllValuesFrom(:r :B))\n\
3827
+ ClassAssertion(:A :x)\n",
3828
+ );
3829
+ assert!(
3830
+ !tbox_only_saturator_eligible(&i),
3831
+ "a ∀ in the TBox must reject even under the TBox-only view"
3832
+ );
3833
+ }
3834
+
3835
+ #[test]
3836
+ fn bot_lowered_disjointness_is_pure_el() {
3837
+ // Lever 1b: an explicit `A ⊓ B ⊑ ⊥` (SubClassOf(And, owl:Nothing)) is a
3838
+ // sound EL disjointness/unsat the saturator handles completely. With no
3839
+ // functional role it must be in the pure-EL fast path. RED before Bot ∈
3840
+ // is_el_concept.
3841
+ let i = internal_of(
3842
+ " Declaration(Class(:A))\n\
3843
+ Declaration(Class(:B))\n\
3844
+ SubClassOf(:A :B)\n\
3845
+ SubClassOf(ObjectIntersectionOf(:A :B) owl:Nothing)\n",
3846
+ );
3847
+ assert!(
3848
+ is_pure_el(&i),
3849
+ "EL + `A⊓B⊑⊥` (no functional) must be pure-EL fast-path eligible"
3850
+ );
3851
+ }
3852
+
3853
+ #[test]
3854
+ fn saturator_fragment_accepts_atomic_unsat() {
3855
+ // A plain `A ⊑ ⊥` (single-class unsatisfiability) carries no
3856
+ // functional-merge interaction, so it stays in-fragment even with a
3857
+ // functional role present.
3858
+ let i = internal_of(
3859
+ " Declaration(Class(:A))\n\
3860
+ Declaration(ObjectProperty(:r))\n\
3861
+ FunctionalObjectProperty(:r)\n\
3862
+ SubClassOf(:A owl:Nothing)\n",
3863
+ );
3864
+ assert!(
3865
+ saturator_complete_fragment(&i),
3866
+ "atomic `A⊑⊥` + functional must stay in the saturator fragment"
3867
+ );
3868
+ }
3869
+
3870
+ #[test]
3871
+ fn saturator_fragment_rejects_conjunctive_bot_with_functional() {
3872
+ // FP-CRITICAL: `A⊓B⊑⊥` is disjointness(A,B); combined with a functional
3873
+ // role it is the UNPROVEN disjoint×functional-merge interaction the gate
3874
+ // deliberately excludes. It must fall back to the hybrid path (same
3875
+ // policy as a native DisjointClasses + functional).
3876
+ let i = internal_of(
3877
+ " Declaration(Class(:A))\n\
3878
+ Declaration(Class(:B))\n\
3879
+ Declaration(ObjectProperty(:r))\n\
3880
+ FunctionalObjectProperty(:r)\n\
3881
+ SubClassOf(ObjectIntersectionOf(:A :B) owl:Nothing)\n",
3882
+ );
3883
+ assert!(
3884
+ !saturator_complete_fragment(&i),
3885
+ "conjunctive `A⊓B⊑⊥` + functional (disjoint×functional) must fall back"
3886
+ );
3887
+ }
3888
+
3889
+ #[test]
3890
+ fn tbox_fragment_inert_without_abox() {
3891
+ // No ABox ⇒ Lever 1 is inert (the ordinary gate already decides). Guards
3892
+ // against changing ABox-free classification behaviour.
3893
+ let i = internal_of(
3894
+ " Declaration(Class(:A))\n\
3895
+ Declaration(Class(:B))\n\
3896
+ SubClassOf(:A :B)\n",
3897
+ );
3898
+ assert!(
3899
+ !tbox_only_saturator_eligible(&i),
3900
+ "no ABox ⇒ Lever 1 must be inert"
3901
+ );
3902
+ }
3903
+
3689
3904
  #[test]
3690
3905
  fn saturator_fragment_rejects_disjoint_union() {
3691
3906
  // DisjointUnion carries a disjunctive covering (class ≡ ⊔members), which
@@ -2908,6 +2908,71 @@ pub fn wedge_consistency_enabled() -> bool {
2908
2908
  std::env::var_os("RUSTDL_WEDGE_CONSISTENCY").is_none_or(|v| v != "0" && !v.is_empty())
2909
2909
  }
2910
2910
 
2911
+ /// Lever A (2026-07-20): when the ontology uses NO nominals, the `ABox` is
2912
+ /// irrelevant to class subsumption, so the per-pair classification tableau
2913
+ /// probes do NOT seed it. This eliminates the `ABox`-driven completion-graph
2914
+ /// blow-up that stalls near-EL `ABox`-bearing ontologies (e.g. ORE
2915
+ /// `ore_ont_10894`: DNF → ~1.6 s, closure byte-identical to saturation/Konclude).
2916
+ /// **Sound:** absent nominals the `ABox` cannot affect `C ⊑ D`; a
2917
+ /// globally-inconsistent `ABox` is still caught by the separate
2918
+ /// `abox_check`/`abox_saturation` pre-checks (so this is FP=0 by construction —
2919
+ /// a missed inconsistency would be a MISS, gated by the corpus MISSED=0 check).
2920
+ /// `RUSTDL_CLASSIFY_TBOX_ONLY=0` reverts to seeding the full `ABox`.
2921
+ #[must_use]
2922
+ pub fn classify_tbox_only_enabled() -> bool {
2923
+ std::env::var_os("RUSTDL_CLASSIFY_TBOX_ONLY").is_none_or(|v| v != "0" && !v.is_empty())
2924
+ }
2925
+
2926
+ /// Lever 1 (2026-07-20): when the ontology is nominal-free, evaluate the
2927
+ /// Horn-shortcircuit FRAGMENT gate on the `TBox` axioms only, ignoring the `ABox`.
2928
+ /// An EL/saturator-fragment `TBox` carrying a large `ABox` is otherwise kicked off
2929
+ /// the saturation fast path (`ABox` assertions fail the fragment allowlist) into
2930
+ /// the O(n²) per-pair hybrid loop, which DNFs on 8k–70k-class ontologies even
2931
+ /// though the saturation closure is already complete (verified == Konclude on
2932
+ /// the ORE ChEBI/OBO tier). **Sound by construction:** the existing fragment
2933
+ /// guarantee applies to the `TBox`; a nominal-free `ABox` cannot contribute a class
2934
+ /// subsumption (monotone, same basis as [`classify_tbox_only_enabled`]); and the
2935
+ /// inconsistent-`ABox` → all-unsat verdict is still produced by the `abox_check`
2936
+ /// pre-check that runs on the fast-path arm when `has_abox_axioms`. Recovers ~67
2937
+ /// ORE onts (e.g. `ore_ont_1043`: DNF → ~7 s, closure == Konclude).
2938
+ /// `RUSTDL_CLASSIFY_TBOX_FRAGMENT=0` reverts to the full-axiom fragment gate.
2939
+ #[must_use]
2940
+ pub fn classify_tbox_fragment_enabled() -> bool {
2941
+ std::env::var_os("RUSTDL_CLASSIFY_TBOX_FRAGMENT").is_none_or(|v| v != "0" && !v.is_empty())
2942
+ }
2943
+
2944
+ /// True iff any axiom's class expression references a nominal (`ObjectOneOf` /
2945
+ /// `ObjectHasValue`, both lowered to `ConceptExpr::Nominal`). When false, the
2946
+ /// `ABox` is provably irrelevant to class subsumption, enabling Lever A. Scanned
2947
+ /// once at `from_internal` time over the un-mutated axioms (nominals only occur
2948
+ /// inside class expressions, so only concept-bearing axioms are walked).
2949
+ pub(crate) fn ontology_uses_nominals(internal: &InternalOntology) -> bool {
2950
+ fn has_nominal(c: ConceptId, pool: &ConceptPool) -> bool {
2951
+ match pool.get(c) {
2952
+ ConceptExpr::Nominal(_) => true,
2953
+ ConceptExpr::Not(x)
2954
+ | ConceptExpr::Some(_, x)
2955
+ | ConceptExpr::All(_, x)
2956
+ | ConceptExpr::Min(_, _, x)
2957
+ | ConceptExpr::Max(_, _, x) => has_nominal(*x, pool),
2958
+ ConceptExpr::And(ops) | ConceptExpr::Or(ops) => {
2959
+ ops.iter().any(|op| has_nominal(*op, pool))
2960
+ }
2961
+ _ => false,
2962
+ }
2963
+ }
2964
+ let pool = &internal.concepts;
2965
+ internal.axioms.iter().any(|ax| match ax {
2966
+ Axiom::SubClassOf { sub, sup } => has_nominal(*sub, pool) || has_nominal(*sup, pool),
2967
+ Axiom::EquivalentClasses(v) | Axiom::DisjointClasses(v) => {
2968
+ v.iter().any(|c| has_nominal(*c, pool))
2969
+ }
2970
+ Axiom::DisjointUnion { members, .. } => members.iter().any(|c| has_nominal(*c, pool)),
2971
+ Axiom::ClassAssertion { class, .. } => has_nominal(*class, pool),
2972
+ _ => false,
2973
+ })
2974
+ }
2975
+
2911
2976
  /// Bounded wall budget (ms) for the main-tableau `decide(Top)`
2912
2977
  /// fall-through used when the consistency wedge returns `Stalled`. The
2913
2978
  /// whole point of the wedge route is to kill the unbounded
@@ -3966,6 +4031,13 @@ pub(crate) struct PreparedOntology {
3966
4031
  disjoint_role_pairs: Vec<(RoleId, RoleId)>,
3967
4032
  complements: Vec<(ConceptId, ConceptId)>,
3968
4033
  pub(crate) abox: Abox,
4034
+ /// Lever A (2026-07-20): true iff the `ABox` is provably irrelevant to class
4035
+ /// subsumption — the ontology has `ABox` axioms, uses NO nominals, and the
4036
+ /// `TBox`-only-classify gate is on. When true, the per-pair classification
4037
+ /// tableau probes (`decide_classify`) do NOT seed the `ABox`, avoiding the
4038
+ /// completion-graph blow-up it causes on near-EL `ABox`-bearing ontologies.
4039
+ /// `abox` is still kept full for `realize`/`materialize`/consistency.
4040
+ abox_irrelevant_to_classify: bool,
3969
4041
  /// EL saturator closure over the un-mutated input ontology.
3970
4042
  /// Used by [`abox_check`] (P1 `is_unsatisfiable`, P2 `subsumers_of`).
3971
4043
  /// Computed once at build time; classify already computes the same
@@ -4237,6 +4309,11 @@ impl PreparedOntology {
4237
4309
  /// `decide` calls only have to allocate a fresh tableau and run
4238
4310
  /// the search.
4239
4311
  pub(crate) fn from_internal(mut internal: InternalOntology) -> Result<Self, ReasonError> {
4312
+ // Lever A: decide up front (on the un-mutated input) whether the ABox is
4313
+ // irrelevant to class subsumption — has-ABox, no nominals, gate on.
4314
+ let abox_irrelevant_to_classify = classify_tbox_only_enabled()
4315
+ && internal_has_abox(&internal)
4316
+ && !ontology_uses_nominals(&internal);
4240
4317
  // Phase A1 (ABox consistency check): EL closure over the
4241
4318
  // un-mutated input. Used by abox_check for P1 (is_unsatisfiable)
4242
4319
  // and P2 (subsumers_of). Cheap on small ABox-bearing ontologies;
@@ -4320,6 +4397,7 @@ impl PreparedOntology {
4320
4397
  disjoint_role_pairs,
4321
4398
  complements,
4322
4399
  abox,
4400
+ abox_irrelevant_to_classify,
4323
4401
  closure,
4324
4402
  told,
4325
4403
  axioms,
@@ -4471,6 +4549,39 @@ impl PreparedOntology {
4471
4549
  .map(|opt| opt.expect("no deadline ⇒ search always returns Some(_)"))
4472
4550
  }
4473
4551
 
4552
+ /// Lever A: like [`Self::decide`], but for the **classification pairwise
4553
+ /// subsumption loop only** — skips the `ABox` seed when it is provably
4554
+ /// irrelevant to class subsumption (`abox_irrelevant_to_classify`: has
4555
+ /// `ABox`, no nominals, gate on). MUST NOT be used for realize / consistency
4556
+ /// / instance queries, which genuinely need the `ABox`. Global `ABox`
4557
+ /// inconsistency is caught by the separate pre-checks before this loop runs.
4558
+ pub(crate) fn decide_classify<F>(&self, build_test_concept: F) -> Result<bool, ReasonError>
4559
+ where
4560
+ F: FnOnce(&mut ConceptPool) -> ConceptId,
4561
+ {
4562
+ let empty = Abox::default();
4563
+ let abox = if self.abox_irrelevant_to_classify {
4564
+ &empty
4565
+ } else {
4566
+ &self.abox
4567
+ };
4568
+ decide(
4569
+ &self.pool,
4570
+ &self.tbox,
4571
+ &self.hierarchy,
4572
+ &self.inverse_pairs,
4573
+ &self.chain_axioms,
4574
+ &self.asymmetric_roles,
4575
+ &self.disjoint_role_pairs,
4576
+ &self.complements,
4577
+ abox,
4578
+ &self.dkey_ranges,
4579
+ None,
4580
+ build_test_concept,
4581
+ )
4582
+ .map(|opt| opt.expect("no deadline ⇒ search always returns Some(_)"))
4583
+ }
4584
+
4474
4585
  /// Like [`Self::decide`] but the search is bounded by `deadline`.
4475
4586
  /// Returns `Ok(Some(sat))` if the tableau reached a verdict in
4476
4587
  /// time, or `Ok(None)` if the deadline elapsed first.
@@ -4497,6 +4608,40 @@ impl PreparedOntology {
4497
4608
  build_test_concept,
4498
4609
  )
4499
4610
  }
4611
+
4612
+ /// Lever A: like [`Self::decide_with_deadline`], but for the classification
4613
+ /// pairwise subsumption loop only — skips the `ABox` seed when it is provably
4614
+ /// irrelevant (`abox_irrelevant_to_classify`). Same scoping caveat as
4615
+ /// [`Self::decide_classify`].
4616
+ pub(crate) fn decide_classify_with_deadline<F>(
4617
+ &self,
4618
+ deadline: std::time::Instant,
4619
+ build_test_concept: F,
4620
+ ) -> Result<Option<bool>, ReasonError>
4621
+ where
4622
+ F: FnOnce(&mut ConceptPool) -> ConceptId,
4623
+ {
4624
+ let empty = Abox::default();
4625
+ let abox = if self.abox_irrelevant_to_classify {
4626
+ &empty
4627
+ } else {
4628
+ &self.abox
4629
+ };
4630
+ decide(
4631
+ &self.pool,
4632
+ &self.tbox,
4633
+ &self.hierarchy,
4634
+ &self.inverse_pairs,
4635
+ &self.chain_axioms,
4636
+ &self.asymmetric_roles,
4637
+ &self.disjoint_role_pairs,
4638
+ &self.complements,
4639
+ abox,
4640
+ &self.dkey_ranges,
4641
+ Some(deadline),
4642
+ build_test_concept,
4643
+ )
4644
+ }
4500
4645
  }
4501
4646
 
4502
4647
  /// Pre-resolved `ABox` state, ready to seed into the tableau context.