rustdl 0.3.0__tar.gz → 0.3.2__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.0 → rustdl-0.3.2}/Cargo.lock +9 -9
- {rustdl-0.3.0 → rustdl-0.3.2}/Cargo.toml +12 -6
- {rustdl-0.3.0 → rustdl-0.3.2}/PKG-INFO +49 -9
- {rustdl-0.3.0/crates/owl-dl-py → rustdl-0.3.2}/README.md +48 -8
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/convert.rs +4 -7
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/data_axioms.rs +52 -32
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/ir.rs +4 -1
- {rustdl-0.3.0 → rustdl-0.3.2/crates/owl-dl-py}/README.md +48 -8
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/src/classify.rs +2 -2
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/src/errors.rs +7 -5
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/src/lib.rs +1 -1
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/src/materialize.rs +5 -11
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/src/queries.rs +3 -18
- rustdl-0.3.2/crates/owl-dl-py/tests/python/test_examples.py +34 -0
- rustdl-0.3.2/crates/owl-dl-reasoner/src/abox_check.rs +692 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/src/classify.rs +109 -13
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/src/lib.rs +55 -34
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/src/union_find.rs +1 -1
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/abox_consistency.rs +74 -39
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/anon349_diagnostic.rs +10 -4
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/datatype_completeness.rs +15 -30
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/konclude_closure_diff.rs +24 -11
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/label_heuristic_canary.rs +21 -4
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/snapshot_phase0_canary.rs +14 -8
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-saturation/src/lib.rs +212 -64
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/counters.rs +3 -6
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/hyper.rs +338 -41
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/lib.rs +116 -7
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/replay.rs +1 -2
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/rules.rs +50 -9
- {rustdl-0.3.0 → rustdl-0.3.2}/pyproject.toml +1 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/python/rustdl/__init__.py +3 -0
- rustdl-0.3.2/python/rustdl/data/pizza.owl.gz +0 -0
- rustdl-0.3.2/python/rustdl/data/sio.owl.gz +0 -0
- rustdl-0.3.2/python/rustdl/data/sulo.owl.gz +0 -0
- rustdl-0.3.2/python/rustdl/examples.py +115 -0
- rustdl-0.3.0/crates/owl-dl-reasoner/src/abox_check.rs +0 -436
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/Cargo.toml +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/README.md +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/absorb.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/clause.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/convert_back.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/definitions.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/lib.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/locality.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/normalize.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/ontology.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/residual_trigger.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/role_hierarchy.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/told.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/transform.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/src/vocab.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/tests/concept_pool_proptest.proptest-regressions +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/tests/concept_pool_proptest.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/tests/convert_round_trip_proptest.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-core/tests/role_hierarchy_proptest.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-datatypes/Cargo.toml +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-datatypes/README.md +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-datatypes/src/lib.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/.gitignore +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/Cargo.toml +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/src/load.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/tests/python/conftest.py +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/tests/python/test_classify.py +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/tests/python/test_materialize.py +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/tests/python/test_queries.py +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/tests/python/test_smoke.py +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-py/tests/python/test_soundness.py +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/Cargo.toml +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/README.md +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/src/model_cache.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/src/realize.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_direct_bot.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p1_no_bot.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_different_individuals.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p2_disjoint_types.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_neg_opa_no_clash.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_consistent.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p3_role_hierarchy_neg_inconsistent.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_different.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p4_same_without_different.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_diff.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p5_functional_same_target.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_asymmetric_one_way.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p6_irreflexive_distinct.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_compatible.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/abox/p7_range_disjoint.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_cardinality_disjoint.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain-classified.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/datatype/data_property_domain.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition-classified.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_definition.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/datatype/datatype_facet.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/datatype/functional_data_property.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property-classified.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/datatype/sub_data_property.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/functional-equiv-some-bug.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/named-pizza-country-bug.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-01.txt +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-02.txt +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-03.txt +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-04.txt +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-05.txt +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-06.txt +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-07.txt +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/p2b0-terms-08.txt +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.hermit.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_01.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.hermit.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_02.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.hermit.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_03.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.hermit.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_04.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.hermit.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_05.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.hermit.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_06.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.hermit.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_07.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.hermit.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/pair_08.owx +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/fixtures/phase2b/phase2b-verdicts.log +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/phase2c_pair_06_canary.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-reasoner/tests/real_ontology_corpus.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-saturation/Cargo.toml +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-saturation/README.md +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-saturation/tests/fixtures/phase2a_functional_role_canary.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-saturation/tests/fixtures/phase2b_compound_existential_canary.ofn +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/Cargo.toml +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/README.md +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/deps.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/graph.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/saturate.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/search.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/snapshot.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/src/trail.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/tests/backprop_risk.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/tests/replay_driver.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/tests/replay_roundtrip.rs +0 -0
- {rustdl-0.3.0 → rustdl-0.3.2}/crates/owl-dl-tableau/tests/snapshot_capture.rs +0 -0
|
@@ -1037,7 +1037,7 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
|
|
1037
1037
|
|
|
1038
1038
|
[[package]]
|
|
1039
1039
|
name = "owl-dl-bench"
|
|
1040
|
-
version = "0.3.
|
|
1040
|
+
version = "0.3.2"
|
|
1041
1041
|
dependencies = [
|
|
1042
1042
|
"anyhow",
|
|
1043
1043
|
"clap",
|
|
@@ -1054,7 +1054,7 @@ dependencies = [
|
|
|
1054
1054
|
|
|
1055
1055
|
[[package]]
|
|
1056
1056
|
name = "owl-dl-cli"
|
|
1057
|
-
version = "0.3.
|
|
1057
|
+
version = "0.3.2"
|
|
1058
1058
|
dependencies = [
|
|
1059
1059
|
"anyhow",
|
|
1060
1060
|
"clap",
|
|
@@ -1066,7 +1066,7 @@ dependencies = [
|
|
|
1066
1066
|
|
|
1067
1067
|
[[package]]
|
|
1068
1068
|
name = "owl-dl-core"
|
|
1069
|
-
version = "0.3.
|
|
1069
|
+
version = "0.3.2"
|
|
1070
1070
|
dependencies = [
|
|
1071
1071
|
"bitvec",
|
|
1072
1072
|
"bumpalo",
|
|
@@ -1080,7 +1080,7 @@ dependencies = [
|
|
|
1080
1080
|
|
|
1081
1081
|
[[package]]
|
|
1082
1082
|
name = "owl-dl-datatypes"
|
|
1083
|
-
version = "0.3.
|
|
1083
|
+
version = "0.3.2"
|
|
1084
1084
|
dependencies = [
|
|
1085
1085
|
"owl-dl-core",
|
|
1086
1086
|
"proptest",
|
|
@@ -1090,7 +1090,7 @@ dependencies = [
|
|
|
1090
1090
|
|
|
1091
1091
|
[[package]]
|
|
1092
1092
|
name = "owl-dl-py"
|
|
1093
|
-
version = "0.3.
|
|
1093
|
+
version = "0.3.2"
|
|
1094
1094
|
dependencies = [
|
|
1095
1095
|
"horned-owl",
|
|
1096
1096
|
"owl-dl-core",
|
|
@@ -1101,7 +1101,7 @@ dependencies = [
|
|
|
1101
1101
|
|
|
1102
1102
|
[[package]]
|
|
1103
1103
|
name = "owl-dl-reasoner"
|
|
1104
|
-
version = "0.3.
|
|
1104
|
+
version = "0.3.2"
|
|
1105
1105
|
dependencies = [
|
|
1106
1106
|
"dashmap",
|
|
1107
1107
|
"horned-owl",
|
|
@@ -1117,7 +1117,7 @@ dependencies = [
|
|
|
1117
1117
|
|
|
1118
1118
|
[[package]]
|
|
1119
1119
|
name = "owl-dl-saturation"
|
|
1120
|
-
version = "0.3.
|
|
1120
|
+
version = "0.3.2"
|
|
1121
1121
|
dependencies = [
|
|
1122
1122
|
"dashmap",
|
|
1123
1123
|
"fixedbitset",
|
|
@@ -1133,7 +1133,7 @@ dependencies = [
|
|
|
1133
1133
|
|
|
1134
1134
|
[[package]]
|
|
1135
1135
|
name = "owl-dl-tableau"
|
|
1136
|
-
version = "0.3.
|
|
1136
|
+
version = "0.3.2"
|
|
1137
1137
|
dependencies = [
|
|
1138
1138
|
"bitvec",
|
|
1139
1139
|
"bumpalo",
|
|
@@ -2569,7 +2569,7 @@ dependencies = [
|
|
|
2569
2569
|
|
|
2570
2570
|
[[package]]
|
|
2571
2571
|
name = "xtask"
|
|
2572
|
-
version = "0.3.
|
|
2572
|
+
version = "0.3.2"
|
|
2573
2573
|
dependencies = [
|
|
2574
2574
|
"anyhow",
|
|
2575
2575
|
"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.2"
|
|
7
7
|
edition = "2024"
|
|
8
8
|
rust-version = "1.88"
|
|
9
9
|
license = "Apache-2.0 OR MIT"
|
|
@@ -15,11 +15,11 @@ keywords = ["owl", "ontology", "reasoner", "description-logic", "semantic-web"]
|
|
|
15
15
|
categories = ["science", "data-structures"]
|
|
16
16
|
|
|
17
17
|
[workspace.dependencies]
|
|
18
|
-
owl-dl-core = { path = "crates/owl-dl-core", version = "0.3.
|
|
19
|
-
owl-dl-saturation = { path = "crates/owl-dl-saturation", version = "0.3.
|
|
20
|
-
owl-dl-tableau = { path = "crates/owl-dl-tableau", version = "0.3.
|
|
21
|
-
owl-dl-datatypes = { path = "crates/owl-dl-datatypes", version = "0.3.
|
|
22
|
-
owl-dl-reasoner = { path = "crates/owl-dl-reasoner", version = "0.3.
|
|
18
|
+
owl-dl-core = { path = "crates/owl-dl-core", version = "0.3.2" }
|
|
19
|
+
owl-dl-saturation = { path = "crates/owl-dl-saturation", version = "0.3.2" }
|
|
20
|
+
owl-dl-tableau = { path = "crates/owl-dl-tableau", version = "0.3.2" }
|
|
21
|
+
owl-dl-datatypes = { path = "crates/owl-dl-datatypes", version = "0.3.2" }
|
|
22
|
+
owl-dl-reasoner = { path = "crates/owl-dl-reasoner", version = "0.3.2" }
|
|
23
23
|
|
|
24
24
|
horned-owl = { version = "1.4", default-features = false }
|
|
25
25
|
|
|
@@ -60,6 +60,12 @@ missing_errors_doc = "allow"
|
|
|
60
60
|
missing_panics_doc = "allow"
|
|
61
61
|
must_use_candidate = "allow"
|
|
62
62
|
unnecessary_wraps = "allow"
|
|
63
|
+
# Style-only pedantic lints allowed workspace-wide: refactoring long
|
|
64
|
+
# functions / hoisting nested items / renaming similar bindings is churn
|
|
65
|
+
# without correctness value (and risky on the larger engine functions).
|
|
66
|
+
too_many_lines = "allow"
|
|
67
|
+
items_after_statements = "allow"
|
|
68
|
+
similar_names = "allow"
|
|
63
69
|
unwrap_used = "warn"
|
|
64
70
|
dbg_macro = "warn"
|
|
65
71
|
print_stdout = "allow"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rustdl
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Intended Audience :: Science/Research
|
|
6
6
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -48,18 +48,58 @@ Wheels are published for CPython 3.10+ on Linux (x86_64, aarch64), macOS
|
|
|
48
48
|
```python
|
|
49
49
|
import rustdl
|
|
50
50
|
|
|
51
|
-
#
|
|
51
|
+
# A small OWL 2 DL ontology ships inside the wheel (gzip-compressed) — no
|
|
52
|
+
# download needed. `examples.pizza()` returns its file path (decompressed
|
|
53
|
+
# into a per-user cache dir on first use); `examples.PIZZA_NS` is its
|
|
54
|
+
# namespace, so class IRIs are PIZZA_NS + local name (e.g. + "Pizza").
|
|
55
|
+
from rustdl.examples import pizza, PIZZA_NS, SULO_NS
|
|
56
|
+
|
|
57
|
+
# Classify. Format is auto-detected from the extension:
|
|
52
58
|
# .ofn (OWL Functional), .owx (OWL/XML), .rdf / .owl (RDF/XML).
|
|
53
|
-
result = rustdl.classify(
|
|
59
|
+
result = rustdl.classify(pizza())
|
|
54
60
|
|
|
55
|
-
print(f"{len(result.classes)} classes, {len(result.unsatisfiable)} unsatisfiable"
|
|
61
|
+
print(f"{len(result.classes)} classes, {len(result.unsatisfiable)} unsatisfiable, "
|
|
62
|
+
f"complete={result.complete}")
|
|
63
|
+
# -> 88 classes, 0 unsatisfiable, complete=True
|
|
56
64
|
|
|
57
65
|
# Query the computed hierarchy
|
|
58
|
-
result.is_subclass("
|
|
59
|
-
|
|
60
|
-
result.
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
print(result.is_subclass(PIZZA_NS + "BoxedPizza", PIZZA_NS + "Pizza"))
|
|
67
|
+
# -> True
|
|
68
|
+
print(len(result.subclasses_of(PIZZA_NS + "FoodMaterial")))
|
|
69
|
+
# -> 25
|
|
70
|
+
|
|
71
|
+
# The pizza ontology is aligned to the SULO upper ontology, so reasoning
|
|
72
|
+
# spans both — e.g. a pizza-making timestamp is inferred to be a SULO StartTime:
|
|
73
|
+
print(result.is_subclass(PIZZA_NS + "BakingStartTime", SULO_NS + "StartTime"))
|
|
74
|
+
# -> True
|
|
75
|
+
|
|
76
|
+
# Other hierarchy queries (all take full class IRIs):
|
|
77
|
+
result.superclasses_of(PIZZA_NS + "Cheese") # -> list[str]
|
|
78
|
+
result.equivalent_classes(PIZZA_NS + "Pizza") # -> list[str]
|
|
79
|
+
result.direct_subsumers(PIZZA_NS + "BoxedPizza") # -> list[str] (Hasse-direct parents)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Bundled examples
|
|
83
|
+
|
|
84
|
+
Three real ontologies ship inside the wheel, gzip-compressed (~200 KB total).
|
|
85
|
+
They classify with **no network access** — each `examples.X()` decompresses
|
|
86
|
+
its ontology into a per-user cache dir (`$XDG_CACHE_HOME/rustdl/examples` or
|
|
87
|
+
`~/.cache/rustdl/examples`) on first use, then reuses it. Each `examples.X_NS`
|
|
88
|
+
is the namespace, so a class IRI is the namespace plus the local name.
|
|
89
|
+
|
|
90
|
+
| helper | ontology | classes | notes |
|
|
91
|
+
|---|---|---|---|
|
|
92
|
+
| `pizza()` / `PIZZA_NS` | ontostart pizza | 88 | SULO-aligned pizza-making ontology; classifies instantly + complete |
|
|
93
|
+
| `sulo()` / `SULO_NS` | SULO (Simple Upper-Level Ontology) | 17 | tiny; classifies in milliseconds |
|
|
94
|
+
| `sio()` / `SIO_NS` | SIO (Semanticscience Integrated Ontology) | ~1600 | realistic larger workload; takes tens of seconds. Class IRIs are numeric codes, e.g. `SIO_NS + "SIO_000006"` ("process") |
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
import rustdl
|
|
98
|
+
from rustdl import examples
|
|
99
|
+
|
|
100
|
+
r = rustdl.classify(examples.sulo())
|
|
101
|
+
print(r.is_subclass(examples.SULO_NS + "StartTime", examples.SULO_NS + "Object"))
|
|
102
|
+
# -> True
|
|
63
103
|
```
|
|
64
104
|
|
|
65
105
|
## API
|
|
@@ -23,18 +23,58 @@ Wheels are published for CPython 3.10+ on Linux (x86_64, aarch64), macOS
|
|
|
23
23
|
```python
|
|
24
24
|
import rustdl
|
|
25
25
|
|
|
26
|
-
#
|
|
26
|
+
# A small OWL 2 DL ontology ships inside the wheel (gzip-compressed) — no
|
|
27
|
+
# download needed. `examples.pizza()` returns its file path (decompressed
|
|
28
|
+
# into a per-user cache dir on first use); `examples.PIZZA_NS` is its
|
|
29
|
+
# namespace, so class IRIs are PIZZA_NS + local name (e.g. + "Pizza").
|
|
30
|
+
from rustdl.examples import pizza, PIZZA_NS, SULO_NS
|
|
31
|
+
|
|
32
|
+
# Classify. Format is auto-detected from the extension:
|
|
27
33
|
# .ofn (OWL Functional), .owx (OWL/XML), .rdf / .owl (RDF/XML).
|
|
28
|
-
result = rustdl.classify(
|
|
34
|
+
result = rustdl.classify(pizza())
|
|
29
35
|
|
|
30
|
-
print(f"{len(result.classes)} classes, {len(result.unsatisfiable)} unsatisfiable"
|
|
36
|
+
print(f"{len(result.classes)} classes, {len(result.unsatisfiable)} unsatisfiable, "
|
|
37
|
+
f"complete={result.complete}")
|
|
38
|
+
# -> 88 classes, 0 unsatisfiable, complete=True
|
|
31
39
|
|
|
32
40
|
# Query the computed hierarchy
|
|
33
|
-
result.is_subclass("
|
|
34
|
-
|
|
35
|
-
result.
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
print(result.is_subclass(PIZZA_NS + "BoxedPizza", PIZZA_NS + "Pizza"))
|
|
42
|
+
# -> True
|
|
43
|
+
print(len(result.subclasses_of(PIZZA_NS + "FoodMaterial")))
|
|
44
|
+
# -> 25
|
|
45
|
+
|
|
46
|
+
# The pizza ontology is aligned to the SULO upper ontology, so reasoning
|
|
47
|
+
# spans both — e.g. a pizza-making timestamp is inferred to be a SULO StartTime:
|
|
48
|
+
print(result.is_subclass(PIZZA_NS + "BakingStartTime", SULO_NS + "StartTime"))
|
|
49
|
+
# -> True
|
|
50
|
+
|
|
51
|
+
# Other hierarchy queries (all take full class IRIs):
|
|
52
|
+
result.superclasses_of(PIZZA_NS + "Cheese") # -> list[str]
|
|
53
|
+
result.equivalent_classes(PIZZA_NS + "Pizza") # -> list[str]
|
|
54
|
+
result.direct_subsumers(PIZZA_NS + "BoxedPizza") # -> list[str] (Hasse-direct parents)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Bundled examples
|
|
58
|
+
|
|
59
|
+
Three real ontologies ship inside the wheel, gzip-compressed (~200 KB total).
|
|
60
|
+
They classify with **no network access** — each `examples.X()` decompresses
|
|
61
|
+
its ontology into a per-user cache dir (`$XDG_CACHE_HOME/rustdl/examples` or
|
|
62
|
+
`~/.cache/rustdl/examples`) on first use, then reuses it. Each `examples.X_NS`
|
|
63
|
+
is the namespace, so a class IRI is the namespace plus the local name.
|
|
64
|
+
|
|
65
|
+
| helper | ontology | classes | notes |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| `pizza()` / `PIZZA_NS` | ontostart pizza | 88 | SULO-aligned pizza-making ontology; classifies instantly + complete |
|
|
68
|
+
| `sulo()` / `SULO_NS` | SULO (Simple Upper-Level Ontology) | 17 | tiny; classifies in milliseconds |
|
|
69
|
+
| `sio()` / `SIO_NS` | SIO (Semanticscience Integrated Ontology) | ~1600 | realistic larger workload; takes tens of seconds. Class IRIs are numeric codes, e.g. `SIO_NS + "SIO_000006"` ("process") |
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import rustdl
|
|
73
|
+
from rustdl import examples
|
|
74
|
+
|
|
75
|
+
r = rustdl.classify(examples.sulo())
|
|
76
|
+
print(r.is_subclass(examples.SULO_NS + "StartTime", examples.SULO_NS + "Object"))
|
|
77
|
+
# -> True
|
|
38
78
|
```
|
|
39
79
|
|
|
40
80
|
## API
|
|
@@ -522,12 +522,9 @@ pub fn convert_ontology<A: ForIRI>(
|
|
|
522
522
|
// out.axioms.extend (which doesn't need it but reads cleaner).
|
|
523
523
|
let derived = {
|
|
524
524
|
let concepts_cell = std::cell::RefCell::new(&mut out.concepts);
|
|
525
|
-
crate::data_axioms::derive_data_axioms(
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
bot_id,
|
|
529
|
-
|cid| concepts_cell.borrow_mut().atomic(cid),
|
|
530
|
-
)
|
|
525
|
+
crate::data_axioms::derive_data_axioms(src, &out.vocabulary, bot_id, |cid| {
|
|
526
|
+
concepts_cell.borrow_mut().atomic(cid)
|
|
527
|
+
})
|
|
531
528
|
};
|
|
532
529
|
out.axioms.extend(derived);
|
|
533
530
|
out.axioms.sort();
|
|
@@ -1069,7 +1066,7 @@ mod tests {
|
|
|
1069
1066
|
);
|
|
1070
1067
|
}
|
|
1071
1068
|
|
|
1072
|
-
/// Phase D1: a SubClassOf where the SUP contains a data-range
|
|
1069
|
+
/// Phase D1: a `SubClassOf` where the SUP contains a data-range
|
|
1073
1070
|
/// constructor (e.g., `DataMaxCardinality`) is silently dropped —
|
|
1074
1071
|
/// the `ce_or_skip!` macro maps `UnsupportedDataRange` to `Ok(None)`
|
|
1075
1072
|
/// for the enclosing axiom. Sound under-approximation: we lose the
|
|
@@ -91,7 +91,10 @@ pub fn derive_data_axioms<A: ForIRI>(
|
|
|
91
91
|
/// (or its decomposition into mutual SubClassOf), if any atomic Mi
|
|
92
92
|
/// has cardinality bounds on a data property dp, propagate those
|
|
93
93
|
/// bounds to C. Iterates to fixpoint to handle transitive defs.
|
|
94
|
-
#[allow(
|
|
94
|
+
#[allow(
|
|
95
|
+
clippy::too_many_lines,
|
|
96
|
+
reason = "single fixpoint with 4 facts to propagate; splitting hurts readability"
|
|
97
|
+
)]
|
|
95
98
|
fn propagate_intersection_bounds<A: ForIRI>(src: &SetOntology<A>, facts: &mut Facts) {
|
|
96
99
|
// Collect: class_iri → vec of atomic-member iris from Intersection
|
|
97
100
|
// equivalences. Includes EquivalentClasses(C, Intersection(...)) and
|
|
@@ -110,8 +113,7 @@ fn propagate_intersection_bounds<A: ForIRI>(src: &SetOntology<A>, facts: &mut Fa
|
|
|
110
113
|
}
|
|
111
114
|
});
|
|
112
115
|
for parts in intersection_members {
|
|
113
|
-
let part_iris: Vec<String> =
|
|
114
|
-
parts.iter().filter_map(class_iri).collect();
|
|
116
|
+
let part_iris: Vec<String> = parts.iter().filter_map(class_iri).collect();
|
|
115
117
|
for owner in &atomic_members {
|
|
116
118
|
for part in &part_iris {
|
|
117
119
|
if owner != part {
|
|
@@ -230,7 +232,10 @@ struct IntegerRange {
|
|
|
230
232
|
|
|
231
233
|
impl IntegerRange {
|
|
232
234
|
const fn unbounded() -> Self {
|
|
233
|
-
Self {
|
|
235
|
+
Self {
|
|
236
|
+
min: None,
|
|
237
|
+
max: None,
|
|
238
|
+
}
|
|
234
239
|
}
|
|
235
240
|
fn intersect(self, other: Self) -> Self {
|
|
236
241
|
let min = match (self.min, other.min) {
|
|
@@ -334,11 +339,7 @@ fn scan_component<A: ForIRI>(c: &Component<A>, f: &mut Facts) {
|
|
|
334
339
|
// purposes. Bound-collection: if a is atomic class C and b
|
|
335
340
|
// is an ObjectIntersectionOf with data-cardinality conjuncts,
|
|
336
341
|
// those conjuncts' bounds apply to C.
|
|
337
|
-
let atomic: Vec<String> = ax
|
|
338
|
-
.0
|
|
339
|
-
.iter()
|
|
340
|
-
.filter_map(class_iri)
|
|
341
|
-
.collect();
|
|
342
|
+
let atomic: Vec<String> = ax.0.iter().filter_map(class_iri).collect();
|
|
342
343
|
for c in &atomic {
|
|
343
344
|
for other in &ax.0 {
|
|
344
345
|
scan_class_for_bounds(c, other, f);
|
|
@@ -405,11 +406,7 @@ fn scan_class_for_bounds<A: ForIRI>(class_iri: &str, ce: &ClassExpression<A>, f:
|
|
|
405
406
|
/// `ObjectIntersectionOf`. Phase D5 (Tier C): also records integer
|
|
406
407
|
/// ranges from `DataSomeValuesFrom(dp, DatatypeRestriction(xsd:integer, ...))`
|
|
407
408
|
/// into `f.class_int_ranges`.
|
|
408
|
-
fn scan_class_for_existentials<A: ForIRI>(
|
|
409
|
-
class_iri: &str,
|
|
410
|
-
ce: &ClassExpression<A>,
|
|
411
|
-
f: &mut Facts,
|
|
412
|
-
) {
|
|
409
|
+
fn scan_class_for_existentials<A: ForIRI>(class_iri: &str, ce: &ClassExpression<A>, f: &mut Facts) {
|
|
413
410
|
match ce {
|
|
414
411
|
ClassExpression::DataSomeValuesFrom { dp, dr } => {
|
|
415
412
|
f.class_some.insert((class_iri.to_string(), dpe_iri(dp)));
|
|
@@ -467,14 +464,22 @@ fn parse_integer_facets<A: ForIRI>(facets: &[FacetRestriction<A>]) -> Option<Int
|
|
|
467
464
|
Facet::MinExclusive => {
|
|
468
465
|
// xsd:integer-semantics: exclusive ≥ val + 1
|
|
469
466
|
let inclusive = val.checked_add(1)?;
|
|
470
|
-
range.min = Some(
|
|
467
|
+
range.min = Some(
|
|
468
|
+
range
|
|
469
|
+
.min
|
|
470
|
+
.map_or(inclusive, |existing| existing.max(inclusive)),
|
|
471
|
+
);
|
|
471
472
|
}
|
|
472
473
|
Facet::MaxInclusive => {
|
|
473
474
|
range.max = Some(range.max.map_or(val, |existing| existing.min(val)));
|
|
474
475
|
}
|
|
475
476
|
Facet::MaxExclusive => {
|
|
476
477
|
let inclusive = val.checked_sub(1)?;
|
|
477
|
-
range.max = Some(
|
|
478
|
+
range.max = Some(
|
|
479
|
+
range
|
|
480
|
+
.max
|
|
481
|
+
.map_or(inclusive, |existing| existing.min(inclusive)),
|
|
482
|
+
);
|
|
478
483
|
}
|
|
479
484
|
_ => return None,
|
|
480
485
|
}
|
|
@@ -608,15 +613,18 @@ fn emit_subdataprop_transitivity(
|
|
|
608
613
|
// C ⊑ DataSome(specific) + DataSome(general) ⊑ D ⇒ C ⊑ D.
|
|
609
614
|
let closure = closure_sub_dp(&f.sub_data_property);
|
|
610
615
|
for (class_iri, specific_dp) in &f.class_some {
|
|
611
|
-
let Some(supers) = closure.get(specific_dp) else {
|
|
616
|
+
let Some(supers) = closure.get(specific_dp) else {
|
|
617
|
+
continue;
|
|
618
|
+
};
|
|
612
619
|
for general_dp in supers {
|
|
613
|
-
let Some(super_classes) = f.some_super.get(general_dp) else {
|
|
620
|
+
let Some(super_classes) = f.some_super.get(general_dp) else {
|
|
621
|
+
continue;
|
|
622
|
+
};
|
|
614
623
|
for d_iri in super_classes {
|
|
615
624
|
if class_iri == d_iri {
|
|
616
625
|
continue;
|
|
617
626
|
}
|
|
618
|
-
if let (Some(c_id), Some(d_id)) =
|
|
619
|
-
(vocab.class_id(class_iri), vocab.class_id(d_iri))
|
|
627
|
+
if let (Some(c_id), Some(d_id)) = (vocab.class_id(class_iri), vocab.class_id(d_iri))
|
|
620
628
|
{
|
|
621
629
|
out.push(Axiom::SubClassOf {
|
|
622
630
|
sub: atomic_id(c_id),
|
|
@@ -698,20 +706,22 @@ fn _unused_datarange<A: ForIRI>(_: &DataRange<A>) {}
|
|
|
698
706
|
mod tests {
|
|
699
707
|
use super::*;
|
|
700
708
|
use crate::convert::convert_ontology;
|
|
701
|
-
use horned_owl::io::ofn::reader::read as read_ofn;
|
|
702
709
|
use horned_owl::io::ParserConfiguration;
|
|
710
|
+
use horned_owl::io::ofn::reader::read as read_ofn;
|
|
703
711
|
use horned_owl::model::RcStr;
|
|
704
712
|
use horned_owl::ontology::set::SetOntology;
|
|
705
713
|
use std::io::Cursor;
|
|
706
714
|
|
|
707
715
|
fn parse_str(src: &str) -> SetOntology<RcStr> {
|
|
708
716
|
let mut r = Cursor::new(src);
|
|
709
|
-
read_ofn(&mut r, ParserConfiguration::default())
|
|
717
|
+
read_ofn(&mut r, ParserConfiguration::default())
|
|
718
|
+
.expect("test fixture parses")
|
|
719
|
+
.0
|
|
710
720
|
}
|
|
711
721
|
|
|
712
722
|
#[test]
|
|
713
723
|
fn extracts_functional_dp_min_clash() {
|
|
714
|
-
let src = r
|
|
724
|
+
let src = r"Prefix(:=<http://t/>)
|
|
715
725
|
Prefix(xsd:=<http://www.w3.org/2001/XMLSchema#>)
|
|
716
726
|
Ontology(<http://t/x>
|
|
717
727
|
Declaration(Class(:HasTwoAges))
|
|
@@ -719,19 +729,22 @@ Ontology(<http://t/x>
|
|
|
719
729
|
FunctionalDataProperty(:age)
|
|
720
730
|
SubClassOf(:HasTwoAges DataMinCardinality(2 :age))
|
|
721
731
|
)
|
|
722
|
-
"
|
|
732
|
+
";
|
|
723
733
|
let onto = parse_str(src);
|
|
724
734
|
let facts = extract_facts(&onto);
|
|
725
735
|
assert!(facts.functional_dps.contains("http://t/age"));
|
|
726
736
|
assert_eq!(
|
|
727
|
-
facts.class_min.get(&(
|
|
737
|
+
facts.class_min.get(&(
|
|
738
|
+
"http://t/HasTwoAges".to_string(),
|
|
739
|
+
"http://t/age".to_string()
|
|
740
|
+
)),
|
|
728
741
|
Some(&2)
|
|
729
742
|
);
|
|
730
743
|
}
|
|
731
744
|
|
|
732
745
|
#[test]
|
|
733
746
|
fn derives_functional_dp_min_unsat_in_convert() {
|
|
734
|
-
let src = r
|
|
747
|
+
let src = r"Prefix(:=<http://t/>)
|
|
735
748
|
Prefix(xsd:=<http://www.w3.org/2001/XMLSchema#>)
|
|
736
749
|
Ontology(<http://t/x>
|
|
737
750
|
Declaration(Class(:HasTwoAges))
|
|
@@ -739,15 +752,22 @@ Ontology(<http://t/x>
|
|
|
739
752
|
FunctionalDataProperty(:age)
|
|
740
753
|
SubClassOf(:HasTwoAges DataMinCardinality(2 :age))
|
|
741
754
|
)
|
|
742
|
-
"
|
|
755
|
+
";
|
|
743
756
|
let onto = parse_str(src);
|
|
744
|
-
let mut internal = convert_ontology(&onto).
|
|
745
|
-
let has_two_ages = internal
|
|
757
|
+
let mut internal = convert_ontology(&onto).expect("test ontology converts");
|
|
758
|
+
let has_two_ages = internal
|
|
759
|
+
.vocabulary
|
|
760
|
+
.class_id("http://t/HasTwoAges")
|
|
746
761
|
.expect("HasTwoAges interned");
|
|
747
762
|
let bot = internal.concepts.bot();
|
|
748
763
|
let sub_concept = internal.concepts.atomic(has_two_ages);
|
|
749
|
-
let found_unsat = internal.axioms.iter().any(|ax|
|
|
750
|
-
|
|
751
|
-
|
|
764
|
+
let found_unsat = internal.axioms.iter().any(|ax| {
|
|
765
|
+
matches!(ax,
|
|
766
|
+
Axiom::SubClassOf { sub, sup } if *sub == sub_concept && *sup == bot)
|
|
767
|
+
});
|
|
768
|
+
assert!(
|
|
769
|
+
found_unsat,
|
|
770
|
+
"D4: HasTwoAges ⊑ Bot should be derived from Functional + DataMin"
|
|
771
|
+
);
|
|
752
772
|
}
|
|
753
773
|
}
|
|
@@ -599,7 +599,10 @@ mod tests {
|
|
|
599
599
|
first, second,
|
|
600
600
|
"bot_id() before Bot interning must be stable across pool growth"
|
|
601
601
|
);
|
|
602
|
-
assert!(
|
|
602
|
+
assert!(
|
|
603
|
+
first.is_none(),
|
|
604
|
+
"bot_id() returns None before Bot is interned"
|
|
605
|
+
);
|
|
603
606
|
|
|
604
607
|
// Intern Bot. Both subsequent calls must return the same Some(id).
|
|
605
608
|
let _bot_id = pool.bot();
|
|
@@ -23,18 +23,58 @@ Wheels are published for CPython 3.10+ on Linux (x86_64, aarch64), macOS
|
|
|
23
23
|
```python
|
|
24
24
|
import rustdl
|
|
25
25
|
|
|
26
|
-
#
|
|
26
|
+
# A small OWL 2 DL ontology ships inside the wheel (gzip-compressed) — no
|
|
27
|
+
# download needed. `examples.pizza()` returns its file path (decompressed
|
|
28
|
+
# into a per-user cache dir on first use); `examples.PIZZA_NS` is its
|
|
29
|
+
# namespace, so class IRIs are PIZZA_NS + local name (e.g. + "Pizza").
|
|
30
|
+
from rustdl.examples import pizza, PIZZA_NS, SULO_NS
|
|
31
|
+
|
|
32
|
+
# Classify. Format is auto-detected from the extension:
|
|
27
33
|
# .ofn (OWL Functional), .owx (OWL/XML), .rdf / .owl (RDF/XML).
|
|
28
|
-
result = rustdl.classify(
|
|
34
|
+
result = rustdl.classify(pizza())
|
|
29
35
|
|
|
30
|
-
print(f"{len(result.classes)} classes, {len(result.unsatisfiable)} unsatisfiable"
|
|
36
|
+
print(f"{len(result.classes)} classes, {len(result.unsatisfiable)} unsatisfiable, "
|
|
37
|
+
f"complete={result.complete}")
|
|
38
|
+
# -> 88 classes, 0 unsatisfiable, complete=True
|
|
31
39
|
|
|
32
40
|
# Query the computed hierarchy
|
|
33
|
-
result.is_subclass("
|
|
34
|
-
|
|
35
|
-
result.
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
print(result.is_subclass(PIZZA_NS + "BoxedPizza", PIZZA_NS + "Pizza"))
|
|
42
|
+
# -> True
|
|
43
|
+
print(len(result.subclasses_of(PIZZA_NS + "FoodMaterial")))
|
|
44
|
+
# -> 25
|
|
45
|
+
|
|
46
|
+
# The pizza ontology is aligned to the SULO upper ontology, so reasoning
|
|
47
|
+
# spans both — e.g. a pizza-making timestamp is inferred to be a SULO StartTime:
|
|
48
|
+
print(result.is_subclass(PIZZA_NS + "BakingStartTime", SULO_NS + "StartTime"))
|
|
49
|
+
# -> True
|
|
50
|
+
|
|
51
|
+
# Other hierarchy queries (all take full class IRIs):
|
|
52
|
+
result.superclasses_of(PIZZA_NS + "Cheese") # -> list[str]
|
|
53
|
+
result.equivalent_classes(PIZZA_NS + "Pizza") # -> list[str]
|
|
54
|
+
result.direct_subsumers(PIZZA_NS + "BoxedPizza") # -> list[str] (Hasse-direct parents)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Bundled examples
|
|
58
|
+
|
|
59
|
+
Three real ontologies ship inside the wheel, gzip-compressed (~200 KB total).
|
|
60
|
+
They classify with **no network access** — each `examples.X()` decompresses
|
|
61
|
+
its ontology into a per-user cache dir (`$XDG_CACHE_HOME/rustdl/examples` or
|
|
62
|
+
`~/.cache/rustdl/examples`) on first use, then reuses it. Each `examples.X_NS`
|
|
63
|
+
is the namespace, so a class IRI is the namespace plus the local name.
|
|
64
|
+
|
|
65
|
+
| helper | ontology | classes | notes |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| `pizza()` / `PIZZA_NS` | ontostart pizza | 88 | SULO-aligned pizza-making ontology; classifies instantly + complete |
|
|
68
|
+
| `sulo()` / `SULO_NS` | SULO (Simple Upper-Level Ontology) | 17 | tiny; classifies in milliseconds |
|
|
69
|
+
| `sio()` / `SIO_NS` | SIO (Semanticscience Integrated Ontology) | ~1600 | realistic larger workload; takes tens of seconds. Class IRIs are numeric codes, e.g. `SIO_NS + "SIO_000006"` ("process") |
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import rustdl
|
|
73
|
+
from rustdl import examples
|
|
74
|
+
|
|
75
|
+
r = rustdl.classify(examples.sulo())
|
|
76
|
+
print(r.is_subclass(examples.SULO_NS + "StartTime", examples.SULO_NS + "Object"))
|
|
77
|
+
# -> True
|
|
38
78
|
```
|
|
39
79
|
|
|
40
80
|
## API
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//! `classify` / `classify_bytes` top-level functions + the
|
|
2
|
-
//! `Classification` PyO3 class that wraps `owl_dl_reasoner::Classification`.
|
|
2
|
+
//! `Classification` `PyO3` class that wraps `owl_dl_reasoner::Classification`.
|
|
3
3
|
|
|
4
4
|
use owl_dl_reasoner::{Classification as RsClassification, classify as rs_classify};
|
|
5
5
|
use pyo3::prelude::*;
|
|
@@ -32,7 +32,7 @@ impl PyClassification {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/// True iff the whole ontology was flagged inconsistent.
|
|
35
|
-
/// (Set by the Phase-A1 ABox consistency check.)
|
|
35
|
+
/// (Set by the Phase-A1 `ABox` consistency check.)
|
|
36
36
|
#[getter]
|
|
37
37
|
fn inconsistent(&self) -> bool {
|
|
38
38
|
self.inner.stats().inconsistent
|
|
@@ -17,7 +17,12 @@ use pyo3::create_exception;
|
|
|
17
17
|
use pyo3::exceptions::PyException;
|
|
18
18
|
use pyo3::prelude::*;
|
|
19
19
|
|
|
20
|
-
create_exception!(
|
|
20
|
+
create_exception!(
|
|
21
|
+
rustdl,
|
|
22
|
+
RustdlError,
|
|
23
|
+
PyException,
|
|
24
|
+
"Base exception for all rustdl errors."
|
|
25
|
+
);
|
|
21
26
|
create_exception!(rustdl, ParseError, RustdlError, "OWL parser failure.");
|
|
22
27
|
create_exception!(
|
|
23
28
|
rustdl,
|
|
@@ -41,10 +46,7 @@ pub(crate) fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
41
46
|
"UnsupportedAxiomError",
|
|
42
47
|
m.py().get_type::<UnsupportedAxiomError>(),
|
|
43
48
|
)?;
|
|
44
|
-
m.add(
|
|
45
|
-
"UnknownClassError",
|
|
46
|
-
m.py().get_type::<UnknownClassError>(),
|
|
47
|
-
)?;
|
|
49
|
+
m.add("UnknownClassError", m.py().get_type::<UnknownClassError>())?;
|
|
48
50
|
Ok(())
|
|
49
51
|
}
|
|
50
52
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//! Python bindings for the rustdl OWL DL reasoner.
|
|
2
2
|
//!
|
|
3
|
-
//! Built with PyO3 + maturin. Distributed on PyPI as `rustdl`;
|
|
3
|
+
//! Built with `PyO3` + maturin. Distributed on `PyPI` as `rustdl`;
|
|
4
4
|
//! imported in Python as `import rustdl`. See the spec at
|
|
5
5
|
//! `docs/superpowers/specs/2026-06-04-python-bindings-design.md`.
|
|
6
6
|
|
|
@@ -13,16 +13,12 @@ use crate::load;
|
|
|
13
13
|
/// - Pairs involving `owl:Thing` or `owl:Nothing`
|
|
14
14
|
/// - Pairs from unsatisfiable classes (which trivially subsume all)
|
|
15
15
|
#[pyfunction]
|
|
16
|
-
pub(crate) fn materialize_inferred_subclass_axioms(
|
|
17
|
-
path: &str,
|
|
18
|
-
) -> PyResult<Vec<(String, String)>> {
|
|
16
|
+
pub(crate) fn materialize_inferred_subclass_axioms(path: &str) -> PyResult<Vec<(String, String)>> {
|
|
19
17
|
let ontology = load::load_path(path)?;
|
|
20
18
|
let classification = owl_dl_reasoner::classify(&ontology).map_err(reason_error_to_py)?;
|
|
21
19
|
let classes = classification.classes();
|
|
22
|
-
let unsat: std::collections::HashSet<&str> =
|
|
23
|
-
.unsatisfiable_classes()
|
|
24
|
-
.into_iter()
|
|
25
|
-
.collect();
|
|
20
|
+
let unsat: std::collections::HashSet<&str> =
|
|
21
|
+
classification.unsatisfiable_classes().into_iter().collect();
|
|
26
22
|
let mut out = Vec::new();
|
|
27
23
|
for sub in classes {
|
|
28
24
|
if unsat.contains(sub.as_str()) {
|
|
@@ -53,15 +49,13 @@ pub(crate) fn materialize_inferred_subclass_axioms(
|
|
|
53
49
|
/// Returns every (class IRI, individual IRI) pair `(c, i)` such that
|
|
54
50
|
/// `ClassAssertion(c, i)` is entailed.
|
|
55
51
|
#[pyfunction]
|
|
56
|
-
pub(crate) fn materialize_inferred_class_assertions(
|
|
57
|
-
path: &str,
|
|
58
|
-
) -> PyResult<Vec<(String, String)>> {
|
|
52
|
+
pub(crate) fn materialize_inferred_class_assertions(path: &str) -> PyResult<Vec<(String, String)>> {
|
|
59
53
|
let ontology = load::load_path(path)?;
|
|
60
54
|
let realization = owl_dl_reasoner::realize(&ontology).map_err(reason_error_to_py)?;
|
|
61
55
|
let mut out = Vec::new();
|
|
62
56
|
for ind in realization.individuals() {
|
|
63
57
|
for c in realization.most_specific_types(ind) {
|
|
64
|
-
out.push((c.
|
|
58
|
+
out.push((c.clone(), ind.clone()));
|
|
65
59
|
}
|
|
66
60
|
}
|
|
67
61
|
Ok(out)
|