1use alloc::vec;
2use core::{
3 hash::{BuildHasher, Hash},
4 iter::{from_fn, FromIterator},
5};
6
7use hashbrown::HashSet;
8use indexmap::IndexSet;
9
10use crate::{
11 visit::{IntoNeighborsDirected, NodeCount},
12 Direction::Outgoing,
13};
14
15pub fn all_simple_paths<TargetColl, G, S>(
71 graph: G,
72 from: G::NodeId,
73 to: G::NodeId,
74 min_intermediate_nodes: usize,
75 max_intermediate_nodes: Option<usize>,
76) -> impl Iterator<Item = TargetColl>
77where
78 G: NodeCount,
79 G: IntoNeighborsDirected,
80 G::NodeId: Eq + Hash,
81 TargetColl: FromIterator<G::NodeId>,
82 S: BuildHasher + Default,
83{
84 let max_length = if let Some(l) = max_intermediate_nodes {
88 l + 1
89 } else {
90 graph.node_count() - 1
91 };
92
93 let min_length = min_intermediate_nodes + 1;
94
95 let mut visited: IndexSet<G::NodeId, S> = IndexSet::from_iter(Some(from));
97 let mut stack = vec![graph.neighbors_directed(from, Outgoing)];
100
101 from_fn(move || {
102 while let Some(children) = stack.last_mut() {
103 if let Some(child) = children.next() {
104 if visited.contains(&child) {
105 continue;
106 }
107 if visited.len() < max_length {
108 if child == to {
109 if visited.len() >= min_length {
110 let path = visited
111 .iter()
112 .cloned()
113 .chain(Some(to))
114 .collect::<TargetColl>();
115 return Some(path);
116 }
117 } else {
118 visited.insert(child);
119 stack.push(graph.neighbors_directed(child, Outgoing));
120 }
121 } else {
122 if (child == to || children.any(|v| v == to && !visited.contains(&v)))
123 && visited.len() >= min_length
124 {
125 let path = visited
126 .iter()
127 .cloned()
128 .chain(Some(to))
129 .collect::<TargetColl>();
130 return Some(path);
131 }
132 stack.pop();
133 visited.pop();
134 }
135 } else {
136 stack.pop();
137 visited.pop();
138 }
139 }
140 None
141 })
142}
143
144pub fn all_simple_paths_multi<'a, TargetColl, G, S>(
208 graph: G,
209 from: G::NodeId,
210 to: &'a HashSet<G::NodeId, S>,
211 min_intermediate_nodes: usize,
212 max_intermediate_nodes: Option<usize>,
213) -> impl Iterator<Item = TargetColl> + 'a
214where
215 G: NodeCount + IntoNeighborsDirected + 'a,
216 <G as IntoNeighborsDirected>::NeighborsDirected: 'a,
217 G::NodeId: Eq + Hash,
218 TargetColl: FromIterator<G::NodeId>,
219 S: BuildHasher + Default,
220{
221 let max_nodes = if let Some(l) = max_intermediate_nodes {
222 l + 2
223 } else {
224 graph.node_count()
225 };
226
227 let min_nodes = min_intermediate_nodes + 2;
228
229 let mut visited: IndexSet<G::NodeId, S> = IndexSet::from_iter(Some(from));
231 let mut stack = vec![graph.neighbors_directed(from, Outgoing)];
234
235 from_fn(move || {
236 while let Some(children) = stack.last_mut() {
237 if let Some(child) = children.next() {
238 if visited.contains(&child) {
239 continue;
240 }
241
242 let current_nodes = visited.len();
243 let mut valid_path: Option<TargetColl> = None;
244
245 if to.contains(&child) && (current_nodes + 1) >= min_nodes {
247 valid_path = Some(
248 visited
249 .iter()
250 .cloned()
251 .chain(Some(child))
252 .collect::<TargetColl>(),
253 );
254 }
255
256 if (current_nodes < max_nodes)
258 && to.iter().any(|n| *n != child && !visited.contains(n))
259 {
260 visited.insert(child);
261 stack.push(graph.neighbors_directed(child, Outgoing));
262 }
263
264 if valid_path.is_some() {
266 return valid_path;
267 }
268 } else {
269 stack.pop();
271 visited.pop();
272 }
273 }
274 None
275 })
276}
277
278#[cfg(test)]
279mod test {
280 use alloc::{vec, vec::Vec};
281 use core::iter::FromIterator;
282 use std::{collections::hash_map::RandomState, println};
283
284 use hashbrown::HashSet;
285 use itertools::assert_equal;
286
287 use super::{all_simple_paths, all_simple_paths_multi};
288 use crate::{
289 dot::Dot,
290 prelude::{DiGraph, UnGraph},
291 };
292
293 #[test]
294 fn test_all_simple_paths() {
295 let graph = DiGraph::<i32, i32, _>::from_edges([
296 (0, 1),
297 (0, 2),
298 (0, 3),
299 (1, 2),
300 (1, 3),
301 (2, 3),
302 (2, 4),
303 (3, 2),
304 (3, 4),
305 (4, 2),
306 (4, 5),
307 (5, 2),
308 (5, 3),
309 ]);
310
311 let expexted_simple_paths_0_to_5 = vec![
312 vec![0usize, 1, 2, 3, 4, 5],
313 vec![0, 1, 2, 4, 5],
314 vec![0, 1, 3, 2, 4, 5],
315 vec![0, 1, 3, 4, 5],
316 vec![0, 2, 3, 4, 5],
317 vec![0, 2, 4, 5],
318 vec![0, 3, 2, 4, 5],
319 vec![0, 3, 4, 5],
320 ];
321
322 println!("{}", Dot::new(&graph));
323 let actual_simple_paths_0_to_5: HashSet<Vec<_>> =
324 all_simple_paths::<_, _, RandomState>(&graph, 0u32.into(), 5u32.into(), 0, None)
325 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
326 .collect();
327 assert_eq!(actual_simple_paths_0_to_5.len(), 8);
328 assert_eq!(
329 HashSet::from_iter(expexted_simple_paths_0_to_5),
330 actual_simple_paths_0_to_5
331 );
332 }
333
334 #[test]
335 fn test_one_simple_path() {
336 let graph = DiGraph::<i32, i32, _>::from_edges([(0, 1), (2, 1)]);
337
338 let expexted_simple_paths_0_to_1 = &[vec![0usize, 1]];
339 println!("{}", Dot::new(&graph));
340 let actual_simple_paths_0_to_1: Vec<Vec<_>> =
341 all_simple_paths::<_, _, RandomState>(&graph, 0u32.into(), 1u32.into(), 0, None)
342 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
343 .collect();
344
345 assert_eq!(actual_simple_paths_0_to_1.len(), 1);
346 assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
347 }
348
349 #[test]
350 fn test_no_simple_paths() {
351 let graph = DiGraph::<i32, i32, _>::from_edges([(0, 1), (2, 1)]);
352
353 println!("{}", Dot::new(&graph));
354 let actual_simple_paths_0_to_2: Vec<Vec<_>> =
355 all_simple_paths::<_, _, RandomState>(&graph, 0u32.into(), 2u32.into(), 0, None)
356 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
357 .collect();
358
359 assert_eq!(actual_simple_paths_0_to_2.len(), 0);
360 }
361
362 #[test]
363 fn test_path_graph() {
364 let graph = UnGraph::<i32, i32>::from_edges([(0, 1), (1, 2), (2, 3)]);
365 let paths: Vec<Vec<_>> =
366 all_simple_paths::<_, _, RandomState>(&graph, 0u32.into(), 3u32.into(), 0, None)
367 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
368 .collect();
369 assert_eq!(paths, vec![vec![0, 1, 2, 3]]);
370 }
371
372 #[test]
373 fn test_multi_target_paths() {
374 let graph = UnGraph::<i32, i32>::from_edges([(0, 1), (1, 2), (2, 3), (2, 4)]);
375 let targets = HashSet::from_iter([3.into(), 4.into()]);
376 let paths: HashSet<Vec<_>> =
377 all_simple_paths_multi::<_, _, RandomState>(&graph, 0.into(), &targets, 0, None)
378 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
379 .collect();
380 let expected: HashSet<Vec<_>> = HashSet::from_iter([vec![0, 1, 2, 3], vec![0, 1, 2, 4]]);
381 assert_eq!(paths, expected);
382 }
383
384 #[test]
385 fn test_digraph_multi_target_paths() {
386 let graph = DiGraph::<i32, ()>::from_edges([(0, 1), (1, 2), (2, 3), (2, 4)]);
387 let targets = HashSet::from_iter([3.into(), 4.into()]);
388 let paths: HashSet<Vec<_>> =
389 all_simple_paths_multi::<_, _, RandomState>(&graph, 0.into(), &targets, 0, None)
390 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
391 .collect();
392 let expected: HashSet<Vec<_>> = HashSet::from_iter([vec![0, 1, 2, 3], vec![0, 1, 2, 4]]);
393 assert_eq!(paths, expected);
394 }
395
396 #[test]
397 fn test_multi_target_paths_cutoff() {
398 let graph = UnGraph::<i32, ()>::from_edges([(0, 1), (1, 2), (2, 3), (2, 4)]);
399 let targets = HashSet::from_iter([3.into(), 4.into()]);
400 let paths: HashSet<Vec<_>> =
401 all_simple_paths_multi::<_, _, RandomState>(&graph, 0.into(), &targets, 0, Some(2))
402 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
403 .collect();
404 let expected: HashSet<Vec<_>> = HashSet::from_iter([vec![0, 1, 2, 3], vec![0, 1, 2, 4]]);
405 assert_eq!(paths, expected);
406 }
407
408 #[test]
409 fn test_digraph_multi_target_paths_cutoff() {
410 let graph = DiGraph::<i32, ()>::from_edges([(0, 1), (1, 2), (2, 3), (2, 4)]);
411 let targets = HashSet::from_iter([3.into(), 4.into()]);
412 let paths: HashSet<Vec<_>> =
413 all_simple_paths_multi::<_, _, RandomState>(&graph, 0.into(), &targets, 0, Some(2))
414 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
415 .collect();
416 let expected: HashSet<Vec<_>> = HashSet::from_iter([vec![0, 1, 2, 3], vec![0, 1, 2, 4]]);
417 assert_eq!(paths, expected);
418 }
419
420 #[test]
421 fn test_multi_target_paths_inline() {
422 let graph = UnGraph::<i32, ()>::from_edges([(0, 1), (1, 2), (2, 3)]);
423 let targets = HashSet::from_iter([2.into(), 3.into()]);
424 let paths: HashSet<Vec<_>> =
425 all_simple_paths_multi::<_, _, RandomState>(&graph, 0.into(), &targets, 0, None)
426 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
427 .collect();
428 let expected: HashSet<Vec<_>> = HashSet::from_iter([vec![0, 1, 2], vec![0, 1, 2, 3]]);
429 assert_eq!(paths, expected);
430 }
431
432 #[test]
433 fn test_all_simple_paths_ignores_cycle() {
434 let graph = DiGraph::<i32, ()>::from_edges([(0, 1), (1, 2), (2, 0), (1, 3)]);
435 let paths: Vec<Vec<_>> =
436 all_simple_paths::<_, _, RandomState>(&graph, 0.into(), 3.into(), 0, None)
437 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
438 .collect();
439 assert_eq!(paths, vec![vec![0, 1, 3]]);
440 }
441
442 #[test]
443 fn test_multi_target_paths_in_cycle() {
444 let graph = DiGraph::<i32, ()>::from_edges([(0, 1), (1, 2), (2, 0), (1, 3)]);
445 let targets = HashSet::from_iter([2.into(), 3.into()]);
446 let paths: HashSet<Vec<_>> =
447 all_simple_paths_multi::<_, _, RandomState>(&graph, 0.into(), &targets, 0, None)
448 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
449 .collect();
450 let expected = HashSet::from_iter([vec![0, 1, 2], vec![0, 1, 3]]);
451 assert_eq!(paths, expected);
452 }
453
454 #[test]
455 fn test_simple_path_source_target() {
456 let graph = UnGraph::<i32, ()>::from_edges([(0, 1), (1, 2), (2, 3)]);
457 let paths: Vec<Vec<_>> =
458 all_simple_paths::<_, _, RandomState>(&graph, 1.into(), 1.into(), 0, None)
459 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
460 .collect();
461 assert!(paths.is_empty());
462 }
463
464 #[test]
465 fn test_simple_paths_cutoff() {
466 let graph =
467 UnGraph::<i32, ()>::from_edges([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]);
468 let paths: HashSet<Vec<_>> =
469 all_simple_paths::<_, _, RandomState>(&graph, 0.into(), 1.into(), 0, Some(0))
470 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
471 .collect();
472 assert_eq!(paths, HashSet::from_iter([vec![0, 1]]));
473
474 let paths: HashSet<Vec<_>> =
475 all_simple_paths::<_, _, RandomState>(&graph, 0.into(), 1.into(), 0, Some(1))
476 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
477 .collect();
478 let expected = HashSet::from_iter([vec![0, 1], vec![0, 2, 1], vec![0, 3, 1]]);
479 assert_eq!(paths, expected);
480 }
481
482 #[test]
483 fn test_multi_target_source_is_target() {
484 let graph = UnGraph::<i32, ()>::from_edges([(0, 1), (1, 2)]);
485 let targets = HashSet::from_iter([0.into(), 1.into(), 2.into()]);
486 let paths: HashSet<Vec<_>> =
487 all_simple_paths_multi::<_, _, RandomState>(&graph, 0.into(), &targets, 0, None)
488 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
489 .collect();
490 let expected = HashSet::from_iter([vec![0, 1], vec![0, 1, 2]]);
491 assert_eq!(paths, expected);
492 }
493
494 #[test]
495 fn test_all_simple_paths_empty() {
496 let graph = UnGraph::<i32, ()>::from_edges([(0, 1), (1, 2), (2, 3)]);
497 let paths: Vec<Vec<_>> =
498 all_simple_paths::<_, _, RandomState>(&graph, 0.into(), 3.into(), 0, Some(1))
499 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
500 .collect();
501 assert!(paths.is_empty());
502 }
503
504 #[test]
505 fn test_all_simple_paths_on_non_trivial_graph() {
506 let graph = DiGraph::<i32, ()>::from_edges([
507 (0, 1),
508 (1, 2),
509 (2, 3),
510 (3, 4),
511 (0, 5),
512 (1, 5),
513 (1, 3),
514 (5, 4),
515 (4, 2),
516 (4, 3),
517 ]);
518 let targets = HashSet::from_iter([2.into(), 3.into()]);
519 let paths: HashSet<Vec<_>> =
520 all_simple_paths_multi::<_, _, RandomState>(&graph, 1.into(), &targets, 0, None)
521 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
522 .collect();
523 let expected = HashSet::from_iter([
524 vec![1, 2],
525 vec![1, 5, 4, 2],
526 vec![1, 3, 4, 2],
527 vec![1, 3],
528 vec![1, 2, 3],
529 vec![1, 5, 4, 3],
530 vec![1, 5, 4, 2, 3],
531 ]);
532 assert_eq!(paths, expected);
533 }
534
535 #[test]
536 fn test_all_simple_paths_directed() {
537 let graph = DiGraph::<i32, ()>::from_edges([(1, 2), (2, 3), (3, 2), (2, 1)]);
538 let paths: HashSet<Vec<_>> =
539 all_simple_paths::<_, _, RandomState>(&graph, 1.into(), 3.into(), 0, None)
540 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
541 .collect();
542 let expected = HashSet::from_iter([vec![1, 2, 3]]);
543 assert_eq!(paths, expected);
544 }
545
546 #[test]
547 fn test_all_simple_paths_corner_cases() {
548 let mut graph = DiGraph::<i32, ()>::new();
549 graph.add_node(0);
550 graph.add_node(1);
551
552 let paths: Vec<Vec<_>> =
553 all_simple_paths::<_, _, RandomState>(&graph, 0.into(), 0.into(), 0, None)
554 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
555 .collect();
556 assert!(paths.is_empty());
557
558 let paths: Vec<Vec<_>> =
559 all_simple_paths::<_, _, RandomState>(&graph, 0.into(), 1.into(), 0, None)
560 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
561 .collect();
562 assert!(paths.is_empty());
563 }
564
565 #[test]
566 fn test_simple_paths_min_intermediate_nodes() {
567 let graph =
568 UnGraph::<i32, ()>::from_edges([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]);
569 let paths: HashSet<Vec<_>> =
570 all_simple_paths::<_, _, RandomState>(&graph, 0.into(), 1.into(), 2, None)
571 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
572 .collect();
573 let expected = HashSet::from_iter([vec![0, 2, 3, 1], vec![0, 3, 2, 1]]);
574 assert_eq!(paths, expected);
575 }
576
577 #[test]
578 fn test_multi_target_paths_min_intermediate_nodes() {
579 let graph =
580 UnGraph::<i32, ()>::from_edges([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]);
581 let targets = HashSet::from_iter([1.into(), 3.into()]);
582 let paths: HashSet<Vec<_>> =
583 all_simple_paths_multi::<_, _, RandomState>(&graph, 0.into(), &targets, 2, None)
584 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
585 .collect();
586 let expected = HashSet::from_iter([
587 vec![0, 2, 3, 1],
588 vec![0, 3, 2, 1],
589 vec![0, 1, 2, 3],
590 vec![0, 2, 1, 3],
591 ]);
592 assert_eq!(paths, expected);
593 }
594
595 #[test]
596 fn test_simple_paths_from_node_to_itself_in_complete_graph() {
597 let mut graph = DiGraph::new();
599
600 let a = graph.add_node("A");
601 let b = graph.add_node("B");
602 let c = graph.add_node("C");
603
604 graph.add_edge(a, b, ());
606 graph.add_edge(a, c, ());
607 graph.add_edge(b, a, ());
608 graph.add_edge(b, c, ());
609 graph.add_edge(c, a, ());
610 graph.add_edge(c, b, ());
611
612 let paths: Vec<Vec<_>> =
614 all_simple_paths::<Vec<_>, _, RandomState>(&graph, a, a, 0, None).collect();
615
616 assert!(paths.is_empty());
618 }
619}