1use std::collections::VecDeque;
10
11use crate::core::{Graph, IgraphError, IgraphResult, VertexId};
12
13pub fn get_shortest_paths(graph: &Graph, source: VertexId) -> IgraphResult<Vec<Vec<VertexId>>> {
44 if graph.is_directed() {
45 return get_shortest_paths_directed(graph, source, true);
46 }
47 get_shortest_paths_impl(graph, source)
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub enum ShortestPathMode {
53 Out,
55 In,
57 All,
59}
60
61pub fn get_shortest_paths_with_mode(
88 graph: &Graph,
89 source: VertexId,
90 mode: ShortestPathMode,
91) -> IgraphResult<Vec<Vec<VertexId>>> {
92 if !graph.is_directed() {
93 return get_shortest_paths_impl(graph, source);
94 }
95 match mode {
96 ShortestPathMode::Out => get_shortest_paths_directed(graph, source, true),
97 ShortestPathMode::In => get_shortest_paths_directed(graph, source, false),
98 ShortestPathMode::All => get_shortest_paths_directed_all(graph, source),
99 }
100}
101
102fn get_shortest_paths_impl(graph: &Graph, source: VertexId) -> IgraphResult<Vec<Vec<VertexId>>> {
104 let n = graph.vcount();
105 if source >= n {
106 return Err(IgraphError::InvalidArgument(format!(
107 "get_shortest_paths: source {source} out of range (vcount={n})"
108 )));
109 }
110
111 let n_us = n as usize;
112 let mut parent: Vec<Option<VertexId>> = vec![None; n_us];
113 let mut visited = vec![false; n_us];
114
115 let mut queue = VecDeque::new();
116 visited[source as usize] = true;
117 queue.push_back(source);
118
119 while let Some(cur) = queue.pop_front() {
120 let neighbors = graph.neighbors(cur)?;
121 for &nb in &neighbors {
122 if !visited[nb as usize] {
123 visited[nb as usize] = true;
124 parent[nb as usize] = Some(cur);
125 queue.push_back(nb);
126 }
127 }
128 }
129
130 Ok(build_paths(source, n_us, &parent, &visited))
131}
132
133fn get_shortest_paths_directed(
135 graph: &Graph,
136 source: VertexId,
137 follow_out: bool,
138) -> IgraphResult<Vec<Vec<VertexId>>> {
139 let n = graph.vcount();
140 if source >= n {
141 return Err(IgraphError::InvalidArgument(format!(
142 "get_shortest_paths: source {source} out of range (vcount={n})"
143 )));
144 }
145
146 let n_us = n as usize;
147 let m =
148 u32::try_from(graph.ecount()).map_err(|_| IgraphError::Internal("ecount overflows u32"))?;
149
150 let mut adj: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
152 for eid in 0..m {
153 let (from, to) = graph.edge(eid)?;
154 if follow_out {
155 adj[from as usize].push(to);
156 } else {
157 adj[to as usize].push(from);
158 }
159 }
160
161 let mut parent: Vec<Option<VertexId>> = vec![None; n_us];
162 let mut visited = vec![false; n_us];
163
164 let mut queue = VecDeque::new();
165 visited[source as usize] = true;
166 queue.push_back(source);
167
168 while let Some(cur) = queue.pop_front() {
169 for &nb in &adj[cur as usize] {
170 if !visited[nb as usize] {
171 visited[nb as usize] = true;
172 parent[nb as usize] = Some(cur);
173 queue.push_back(nb);
174 }
175 }
176 }
177
178 Ok(build_paths(source, n_us, &parent, &visited))
179}
180
181fn get_shortest_paths_directed_all(
183 graph: &Graph,
184 source: VertexId,
185) -> IgraphResult<Vec<Vec<VertexId>>> {
186 let n = graph.vcount();
187 if source >= n {
188 return Err(IgraphError::InvalidArgument(format!(
189 "get_shortest_paths: source {source} out of range (vcount={n})"
190 )));
191 }
192
193 let n_us = n as usize;
194 let m =
195 u32::try_from(graph.ecount()).map_err(|_| IgraphError::Internal("ecount overflows u32"))?;
196
197 let mut adj: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
199 for eid in 0..m {
200 let (from, to) = graph.edge(eid)?;
201 adj[from as usize].push(to);
202 if from != to {
203 adj[to as usize].push(from);
204 }
205 }
206
207 let mut parent: Vec<Option<VertexId>> = vec![None; n_us];
208 let mut visited = vec![false; n_us];
209
210 let mut queue = VecDeque::new();
211 visited[source as usize] = true;
212 queue.push_back(source);
213
214 while let Some(cur) = queue.pop_front() {
215 for &nb in &adj[cur as usize] {
216 if !visited[nb as usize] {
217 visited[nb as usize] = true;
218 parent[nb as usize] = Some(cur);
219 queue.push_back(nb);
220 }
221 }
222 }
223
224 Ok(build_paths(source, n_us, &parent, &visited))
225}
226
227fn build_paths(
229 source: VertexId,
230 n_us: usize,
231 parent: &[Option<VertexId>],
232 visited: &[bool],
233) -> Vec<Vec<VertexId>> {
234 let mut result: Vec<Vec<VertexId>> = Vec::with_capacity(n_us);
235 for (v, &is_visited) in visited.iter().enumerate().take(n_us) {
236 if !is_visited {
237 result.push(Vec::new());
238 continue;
239 }
240 #[allow(clippy::cast_possible_truncation)] let v_id = v as u32;
242 if v_id == source {
243 result.push(vec![source]);
244 continue;
245 }
246 let mut path = Vec::new();
247 let mut cur = v_id;
248 loop {
249 path.push(cur);
250 if cur == source {
251 break;
252 }
253 cur = parent[cur as usize].unwrap_or(source);
254 }
255 path.reverse();
256 result.push(path);
257 }
258 result
259}
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264
265 #[test]
266 fn empty_graph() {
267 let g = Graph::with_vertices(0);
268 assert!(get_shortest_paths(&g, 0).is_err());
271 }
272
273 #[test]
274 fn singleton() {
275 let g = Graph::with_vertices(1);
276 let paths = get_shortest_paths(&g, 0).unwrap();
277 assert_eq!(paths, vec![vec![0]]);
278 }
279
280 #[test]
281 fn path_graph() {
282 let mut g = Graph::with_vertices(4);
283 g.add_edge(0, 1).unwrap();
284 g.add_edge(1, 2).unwrap();
285 g.add_edge(2, 3).unwrap();
286 let paths = get_shortest_paths(&g, 0).unwrap();
287 assert_eq!(paths[0], vec![0]);
288 assert_eq!(paths[1], vec![0, 1]);
289 assert_eq!(paths[2], vec![0, 1, 2]);
290 assert_eq!(paths[3], vec![0, 1, 2, 3]);
291 }
292
293 #[test]
294 fn two_components_unreachable() {
295 let mut g = Graph::with_vertices(4);
296 g.add_edge(0, 1).unwrap();
297 g.add_edge(2, 3).unwrap();
298 let paths = get_shortest_paths(&g, 0).unwrap();
299 assert_eq!(paths[0], vec![0]);
300 assert_eq!(paths[1], vec![0, 1]);
301 assert!(paths[2].is_empty());
302 assert!(paths[3].is_empty());
303 }
304
305 #[test]
306 fn shortest_path_prefers_shorter() {
307 let mut g = Graph::with_vertices(4);
310 g.add_edge(0, 1).unwrap();
311 g.add_edge(1, 2).unwrap();
312 g.add_edge(2, 3).unwrap();
313 g.add_edge(0, 3).unwrap();
314 let paths = get_shortest_paths(&g, 0).unwrap();
315 assert_eq!(paths[3].len(), 2); assert_eq!(paths[3][0], 0);
317 assert_eq!(paths[3][1], 3);
318 }
319
320 #[test]
321 fn cycle_graph() {
322 let mut g = Graph::with_vertices(5);
325 g.add_edge(0, 1).unwrap();
326 g.add_edge(1, 2).unwrap();
327 g.add_edge(2, 3).unwrap();
328 g.add_edge(3, 4).unwrap();
329 g.add_edge(4, 0).unwrap();
330 let paths = get_shortest_paths(&g, 0).unwrap();
331 assert_eq!(paths[3].len(), 3);
333 assert_eq!(paths[3][0], 0);
334 assert_eq!(*paths[3].last().unwrap(), 3);
335 }
336
337 #[test]
338 fn directed_out() {
339 let mut g = Graph::new(3, true).unwrap();
341 g.add_edge(0, 1).unwrap();
342 g.add_edge(1, 2).unwrap();
343 let paths = get_shortest_paths_with_mode(&g, 0, ShortestPathMode::Out).unwrap();
344 assert_eq!(paths[0], vec![0]);
345 assert_eq!(paths[1], vec![0, 1]);
346 assert_eq!(paths[2], vec![0, 1, 2]);
347 }
348
349 #[test]
350 fn directed_in() {
351 let mut g = Graph::new(3, true).unwrap();
353 g.add_edge(0, 1).unwrap();
354 g.add_edge(1, 2).unwrap();
355 let paths = get_shortest_paths_with_mode(&g, 2, ShortestPathMode::In).unwrap();
356 assert_eq!(paths[2], vec![2]);
357 assert_eq!(paths[1], vec![2, 1]);
358 assert_eq!(paths[0], vec![2, 1, 0]);
359 }
360
361 #[test]
362 fn directed_unreachable() {
363 let mut g = Graph::new(3, true).unwrap();
365 g.add_edge(0, 1).unwrap();
366 g.add_edge(1, 2).unwrap();
367 let paths = get_shortest_paths_with_mode(&g, 2, ShortestPathMode::Out).unwrap();
368 assert_eq!(paths[2], vec![2]);
369 assert!(paths[0].is_empty());
370 assert!(paths[1].is_empty());
371 }
372
373 #[test]
374 fn directed_all_mode() {
375 let mut g = Graph::new(3, true).unwrap();
377 g.add_edge(0, 1).unwrap();
378 g.add_edge(1, 2).unwrap();
379 let paths = get_shortest_paths_with_mode(&g, 2, ShortestPathMode::All).unwrap();
380 assert_eq!(paths[2], vec![2]);
381 assert_eq!(paths[1], vec![2, 1]);
382 assert_eq!(paths[0], vec![2, 1, 0]);
383 }
384
385 #[test]
386 fn star_graph() {
387 let mut g = Graph::with_vertices(5);
389 g.add_edge(0, 1).unwrap();
390 g.add_edge(0, 2).unwrap();
391 g.add_edge(0, 3).unwrap();
392 g.add_edge(0, 4).unwrap();
393 let paths = get_shortest_paths(&g, 0).unwrap();
394 for leaf in 1..5 {
395 assert_eq!(paths[leaf as usize], vec![0, leaf]);
396 }
397 let paths_1 = get_shortest_paths(&g, 1).unwrap();
399 assert_eq!(paths_1[2], vec![1, 0, 2]);
400 }
401
402 #[test]
403 fn source_out_of_range() {
404 let g = Graph::with_vertices(3);
405 assert!(get_shortest_paths(&g, 5).is_err());
406 }
407
408 #[test]
409 fn self_loop_ignored() {
410 let mut g = Graph::with_vertices(3);
412 g.add_edge(0, 1).unwrap();
413 g.add_edge(1, 1).unwrap();
414 g.add_edge(1, 2).unwrap();
415 let paths = get_shortest_paths(&g, 0).unwrap();
416 assert_eq!(paths[2], vec![0, 1, 2]);
417 }
418
419 #[test]
420 fn oracle_6_vertices() {
421 let mut g = Graph::with_vertices(6);
423 g.add_edge(0, 1).unwrap();
424 g.add_edge(1, 2).unwrap();
425 g.add_edge(2, 3).unwrap();
426 g.add_edge(0, 4).unwrap();
427 g.add_edge(4, 5).unwrap();
428 g.add_edge(5, 3).unwrap();
429 let paths = get_shortest_paths(&g, 0).unwrap();
430 assert_eq!(paths[0], vec![0]);
431 assert_eq!(paths[1], vec![0, 1]);
432 assert_eq!(paths[4], vec![0, 4]);
433 assert_eq!(paths[5], vec![0, 4, 5]);
434 assert_eq!(paths[3].len(), 4);
436 assert_eq!(paths[3][0], 0);
437 assert_eq!(*paths[3].last().unwrap(), 3);
438 }
439}