rustdl 0.3.25__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.25 → rustdl-0.3.26}/Cargo.lock +10 -10
  2. {rustdl-0.3.25 → rustdl-0.3.26}/Cargo.toml +1 -1
  3. {rustdl-0.3.25 → rustdl-0.3.26}/PKG-INFO +1 -1
  4. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/classify.rs +217 -2
  5. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/lib.rs +19 -1
  6. {rustdl-0.3.25 → rustdl-0.3.26}/README.md +0 -0
  7. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/Cargo.toml +0 -0
  8. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/README.md +0 -0
  9. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/absorb.rs +0 -0
  10. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/approx_saturation.rs +0 -0
  11. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/clause.rs +0 -0
  12. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/convert.rs +0 -0
  13. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/convert_back.rs +0 -0
  14. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/data_axioms.rs +0 -0
  15. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/definitions.rs +0 -0
  16. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/disjunction_existential.rs +0 -0
  17. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/disjunctive_antecedent.rs +0 -0
  18. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/ir.rs +0 -0
  19. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/lib.rs +0 -0
  20. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/locality.rs +0 -0
  21. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/normalize.rs +0 -0
  22. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/ontology.rs +0 -0
  23. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/residual_trigger.rs +0 -0
  24. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/role_hierarchy.rs +0 -0
  25. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/told.rs +0 -0
  26. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/transform.rs +0 -0
  27. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/src/vocab.rs +0 -0
  28. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/tests/concept_pool_proptest.proptest-regressions +0 -0
  29. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/tests/concept_pool_proptest.rs +0 -0
  30. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/tests/convert_round_trip_proptest.rs +0 -0
  31. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-core/tests/role_hierarchy_proptest.rs +0 -0
  32. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-datatypes/Cargo.toml +0 -0
  33. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-datatypes/README.md +0 -0
  34. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-datatypes/src/lib.rs +0 -0
  35. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/.gitignore +0 -0
  36. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/Cargo.toml +0 -0
  37. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/README.md +0 -0
  38. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/.gitignore +0 -0
  39. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/README.md +0 -0
  40. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/__init__.py +0 -0
  41. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/fixtures/recorded_replies_clash.json +0 -0
  42. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/fixtures/seed.ofn +0 -0
  43. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/gate.py +0 -0
  44. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/llm.py +0 -0
  45. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/loop.py +0 -0
  46. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/candidate.ofn +0 -0
  47. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/current.ofn +0 -0
  48. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/metrics.md +0 -0
  49. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/transcript.jsonl +0 -0
  50. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/candidate.ofn +0 -0
  51. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/current.ofn +0 -0
  52. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/metrics.md +0 -0
  53. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/transcript.jsonl +0 -0
  54. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/requirements.txt +0 -0
  55. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/run.py +0 -0
  56. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/__init__.py +0 -0
  57. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_gate.py +0 -0
  58. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_llm.py +0 -0
  59. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_loop.py +0 -0
  60. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_run.py +0 -0
  61. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_seed.py +0 -0
  62. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/src/classify.rs +0 -0
  63. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/src/errors.rs +0 -0
  64. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/src/explain.rs +0 -0
  65. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/src/lib.rs +0 -0
  66. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/src/load.rs +0 -0
  67. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/src/materialize.rs +0 -0
  68. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/src/queries.rs +0 -0
  69. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/conftest.py +0 -0
  70. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_classify.py +0 -0
  71. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_examples.py +0 -0
  72. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_explain.py +0 -0
  73. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_manchester.py +0 -0
  74. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_materialize.py +0 -0
  75. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_queries.py +0 -0
  76. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_results.py +0 -0
  77. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_smoke.py +0 -0
  78. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_soundness.py +0 -0
  79. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_stubs.py +0 -0
  80. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_tutorial.py +0 -0
  81. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/Cargo.toml +0 -0
  82. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/README.md +0 -0
  83. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/examples/embed_classify.rs +0 -0
  84. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/abox_check.rs +0 -0
  85. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/abox_saturation.rs +0 -0
  86. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/diagnose.rs +0 -0
  87. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/justify.rs +0 -0
  88. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/laconic.rs +0 -0
  89. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/model_cache.rs +0 -0
  90. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/oracle_diff.rs +0 -0
  91. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/realize.rs +0 -0
  92. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/repair.rs +0 -0
  93. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/union_find.rs +0 -0
  94. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/abox_consistency.rs +0 -0
  95. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/abox_sat_fp_probe.rs +0 -0
  96. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/abox_saturation.rs +0 -0
  97. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/adaptive_budget.rs +0 -0
  98. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/anon349_diagnostic.rs +0 -0
  99. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/anonymous_individuals_identity.rs +0 -0
  100. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/anonymous_individuals_reporting.rs +0 -0
  101. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/approx_saturation_forced_disjunct.rs +0 -0
  102. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/backfold.rs +0 -0
  103. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/backjump_precision_gate.rs +0 -0
  104. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/blocked_disjunction_soundness.rs +0 -0
  105. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/blocked_disjunction_termination.rs +0 -0
  106. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/cardinality_disjunct_atoms.rs +0 -0
  107. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/classify_concrete_domain.rs +0 -0
  108. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/classify_defined_sweep.rs +0 -0
  109. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/classify_inverse_domain.rs +0 -0
  110. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/completeness_contract.rs +0 -0
  111. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/concrete_domain_clash.rs +0 -0
  112. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/data_properties.rs +0 -0
  113. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/data_property_assertions.rs +0 -0
  114. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/datatype_completeness.rs +0 -0
  115. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/datatype_inconsistency.rs +0 -0
  116. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/datatype_value_membership.rs +0 -0
  117. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/decide_pair_probe.rs +0 -0
  118. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/diagnose_partition.rs +0 -0
  119. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/disjunctive_existential_marker_fp.rs +0 -0
  120. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/domain_gci_completeness.rs +0 -0
  121. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/existential_successors.rs +0 -0
  122. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/exists_top_filler.rs +0 -0
  123. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_direct_bot.ofn +0 -0
  124. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_no_bot.ofn +0 -0
  125. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_different_individuals.ofn +0 -0
  126. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_types.ofn +0 -0
  127. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa.ofn +0 -0
  128. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa_no_clash.ofn +0 -0
  129. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_consistent.ofn +0 -0
  130. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_inconsistent.ofn +0 -0
  131. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_different.ofn +0 -0
  132. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_without_different.ofn +0 -0
  133. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_diff.ofn +0 -0
  134. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_same_target.ofn +0 -0
  135. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric.ofn +0 -0
  136. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric_one_way.ofn +0 -0
  137. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive.ofn +0 -0
  138. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive_distinct.ofn +0 -0
  139. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_compatible.ofn +0 -0
  140. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_disjoint.ofn +0 -0
  141. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_cardinality_disjoint.ofn +0 -0
  142. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain-classified.owx +0 -0
  143. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain.ofn +0 -0
  144. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition-classified.owx +0 -0
  145. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition.ofn +0 -0
  146. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_facet.ofn +0 -0
  147. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/functional_data_property.ofn +0 -0
  148. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property-classified.owx +0 -0
  149. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property.ofn +0 -0
  150. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/functional-equiv-some-bug.ofn +0 -0
  151. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/materialize/rbox-materialized.owx +0 -0
  152. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/materialize/rbox.ofn +0 -0
  153. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/named-pizza-country-bug.ofn +0 -0
  154. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-01.txt +0 -0
  155. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-02.txt +0 -0
  156. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-03.txt +0 -0
  157. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-04.txt +0 -0
  158. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-05.txt +0 -0
  159. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-06.txt +0 -0
  160. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-07.txt +0 -0
  161. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-08.txt +0 -0
  162. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.hermit.owx +0 -0
  163. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.ofn +0 -0
  164. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.owx +0 -0
  165. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.hermit.owx +0 -0
  166. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.ofn +0 -0
  167. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.owx +0 -0
  168. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.hermit.owx +0 -0
  169. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.ofn +0 -0
  170. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.owx +0 -0
  171. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.hermit.owx +0 -0
  172. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.ofn +0 -0
  173. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.owx +0 -0
  174. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.hermit.owx +0 -0
  175. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.ofn +0 -0
  176. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.owx +0 -0
  177. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.hermit.owx +0 -0
  178. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.ofn +0 -0
  179. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.owx +0 -0
  180. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.hermit.owx +0 -0
  181. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.ofn +0 -0
  182. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.owx +0 -0
  183. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.hermit.owx +0 -0
  184. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.ofn +0 -0
  185. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.owx +0 -0
  186. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/phase2b-verdicts.log +0 -0
  187. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/funcmerge_inverse.rs +0 -0
  188. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/funcmerge_scaling.rs +0 -0
  189. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/functional_enforcement.rs +0 -0
  190. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/inverse_cardinality_soundness.rs +0 -0
  191. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/inverse_symmetric_domain.rs +0 -0
  192. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/justification.rs +0 -0
  193. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/konclude_closure_diff.rs +0 -0
  194. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/label_heuristic_canary.rs +0 -0
  195. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/laconic_justification.rs +0 -0
  196. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/materialize_oracle.rs +0 -0
  197. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/object_has_self_domain.rs +0 -0
  198. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/phase2c_pair_06_canary.rs +0 -0
  199. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/precompletion_probe_gate.rs +0 -0
  200. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/property_assertions.rs +0 -0
  201. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/real_ontology_corpus.rs +0 -0
  202. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/repair_suggestions.rs +0 -0
  203. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/sat_lookahead_gate.rs +0 -0
  204. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/saturator_disjointness.rs +0 -0
  205. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/seed_probe_gate.rs +0 -0
  206. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/shadow_dep_gate.rs +0 -0
  207. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/snapshot_phase0_canary.rs +0 -0
  208. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/sp2_nogood_gate.rs +0 -0
  209. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/subproperty_axioms.rs +0 -0
  210. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/tautology_skip_canary.rs +0 -0
  211. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/tbox_only_classify.rs +0 -0
  212. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/top_subsumes_all.rs +0 -0
  213. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/value_type_disjoint_canary.rs +0 -0
  214. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/value_type_disjoint_probe.rs +0 -0
  215. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/wedge_consistency.rs +0 -0
  216. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-saturation/Cargo.toml +0 -0
  217. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-saturation/README.md +0 -0
  218. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-saturation/src/lib.rs +0 -0
  219. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-saturation/src/proof.rs +0 -0
  220. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-saturation/src/seed_sat.rs +0 -0
  221. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-saturation/tests/fixtures/phase2a_functional_role_canary.ofn +0 -0
  222. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-saturation/tests/fixtures/phase2b_compound_existential_canary.ofn +0 -0
  223. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/Cargo.toml +0 -0
  224. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/README.md +0 -0
  225. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/counters.rs +0 -0
  226. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/deps.rs +0 -0
  227. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/graph.rs +0 -0
  228. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/hyper.rs +0 -0
  229. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/lib.rs +0 -0
  230. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/replay.rs +0 -0
  231. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/rules.rs +0 -0
  232. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/saturate.rs +0 -0
  233. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/search.rs +0 -0
  234. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/shadow_measures.rs +0 -0
  235. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/snapshot.rs +0 -0
  236. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/src/trail.rs +0 -0
  237. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/backprop_risk.rs +0 -0
  238. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/replay_driver.rs +0 -0
  239. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/replay_roundtrip.rs +0 -0
  240. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/sat_lookahead_drop.rs +0 -0
  241. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/semantic_branching.rs +0 -0
  242. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/shadow_dep_probe.rs +0 -0
  243. {rustdl-0.3.25 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/snapshot_capture.rs +0 -0
  244. {rustdl-0.3.25 → rustdl-0.3.26}/pyproject.toml +0 -0
  245. {rustdl-0.3.25 → rustdl-0.3.26}/python/rustdl/__init__.py +0 -0
  246. {rustdl-0.3.25 → rustdl-0.3.26}/python/rustdl/__init__.pyi +0 -0
  247. {rustdl-0.3.25 → rustdl-0.3.26}/python/rustdl/_results.py +0 -0
  248. {rustdl-0.3.25 → rustdl-0.3.26}/python/rustdl/data/pizza.owl.gz +0 -0
  249. {rustdl-0.3.25 → rustdl-0.3.26}/python/rustdl/data/sio.owl.gz +0 -0
  250. {rustdl-0.3.25 → rustdl-0.3.26}/python/rustdl/data/sulo.owl.gz +0 -0
  251. {rustdl-0.3.25 → rustdl-0.3.26}/python/rustdl/examples.py +0 -0
  252. {rustdl-0.3.25 → 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.25"
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.25"
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.25"
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.25"
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.25"
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.25"
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.25"
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.25"
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.25"
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.25"
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.25"
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.25
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
 
@@ -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 +
@@ -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
@@ -2923,12 +2923,30 @@ pub fn classify_tbox_only_enabled() -> bool {
2923
2923
  std::env::var_os("RUSTDL_CLASSIFY_TBOX_ONLY").is_none_or(|v| v != "0" && !v.is_empty())
2924
2924
  }
2925
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
+
2926
2944
  /// True iff any axiom's class expression references a nominal (`ObjectOneOf` /
2927
2945
  /// `ObjectHasValue`, both lowered to `ConceptExpr::Nominal`). When false, the
2928
2946
  /// `ABox` is provably irrelevant to class subsumption, enabling Lever A. Scanned
2929
2947
  /// once at `from_internal` time over the un-mutated axioms (nominals only occur
2930
2948
  /// inside class expressions, so only concept-bearing axioms are walked).
2931
- fn ontology_uses_nominals(internal: &InternalOntology) -> bool {
2949
+ pub(crate) fn ontology_uses_nominals(internal: &InternalOntology) -> bool {
2932
2950
  fn has_nominal(c: ConceptId, pool: &ConceptPool) -> bool {
2933
2951
  match pool.get(c) {
2934
2952
  ConceptExpr::Nominal(_) => true,
File without changes