1use std::collections::{BTreeSet, btree_set};
15use std::iter::Map;
16
17use serde::{Deserialize, Serialize};
18
19use crate::vertex::Vertex;
20
21#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
22#[serde(transparent)]
23pub struct VertexSet {
24 inner: BTreeSet<Vertex>,
25}
26
27impl VertexSet {
28 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub fn insert(&mut self, v: Vertex) -> bool {
35 self.inner.insert(v)
36 }
37
38 pub fn contains(&self, v: &Vertex) -> bool {
40 self.inner.contains(v)
41 }
42
43 pub fn len(&self) -> usize {
45 self.inner.len()
46 }
47
48 pub fn is_empty(&self) -> bool {
50 self.inner.is_empty()
51 }
52
53 pub fn iter(&self) -> impl Iterator<Item = &Vertex> {
55 self.inner.iter()
56 }
57
58 pub fn union(&self, other: &VertexSet) -> VertexSet {
60 VertexSet {
61 inner: self.inner.union(&other.inner).cloned().collect(),
62 }
63 }
64
65 pub fn intersection(&self, other: &VertexSet) -> VertexSet {
67 VertexSet {
68 inner: self.inner.intersection(&other.inner).cloned().collect(),
69 }
70 }
71
72 pub fn difference(&self, other: &VertexSet) -> VertexSet {
74 VertexSet {
75 inner: self.inner.difference(&other.inner).cloned().collect(),
76 }
77 }
78}
79
80impl FromIterator<Vertex> for VertexSet {
81 fn from_iter<I: IntoIterator<Item = Vertex>>(iter: I) -> Self {
82 Self {
83 inner: iter.into_iter().collect(),
84 }
85 }
86}
87
88impl<'a> IntoIterator for &'a VertexSet {
89 type Item = &'a Vertex;
90 type IntoIter = btree_set::Iter<'a, Vertex>;
91
92 fn into_iter(self) -> Self::IntoIter {
93 self.inner.iter()
94 }
95}
96
97#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
98#[serde(transparent)]
99pub struct Relation {
100 inner: BTreeSet<(Vertex, Vertex)>,
101}
102
103impl Relation {
104 pub fn new() -> Self {
106 Self::default()
107 }
108
109 pub fn insert(&mut self, src: Vertex, tgt: Vertex) -> bool {
111 self.inner.insert((src, tgt))
112 }
113
114 pub fn contains(&self, src: &Vertex, tgt: &Vertex) -> bool {
116 self.inner.contains(&(src.clone(), tgt.clone()))
117 }
118
119 pub fn len(&self) -> usize {
121 self.inner.len()
122 }
123
124 pub fn is_empty(&self) -> bool {
126 self.inner.is_empty()
127 }
128
129 pub fn iter(&self) -> impl Iterator<Item = (&Vertex, &Vertex)> {
131 self.inner.iter().map(|(a, b)| (a, b))
132 }
133
134 pub fn union(&self, other: &Relation) -> Relation {
136 Relation {
137 inner: self.inner.union(&other.inner).cloned().collect(),
138 }
139 }
140
141 pub fn intersection(&self, other: &Relation) -> Relation {
143 Relation {
144 inner: self.inner.intersection(&other.inner).cloned().collect(),
145 }
146 }
147
148 pub fn difference(&self, other: &Relation) -> Relation {
150 Relation {
151 inner: self.inner.difference(&other.inner).cloned().collect(),
152 }
153 }
154
155 pub fn targets(&self) -> VertexSet {
157 self.inner.iter().map(|(_, t)| t.clone()).collect()
158 }
159
160 pub fn image(&self, sources: &VertexSet) -> VertexSet {
162 self.inner
163 .iter()
164 .filter(|(s, _)| sources.contains(s))
165 .map(|(_, t)| t.clone())
166 .collect()
167 }
168
169 pub fn preimage(&self, targets: &VertexSet) -> VertexSet {
171 self.inner
172 .iter()
173 .filter(|(_, t)| targets.contains(t))
174 .map(|(s, _)| s.clone())
175 .collect()
176 }
177
178 pub fn reversed(&self) -> Relation {
180 Relation {
181 inner: self
182 .inner
183 .iter()
184 .map(|(s, t)| (t.clone(), s.clone()))
185 .collect(),
186 }
187 }
188
189 pub fn transitive_closure(&self) -> Relation {
194 closure::compute(self)
195 }
196}
197
198impl FromIterator<(Vertex, Vertex)> for Relation {
199 fn from_iter<I: IntoIterator<Item = (Vertex, Vertex)>>(iter: I) -> Self {
200 Self {
201 inner: iter.into_iter().collect(),
202 }
203 }
204}
205
206impl<'a> IntoIterator for &'a Relation {
207 type Item = (&'a Vertex, &'a Vertex);
208 type IntoIter = Map<
209 btree_set::Iter<'a, (Vertex, Vertex)>,
210 fn(&'a (Vertex, Vertex)) -> (&'a Vertex, &'a Vertex),
211 >;
212
213 fn into_iter(self) -> Self::IntoIter {
214 self.inner.iter().map(|(a, b)| (a, b))
215 }
216}
217
218mod closure {
219 use std::collections::{BTreeMap, BTreeSet};
220
221 use crate::relation::Relation;
222 use crate::vertex::Vertex;
223
224 pub(super) fn compute(r: &Relation) -> Relation {
225 let adj = build_adj(r);
226 let sccs = tarjan_sccs(&adj);
227 let mut comp_of: BTreeMap<&Vertex, usize> = BTreeMap::new();
228 for (idx, scc) in sccs.iter().enumerate() {
229 for v in scc {
230 comp_of.insert(v, idx);
231 }
232 }
233 let mut cond_adj: Vec<BTreeSet<usize>> = vec![BTreeSet::new(); sccs.len()];
234 for (s, ts) in &adj {
235 let ci = comp_of[s];
236 for t in ts {
237 let cj = comp_of[t];
238 if ci != cj {
239 cond_adj[ci].insert(cj);
240 }
241 }
242 }
243 let topo = reverse_topo(&cond_adj);
244 let mut reach: Vec<BTreeSet<usize>> = vec![BTreeSet::new(); sccs.len()];
245 for &c in &topo {
246 let mut rr = BTreeSet::new();
247 for &nc in &cond_adj[c] {
248 rr.insert(nc);
249 rr.extend(reach[nc].iter().copied());
250 }
251 reach[c] = rr;
252 }
253 let mut out: BTreeSet<(Vertex, Vertex)> = BTreeSet::new();
254 for (idx, scc) in sccs.iter().enumerate() {
255 let intra_cycle =
257 scc.len() > 1 || adj.get(&scc[0]).is_some_and(|out| out.contains(&scc[0]));
258 for v in scc {
259 if intra_cycle {
260 for u in scc {
261 out.insert(((*v).clone(), (*u).clone()));
262 }
263 }
264 for &nc in &reach[idx] {
265 for u in &sccs[nc] {
266 out.insert(((*v).clone(), (*u).clone()));
267 }
268 }
269 }
270 }
271 Relation { inner: out }
272 }
273
274 fn build_adj(r: &Relation) -> BTreeMap<&Vertex, Vec<&Vertex>> {
275 let mut adj: BTreeMap<&Vertex, Vec<&Vertex>> = BTreeMap::new();
276 for (s, t) in r.iter() {
277 adj.entry(s).or_default().push(t);
278 adj.entry(t).or_default();
279 }
280 adj
281 }
282
283 fn tarjan_sccs<'a>(adj: &BTreeMap<&'a Vertex, Vec<&'a Vertex>>) -> Vec<Vec<&'a Vertex>> {
286 let nodes: Vec<&'a Vertex> = adj.keys().copied().collect();
287 let id_of: BTreeMap<&Vertex, usize> =
288 nodes.iter().enumerate().map(|(i, v)| (*v, i)).collect();
289 let neighbours: Vec<Vec<usize>> = nodes
290 .iter()
291 .map(|v| adj[v].iter().map(|w| id_of[w]).collect())
292 .collect();
293 let n = nodes.len();
294
295 const UNVISITED: usize = usize::MAX;
296 let mut indices = vec![UNVISITED; n];
297 let mut lowlinks = vec![0usize; n];
298 let mut on_stack = vec![false; n];
299 let mut tarjan_stack: Vec<usize> = Vec::new();
300 let mut next_index = 0usize;
301 let mut out: Vec<Vec<&'a Vertex>> = Vec::new();
302
303 let mut work: Vec<(usize, usize)> = Vec::new();
305 for start in 0..n {
306 if indices[start] != UNVISITED {
307 continue;
308 }
309 work.push((start, 0));
310 while let Some(&(v, child)) = work.last() {
311 if child == 0 {
312 indices[v] = next_index;
313 lowlinks[v] = next_index;
314 next_index += 1;
315 tarjan_stack.push(v);
316 on_stack[v] = true;
317 }
318 let mut recursed = false;
319 let mut i = child;
320 while i < neighbours[v].len() {
321 let w = neighbours[v][i];
322 if indices[w] == UNVISITED {
323 work.last_mut().unwrap().1 = i + 1;
324 work.push((w, 0));
325 recursed = true;
326 break;
327 }
328 if on_stack[w] {
329 lowlinks[v] = lowlinks[v].min(indices[w]);
330 }
331 i += 1;
332 }
333 if recursed {
334 continue;
335 }
336 if lowlinks[v] == indices[v] {
337 let mut scc = Vec::new();
338 loop {
339 let w = tarjan_stack.pop().expect("stack non-empty during SCC pop");
340 on_stack[w] = false;
341 scc.push(nodes[w]);
342 if w == v {
343 break;
344 }
345 }
346 scc.sort();
347 out.push(scc);
348 }
349 work.pop();
350 if let Some(&(parent, _)) = work.last() {
351 lowlinks[parent] = lowlinks[parent].min(lowlinks[v]);
352 }
353 }
354 }
355 out
356 }
357
358 fn reverse_topo(adj: &[BTreeSet<usize>]) -> Vec<usize> {
359 let n = adj.len();
360 let mut state = vec![0u8; n];
361 let mut order = Vec::new();
362 for v in 0..n {
363 if state[v] == 0 {
364 dfs(v, adj, &mut state, &mut order);
365 }
366 }
367 order
368 }
369
370 fn dfs(v: usize, adj: &[BTreeSet<usize>], state: &mut [u8], order: &mut Vec<usize>) {
371 state[v] = 1;
372 for &u in &adj[v] {
373 if state[u] == 0 {
374 dfs(u, adj, state, order);
375 }
376 }
377 state[v] = 2;
378 order.push(v);
379 }
380}