1use std::cmp::min;
32
33pub use petgraph;
34
35use petgraph::{
36 graph::Edge, prelude::UnGraph, stable_graph::IndexType,
37 stable_graph::NodeIndex, visit::NodeIndexable,
38};
39
40pub trait Bcc {
41 type Output;
42
43 fn bcc(&self) -> Self::Output;
45}
46
47impl<N, E, Ix: IndexType> Bcc for UnGraph<N, E, Ix> {
48 type Output = Vec<Vec<NodeIndex<Ix>>>;
49
50 fn bcc(&self) -> Self::Output {
51 let mut dfs = HopcroftTarjan::new(self.node_count());
52 dfs.find_bcc(self)
53 }
54}
55
56pub trait SplitIntoBcc {
57 type Output;
58
59 fn split_into_bcc(self) -> Self::Output;
61}
62
63impl<N: Clone, E, Ix: IndexType> SplitIntoBcc for UnGraph<N, E, Ix> {
64 type Output = Vec<UnGraph<N, E, Ix>>;
65
66 fn split_into_bcc(self) -> Self::Output {
67 let bccs = self.bcc();
68 let res = bccs.iter().map(|bcc| {
69 let mut g = UnGraph::with_capacity(bcc.len(), 0);
70 for n in bcc {
71 g.add_node(self.node_weight(*n).unwrap().clone());
72 }
73 g
74 });
75 let mut res = Vec::from_iter(res);
76 let (nodes, edges) = self.into_nodes_edges();
77 for edge in edges {
78 if edge.source() == edge.target() {
79 if res.len() == 1
83 && res[0].node_count() == 1
84 && res[0].edge_count() == 0
85 {
86 res.clear();
87 }
88 let mut g = UnGraph::with_capacity(1, 1);
90 let weight = nodes[edge.source().index()].weight.clone();
91 let idx = g.add_node(weight);
92 g.add_edge(idx, idx, edge.weight);
93 res.push(g);
94 } else {
95 add_edge(&mut res, &bccs, edge);
96 }
97 }
98 res
99 }
100}
101
102fn add_edge<N: Clone, E, Ix: IndexType>(
103 res: &mut [UnGraph<N, E, Ix>],
104 bccs: &[Vec<NodeIndex<Ix>>],
105 edge: Edge<E, Ix>,
106) {
107 for (res, bcc) in res.iter_mut().zip(bccs.iter()) {
108 let source_pos = bcc.iter().position(|&n| n == edge.source());
109 if let Some(from) = source_pos {
110 let target_pos = bcc.iter().position(|&n| n == edge.target());
111 if let Some(to) = target_pos {
112 let from = res.from_index(from);
113 let to = res.from_index(to);
114 res.add_edge(from, to, edge.weight);
115 return;
116 }
117 }
118 }
119 unreachable!("Found edge that is in none of the biconnected components");
120}
121
122struct HopcroftTarjan {
128 visited: Vec<bool>,
129 depth: Vec<usize>,
130 lowpoint: Vec<usize>,
131 parent: Vec<usize>,
132}
133
134impl HopcroftTarjan {
135 fn new(nnodes: usize) -> Self {
136 Self {
137 visited: vec![false; nnodes],
138 depth: vec![0; nnodes],
139 lowpoint: vec![0; nnodes],
140 parent: vec![0; nnodes],
141 }
142 }
143
144 fn find_bcc<N, E, Ix: IndexType>(
145 &mut self,
146 g: &UnGraph<N, E, Ix>,
147 ) -> Vec<Vec<NodeIndex<Ix>>> {
148 if g.node_count() == 0 {
149 return vec![];
150 }
151 let mut res = vec![];
152 let mut start_node = 0;
153 while let Some(start) = self.next_start_pos(start_node) {
154 self.find_bcc_from(g, start, 0, &mut res);
155 start_node = start + 1;
156 }
157 if res.is_empty() {
158 vec![g.node_indices().collect()]
159 } else {
160 res
161 }
162 }
163
164 fn find_bcc_from<N, E, Ix: IndexType>(
165 &mut self,
166 g: &UnGraph<N, E, Ix>,
167 node: usize,
168 depth: usize,
169 res: &mut Vec<Vec<NodeIndex<Ix>>>,
170 ) {
171 self.visited[node] = true;
172 self.depth[node] = depth;
173 self.lowpoint[node] = depth;
174
175 let mut is_cut_vx = false;
176
177 let idx = g.from_index(node);
178 for n_idx in g.neighbors(idx).filter(|&n_idx| n_idx != idx) {
180 let n = g.to_index(n_idx);
181 if !self.visited[n] {
182 let parent = node;
183 self.parent[n] = parent;
184 self.find_bcc_from(g, n, depth + 1, res);
185 if self.lowpoint[n] >= self.depth[parent] {
186 is_cut_vx = true;
187 }
188 self.lowpoint[parent] =
189 min(self.lowpoint[parent], self.lowpoint[n]);
190 } else if n != self.parent[node] {
191 self.lowpoint[node] = min(self.lowpoint[node], self.depth[n]);
192 }
193 }
194 if node > 0 && is_cut_vx {
195 for n_idx in g.neighbors(idx) {
196 let n = g.to_index(n_idx);
197 if self.parent[n] == node
198 && self.lowpoint[n] >= self.depth[node]
199 {
200 let mut bcc = vec![idx, n_idx];
201 self.add_subtree(g, n, &mut bcc);
202 res.push(bcc);
203 }
204 }
205 } else if node == 0 {
206 for n_idx in g.neighbors(idx).filter(|&n_idx| n_idx != idx) {
211 let n = g.to_index(n_idx);
212 if self.parent[n] == node {
213 let mut bcc = vec![idx, n_idx];
214 self.add_subtree(g, n, &mut bcc);
215 res.push(bcc);
216 }
217 }
218 }
219 }
220
221 fn add_subtree<N, E, Ix: IndexType>(
222 &mut self,
223 g: &UnGraph<N, E, Ix>,
224 root: usize,
225 bcc: &mut Vec<NodeIndex<Ix>>,
226 ) {
227 self.parent[root] = usize::MAX;
229 let root_idx = g.from_index(root);
230 for n_idx in g.neighbors(root_idx) {
231 let n = g.to_index(n_idx);
232 if self.parent[n] == root {
233 bcc.push(n_idx);
234 self.add_subtree(g, n, bcc)
235 }
236 }
237 }
238
239 fn next_start_pos(&self, nskip: usize) -> Option<usize> {
240 self.visited
241 .iter()
242 .skip(nskip)
243 .position(|v| !v)
244 .map(|p| p + nskip)
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use petgraph::Graph;
251
252 use super::*;
253
254 fn bcc_indices(g: &UnGraph<(), (), u32>) -> Vec<Vec<usize>> {
255 let mut bcc: Vec<Vec<usize>> = g
256 .bcc()
257 .into_iter()
258 .map(|bcc| bcc.into_iter().map(|i| g.to_index(i)).collect())
259 .collect();
260 for bcc in &mut bcc {
261 bcc.sort();
262 }
263 bcc.sort();
264 bcc
265 }
266
267 #[test]
268 fn trivial() {
269 let g: UnGraph<(), (), u32> = UnGraph::default();
270 assert!(g.bcc().is_empty());
271 }
272
273 #[test]
274 fn single_edge() {
275 let g: UnGraph<(), (), u32> = Graph::from_edges([(0, 1)]);
276 let bcc = bcc_indices(&g);
277 assert_eq!(bcc, [[0, 1]]);
278 }
279
280 #[test]
281 fn star_2() {
282 let g: UnGraph<(), (), u32> = Graph::from_edges([(0, 1), (0, 2)]);
283 let bcc = bcc_indices(&g);
284 let bcc_ref = [[0, 1], [0, 2]];
285 assert_eq!(bcc, bcc_ref);
286 }
287
288 #[test]
289 fn star_2_alt() {
290 let g: UnGraph<(), (), u32> = Graph::from_edges([(0, 1), (1, 2)]);
291 let bcc = bcc_indices(&g);
292 let bcc_ref = [[0, 1], [1, 2]];
293 assert_eq!(bcc, bcc_ref);
294 }
295
296 #[test]
297 fn lacrosse_stick() {
298 let g: UnGraph<(), (), u32> =
299 Graph::from_edges([(0, 1), (1, 2), (2, 0), (2, 3)]);
300 let bcc = bcc_indices(&g);
301 let bcc_ref = [vec![0, 1, 2], vec![2, 3]];
302 assert_eq!(bcc, bcc_ref);
303 }
304
305 #[test]
306 fn forest() {
307 let g: UnGraph<(), (), u32> =
308 Graph::from_edges([(0, 1), (1, 2), (3, 4), (3, 5)]);
309 let bcc = bcc_indices(&g);
310 let bcc_ref = [[0, 1], [1, 2], [3, 4], [3, 5]];
311 assert_eq!(bcc, bcc_ref);
312 }
313
314 #[test]
315 fn wp_example() {
316 let g: UnGraph<(), (), u32> = Graph::from_edges([
318 (0, 1, ()),
319 (0, 9, ()),
320 (1, 2, ()),
321 (1, 6, ()),
322 (1, 8, ()),
323 (2, 3, ()),
324 (2, 4, ()),
325 (3, 4, ()),
326 (4, 5, ()),
327 (5, 6, ()),
328 (6, 7, ()),
329 (9, 10, ()),
330 (10, 11, ()),
331 (10, 13, ()),
332 (11, 12, ()),
333 (12, 13, ()),
334 ]);
335 let bcc = bcc_indices(&g);
336 let bcc_ref = [
337 vec![0, 1],
338 vec![0, 9],
339 vec![1, 2, 3, 4, 5, 6],
340 vec![1, 8],
341 vec![6, 7],
342 vec![9, 10],
343 vec![10, 11, 12, 13],
344 ];
345 assert_eq!(bcc, bcc_ref);
346 }
347
348 #[test]
349 fn self_loops() {
350 let g: UnGraph<(), (), u32> = Graph::from_edges([(0, 0, ())]);
351 let bcc = bcc_indices(&g);
352 let bcc_ref = [vec![0]];
353 assert_eq!(bcc, bcc_ref);
354
355 let g: UnGraph<(), (), u32> =
356 Graph::from_edges([(0, 0, ()), (1, 0, ()), (1, 1, ())]);
357 let bcc = bcc_indices(&g);
358 let bcc_ref = [vec![0, 1]];
359 assert_eq!(bcc, bcc_ref);
360 }
361
362 #[test]
363 fn split() {
364 let g: UnGraph<(), (), u32> = Graph::new_undirected();
365 let bccs = g.split_into_bcc();
366 assert!(bccs.is_empty());
367
368 let mut g: UnGraph<(), (), u32> = Graph::new_undirected();
369 g.add_node(());
370 let bccs = g.clone().split_into_bcc();
371 assert_eq!(bccs.len(), 1);
372 assert_eq!(bccs[0].node_count(), 1);
373 assert_eq!(bccs[0].edge_count(), 0);
374
375 let g: UnGraph<(), (), u32> = Graph::from_edges([(0, 0, ())]);
376 let bccs = g.split_into_bcc();
377 assert_eq!(bccs.len(), 1);
378 assert_eq!(bccs[0].node_count(), 1);
379 assert_eq!(bccs[0].edge_count(), 1);
380 }
381}