1use hashbrown::{HashMap, HashSet};
14use std::hash::Hash;
15
16use petgraph::{
17 visit::{
18 EdgeCount, GraphBase, GraphProp, IntoEdges, IntoNodeIdentifiers, NodeIndexable, Time,
19 Visitable,
20 },
21 Undirected,
22};
23
24use crate::traversal::{depth_first_search, DfsEvent};
25
26const NULL: usize = usize::MAX;
27
28type Edge<G> = (<G as GraphBase>::NodeId, <G as GraphBase>::NodeId);
29
30#[inline]
31fn is_root(parent: &[usize], u: usize) -> bool {
32 parent[u] == NULL
33}
34
35fn _articulation_points<G>(
36 graph: G,
37 components: Option<&mut HashMap<Edge<G>, usize>>,
38 bridges: Option<&mut HashSet<Edge<G>>>,
39) -> HashSet<G::NodeId>
40where
41 G: GraphProp<EdgeType = Undirected>
42 + EdgeCount
43 + IntoEdges
44 + Visitable
45 + NodeIndexable
46 + IntoNodeIdentifiers,
47 G::NodeId: Eq + Hash,
48{
49 let num_nodes = graph.node_bound();
50
51 let mut low = vec![NULL; num_nodes];
52 let mut disc = vec![NULL; num_nodes];
53 let mut parent = vec![NULL; num_nodes];
54
55 let mut root_children: usize = 0;
56 let mut points = HashSet::new();
57
58 let mut edge_stack = Vec::new();
59 let need_components = components.is_some();
60 let mut tmp_components = if need_components {
61 HashMap::with_capacity(graph.edge_count())
62 } else {
63 HashMap::new()
64 };
65 let need_bridges = bridges.is_some();
66 let mut tmp_bridges = if need_bridges {
67 HashSet::with_capacity(graph.edge_count())
68 } else {
69 HashSet::new()
70 };
71 let mut num_components: usize = 0;
72
73 depth_first_search(graph, graph.node_identifiers(), |event| match event {
74 DfsEvent::Discover(u_id, Time(t)) => {
75 let u = graph.to_index(u_id);
76 low[u] = t;
77 disc[u] = t;
78 }
79 DfsEvent::TreeEdge(u_id, v_id, _) => {
80 let u = graph.to_index(u_id);
81 let v = graph.to_index(v_id);
82 parent[v] = u;
83 if is_root(&parent, u) {
84 root_children += 1;
85 }
86 if need_components {
87 edge_stack.push((u_id, v_id));
88 }
89 }
90 DfsEvent::BackEdge(u_id, v_id, _) => {
91 let u = graph.to_index(u_id);
92 let v = graph.to_index(v_id);
93
94 if v != parent[u] {
96 low[u] = low[u].min(disc[v]);
97 if need_components {
98 edge_stack.push((u_id, v_id));
99 }
100 }
101 }
102 DfsEvent::Finish(u_id, _) => {
103 let u = graph.to_index(u_id);
104 if is_root(&parent, u) {
105 if root_children > 1 {
106 points.insert(u_id);
107 }
108 root_children = 0;
110 } else {
111 let pu = parent[u];
112 let pu_id = graph.from_index(pu);
113 low[pu] = low[pu].min(low[u]);
114
115 if !is_root(&parent, pu) && low[u] >= disc[pu] {
116 points.insert(pu_id);
117 if need_components {
120 if let Some(at) = edge_stack.iter().rposition(|&x| x == (pu_id, u_id)) {
121 tmp_components.extend(
122 edge_stack[at..].iter().map(|edge| (*edge, num_components)),
123 );
124 edge_stack.truncate(at);
125 num_components += 1;
126 }
127 }
128 if need_bridges && low[u] != disc[pu] {
129 tmp_bridges.insert((pu_id, u_id));
130 }
131 }
132
133 if is_root(&parent, pu) && need_components {
134 if let Some(at) = edge_stack.iter().position(|&x| x == (pu_id, u_id)) {
135 tmp_components
136 .extend(edge_stack[at..].iter().map(|edge| (*edge, num_components)));
137 edge_stack.truncate(at);
138 num_components += 1;
139 }
140 }
141 }
142 }
143 _ => (),
144 });
145
146 if let Some(x) = components {
147 *x = tmp_components;
148 }
149 if let Some(x) = bridges {
150 *x = tmp_bridges;
151 }
152
153 points
154}
155
156pub fn articulation_points<G>(
201 graph: G,
202 components: Option<&mut HashMap<Edge<G>, usize>>,
203) -> HashSet<G::NodeId>
204where
205 G: GraphProp<EdgeType = Undirected>
206 + EdgeCount
207 + IntoEdges
208 + Visitable
209 + NodeIndexable
210 + IntoNodeIdentifiers,
211 G::NodeId: Eq + Hash,
212{
213 _articulation_points(graph, components, None)
214}
215
216pub fn bridges<G>(graph: G) -> HashSet<Edge<G>>
245where
246 G: GraphProp<EdgeType = Undirected>
247 + EdgeCount
248 + IntoEdges
249 + Visitable
250 + NodeIndexable
251 + IntoNodeIdentifiers,
252 G::NodeId: Eq + Hash,
253{
254 let mut bridges = HashSet::new();
255 _articulation_points(graph, None, Some(&mut bridges));
256 bridges
257}
258
259#[cfg(test)]
260mod tests {
261 use crate::connectivity::{articulation_points, bridges};
262 use hashbrown::{HashMap, HashSet};
263 use petgraph::graph::node_index as nx;
264 use petgraph::prelude::*;
265 use std::iter::FromIterator;
266
267 #[test]
268 fn test_articulation_points_repetitions() {
269 let graph = UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (1, 3)]);
270
271 let a_points = articulation_points(&graph, None);
272
273 assert_eq!(a_points, HashSet::from_iter([nx(1)]));
274 }
275
276 #[test]
277 fn test_articulation_points_cycle() {
278 let graph = UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 0), (1, 3), (3, 4), (4, 1)]);
280
281 let a_points = articulation_points(&graph, None);
282
283 assert_eq!(a_points, HashSet::from_iter([nx(1)]));
284 }
285
286 #[test]
287 fn test_single_bridge() {
288 let graph = UnGraph::<(), ()>::from_edges([
289 (1, 2),
290 (2, 3),
291 (3, 4),
292 (3, 5),
293 (5, 6),
294 (6, 7),
295 (7, 8),
296 (5, 9),
297 (9, 10),
298 (1, 3),
300 (1, 4),
301 (2, 5),
302 (5, 10),
303 (6, 8),
304 ]);
305
306 assert_eq!(bridges(&graph), HashSet::from_iter([(nx(5), nx(6))]));
307 }
308
309 #[test]
310 fn test_bridges_cycle() {
312 let graph = UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 0), (1, 3), (3, 4), (4, 1)]);
313 assert_eq!(bridges(&graph), HashSet::from_iter([]));
314 }
315
316 #[test]
317 fn test_biconnected_components_cycle() {
318 let graph = UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 0), (1, 3), (3, 4), (4, 1)]);
320
321 let mut components = HashMap::new();
322 let _ = articulation_points(&graph, Some(&mut components));
323
324 assert_eq!(
325 components,
326 HashMap::from_iter([
327 ((nx(1), nx(3)), 0),
328 ((nx(3), nx(4)), 0),
329 ((nx(4), nx(1)), 0),
330 ((nx(1), nx(2)), 1),
331 ((nx(2), nx(0)), 1),
332 ((nx(0), nx(1)), 1)
333 ])
334 );
335 }
336
337 #[test]
338 fn test_biconnected_components1() {
339 let graph = UnGraph::<(), ()>::from_edges([
341 (0, 1),
342 (0, 5),
343 (0, 6),
344 (0, 14),
345 (1, 5),
346 (1, 6),
347 (1, 14),
348 (2, 4),
349 (2, 10),
350 (3, 4),
351 (3, 15),
352 (4, 6),
353 (4, 7),
354 (4, 10),
355 (5, 14),
356 (6, 14),
357 (7, 9),
358 (8, 9),
359 (8, 12),
360 (8, 13),
361 (10, 15),
362 (11, 12),
363 (11, 13),
364 (12, 13),
365 ]);
366
367 let mut components = HashMap::new();
368 let a_points = articulation_points(&graph, Some(&mut components));
369
370 assert_eq!(
371 a_points,
372 HashSet::from_iter([nx(4), nx(6), nx(7), nx(8), nx(9)])
373 );
374 assert_eq!(
375 components,
376 HashMap::from_iter([
377 ((nx(3), nx(4)), 0),
378 ((nx(15), nx(3)), 0),
379 ((nx(10), nx(15)), 0),
380 ((nx(4), nx(10)), 0),
381 ((nx(10), nx(2)), 0),
382 ((nx(2), nx(4)), 0),
383 ((nx(13), nx(12)), 1),
384 ((nx(8), nx(13)), 1),
385 ((nx(11), nx(13)), 1),
386 ((nx(12), nx(11)), 1),
387 ((nx(12), nx(8)), 1),
388 ((nx(9), nx(8)), 2),
389 ((nx(7), nx(9)), 3),
390 ((nx(4), nx(7)), 4),
391 ((nx(6), nx(4)), 5),
392 ((nx(0), nx(14)), 6),
393 ((nx(1), nx(5)), 6),
394 ((nx(5), nx(0)), 6),
395 ((nx(5), nx(14)), 6),
396 ((nx(1), nx(14)), 6),
397 ((nx(14), nx(6)), 6),
398 ((nx(6), nx(0)), 6),
399 ((nx(6), nx(1)), 6),
400 ((nx(1), nx(0)), 6),
401 ])
402 )
403 }
404
405 #[test]
406 fn test_biconnected_components2() {
407 let mut graph: Graph<&str, (), Undirected> = Graph::new_undirected();
408 let a = graph.add_node("A");
409 let b = graph.add_node("B");
410 let c = graph.add_node("C");
411 let d = graph.add_node("D");
412 let e = graph.add_node("E");
413 let f = graph.add_node("F");
414 let g = graph.add_node("G");
415 let h = graph.add_node("H");
416 let i = graph.add_node("I");
417 let j = graph.add_node("J");
418
419 graph.extend_with_edges([
420 (a, b),
421 (b, c),
422 (c, a),
423 (c, d),
424 (d, e),
425 (e, c),
426 (f, i),
427 (i, j),
428 (j, h),
429 (h, g),
430 (g, f),
431 (g, i),
432 (g, j),
433 (e, g),
434 ]);
435
436 let mut components = HashMap::new();
437 let _ = articulation_points(&graph, Some(&mut components));
438
439 assert_eq!(
440 components,
441 HashMap::from_iter([
442 ((f, g), 0),
443 ((i, f), 0),
444 ((i, g), 0),
445 ((j, i), 0),
446 ((g, j), 0),
447 ((j, h), 0),
448 ((h, g), 0),
449 ((e, g), 1),
450 ((c, d), 2),
451 ((d, e), 2),
452 ((e, c), 2),
453 ((c, a), 3),
454 ((a, b), 3),
455 ((b, c), 3),
456 ])
457 )
458 }
459
460 #[test]
461 fn test_null_graph() {
462 let graph: Graph<(), (), Undirected> = Graph::new_undirected();
463
464 let mut components = HashMap::new();
465 let a_points = articulation_points(&graph, Some(&mut components));
466 let bridges = bridges(&graph);
467
468 assert_eq!(a_points, HashSet::new());
469 assert_eq!(bridges, HashSet::new());
470 assert_eq!(components, HashMap::new());
471 }
472}