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>> {
289 let nodes: Vec<&'a Vertex> = adj.keys().copied().collect();
290 let id_of: BTreeMap<&Vertex, usize> =
291 nodes.iter().enumerate().map(|(i, v)| (*v, i)).collect();
292 let neighbours: Vec<Vec<usize>> = nodes
293 .iter()
294 .map(|v| adj[v].iter().map(|w| id_of[w]).collect())
295 .collect();
296 let n = nodes.len();
297
298 const UNVISITED: usize = usize::MAX;
299 let mut indices = vec![UNVISITED; n];
300 let mut lowlinks = vec![0usize; n];
301 let mut on_stack = vec![false; n];
302 let mut tarjan_stack: Vec<usize> = Vec::new();
303 let mut next_index = 0usize;
304 let mut out: Vec<Vec<&'a Vertex>> = Vec::new();
305
306 let mut work: Vec<(usize, usize)> = Vec::new();
308 for start in 0..n {
309 if indices[start] != UNVISITED {
310 continue;
311 }
312 work.push((start, 0));
313 while let Some(&(v, child)) = work.last() {
314 if child == 0 {
315 indices[v] = next_index;
316 lowlinks[v] = next_index;
317 next_index += 1;
318 tarjan_stack.push(v);
319 on_stack[v] = true;
320 }
321 let mut recursed = false;
322 let mut i = child;
323 while i < neighbours[v].len() {
324 let w = neighbours[v][i];
325 if indices[w] == UNVISITED {
326 work.last_mut().unwrap().1 = i + 1;
327 work.push((w, 0));
328 recursed = true;
329 break;
330 }
331 if on_stack[w] {
332 lowlinks[v] = lowlinks[v].min(indices[w]);
333 }
334 i += 1;
335 }
336 if recursed {
337 continue;
338 }
339 if lowlinks[v] == indices[v] {
340 let mut scc = Vec::new();
341 loop {
342 let w = tarjan_stack.pop().expect("stack non-empty during SCC pop");
343 on_stack[w] = false;
344 scc.push(nodes[w]);
345 if w == v {
346 break;
347 }
348 }
349 scc.sort();
350 out.push(scc);
351 }
352 work.pop();
353 if let Some(&(parent, _)) = work.last() {
354 lowlinks[parent] = lowlinks[parent].min(lowlinks[v]);
355 }
356 }
357 }
358 out
359 }
360
361 fn reverse_topo(adj: &[BTreeSet<usize>]) -> Vec<usize> {
362 let n = adj.len();
363 let mut state = vec![0u8; n];
364 let mut order = Vec::new();
365 for v in 0..n {
366 if state[v] == 0 {
367 dfs(v, adj, &mut state, &mut order);
368 }
369 }
370 order
371 }
372
373 fn dfs(v: usize, adj: &[BTreeSet<usize>], state: &mut [u8], order: &mut Vec<usize>) {
374 state[v] = 1;
375 for &u in &adj[v] {
376 if state[u] == 0 {
377 dfs(u, adj, state, order);
378 }
379 }
380 state[v] = 2;
381 order.push(v);
382 }
383}