use std::collections::HashSet;
use super::{mk_triple, vocab, Owl2DLReasoner, RuleFirings, Triple};
impl Owl2DLReasoner {
pub(crate) fn apply_sub_property_of(
&self,
triples: &HashSet<Triple>,
new_triples: &mut HashSet<Triple>,
firings: &mut RuleFirings,
) {
for (sub_prop, sup_prop) in self
.sub_object_property_of
.iter()
.chain(self.sub_data_property_of.iter())
{
let is_data = self
.sub_data_property_of
.contains(&(sub_prop.clone(), sup_prop.clone()));
for (s, p, o) in triples {
if p != sub_prop {
continue;
}
if p == vocab::RDF_TYPE
|| p == vocab::RDFS_SUBPROPERTY_OF
|| p == vocab::RDFS_SUBCLASS_OF
{
continue;
}
let t = mk_triple(s, sup_prop, o);
if !triples.contains(&t) {
new_triples.insert(t);
if is_data {
firings.sub_data_property += 1;
} else {
firings.sub_object_property += 1;
}
}
}
}
}
pub(crate) fn apply_equivalent_properties(
&self,
triples: &HashSet<Triple>,
new_triples: &mut HashSet<Triple>,
firings: &mut RuleFirings,
) {
for (p1, p2) in &self.equivalent_properties {
for (s, p, o) in triples {
if p != p1 {
continue;
}
if p == vocab::RDF_TYPE
|| p == vocab::RDFS_SUBPROPERTY_OF
|| p == vocab::RDFS_SUBCLASS_OF
|| p == vocab::OWL_EQUIVALENT_PROPERTY
{
continue;
}
let t = mk_triple(s, p2, o);
if !triples.contains(&t) {
new_triples.insert(t);
firings.equivalent_properties += 1;
}
}
}
}
pub(crate) fn apply_reflexive_property(
&self,
triples: &HashSet<Triple>,
new_triples: &mut HashSet<Triple>,
firings: &mut RuleFirings,
) {
let reflexive_props: Vec<&String> = self
.property_chars
.iter()
.filter(|(_, c)| c.is_reflexive)
.map(|(p, _)| p)
.collect();
if reflexive_props.is_empty() {
return;
}
let mut individuals: HashSet<&str> = HashSet::new();
for (s, p, o) in triples {
individuals.insert(s.as_str());
if p == vocab::RDF_TYPE {
let _ = o; }
}
for (_, p, o) in triples {
if p != vocab::RDFS_SUBCLASS_OF
&& p != vocab::RDFS_SUBPROPERTY_OF
&& p != vocab::OWL_EQUIVALENT_CLASS
&& p != vocab::OWL_EQUIVALENT_PROPERTY
&& p != vocab::OWL_INVERSE_OF
&& p != vocab::RDFS_DOMAIN
&& p != vocab::RDFS_RANGE
&& p != vocab::OWL_PROPERTY_DISJOINT_WITH
&& p != vocab::OWL_DISJOINT_WITH
{
individuals.insert(o.as_str());
}
}
for prop in &reflexive_props {
for ind in &individuals {
let t = mk_triple(ind, prop, ind);
if !triples.contains(&t) {
new_triples.insert(t);
firings.reflexive_self += 1;
}
}
}
}
pub(crate) fn apply_has_self(
&self,
triples: &HashSet<Triple>,
new_triples: &mut HashSet<Triple>,
firings: &mut RuleFirings,
) {
for hs in &self.has_self_restrictions {
for (s, p, o) in triples {
if p == &hs.property && s == o {
let t = mk_triple(s, vocab::RDF_TYPE, &hs.restriction_class);
if !triples.contains(&t) {
new_triples.insert(t);
firings.has_self += 1;
}
}
}
for (s, p, o) in triples {
if p == vocab::RDF_TYPE && o == &hs.restriction_class {
let t = mk_triple(s, &hs.property, s);
if !triples.contains(&t) {
new_triples.insert(t);
firings.has_self += 1;
}
}
}
}
}
pub(crate) fn check_disjoint_property_violations(&mut self) {
let canonical_pairs: HashSet<(String, String)> = self
.disjoint_properties
.iter()
.filter(|(p1, p2)| p1 < p2)
.cloned()
.collect();
for (p1, p2) in &canonical_pairs {
let p1_pairs: Vec<(String, String)> = self
.abox
.iter()
.filter(|(_, p, _)| p == p1)
.map(|(s, _, o)| (s.clone(), o.clone()))
.collect();
for (s, o) in &p1_pairs {
if self.abox.contains(&mk_triple(s, p2, o)) {
let msg = format!(
"DisjointProperties violation: {s} {p1} {o} AND {s} {p2} {o} \
(properties are declared disjoint)"
);
if !self.inconsistencies.contains(&msg) {
self.inconsistencies.push(msg);
}
}
}
}
}
pub(crate) fn check_negative_property_assertion_violations(
&mut self,
firings: &mut RuleFirings,
) {
let obj_negatives: Vec<_> = self.negative_object_assertions.clone();
for npa in &obj_negatives {
if self.abox.contains(&mk_triple(
&npa.source_individual,
&npa.assertion_property,
&npa.target_individual,
)) {
let msg = format!(
"NegativePropertyAssertion violation: {} {} {} is asserted \
but declared as a negative object property assertion",
npa.source_individual, npa.assertion_property, npa.target_individual
);
if !self.inconsistencies.contains(&msg) {
self.inconsistencies.push(msg);
firings.negative_property_assertion += 1;
}
}
}
let data_negatives: Vec<_> = self.negative_data_assertions.clone();
for npa in &data_negatives {
if self.abox.contains(&mk_triple(
&npa.source_individual,
&npa.assertion_property,
&npa.target_value,
)) {
let msg = format!(
"NegativeDataPropertyAssertion violation: {} {} {} is asserted \
but declared as a negative data property assertion",
npa.source_individual, npa.assertion_property, npa.target_value
);
if !self.inconsistencies.contains(&msg) {
self.inconsistencies.push(msg);
firings.negative_property_assertion += 1;
}
}
}
}
}