use ontologos_bridge::{
materialize_with_session, take_reasonable_session, MaterializeOutcome, MergeLimits,
};
use ontologos_core::{Ontology, Profile, Reasoner};
use crate::report::MaterializationReport;
#[derive(Debug)]
pub struct RlEngine {
_record_traces: bool,
merge_limits: MergeLimits,
}
impl RlEngine {
#[must_use]
pub fn new(_parallelism: usize) -> Self {
Self {
_record_traces: false,
merge_limits: MergeLimits::default(),
}
}
pub fn try_new(parallelism: usize) -> crate::Result<Self> {
if parallelism == 0 || parallelism > 64 {
return Err(crate::Error::Core(ontologos_core::Error::Message(format!(
"parallelism must be in 1..=64, got {parallelism}"
))));
}
Ok(Self::new(parallelism))
}
#[must_use]
pub fn with_traces(mut self, enabled: bool) -> Self {
self._record_traces = enabled;
self
}
#[must_use]
pub fn with_merge_limits(mut self, limits: MergeLimits) -> Self {
self.merge_limits = limits;
self
}
pub fn saturate(&self, ontology: &mut Ontology) -> crate::Result<MaterializationReport> {
let initial_axiom_count = ontology.axiom_count();
let (outcome, _) = materialize_with_session(
ontology,
ontologos_bridge::ReasonableSession::new(),
false,
self.merge_limits,
)
.map_err(|boxed| crate::Error::Bridge(boxed.0))?;
Ok(report_from_outcome(
initial_axiom_count,
ontology.axiom_count(),
outcome,
))
}
pub fn saturate_reasoner(
&self,
reasoner: &mut Reasoner,
) -> crate::Result<MaterializationReport> {
let initial_axiom_count = reasoner.ontology().axiom_count();
let incremental = reasoner.config().incremental;
let session = take_reasonable_session(reasoner, Profile::Rl);
match materialize_with_session(
reasoner.ontology_mut(),
session,
incremental,
self.merge_limits,
) {
Ok((outcome, session)) => {
reasoner.set_session(Box::new(session));
Ok(report_from_outcome(
initial_axiom_count,
reasoner.ontology().axiom_count(),
outcome,
))
}
Err(boxed) => {
let (e, session) = *boxed;
reasoner.set_session(Box::new(session));
Err(crate::Error::Bridge(e))
}
}
}
}
fn report_from_outcome(
initial_axiom_count: usize,
final_axiom_count: usize,
outcome: MaterializeOutcome,
) -> MaterializationReport {
MaterializationReport {
initial_axiom_count,
final_axiom_count,
rdfs_inferred: 0,
inferred_by_rule: std::collections::BTreeMap::new(),
trace: ontologos_core::InferenceTrace::new(),
clashes: outcome.merge.clashes,
disjoint_clash_keys: std::collections::HashSet::new(),
same_as_clash_keys: std::collections::HashSet::new(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use ontologos_core::{Axiom, EntityKind};
#[test]
fn saturates_subclass_chain() {
let mut ontology = Ontology::new();
let a = ontology
.entity_id("http://ex.org/A", EntityKind::Class)
.unwrap();
let b = ontology
.entity_id("http://ex.org/B", EntityKind::Class)
.unwrap();
let c = ontology
.entity_id("http://ex.org/C", EntityKind::Class)
.unwrap();
ontology
.add_axiom(Axiom::SubClassOf {
subclass: a,
superclass: b,
})
.unwrap();
ontology
.add_axiom(Axiom::SubClassOf {
subclass: b,
superclass: c,
})
.unwrap();
let report = RlEngine::new(1).saturate(&mut ontology).unwrap();
assert!(
report.inferred_total() >= 1 || report.final_axiom_count > report.initial_axiom_count
);
}
}