OWL EL Classification¶
Completion-based OWL EL taxonomy classification via ontologos-el. The engine computes direct and indirect subsumptions, equivalence clusters, and unsatisfiable classes from mapped EL TBox axioms.
Prerequisites¶
- Rust 1.88+
- An EL-shaped ontology (
.owl,.rdf,.ttl,.ofn) or a repository clone for benchmark examples
Download Pizza (not bundled in pip/crates.io installs):
Verify profile before classifying:
Expected output (abbreviated):
Pizza often detects as DL because of inverse/functional properties in the source — use --profile el to force EL classification on mapped axioms, or use a corpus that is EL-only.
Run the CLI¶
cargo build -p ontologos-cli --release
./target/release/ontologos classify --profile el pizza.owl
./target/release/ontologos classify --profile auto family.owl
classify --profile auto routes to EL taxonomy when detection reports EL, otherwise RL saturation. Use --profile rdfs for RDFS materialization, or materialize for explicit RDFS.
Expected text output (abbreviated):
JSON output:
Explain inferences:
Library (crates.io)¶
Download Family (for auto/rl demos) or clone for Pizza:
curl -L -o family.owl \
https://raw.githubusercontent.com/eddiethedean/ontologos/main/benchmarks/data/family.owl
Add dependencies:
Remove ontologos-ql unless you use TaxonomyHierarchy (see Query API).
Load and classify:
use ontologos_el::ElClassifier;
use ontologos_parser::load_ontology;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = std::path::Path::new("family.owl");
let ontology = load_ontology(path)?;
let taxonomy = ElClassifier::new().classify(&ontology)?;
println!("subsumptions: {}", taxonomy.subsumption_count());
for (sub, sup) in taxonomy.subsumptions() {
println!(" {} ⊑ {}", sub, sup);
}
Ok(())
}
For EL via the reasoner wrapper, use ontologos_facade::classify or ontologos_el::classify_reasoner. See Facade API.
Via the reasoner facade¶
use ontologos_core::{Profile, Reasoner, ReasonerConfig};
use ontologos_facade::{classify, ClassifyOutcome};
use ontologos_parser::load_ontology;
let ontology = load_ontology(path)?;
let mut reasoner = Reasoner::builder()
.profile(Profile::El)
.config(ReasonerConfig::default())
.build(ontology)?;
match classify(&mut reasoner)? {
ClassifyOutcome::Taxonomy(t) => {
println!("subsumptions: {}", t.subsumption_count());
}
_ => unreachable!("EL profile yields taxonomy"),
}
Query the taxonomy¶
use ontologos_el::ElClassifier;
use ontologos_parser::load_ontology;
use ontologos_ql::TaxonomyHierarchy;
let ontology = load_ontology(path)?;
let taxonomy = ElClassifier::new().classify(&ontology)?;
let hierarchy = TaxonomyHierarchy::new(&ontology, &taxonomy);
let pizza = hierarchy
.lookup("http://www.co-ode.org/ontologies/pizza/pizza.owl#Pizza")
.expect("class registered");
let supers = hierarchy.direct_superclasses(pizza)?;
println!("direct superclasses of Pizza: {supers:?}");
See Query API reference.
Reading the taxonomy¶
| Field | Meaning |
|---|---|
subsumption_count |
Number of direct and indirect subClassOf relationships inferred |
subsumptions |
Pairs (sub, sup) of class entity IDs |
equivalences |
Clusters of mutually equivalent classes |
unsatisfiable |
Classes inferred to be equivalent to owl:Nothing |
IRIs are resolved via ontology.iri(entity_id) or Python reasoner.taxonomy after classify().
Python¶
EL file demo (Pizza): clone the repo and run ./benchmarks/scripts/download.sh, then use benchmarks/data/pizza.owl. For a no-clone EL demo, use the in-memory builder from Examples gallery.
from ontologos import OntologyBuilder, Reasoner
b = OntologyBuilder()
b.add_class("http://example.org/Food")
b.add_class("http://example.org/Pizza")
b.subclass_of("http://example.org/Pizza", "http://example.org/Food")
reasoner = Reasoner(ontology=b.build(), profile="el")
taxonomy = reasoner.classify()
print(taxonomy["subsumption_count"])
Pizza from clone:
from ontologos import Reasoner
reasoner = Reasoner(path="benchmarks/data/pizza.owl", profile="el")
taxonomy = reasoner.classify()
print(taxonomy["subsumption_count"])
graph = reasoner.explain()
print(graph["node_count"])
See Python guide and Incremental reasoning.
Limitations¶
- Classifies mapped EL TBox axioms only; complex DL constructs remain skipped by the parser.
- Hybrid ontologies (EL + RL shapes) should use an explicit
--profileorprofile=flag. - QL and DL profiles are detect-only — no reasoning engine;
autoerrors on pure DL ontologies. - Explanations for EL inferences are available via
ontologos-explain, CLIexplain, and Pythonexplain(). RL/RDFS explain coverage is partial — see Explain API.
Next steps¶
- Choosing an API — RDFS vs RL vs EL
- Profile detection — EL/RL/QL/DL diagnostics
- Explain API — proof graphs
- Supported constructs
- Migration v0.4→v0.5 — CLI classify semantics change