1use std::{
2 hash::Hash,
3 iter::{from_fn, FromIterator},
4};
5
6use indexmap::IndexSet;
7
8use crate::{
9 visit::{IntoNeighborsDirected, NodeCount},
10 Direction::Outgoing,
11};
12
13pub fn all_simple_paths<TargetColl, G>(
37 graph: G,
38 from: G::NodeId,
39 to: G::NodeId,
40 min_intermediate_nodes: usize,
41 max_intermediate_nodes: Option<usize>,
42) -> impl Iterator<Item = TargetColl>
43where
44 G: NodeCount,
45 G: IntoNeighborsDirected,
46 G::NodeId: Eq + Hash,
47 TargetColl: FromIterator<G::NodeId>,
48{
49 let max_length = if let Some(l) = max_intermediate_nodes {
53 l + 1
54 } else {
55 graph.node_count() - 1
56 };
57
58 let min_length = min_intermediate_nodes + 1;
59
60 let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
62 let mut stack = vec![graph.neighbors_directed(from, Outgoing)];
65
66 from_fn(move || {
67 while let Some(children) = stack.last_mut() {
68 if let Some(child) = children.next() {
69 if visited.len() < max_length {
70 if child == to {
71 if visited.len() >= min_length {
72 let path = visited
73 .iter()
74 .cloned()
75 .chain(Some(to))
76 .collect::<TargetColl>();
77 return Some(path);
78 }
79 } else if !visited.contains(&child) {
80 visited.insert(child);
81 stack.push(graph.neighbors_directed(child, Outgoing));
82 }
83 } else {
84 if (child == to || children.any(|v| v == to)) && visited.len() >= min_length {
85 let path = visited
86 .iter()
87 .cloned()
88 .chain(Some(to))
89 .collect::<TargetColl>();
90 return Some(path);
91 }
92 stack.pop();
93 visited.pop();
94 }
95 } else {
96 stack.pop();
97 visited.pop();
98 }
99 }
100 None
101 })
102}
103
104#[cfg(test)]
105mod test {
106 use std::{collections::HashSet, iter::FromIterator};
107
108 use itertools::assert_equal;
109
110 use crate::{dot::Dot, prelude::DiGraph};
111
112 use super::all_simple_paths;
113
114 #[test]
115 fn test_all_simple_paths() {
116 let graph = DiGraph::<i32, i32, _>::from_edges(&[
117 (0, 1),
118 (0, 2),
119 (0, 3),
120 (1, 2),
121 (1, 3),
122 (2, 3),
123 (2, 4),
124 (3, 2),
125 (3, 4),
126 (4, 2),
127 (4, 5),
128 (5, 2),
129 (5, 3),
130 ]);
131
132 let expexted_simple_paths_0_to_5 = vec![
133 vec![0usize, 1, 2, 3, 4, 5],
134 vec![0, 1, 2, 4, 5],
135 vec![0, 1, 3, 2, 4, 5],
136 vec![0, 1, 3, 4, 5],
137 vec![0, 2, 3, 4, 5],
138 vec![0, 2, 4, 5],
139 vec![0, 3, 2, 4, 5],
140 vec![0, 3, 4, 5],
141 ];
142
143 println!("{}", Dot::new(&graph));
144 let actual_simple_paths_0_to_5: HashSet<Vec<_>> =
145 all_simple_paths(&graph, 0u32.into(), 5u32.into(), 0, None)
146 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
147 .collect();
148 assert_eq!(actual_simple_paths_0_to_5.len(), 8);
149 assert_eq!(
150 HashSet::from_iter(expexted_simple_paths_0_to_5),
151 actual_simple_paths_0_to_5
152 );
153 }
154
155 #[test]
156 fn test_one_simple_path() {
157 let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);
158
159 let expexted_simple_paths_0_to_1 = &[vec![0usize, 1]];
160 println!("{}", Dot::new(&graph));
161 let actual_simple_paths_0_to_1: Vec<Vec<_>> =
162 all_simple_paths(&graph, 0u32.into(), 1u32.into(), 0, None)
163 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
164 .collect();
165
166 assert_eq!(actual_simple_paths_0_to_1.len(), 1);
167 assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
168 }
169
170 #[test]
171 fn test_no_simple_paths() {
172 let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);
173
174 println!("{}", Dot::new(&graph));
175 let actual_simple_paths_0_to_2: Vec<Vec<_>> =
176 all_simple_paths(&graph, 0u32.into(), 2u32.into(), 0, None)
177 .map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
178 .collect();
179
180 assert_eq!(actual_simple_paths_0_to_2.len(), 0);
181 }
182}