1use roaring::RoaringBitmap;
11
12use crate::csr::{Csr, CsrError};
13use crate::ordinal::{Ordinal, to_usize};
14
15#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
17pub enum ClosureError {
18 #[error("the is-a hierarchy has a cycle through {} node(s), for example {first}", .members.len())]
20 Cycle {
21 first: Ordinal,
23 members: Vec<Ordinal>,
25 },
26 #[error(transparent)]
28 Csr(#[from] CsrError),
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct Closure {
34 ancestors: Vec<RoaringBitmap>,
35 descendants: Vec<RoaringBitmap>,
36}
37
38static EMPTY: std::sync::LazyLock<RoaringBitmap> = std::sync::LazyLock::new(RoaringBitmap::new);
39
40impl Closure {
41 pub fn compute(is_a: &Csr) -> Result<Self, ClosureError> {
47 let parents = is_a;
48 let children = is_a.transpose()?;
49 let order = topological_order(parents, &children)?;
50 let nodes = to_usize(parents.nodes());
51 let mut ancestors: Vec<RoaringBitmap> = vec![RoaringBitmap::new(); nodes];
52 for node in &order {
53 let mut set = RoaringBitmap::new();
54 for parent in parents.neighbours(*node) {
55 set.insert(*parent);
56 if let Some(above) = ancestors.get(to_usize(*parent)) {
57 set |= above;
58 }
59 }
60 if let Some(slot) = ancestors.get_mut(node.as_usize()) {
61 *slot = set;
62 }
63 }
64 let mut descendants: Vec<RoaringBitmap> = vec![RoaringBitmap::new(); nodes];
65 for node in order.iter().rev() {
66 let mut set = RoaringBitmap::new();
67 for child in children.neighbours(*node) {
68 set.insert(*child);
69 if let Some(below) = descendants.get(to_usize(*child)) {
70 set |= below;
71 }
72 }
73 if let Some(slot) = descendants.get_mut(node.as_usize()) {
74 *slot = set;
75 }
76 }
77 Ok(Self {
78 ancestors,
79 descendants,
80 })
81 }
82
83 #[must_use]
85 pub fn from_parts(ancestors: Vec<RoaringBitmap>, descendants: Vec<RoaringBitmap>) -> Self {
86 Self {
87 ancestors,
88 descendants,
89 }
90 }
91
92 #[must_use]
94 pub fn nodes(&self) -> u32 {
95 u32::try_from(self.ancestors.len()).unwrap_or(u32::MAX)
96 }
97
98 #[must_use]
100 pub fn ancestors(&self, node: Ordinal) -> &RoaringBitmap {
101 self.ancestors
102 .get(node.as_usize())
103 .unwrap_or_else(|| &*EMPTY)
104 }
105
106 #[must_use]
108 pub fn descendants(&self, node: Ordinal) -> &RoaringBitmap {
109 self.descendants
110 .get(node.as_usize())
111 .unwrap_or_else(|| &*EMPTY)
112 }
113
114 #[must_use]
116 pub fn descendants_or_self(&self, node: Ordinal) -> RoaringBitmap {
117 let mut set = self.descendants(node).clone();
118 set.insert(node.index());
119 set
120 }
121
122 #[must_use]
124 pub fn ancestors_or_self(&self, node: Ordinal) -> RoaringBitmap {
125 let mut set = self.ancestors(node).clone();
126 set.insert(node.index());
127 set
128 }
129
130 #[must_use]
132 pub fn is_ancestor(&self, ancestor: Ordinal, node: Ordinal) -> bool {
133 self.ancestors(node).contains(ancestor.index())
134 }
135
136 #[must_use]
138 pub fn ancestor_sets(&self) -> &[RoaringBitmap] {
139 &self.ancestors
140 }
141
142 #[must_use]
144 pub fn descendant_sets(&self) -> &[RoaringBitmap] {
145 &self.descendants
146 }
147}
148
149fn topological_order(parents: &Csr, children: &Csr) -> Result<Vec<Ordinal>, ClosureError> {
151 let nodes = parents.nodes();
152 let mut remaining: Vec<u32> = (0..nodes)
153 .map(|n| u32::try_from(parents.neighbours(Ordinal::new(n)).len()).unwrap_or(u32::MAX))
154 .collect();
155 let mut ready: Vec<Ordinal> = (0..nodes)
156 .filter(|n| remaining.get(to_usize(*n)) == Some(&0))
157 .map(Ordinal::new)
158 .collect();
159 let mut order = Vec::with_capacity(to_usize(nodes));
160 while let Some(node) = ready.pop() {
161 order.push(node);
162 for child in children.neighbours(node) {
163 if let Some(count) = remaining.get_mut(to_usize(*child)) {
164 *count = count.saturating_sub(1);
165 if *count == 0 {
166 ready.push(Ordinal::new(*child));
167 }
168 }
169 }
170 }
171 if order.len() != to_usize(nodes) {
172 let members: Vec<Ordinal> = (0..nodes)
173 .filter(|n| remaining.get(to_usize(*n)).is_some_and(|c| *c > 0))
174 .map(Ordinal::new)
175 .collect();
176 let first = members.first().copied().unwrap_or(Ordinal::new(0));
177 return Err(ClosureError::Cycle { first, members });
178 }
179 Ok(order)
180}
181
182#[cfg(test)]
183mod tests {
184 use super::{Closure, ClosureError};
185 use crate::csr::Csr;
186 use crate::ordinal::Ordinal;
187
188 fn o(i: u32) -> Ordinal {
189 Ordinal::new(i)
190 }
191
192 fn diamond() -> Closure {
194 let is_a = Csr::build(4, [(o(1), o(0)), (o(2), o(0)), (o(3), o(1)), (o(3), o(2))])
195 .expect("builds");
196 Closure::compute(&is_a).expect("acyclic")
197 }
198
199 #[test]
200 fn ancestors_and_descendants_are_transitive_and_inverse() {
201 let closure = diamond();
202 assert_eq!(
203 closure.ancestors(o(3)).iter().collect::<Vec<_>>(),
204 vec![0, 1, 2]
205 );
206 assert_eq!(
207 closure.descendants(o(0)).iter().collect::<Vec<_>>(),
208 vec![1, 2, 3]
209 );
210 assert_eq!(
211 closure.descendants(o(1)).iter().collect::<Vec<_>>(),
212 vec![3]
213 );
214 assert!(closure.ancestors(o(0)).is_empty());
215 assert!(closure.descendants(o(3)).is_empty());
216 assert!(closure.is_ancestor(o(0), o(3)));
217 assert!(!closure.is_ancestor(o(3), o(0)));
218 assert!(closure.descendants_or_self(o(3)).contains(3));
219 assert_eq!(closure.ancestors_or_self(o(3)).len(), 4);
220 }
221
222 #[test]
223 fn a_cycle_is_refused() {
224 let is_a = Csr::build(3, [(o(0), o(1)), (o(1), o(2)), (o(2), o(0))]).expect("builds");
225 match Closure::compute(&is_a) {
226 Err(ClosureError::Cycle { members, .. }) => assert_eq!(members.len(), 3),
227 other => panic!("expected a cycle, got {other:?}"),
228 }
229 }
230
231 #[test]
232 fn unknown_nodes_have_empty_sets() {
233 let closure = diamond();
234 assert!(closure.ancestors(o(99)).is_empty());
235 assert!(closure.descendants(o(99)).is_empty());
236 }
237}