ontologos-rl 0.4.0

OWL RL rule-based reasoning engine for OntoLogos
Documentation
use ontologos_core::{Axiom, EntityId, EntityKind};

use super::helpers::{
    expand_equivalent_classes, expand_equivalent_properties, infer_axiom, transitive_subproperties,
    transitive_superproperties, RuleContext,
};
use crate::report::RlRule;

pub(crate) fn apply_batch_a(ctx: &mut RuleContext<'_>) -> ontologos_core::Result<()> {
    apply_equivalent_classes(ctx)?;
    apply_equivalent_properties(ctx)?;
    apply_characteristic_propagation(ctx)?;
    apply_existential_subproperty(ctx)?;
    apply_existential_subsumption(ctx)?;
    Ok(())
}

fn apply_equivalent_classes(ctx: &mut RuleContext<'_>) -> ontologos_core::Result<()> {
    let classes: Vec<EntityId> = ctx
        .ontology
        .entities()
        .iter()
        .filter(|(_, record)| record.kind == EntityKind::Class)
        .map(|(id, _)| id)
        .collect();

    for class in classes {
        let equiv: Vec<EntityId> = ctx
            .ontology
            .equivalents_of(class)
            .map(|set| set.iter().copied().collect())
            .unwrap_or_default();
        for other in equiv {
            if class != other {
                infer_axiom(
                    ctx,
                    RlRule::EqClassSub,
                    Axiom::SubClassOf {
                        subclass: class,
                        superclass: other,
                    },
                    vec![],
                )?;
            }
        }
    }
    Ok(())
}

fn apply_equivalent_properties(ctx: &mut RuleContext<'_>) -> ontologos_core::Result<()> {
    let properties: Vec<EntityId> = ctx
        .ontology
        .entities()
        .iter()
        .filter(|(_, record)| record.kind == EntityKind::ObjectProperty)
        .map(|(id, _)| id)
        .collect();

    for property in properties {
        let equiv: Vec<EntityId> = ctx
            .ontology
            .equivalent_properties_of(property)
            .map(|set| set.iter().copied().collect())
            .unwrap_or_default();
        for other in equiv {
            if property != other {
                infer_axiom(
                    ctx,
                    RlRule::EqPropSub,
                    Axiom::SubObjectPropertyOf {
                        sub_property: property,
                        super_property: other,
                    },
                    vec![],
                )?;
            }
        }
    }
    Ok(())
}

fn apply_characteristic_propagation(ctx: &mut RuleContext<'_>) -> ontologos_core::Result<()> {
    let properties: Vec<EntityId> = ctx
        .ontology
        .entities()
        .iter()
        .filter(|(_, record)| record.kind == EntityKind::ObjectProperty)
        .map(|(id, _)| id)
        .collect();

    for sub_property in properties {
        for super_property in transitive_superproperties(ctx.ontology, sub_property) {
            if super_property == sub_property {
                continue;
            }
            if ctx
                .ontology
                .index()
                .transitive_properties()
                .contains(&super_property)
            {
                infer_axiom(
                    ctx,
                    RlRule::CharPropagate,
                    Axiom::TransitiveObjectProperty(sub_property),
                    vec![],
                )?;
            }
            if ctx
                .ontology
                .index()
                .symmetric_properties()
                .contains(&super_property)
            {
                infer_axiom(
                    ctx,
                    RlRule::CharPropagate,
                    Axiom::SymmetricObjectProperty(sub_property),
                    vec![],
                )?;
            }
            if ctx
                .ontology
                .index()
                .reflexive_properties()
                .contains(&super_property)
            {
                infer_axiom(
                    ctx,
                    RlRule::CharPropagate,
                    Axiom::ReflexiveObjectProperty(sub_property),
                    vec![],
                )?;
            }
            if ctx
                .ontology
                .index()
                .functional_properties()
                .contains(&super_property)
            {
                infer_axiom(
                    ctx,
                    RlRule::CharPropagate,
                    Axiom::FunctionalObjectProperty(sub_property),
                    vec![],
                )?;
            }
            if ctx
                .ontology
                .index()
                .asymmetric_properties()
                .contains(&super_property)
            {
                infer_axiom(
                    ctx,
                    RlRule::CharPropagate,
                    Axiom::AsymmetricObjectProperty(sub_property),
                    vec![],
                )?;
            }
        }
    }
    Ok(())
}

fn apply_existential_subproperty(ctx: &mut RuleContext<'_>) -> ontologos_core::Result<()> {
    let classes: Vec<EntityId> = ctx
        .ontology
        .entities()
        .iter()
        .filter(|(_, record)| record.kind == EntityKind::Class)
        .map(|(id, _)| id)
        .collect();

    for subclass in classes.clone() {
        let existentials = ctx.ontology.existentials_of(subclass).to_vec();
        for (property, filler) in existentials {
            for super_property in transitive_subproperties(ctx.ontology, property) {
                if super_property == property {
                    continue;
                }
                infer_axiom(
                    ctx,
                    RlRule::ExistentialSubProp,
                    Axiom::SubClassOfExistential {
                        subclass,
                        property: super_property,
                        filler,
                    },
                    vec![],
                )?;
            }
            for equiv_property in expand_equivalent_properties(ctx.ontology, property) {
                if equiv_property == property {
                    continue;
                }
                infer_axiom(
                    ctx,
                    RlRule::ExistentialSubProp,
                    Axiom::SubClassOfExistential {
                        subclass,
                        property: equiv_property,
                        filler,
                    },
                    vec![],
                )?;
            }
        }
    }

    for class in classes {
        for equiv_class in expand_equivalent_classes(ctx.ontology, class) {
            if equiv_class == class {
                continue;
            }
            let existentials = ctx.ontology.existentials_of(class).to_vec();
            for (property, filler) in existentials {
                infer_axiom(
                    ctx,
                    RlRule::ExistentialSubProp,
                    Axiom::SubClassOfExistential {
                        subclass: equiv_class,
                        property,
                        filler,
                    },
                    vec![],
                )?;
            }
        }
    }

    Ok(())
}

fn apply_existential_subsumption(ctx: &mut RuleContext<'_>) -> ontologos_core::Result<()> {
    let classes: Vec<EntityId> = ctx
        .ontology
        .entities()
        .iter()
        .filter(|(_, record)| record.kind == EntityKind::Class)
        .map(|(id, _)| id)
        .collect();

    let mut existentials: Vec<(EntityId, EntityId, EntityId)> = Vec::new();
    for subclass in &classes {
        for &(property, filler) in ctx.ontology.existentials_of(*subclass) {
            existentials.push((*subclass, property, filler));
        }
    }

    for (sub_x, prop_x, filler_x) in &existentials {
        let supers = transitive_superproperties(ctx.ontology, *prop_x);
        for (sub_y, prop_y, filler_y) in &existentials {
            if sub_x == sub_y || filler_x != filler_y {
                continue;
            }
            if supers.contains(prop_y) {
                infer_axiom(
                    ctx,
                    RlRule::ExistentialSubsumption,
                    Axiom::SubClassOf {
                        subclass: *sub_x,
                        superclass: *sub_y,
                    },
                    vec![],
                )?;
            }
        }
    }
    Ok(())
}