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.
- {rustdl-0.3.24 → rustdl-0.3.26}/Cargo.lock +10 -10
- {rustdl-0.3.24 → rustdl-0.3.26}/Cargo.toml +1 -1
- {rustdl-0.3.24 → rustdl-0.3.26}/PKG-INFO +1 -1
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/classify.rs +225 -10
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/lib.rs +145 -0
- rustdl-0.3.26/crates/owl-dl-reasoner/tests/tbox_only_classify.rs +66 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/README.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/Cargo.toml +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/README.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/absorb.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/approx_saturation.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/clause.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/convert.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/convert_back.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/data_axioms.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/definitions.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/disjunction_existential.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/disjunctive_antecedent.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/ir.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/lib.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/locality.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/normalize.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/ontology.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/residual_trigger.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/role_hierarchy.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/told.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/transform.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/src/vocab.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/tests/concept_pool_proptest.proptest-regressions +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/tests/concept_pool_proptest.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/tests/convert_round_trip_proptest.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-core/tests/role_hierarchy_proptest.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-datatypes/Cargo.toml +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-datatypes/README.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-datatypes/src/lib.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/.gitignore +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/Cargo.toml +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/README.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/.gitignore +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/README.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/__init__.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/fixtures/recorded_replies_clash.json +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/fixtures/seed.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/gate.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/llm.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/loop.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/candidate.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/current.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/metrics.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out/transcript.jsonl +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/candidate.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/current.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/metrics.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/out-clash/transcript.jsonl +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/requirements.txt +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/run.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/__init__.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_gate.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_llm.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_loop.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_run.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/examples/nesy_loop/tests/test_seed.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/classify.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/errors.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/explain.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/lib.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/load.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/materialize.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/src/queries.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/conftest.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_classify.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_examples.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_explain.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_manchester.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_materialize.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_queries.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_results.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_smoke.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_soundness.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_stubs.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-py/tests/python/test_tutorial.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/Cargo.toml +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/README.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/examples/embed_classify.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/abox_check.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/abox_saturation.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/diagnose.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/justify.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/laconic.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/model_cache.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/oracle_diff.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/realize.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/repair.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/src/union_find.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/abox_consistency.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/abox_sat_fp_probe.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/abox_saturation.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/adaptive_budget.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/anon349_diagnostic.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/anonymous_individuals_identity.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/anonymous_individuals_reporting.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/approx_saturation_forced_disjunct.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/backfold.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/backjump_precision_gate.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/blocked_disjunction_soundness.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/blocked_disjunction_termination.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/cardinality_disjunct_atoms.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/classify_concrete_domain.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/classify_defined_sweep.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/classify_inverse_domain.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/completeness_contract.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/concrete_domain_clash.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/data_properties.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/data_property_assertions.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/datatype_completeness.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/datatype_inconsistency.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/datatype_value_membership.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/decide_pair_probe.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/diagnose_partition.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/disjunctive_existential_marker_fp.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/domain_gci_completeness.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/existential_successors.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/exists_top_filler.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_direct_bot.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_no_bot.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_different_individuals.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_types.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa_no_clash.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_consistent.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_inconsistent.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_different.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_without_different.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_diff.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_same_target.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric_one_way.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive_distinct.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_compatible.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_disjoint.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_cardinality_disjoint.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain-classified.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition-classified.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_facet.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/functional_data_property.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property-classified.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/functional-equiv-some-bug.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/materialize/rbox-materialized.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/materialize/rbox.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/named-pizza-country-bug.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-01.txt +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-02.txt +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-03.txt +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-04.txt +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-05.txt +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-06.txt +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-07.txt +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-08.txt +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.hermit.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.hermit.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.hermit.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.hermit.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.hermit.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.hermit.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.hermit.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.hermit.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.owx +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/fixtures/phase2b/phase2b-verdicts.log +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/funcmerge_inverse.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/funcmerge_scaling.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/functional_enforcement.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/inverse_cardinality_soundness.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/inverse_symmetric_domain.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/justification.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/konclude_closure_diff.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/label_heuristic_canary.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/laconic_justification.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/materialize_oracle.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/object_has_self_domain.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/phase2c_pair_06_canary.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/precompletion_probe_gate.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/property_assertions.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/real_ontology_corpus.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/repair_suggestions.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/sat_lookahead_gate.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/saturator_disjointness.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/seed_probe_gate.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/shadow_dep_gate.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/snapshot_phase0_canary.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/sp2_nogood_gate.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/subproperty_axioms.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/tautology_skip_canary.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/top_subsumes_all.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/value_type_disjoint_canary.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/value_type_disjoint_probe.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-reasoner/tests/wedge_consistency.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/Cargo.toml +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/README.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/src/lib.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/src/proof.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/src/seed_sat.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/tests/fixtures/phase2a_functional_role_canary.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-saturation/tests/fixtures/phase2b_compound_existential_canary.ofn +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/Cargo.toml +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/README.md +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/counters.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/deps.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/graph.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/hyper.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/lib.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/replay.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/rules.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/saturate.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/search.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/shadow_measures.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/snapshot.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/src/trail.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/backprop_risk.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/replay_driver.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/replay_roundtrip.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/sat_lookahead_drop.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/semantic_branching.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/shadow_dep_probe.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/crates/owl-dl-tableau/tests/snapshot_capture.rs +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/pyproject.toml +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/__init__.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/__init__.pyi +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/_results.py +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/data/pizza.owl.gz +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/data/sio.owl.gz +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/data/sulo.owl.gz +0 -0
- {rustdl-0.3.24 → rustdl-0.3.26}/python/rustdl/examples.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
6
|
+
version = "0.3.26"
|
|
7
7
|
edition = "2024"
|
|
8
8
|
rust-version = "1.88"
|
|
9
9
|
license = "Apache-2.0 OR MIT"
|
|
@@ -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
|
-
.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|