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).unwrap();
105 let v_lowlink = *state.lowlinks.get(&v).unwrap();
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).unwrap();
110 let v_lowlink = *state.lowlinks.get(&v).unwrap();
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().unwrap();
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).unwrap();
251 let u_low = *state.low.get(&u).unwrap();
252 state.low.insert(u, u_low.min(v_low));
253
254 let u_disc = *state.disc.get(&u).unwrap();
258 if (state.parent.get(&u).unwrap().is_none() && children > 1)
259 || (state.parent.get(&u).unwrap().is_some() && v_low >= u_disc)
260 {
261 articulation_points.insert(graph.inner()[u].clone());
262 }
263 } else if state.parent.get(&u).unwrap() != &Some(v) {
264 let v_disc = *state.disc.get(&v).unwrap();
266 let u_low = *state.low.get(&u).unwrap();
267 state.low.insert(u, u_low.min(v_disc));
268 }
269 }
270 }
271
272 let mut articulation_points = HashSet::new();
273 let mut state = DfsState {
274 time: 0,
275 disc: HashMap::new(),
276 low: HashMap::new(),
277 parent: HashMap::new(),
278 visited: HashSet::new(),
279 };
280
281 for node in graph.inner().node_indices() {
282 if !state.visited.contains(&node) {
283 state.parent.insert(node, None);
284 dfs(node, graph, &mut state, &mut articulation_points);
285 }
286 }
287
288 articulation_points
289}
290
291#[derive(Debug, Clone)]
293pub struct BipartiteResult<N: Node> {
294 pub is_bipartite: bool,
296 pub coloring: HashMap<N, u8>,
298}
299
300#[allow(dead_code)]
311pub fn is_bipartite<N, E, Ix>(graph: &Graph<N, E, Ix>) -> BipartiteResult<N>
312where
313 N: Node + std::fmt::Debug,
314 E: EdgeWeight,
315 Ix: petgraph::graph::IndexType,
316{
317 let mut coloring: HashMap<petgraph::graph::NodeIndex<Ix>, u8> = HashMap::new();
318 let mut queue = VecDeque::new();
319
320 for start_idx in graph.inner().node_indices() {
322 if coloring.contains_key(&start_idx) {
323 continue;
324 }
325
326 queue.push_back(start_idx);
328 coloring.insert(start_idx, 0);
329
330 while let Some(node_idx) = queue.pop_front() {
331 let node_color = *coloring.get(&node_idx).unwrap();
332 let next_color = 1 - node_color;
333
334 for neighbor in graph.inner().neighbors(node_idx) {
335 if let Some(&neighbor_color) = coloring.get(&neighbor) {
336 if neighbor_color == node_color {
338 return BipartiteResult {
339 is_bipartite: false,
340 coloring: HashMap::new(),
341 };
342 }
343 } else {
344 coloring.insert(neighbor, next_color);
346 queue.push_back(neighbor);
347 }
348 }
349 }
350 }
351
352 let node_coloring: HashMap<N, u8> = coloring
354 .into_iter()
355 .map(|(idx, color)| (graph.inner()[idx].clone(), color))
356 .collect();
357
358 BipartiteResult {
359 is_bipartite: true,
360 coloring: node_coloring,
361 }
362}
363
364#[allow(dead_code)]
374pub fn bridges<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Vec<(N, N)>
375where
376 N: Node + std::fmt::Debug,
377 E: EdgeWeight,
378 Ix: petgraph::graph::IndexType,
379{
380 struct DfsState<Ix: petgraph::graph::IndexType> {
381 time: usize,
382 disc: HashMap<petgraph::graph::NodeIndex<Ix>, usize>,
383 low: HashMap<petgraph::graph::NodeIndex<Ix>, usize>,
384 parent: HashMap<petgraph::graph::NodeIndex<Ix>, Option<petgraph::graph::NodeIndex<Ix>>>,
385 visited: HashSet<petgraph::graph::NodeIndex<Ix>>,
386 }
387
388 fn dfs<N, E, Ix>(
389 u: petgraph::graph::NodeIndex<Ix>,
390 graph: &Graph<N, E, Ix>,
391 state: &mut DfsState<Ix>,
392 bridges: &mut Vec<(N, N)>,
393 ) where
394 N: Node + std::fmt::Debug,
395 E: EdgeWeight,
396 Ix: petgraph::graph::IndexType,
397 {
398 state.visited.insert(u);
399 state.disc.insert(u, state.time);
400 state.low.insert(u, state.time);
401 state.time += 1;
402
403 for v in graph.inner().neighbors(u) {
404 if !state.visited.contains(&v) {
405 state.parent.insert(v, Some(u));
406 dfs(v, graph, state, bridges);
407
408 let v_low = *state.low.get(&v).unwrap();
410 let u_low = *state.low.get(&u).unwrap();
411 state.low.insert(u, u_low.min(v_low));
412
413 let u_disc = *state.disc.get(&u).unwrap();
415 if v_low > u_disc {
416 bridges.push((graph.inner()[u].clone(), graph.inner()[v].clone()));
417 }
418 } else if state.parent.get(&u).unwrap() != &Some(v) {
419 let v_disc = *state.disc.get(&v).unwrap();
421 let u_low = *state.low.get(&u).unwrap();
422 state.low.insert(u, u_low.min(v_disc));
423 }
424 }
425 }
426
427 let mut bridges = Vec::new();
428 let mut state = DfsState {
429 time: 0,
430 disc: HashMap::new(),
431 low: HashMap::new(),
432 parent: HashMap::new(),
433 visited: HashSet::new(),
434 };
435
436 for node in graph.inner().node_indices() {
437 if !state.visited.contains(&node) {
438 state.parent.insert(node, None);
439 dfs(node, graph, &mut state, &mut bridges);
440 }
441 }
442
443 bridges
444}
445
446#[cfg(test)]
447mod tests {
448 use super::*;
449 use crate::error::Result as GraphResult;
450 use crate::generators::create_graph;
451
452 #[test]
453 fn test_connected_components() -> GraphResult<()> {
454 let mut graph = create_graph::<i32, ()>();
456
457 graph.add_edge(0, 1, ())?;
458 graph.add_edge(1, 2, ())?;
459 graph.add_edge(3, 4, ())?;
460
461 let components = connected_components(&graph);
462 assert_eq!(components.len(), 2);
463
464 let sizes: Vec<usize> = components.iter().map(|c| c.len()).collect();
466 assert!(sizes.contains(&3));
467 assert!(sizes.contains(&2));
468
469 Ok(())
470 }
471
472 #[test]
473 fn test_strongly_connected_components() -> GraphResult<()> {
474 let mut graph = crate::base::DiGraph::<&str, ()>::new();
476
477 graph.add_edge("A", "B", ())?;
479 graph.add_edge("B", "C", ())?;
480 graph.add_edge("C", "A", ())?;
481
482 graph.add_edge("D", "E", ())?;
484
485 let sccs = strongly_connected_components(&graph);
486 assert_eq!(sccs.len(), 3);
487
488 let sizes: Vec<usize> = sccs.iter().map(|c| c.len()).collect();
490 assert!(sizes.contains(&3));
491 assert_eq!(sizes.iter().filter(|&&s| s == 1).count(), 2);
492
493 Ok(())
494 }
495
496 #[test]
497 fn test_articulation_points() -> GraphResult<()> {
498 let mut graph = create_graph::<i32, ()>();
500
501 graph.add_edge(0, 1, ())?;
505 graph.add_edge(1, 2, ())?;
506 graph.add_edge(1, 3, ())?;
507
508 let aps = articulation_points(&graph);
509 assert_eq!(aps.len(), 1);
510 assert!(aps.contains(&1));
511
512 Ok(())
513 }
514
515 #[test]
516 fn test_is_bipartite() -> GraphResult<()> {
517 let mut bipartite = create_graph::<i32, ()>();
519
520 bipartite.add_edge(0, 1, ())?;
521 bipartite.add_edge(1, 2, ())?;
522 bipartite.add_edge(2, 3, ())?;
523 bipartite.add_edge(3, 0, ())?;
524
525 let result = is_bipartite(&bipartite);
526 assert!(result.is_bipartite);
527 assert_eq!(result.coloring.len(), 4);
528
529 let mut non_bipartite = create_graph::<i32, ()>();
531
532 non_bipartite.add_edge(0, 1, ())?;
533 non_bipartite.add_edge(1, 2, ())?;
534 non_bipartite.add_edge(2, 0, ())?;
535
536 let result = is_bipartite(&non_bipartite);
537 assert!(!result.is_bipartite);
538
539 Ok(())
540 }
541
542 #[test]
543 fn test_weakly_connected_components() -> GraphResult<()> {
544 let mut graph = crate::base::DiGraph::<&str, ()>::new();
546
547 graph.add_edge("A", "B", ())?;
549 graph.add_edge("B", "C", ())?;
550
551 graph.add_edge("D", "E", ())?;
553 graph.add_edge("F", "E", ())?;
554 graph.add_edge("D", "F", ())?;
555
556 let wccs = weakly_connected_components(&graph);
557 assert_eq!(wccs.len(), 2);
558
559 let sizes: Vec<usize> = wccs.iter().map(|c| c.len()).collect();
561 assert!(sizes.contains(&3));
562 assert_eq!(sizes.iter().filter(|&&s| s == 3).count(), 2);
563
564 Ok(())
565 }
566
567 #[test]
568 fn test_bridges() -> GraphResult<()> {
569 let mut graph = create_graph::<i32, ()>();
571
572 graph.add_edge(0, 1, ())?;
575 graph.add_edge(1, 2, ())?;
576 graph.add_edge(2, 0, ())?;
577
578 graph.add_edge(2, 3, ())?;
580
581 graph.add_edge(3, 4, ())?;
583 graph.add_edge(4, 5, ())?;
584 graph.add_edge(5, 3, ())?;
585
586 let bridges_found = bridges(&graph);
587 assert_eq!(bridges_found.len(), 1);
588
589 let bridge = &bridges_found[0];
591 assert!((bridge.0 == 2 && bridge.1 == 3) || (bridge.0 == 3 && bridge.1 == 2));
592
593 Ok(())
594 }
595}