1use crate::base::{DiGraph, EdgeWeight, Graph, Node};
7use petgraph::Direction;
8use std::collections::{HashMap, HashSet, VecDeque};
9
10pub type Component<N> = HashSet<N>;
12
13#[allow(dead_code)]
21pub fn connected_components<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Vec<Component<N>>
22where
23 N: Node + std::fmt::Debug,
24 E: EdgeWeight,
25 Ix: petgraph::graph::IndexType,
26{
27 let mut components: Vec<Component<N>> = Vec::new();
28 let mut visited = HashSet::new();
29
30 for node_idx in graph.inner().node_indices() {
32 if visited.contains(&node_idx) {
34 continue;
35 }
36
37 let mut component = HashSet::new();
39 let mut queue = VecDeque::new();
40 queue.push_back(node_idx);
41 visited.insert(node_idx);
42
43 while let Some(current) = queue.pop_front() {
44 component.insert(graph.inner()[current].clone());
45
46 for neighbor in graph.inner().neighbors(current) {
48 if !visited.contains(&neighbor) {
49 visited.insert(neighbor);
50 queue.push_back(neighbor);
51 }
52 }
53 }
54
55 components.push(component);
56 }
57
58 components
59}
60
61#[allow(dead_code)]
69pub fn strongly_connected_components<N, E, Ix>(graph: &DiGraph<N, E, Ix>) -> Vec<Component<N>>
70where
71 N: Node + std::fmt::Debug,
72 E: EdgeWeight,
73 Ix: petgraph::graph::IndexType,
74{
75 struct TarjanState<Ix: petgraph::graph::IndexType> {
76 index: usize,
77 stack: Vec<petgraph::graph::NodeIndex<Ix>>,
78 indices: HashMap<petgraph::graph::NodeIndex<Ix>, usize>,
79 lowlinks: HashMap<petgraph::graph::NodeIndex<Ix>, usize>,
80 on_stack: HashSet<petgraph::graph::NodeIndex<Ix>>,
81 }
82
83 fn strongconnect<N, E, Ix>(
84 v: petgraph::graph::NodeIndex<Ix>,
85 graph: &DiGraph<N, E, Ix>,
86 state: &mut TarjanState<Ix>,
87 components: &mut Vec<Component<N>>,
88 ) where
89 N: Node + std::fmt::Debug,
90 E: EdgeWeight,
91 Ix: petgraph::graph::IndexType,
92 {
93 state.indices.insert(v, state.index);
94 state.lowlinks.insert(v, state.index);
95 state.index += 1;
96 state.stack.push(v);
97 state.on_stack.insert(v);
98
99 for w in graph.inner().neighbors_directed(v, Direction::Outgoing) {
101 if !state.indices.contains_key(&w) {
102 strongconnect(w, graph, state, components);
104 let w_lowlink = *state.lowlinks.get(&w).expect("Operation failed");
105 let v_lowlink = *state.lowlinks.get(&v).expect("Operation failed");
106 state.lowlinks.insert(v, v_lowlink.min(w_lowlink));
107 } else if state.on_stack.contains(&w) {
108 let w_index = *state.indices.get(&w).expect("Operation failed");
110 let v_lowlink = *state.lowlinks.get(&v).expect("Operation failed");
111 state.lowlinks.insert(v, v_lowlink.min(w_index));
112 }
113 }
114
115 if state.lowlinks.get(&v) == state.indices.get(&v) {
117 let mut component = HashSet::new();
118 loop {
119 let w = state.stack.pop().expect("Operation failed");
120 state.on_stack.remove(&w);
121 component.insert(graph.inner()[w].clone());
122 if w == v {
123 break;
124 }
125 }
126 if !component.is_empty() {
127 components.push(component);
128 }
129 }
130 }
131
132 let mut state = TarjanState {
133 index: 0,
134 stack: Vec::new(),
135 indices: HashMap::new(),
136 lowlinks: HashMap::new(),
137 on_stack: HashSet::new(),
138 };
139 let mut components = Vec::new();
140
141 for v in graph.inner().node_indices() {
142 if !state.indices.contains_key(&v) {
143 strongconnect(v, graph, &mut state, &mut components);
144 }
145 }
146
147 components
148}
149
150#[allow(dead_code)]
162pub fn weakly_connected_components<N, E, Ix>(graph: &DiGraph<N, E, Ix>) -> Vec<Component<N>>
163where
164 N: Node + std::fmt::Debug,
165 E: EdgeWeight,
166 Ix: petgraph::graph::IndexType,
167{
168 let mut components: Vec<Component<N>> = Vec::new();
169 let mut visited = HashSet::new();
170
171 for node_idx in graph.inner().node_indices() {
173 if visited.contains(&node_idx) {
175 continue;
176 }
177
178 let mut component = HashSet::new();
180 let mut queue = VecDeque::new();
181 queue.push_back(node_idx);
182 visited.insert(node_idx);
183
184 while let Some(current) = queue.pop_front() {
185 component.insert(graph.inner()[current].clone());
186
187 for neighbor in graph.inner().neighbors_undirected(current) {
189 if !visited.contains(&neighbor) {
190 visited.insert(neighbor);
191 queue.push_back(neighbor);
192 }
193 }
194 }
195
196 components.push(component);
197 }
198
199 components
200}
201
202#[allow(dead_code)]
212pub fn articulation_points<N, E, Ix>(graph: &Graph<N, E, Ix>) -> HashSet<N>
213where
214 N: Node + std::fmt::Debug,
215 E: EdgeWeight,
216 Ix: petgraph::graph::IndexType,
217{
218 struct DfsState<Ix: petgraph::graph::IndexType> {
219 time: usize,
220 disc: HashMap<petgraph::graph::NodeIndex<Ix>, usize>,
221 low: HashMap<petgraph::graph::NodeIndex<Ix>, usize>,
222 parent: HashMap<petgraph::graph::NodeIndex<Ix>, Option<petgraph::graph::NodeIndex<Ix>>>,
223 visited: HashSet<petgraph::graph::NodeIndex<Ix>>,
224 }
225
226 fn dfs<N, E, Ix>(
227 u: petgraph::graph::NodeIndex<Ix>,
228 graph: &Graph<N, E, Ix>,
229 state: &mut DfsState<Ix>,
230 articulation_points: &mut HashSet<N>,
231 ) where
232 N: Node + std::fmt::Debug,
233 E: EdgeWeight,
234 Ix: petgraph::graph::IndexType,
235 {
236 state.visited.insert(u);
237 state.disc.insert(u, state.time);
238 state.low.insert(u, state.time);
239 state.time += 1;
240
241 let mut children = 0;
242
243 for v in graph.inner().neighbors(u) {
244 if !state.visited.contains(&v) {
245 children += 1;
246 state.parent.insert(v, Some(u));
247 dfs(v, graph, state, articulation_points);
248
249 let v_low = *state.low.get(&v).expect("Operation failed");
251 let u_low = *state.low.get(&u).expect("Operation failed");
252 state.low.insert(u, u_low.min(v_low));
253
254 let u_disc = *state.disc.get(&u).expect("Operation failed");
258 if (state.parent.get(&u).expect("Operation failed").is_none() && children > 1)
259 || (state.parent.get(&u).expect("Operation failed").is_some()
260 && v_low >= u_disc)
261 {
262 articulation_points.insert(graph.inner()[u].clone());
263 }
264 } else if state.parent.get(&u).expect("Operation failed") != &Some(v) {
265 let v_disc = *state.disc.get(&v).expect("Operation failed");
267 let u_low = *state.low.get(&u).expect("Operation failed");
268 state.low.insert(u, u_low.min(v_disc));
269 }
270 }
271 }
272
273 let mut articulation_points = HashSet::new();
274 let mut state = DfsState {
275 time: 0,
276 disc: HashMap::new(),
277 low: HashMap::new(),
278 parent: HashMap::new(),
279 visited: HashSet::new(),
280 };
281
282 for node in graph.inner().node_indices() {
283 if !state.visited.contains(&node) {
284 state.parent.insert(node, None);
285 dfs(node, graph, &mut state, &mut articulation_points);
286 }
287 }
288
289 articulation_points
290}
291
292#[derive(Debug, Clone)]
294pub struct BipartiteResult<N: Node> {
295 pub is_bipartite: bool,
297 pub coloring: HashMap<N, u8>,
299}
300
301#[allow(dead_code)]
312pub fn is_bipartite<N, E, Ix>(graph: &Graph<N, E, Ix>) -> BipartiteResult<N>
313where
314 N: Node + std::fmt::Debug,
315 E: EdgeWeight,
316 Ix: petgraph::graph::IndexType,
317{
318 let mut coloring: HashMap<petgraph::graph::NodeIndex<Ix>, u8> = HashMap::new();
319 let mut queue = VecDeque::new();
320
321 for start_idx in graph.inner().node_indices() {
323 if coloring.contains_key(&start_idx) {
324 continue;
325 }
326
327 queue.push_back(start_idx);
329 coloring.insert(start_idx, 0);
330
331 while let Some(node_idx) = queue.pop_front() {
332 let node_color = *coloring.get(&node_idx).expect("Operation failed");
333 let next_color = 1 - node_color;
334
335 for neighbor in graph.inner().neighbors(node_idx) {
336 if let Some(&neighbor_color) = coloring.get(&neighbor) {
337 if neighbor_color == node_color {
339 return BipartiteResult {
340 is_bipartite: false,
341 coloring: HashMap::new(),
342 };
343 }
344 } else {
345 coloring.insert(neighbor, next_color);
347 queue.push_back(neighbor);
348 }
349 }
350 }
351 }
352
353 let node_coloring: HashMap<N, u8> = coloring
355 .into_iter()
356 .map(|(idx, color)| (graph.inner()[idx].clone(), color))
357 .collect();
358
359 BipartiteResult {
360 is_bipartite: true,
361 coloring: node_coloring,
362 }
363}
364
365#[allow(dead_code)]
375pub fn bridges<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Vec<(N, N)>
376where
377 N: Node + std::fmt::Debug,
378 E: EdgeWeight,
379 Ix: petgraph::graph::IndexType,
380{
381 struct DfsState<Ix: petgraph::graph::IndexType> {
382 time: usize,
383 disc: HashMap<petgraph::graph::NodeIndex<Ix>, usize>,
384 low: HashMap<petgraph::graph::NodeIndex<Ix>, usize>,
385 parent: HashMap<petgraph::graph::NodeIndex<Ix>, Option<petgraph::graph::NodeIndex<Ix>>>,
386 visited: HashSet<petgraph::graph::NodeIndex<Ix>>,
387 }
388
389 fn dfs<N, E, Ix>(
390 u: petgraph::graph::NodeIndex<Ix>,
391 graph: &Graph<N, E, Ix>,
392 state: &mut DfsState<Ix>,
393 bridges: &mut Vec<(N, N)>,
394 ) where
395 N: Node + std::fmt::Debug,
396 E: EdgeWeight,
397 Ix: petgraph::graph::IndexType,
398 {
399 state.visited.insert(u);
400 state.disc.insert(u, state.time);
401 state.low.insert(u, state.time);
402 state.time += 1;
403
404 for v in graph.inner().neighbors(u) {
405 if !state.visited.contains(&v) {
406 state.parent.insert(v, Some(u));
407 dfs(v, graph, state, bridges);
408
409 let v_low = *state.low.get(&v).expect("Operation failed");
411 let u_low = *state.low.get(&u).expect("Operation failed");
412 state.low.insert(u, u_low.min(v_low));
413
414 let u_disc = *state.disc.get(&u).expect("Operation failed");
416 if v_low > u_disc {
417 bridges.push((graph.inner()[u].clone(), graph.inner()[v].clone()));
418 }
419 } else if state.parent.get(&u).expect("Operation failed") != &Some(v) {
420 let v_disc = *state.disc.get(&v).expect("Operation failed");
422 let u_low = *state.low.get(&u).expect("Operation failed");
423 state.low.insert(u, u_low.min(v_disc));
424 }
425 }
426 }
427
428 let mut bridges = Vec::new();
429 let mut state = DfsState {
430 time: 0,
431 disc: HashMap::new(),
432 low: HashMap::new(),
433 parent: HashMap::new(),
434 visited: HashSet::new(),
435 };
436
437 for node in graph.inner().node_indices() {
438 if !state.visited.contains(&node) {
439 state.parent.insert(node, None);
440 dfs(node, graph, &mut state, &mut bridges);
441 }
442 }
443
444 bridges
445}
446
447#[cfg(test)]
448mod tests {
449 use super::*;
450 use crate::error::Result as GraphResult;
451 use crate::generators::create_graph;
452
453 #[test]
454 fn test_connected_components() -> GraphResult<()> {
455 let mut graph = create_graph::<i32, ()>();
457
458 graph.add_edge(0, 1, ())?;
459 graph.add_edge(1, 2, ())?;
460 graph.add_edge(3, 4, ())?;
461
462 let components = connected_components(&graph);
463 assert_eq!(components.len(), 2);
464
465 let sizes: Vec<usize> = components.iter().map(|c| c.len()).collect();
467 assert!(sizes.contains(&3));
468 assert!(sizes.contains(&2));
469
470 Ok(())
471 }
472
473 #[test]
474 fn test_strongly_connected_components() -> GraphResult<()> {
475 let mut graph = crate::base::DiGraph::<&str, ()>::new();
477
478 graph.add_edge("A", "B", ())?;
480 graph.add_edge("B", "C", ())?;
481 graph.add_edge("C", "A", ())?;
482
483 graph.add_edge("D", "E", ())?;
485
486 let sccs = strongly_connected_components(&graph);
487 assert_eq!(sccs.len(), 3);
488
489 let sizes: Vec<usize> = sccs.iter().map(|c| c.len()).collect();
491 assert!(sizes.contains(&3));
492 assert_eq!(sizes.iter().filter(|&&s| s == 1).count(), 2);
493
494 Ok(())
495 }
496
497 #[test]
498 fn test_articulation_points() -> GraphResult<()> {
499 let mut graph = create_graph::<i32, ()>();
501
502 graph.add_edge(0, 1, ())?;
506 graph.add_edge(1, 2, ())?;
507 graph.add_edge(1, 3, ())?;
508
509 let aps = articulation_points(&graph);
510 assert_eq!(aps.len(), 1);
511 assert!(aps.contains(&1));
512
513 Ok(())
514 }
515
516 #[test]
517 fn test_is_bipartite() -> GraphResult<()> {
518 let mut bipartite = create_graph::<i32, ()>();
520
521 bipartite.add_edge(0, 1, ())?;
522 bipartite.add_edge(1, 2, ())?;
523 bipartite.add_edge(2, 3, ())?;
524 bipartite.add_edge(3, 0, ())?;
525
526 let result = is_bipartite(&bipartite);
527 assert!(result.is_bipartite);
528 assert_eq!(result.coloring.len(), 4);
529
530 let mut non_bipartite = create_graph::<i32, ()>();
532
533 non_bipartite.add_edge(0, 1, ())?;
534 non_bipartite.add_edge(1, 2, ())?;
535 non_bipartite.add_edge(2, 0, ())?;
536
537 let result = is_bipartite(&non_bipartite);
538 assert!(!result.is_bipartite);
539
540 Ok(())
541 }
542
543 #[test]
544 fn test_weakly_connected_components() -> GraphResult<()> {
545 let mut graph = crate::base::DiGraph::<&str, ()>::new();
547
548 graph.add_edge("A", "B", ())?;
550 graph.add_edge("B", "C", ())?;
551
552 graph.add_edge("D", "E", ())?;
554 graph.add_edge("F", "E", ())?;
555 graph.add_edge("D", "F", ())?;
556
557 let wccs = weakly_connected_components(&graph);
558 assert_eq!(wccs.len(), 2);
559
560 let sizes: Vec<usize> = wccs.iter().map(|c| c.len()).collect();
562 assert!(sizes.contains(&3));
563 assert_eq!(sizes.iter().filter(|&&s| s == 3).count(), 2);
564
565 Ok(())
566 }
567
568 #[test]
569 fn test_bridges() -> GraphResult<()> {
570 let mut graph = create_graph::<i32, ()>();
572
573 graph.add_edge(0, 1, ())?;
576 graph.add_edge(1, 2, ())?;
577 graph.add_edge(2, 0, ())?;
578
579 graph.add_edge(2, 3, ())?;
581
582 graph.add_edge(3, 4, ())?;
584 graph.add_edge(4, 5, ())?;
585 graph.add_edge(5, 3, ())?;
586
587 let bridges_found = bridges(&graph);
588 assert_eq!(bridges_found.len(), 1);
589
590 let bridge = &bridges_found[0];
592 assert!((bridge.0 == 2 && bridge.1 == 3) || (bridge.0 == 3 && bridge.1 == 2));
593
594 Ok(())
595 }
596}