Skip to content

RDFS Materialization

RDFS TBox materialization via ontologos-rdfs: transitive subClassOf / subPropertyOf closure and object-property domain/range inheritance.

Prerequisites

  • Rust 1.88+
  • An OWL/RDF file (.owl, .rdf, .ttl, .ofn) or a repository clone for benchmark examples

Run the CLI

Build from a clone (CLI is not on crates.io):

cargo build -p ontologos-cli --release
./target/release/ontologos materialize path/to/ontology.owl

Prefer materialize over classify — both run the same RDFS engine in v0.4, but classify is named like OWL taxonomy classification tools (ELK/HermiT) and is easy to misread.

Expected text output (Family corpus, abbreviated):

status: materialized
initial_axiom_count: 57
final_axiom_count: 62
inferred_axioms: 5
inferred_by_rule:
  rng_inherit: 5

JSON output: ./target/release/ontologos --format json materialize path/to/ontology.owl

Library (crates.io)

Add dependencies:

[dependencies]
ontologos-core = "0.5.0"
ontologos-parser = "0.5.0"
ontologos-rdfs = "0.5.0"

Load and materialize:

use ontologos_parser::load_ontology;
use ontologos_rdfs::RdfsEngine;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let path = std::path::Path::new("ontology.owl");
    let mut ontology = load_ontology(path)?;

    let initial = ontology.axiom_count();
    let report = RdfsEngine::new().materialize(&mut ontology)?;

    println!("initial axioms: {initial}");
    println!("final axioms: {}", report.final_axiom_count);
    println!("inferred: {}", report.inferred_total());
    for (rule, count) in &report.inferred_by_rule {
        println!("  {}: {count}", rule.as_str());
    }

    Ok(())
}

Do not call Reasoner::classify() on core for RDFS — it returns a delegate hint. Use RdfsEngine::materialize or ontologos_rdfs::classify_reasoner.

Via the reasoner facade

use ontologos_core::{Profile, Reasoner};
use ontologos_parser::load_ontology;
use ontologos_rdfs::classify_reasoner;

let ontology = load_ontology(path)?;
let mut reasoner = Reasoner::builder()
    .profile(Profile::Rdfs)
    .build(ontology)?;

classify_reasoner(&mut reasoner)?;
println!("axioms: {}", reasoner.ontology().axiom_count());

Reading the report

Field Meaning
initial_axiom_count Axioms before materialization
final_axiom_count Axioms after RDFS closure
inferred_by_rule Per-rule counts (subclass_trans, subprop_trans, dom_inherit, rng_inherit)
traces Per-inference records when tracing is enabled

inferred_total() equals final_axiom_count - initial_axiom_count.

What RDFS materializes (v0.4)

Input in core Materialized
SubClassOf Transitive closure
SubObjectPropertyOf Transitive closure
ObjectPropertyDomain / ObjectPropertyRange Inherited along subPropertyOf
EquivalentClasses Stored only — mutual subsumption via OWL RL saturation
ABox assertions Not propagated — use RL saturation

Python

from ontologos import Reasoner

reasoner = Reasoner("ontology.owl", profile="rdfs")
reasoner.classify()
print(reasoner.parse_meta["mapped_axiom_count"])

See Python guide for limitations.

Next steps