pub mod dl_reasoner;
pub mod el_reasoner;
pub mod ontology;
pub mod profile;
pub mod ql_reasoner;
pub mod rl_reasoner;
pub mod rlel_combined;
pub use dl_reasoner::{Dl2Error, ProfileDlReasoner};
pub use el_reasoner::{El2Error, ProfileElReasoner};
pub use ontology::{
Owl2Axiom, Owl2Ontology, Owl2OntologyBuilder, ProfileEntailment, ReasoningOutcome,
};
pub use profile::OwlProfile;
pub use ql_reasoner::{ProfileQlReasoner, Ql2Error};
pub use rl_reasoner::{ProfileRlReasoner, Rl2Error};
pub use rlel_combined::{RlElError, RlElReasoner, RlElReport};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Owl2DispatchError {
#[error(transparent)]
Rl(#[from] Rl2Error),
#[error(transparent)]
El(#[from] El2Error),
#[error(transparent)]
Ql(#[from] Ql2Error),
#[error(transparent)]
RlEl(#[from] RlElError),
#[error(transparent)]
Dl(#[from] Dl2Error),
}
pub fn reason_in_profile(
profile: OwlProfile,
ontology: &Owl2Ontology,
) -> Result<ReasoningOutcome, Owl2DispatchError> {
match profile {
OwlProfile::Rl => {
let mut r = ProfileRlReasoner::new();
r.load(ontology);
Ok(r.reason()?)
}
OwlProfile::El => {
let mut r = ProfileElReasoner::new();
r.load(ontology);
Ok(r.reason()?)
}
OwlProfile::Ql => {
let mut r = ProfileQlReasoner::new();
r.load(ontology);
Ok(r.reason(ontology)?)
}
OwlProfile::RlEl => {
let mut r = RlElReasoner::new();
r.load(ontology);
Ok(r.reason()?)
}
OwlProfile::Dl => {
let mut r = ProfileDlReasoner::new();
r.load(ontology);
Ok(r.reason()?)
}
}
}
pub trait ProfileReasoner {
type Err;
fn load_ontology(&mut self, ontology: &Owl2Ontology);
fn reason(&mut self, ontology: &Owl2Ontology) -> Result<ReasoningOutcome, Self::Err>;
}
impl ProfileReasoner for ProfileRlReasoner {
type Err = Rl2Error;
fn load_ontology(&mut self, ontology: &Owl2Ontology) {
ProfileRlReasoner::load(self, ontology);
}
fn reason(&mut self, _ontology: &Owl2Ontology) -> Result<ReasoningOutcome, Self::Err> {
ProfileRlReasoner::reason(self)
}
}
impl ProfileReasoner for ProfileElReasoner {
type Err = El2Error;
fn load_ontology(&mut self, ontology: &Owl2Ontology) {
ProfileElReasoner::load(self, ontology);
}
fn reason(&mut self, _ontology: &Owl2Ontology) -> Result<ReasoningOutcome, Self::Err> {
ProfileElReasoner::reason(self)
}
}
impl ProfileReasoner for ProfileQlReasoner {
type Err = Ql2Error;
fn load_ontology(&mut self, ontology: &Owl2Ontology) {
ProfileQlReasoner::load(self, ontology);
}
fn reason(&mut self, ontology: &Owl2Ontology) -> Result<ReasoningOutcome, Self::Err> {
ProfileQlReasoner::reason(self, ontology)
}
}
impl ProfileReasoner for RlElReasoner {
type Err = RlElError;
fn load_ontology(&mut self, ontology: &Owl2Ontology) {
RlElReasoner::load(self, ontology);
}
fn reason(&mut self, _ontology: &Owl2Ontology) -> Result<ReasoningOutcome, Self::Err> {
RlElReasoner::reason(self)
}
}
impl ProfileReasoner for ProfileDlReasoner {
type Err = Dl2Error;
fn load_ontology(&mut self, ontology: &Owl2Ontology) {
ProfileDlReasoner::load(self, ontology);
}
fn reason(&mut self, _ontology: &Owl2Ontology) -> Result<ReasoningOutcome, Self::Err> {
ProfileDlReasoner::reason(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn pizza_subset() -> Owl2Ontology {
Owl2OntologyBuilder::new()
.sub_class_of("Margherita", "Pizza")
.sub_class_of("Pizza", "Food")
.sub_class_of("MozzarellaTopping", "PizzaTopping")
.sub_class_some_values("Margherita", "hasTopping", "MozzarellaTopping")
.some_values_sub_class("hasTopping", "MozzarellaTopping", "PizzaWithMozzarella")
.type_of("pizza1", "Margherita")
.build()
}
#[test]
fn dispatches_rl_profile() {
let ontology = pizza_subset();
let outcome = reason_in_profile(OwlProfile::Rl, &ontology).expect("rl ok");
let pizza1_food = outcome.contains(&ProfileEntailment::Type {
individual: "pizza1".into(),
class: "Food".into(),
});
assert!(pizza1_food, "RL should derive pizza1 ⊑ Food");
}
#[test]
fn dispatches_el_profile() {
let ontology = pizza_subset();
let outcome = reason_in_profile(OwlProfile::El, &ontology).expect("el ok");
let pizza1_pwm = outcome.contains(&ProfileEntailment::Type {
individual: "pizza1".into(),
class: "PizzaWithMozzarella".into(),
});
assert!(
pizza1_pwm,
"EL should derive pizza1 ⊑ PizzaWithMozzarella; got: {:?}",
outcome.entailments
);
}
#[test]
fn dispatches_ql_profile() {
let ontology = pizza_subset();
let outcome = reason_in_profile(OwlProfile::Ql, &ontology).expect("ql ok");
let pizza1_food = outcome.contains(&ProfileEntailment::Type {
individual: "pizza1".into(),
class: "Food".into(),
});
assert!(pizza1_food, "QL should answer pizza1:Food");
}
#[test]
fn dispatches_rlel_profile() {
let ontology = pizza_subset();
let outcome = reason_in_profile(OwlProfile::RlEl, &ontology).expect("rlel ok");
let pizza1_pwm = outcome.contains(&ProfileEntailment::Type {
individual: "pizza1".into(),
class: "PizzaWithMozzarella".into(),
});
let pizza1_food = outcome.contains(&ProfileEntailment::Type {
individual: "pizza1".into(),
class: "Food".into(),
});
assert!(pizza1_food, "RLEL should derive pizza1 ⊑ Food");
assert!(
pizza1_pwm,
"RLEL should derive pizza1 ⊑ PizzaWithMozzarella via EL leg; got: {:?}",
outcome.entailments
);
}
#[test]
fn dispatches_dl_profile() {
let ontology = pizza_subset();
let outcome = reason_in_profile(OwlProfile::Dl, &ontology).expect("dl ok");
let pizza1_food = outcome.contains(&ProfileEntailment::Type {
individual: "pizza1".into(),
class: "Food".into(),
});
assert!(pizza1_food, "DL should derive pizza1 ⊑ Food");
}
}