weavatrix_graph/algo/components/
weak.rs1use crate::IndexGraphView;
2use crate::Vec;
3
4#[must_use]
5pub fn weakly_connected_components<G>(graph: &G) -> Vec<Vec<G::Node>>
6where
7 G: IndexGraphView,
8{
9 with_filter(graph, &|_| true)
10}
11
12#[must_use]
13pub fn weakly_connected_components_filtered<G, F>(graph: &G, allows_edge: F) -> Vec<Vec<G::Node>>
14where
15 G: IndexGraphView,
16 F: Fn(G::Edge) -> bool,
17{
18 with_filter(graph, &allows_edge)
19}
20
21fn with_filter<G, F>(graph: &G, allows_edge: &F) -> Vec<Vec<G::Node>>
22where
23 G: IndexGraphView,
24 F: Fn(G::Edge) -> bool,
25{
26 let node_bound = graph.node_bound();
27 let mut sets = DisjointSet::new(node_bound);
28 for (edge, endpoints) in graph.edge_references() {
29 if !allows_edge(edge) {
30 continue;
31 }
32 let source = G::node_slot(endpoints.source());
33 let target = G::node_slot(endpoints.target());
34 if source < node_bound && target < node_bound {
35 sets.union(source, target);
36 }
37 }
38
39 let mut grouped = vec![Vec::new(); node_bound];
40 for node in graph.node_indices() {
41 let slot = G::node_slot(node);
42 if slot < node_bound {
43 grouped[sets.root(slot)].push(node);
44 }
45 }
46 let mut components = grouped
47 .into_iter()
48 .filter(|component| !component.is_empty())
49 .collect::<Vec<_>>();
50 components.sort_unstable_by_key(|component| G::node_slot(component[0]));
51 components
52}
53
54struct DisjointSet {
55 parent: Vec<usize>,
56 rank: Vec<u8>,
57}
58
59impl DisjointSet {
60 fn new(len: usize) -> Self {
61 Self {
62 parent: (0..len).collect(),
63 rank: vec![0; len],
64 }
65 }
66
67 fn find(&mut self, mut node: usize) -> usize {
68 loop {
69 let parent = self.parent[node];
70 if parent == node {
71 return node;
72 }
73 self.parent[node] = self.parent[parent];
74 node = parent;
75 }
76 }
77
78 fn root(&self, mut node: usize) -> usize {
79 loop {
80 let parent = self.parent[node];
81 if parent == node {
82 return node;
83 }
84 node = parent;
85 }
86 }
87
88 fn union(&mut self, left: usize, right: usize) {
89 let mut left = self.find(left);
90 let mut right = self.find(right);
91 if left == right {
92 return;
93 }
94 if self.rank[left] < self.rank[right] {
95 core::mem::swap(&mut left, &mut right);
96 }
97 self.parent[right] = left;
98 if self.rank[left] == self.rank[right] {
99 self.rank[left] += 1;
100 }
101 }
102}