use serde::{Deserialize, Serialize};
use crate::entity::EntityId;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Taxonomy {
pub subsumptions: Vec<(EntityId, EntityId)>,
pub equivalences: Vec<Vec<EntityId>>,
pub unsatisfiable: Vec<EntityId>,
}
impl Taxonomy {
#[must_use]
pub fn subsumption_count(&self) -> usize {
self.subsumptions.len()
}
#[must_use]
pub fn direct_superclasses(&self, class: EntityId) -> Vec<EntityId> {
self.subsumptions
.iter()
.filter_map(|&(sub, sup)| (sub == class).then_some(sup))
.collect()
}
#[must_use]
pub fn direct_subclasses(&self, class: EntityId) -> Vec<EntityId> {
self.subsumptions
.iter()
.filter_map(|&(sub, sup)| (sup == class).then_some(sub))
.collect()
}
#[must_use]
pub fn is_subsumed(&self, sub: EntityId, sup: EntityId) -> bool {
if sub == sup {
return true;
}
let mut stack: Vec<EntityId> = self.direct_superclasses(sub);
let mut seen = std::collections::HashSet::new();
while let Some(current) = stack.pop() {
if current == sup {
return true;
}
if !seen.insert(current) {
continue;
}
stack.extend(self.direct_superclasses(current));
}
false
}
#[must_use]
pub fn equivalent_classes(&self, class: EntityId) -> Option<&[EntityId]> {
self.equivalences
.iter()
.find(|cluster| cluster.contains(&class))
.map(Vec::as_slice)
}
}