1use std::collections::VecDeque;
10
11use crate::core::{Graph, IgraphError, IgraphResult, VertexId};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum AllShortestPathsMode {
17 Out,
19 In,
21 All,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct AllShortestPaths {
29 pub paths: Vec<Vec<Vec<VertexId>>>,
33 pub nrgeo: Vec<u64>,
37}
38
39pub fn get_all_shortest_paths(graph: &Graph, source: VertexId) -> IgraphResult<AllShortestPaths> {
66 if graph.is_directed() {
67 return get_all_shortest_paths_directed(graph, source, DirectedMode::Out);
68 }
69 get_all_shortest_paths_undirected(graph, source)
70}
71
72pub fn get_all_shortest_paths_with_mode(
98 graph: &Graph,
99 source: VertexId,
100 mode: AllShortestPathsMode,
101) -> IgraphResult<AllShortestPaths> {
102 if !graph.is_directed() {
103 return get_all_shortest_paths_undirected(graph, source);
104 }
105 let dir_mode = match mode {
106 AllShortestPathsMode::Out => DirectedMode::Out,
107 AllShortestPathsMode::In => DirectedMode::In,
108 AllShortestPathsMode::All => DirectedMode::All,
109 };
110 get_all_shortest_paths_directed(graph, source, dir_mode)
111}
112
113#[derive(Clone, Copy)]
114enum DirectedMode {
115 Out,
116 In,
117 All,
118}
119
120fn get_all_shortest_paths_undirected(
121 graph: &Graph,
122 source: VertexId,
123) -> IgraphResult<AllShortestPaths> {
124 let n = graph.vcount();
125 if source >= n {
126 return Err(IgraphError::InvalidArgument(format!(
127 "get_all_shortest_paths: source {source} out of range (vcount={n})"
128 )));
129 }
130
131 let n_us = n as usize;
132 let mut dist: Vec<Option<u32>> = vec![None; n_us];
133 let mut parents: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
134 let mut nrgeo: Vec<u64> = vec![0; n_us];
135
136 dist[source as usize] = Some(0);
137 nrgeo[source as usize] = 1;
138
139 let mut queue = VecDeque::new();
140 queue.push_back(source);
141
142 while let Some(cur) = queue.pop_front() {
143 let cur_dist = dist[cur as usize].unwrap_or(0);
144 let next_dist = cur_dist + 1;
145 let neighbors = graph.neighbors(cur)?;
146 for &nb in &neighbors {
147 let nb_idx = nb as usize;
148 let nb_dist = dist[nb_idx];
149 match nb_dist {
150 None => {
151 dist[nb_idx] = Some(next_dist);
152 parents[nb_idx].push(cur);
153 nrgeo[nb_idx] = nrgeo[cur as usize];
154 queue.push_back(nb);
155 }
156 Some(d) if d == next_dist => {
157 parents[nb_idx].push(cur);
158 nrgeo[nb_idx] += nrgeo[cur as usize];
159 }
160 _ => {}
161 }
162 }
163 }
164
165 let paths = enumerate_all_paths(source, n_us, &parents, &dist);
166 Ok(AllShortestPaths { paths, nrgeo })
167}
168
169fn get_all_shortest_paths_directed(
170 graph: &Graph,
171 source: VertexId,
172 mode: DirectedMode,
173) -> IgraphResult<AllShortestPaths> {
174 let n = graph.vcount();
175 if source >= n {
176 return Err(IgraphError::InvalidArgument(format!(
177 "get_all_shortest_paths: source {source} out of range (vcount={n})"
178 )));
179 }
180
181 let n_us = n as usize;
182 let adj = build_adj(graph, n_us, mode)?;
183
184 let mut dist: Vec<Option<u32>> = vec![None; n_us];
185 let mut parents: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
186 let mut nrgeo: Vec<u64> = vec![0; n_us];
187
188 dist[source as usize] = Some(0);
189 nrgeo[source as usize] = 1;
190
191 let mut queue = VecDeque::new();
192 queue.push_back(source);
193
194 while let Some(cur) = queue.pop_front() {
195 let cur_dist = dist[cur as usize].unwrap_or(0);
196 let next_dist = cur_dist + 1;
197 for &nb in &adj[cur as usize] {
198 let nb_idx = nb as usize;
199 let nb_dist = dist[nb_idx];
200 match nb_dist {
201 None => {
202 dist[nb_idx] = Some(next_dist);
203 parents[nb_idx].push(cur);
204 nrgeo[nb_idx] = nrgeo[cur as usize];
205 queue.push_back(nb);
206 }
207 Some(d) if d == next_dist => {
208 parents[nb_idx].push(cur);
209 nrgeo[nb_idx] += nrgeo[cur as usize];
210 }
211 _ => {}
212 }
213 }
214 }
215
216 let paths = enumerate_all_paths(source, n_us, &parents, &dist);
217 Ok(AllShortestPaths { paths, nrgeo })
218}
219
220fn build_adj(graph: &Graph, n_us: usize, mode: DirectedMode) -> IgraphResult<Vec<Vec<VertexId>>> {
221 let m =
222 u32::try_from(graph.ecount()).map_err(|_| IgraphError::Internal("ecount overflows u32"))?;
223 let mut adj: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
224 for eid in 0..m {
225 let (from, to) = graph.edge(eid)?;
226 match mode {
227 DirectedMode::Out => adj[from as usize].push(to),
228 DirectedMode::In => adj[to as usize].push(from),
229 DirectedMode::All => {
230 adj[from as usize].push(to);
231 if from != to {
232 adj[to as usize].push(from);
233 }
234 }
235 }
236 }
237 Ok(adj)
238}
239
240fn enumerate_all_paths(
241 source: VertexId,
242 n_us: usize,
243 parents: &[Vec<VertexId>],
244 dist: &[Option<u32>],
245) -> Vec<Vec<Vec<VertexId>>> {
246 let mut result: Vec<Vec<Vec<VertexId>>> = vec![Vec::new(); n_us];
247
248 result[source as usize] = vec![vec![source]];
249
250 if n_us <= 1 {
251 return result;
252 }
253
254 let mut order: Vec<(u32, usize)> = Vec::with_capacity(n_us);
256 for (v, d) in dist.iter().enumerate() {
257 if let Some(dv) = d {
258 order.push((*dv, v));
259 }
260 }
261 order.sort_unstable();
262
263 for &(_, v) in &order {
264 #[allow(clippy::cast_possible_truncation)]
265 let v_id = v as u32;
266 if v_id == source {
267 continue;
268 }
269 let mut paths_to_v: Vec<Vec<VertexId>> = Vec::new();
270 for &p in &parents[v] {
271 for parent_path in &result[p as usize] {
272 let mut path = parent_path.clone();
273 path.push(v_id);
274 paths_to_v.push(path);
275 }
276 }
277 result[v] = paths_to_v;
278 }
279
280 result
281}
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286
287 #[test]
288 fn empty_graph_err() {
289 let g = Graph::with_vertices(0);
290 assert!(get_all_shortest_paths(&g, 0).is_err());
291 }
292
293 #[test]
294 fn singleton() {
295 let g = Graph::with_vertices(1);
296 let r = get_all_shortest_paths(&g, 0).unwrap();
297 assert_eq!(r.paths[0], vec![vec![0]]);
298 assert_eq!(r.nrgeo[0], 1);
299 }
300
301 #[test]
302 fn path_graph_unique() {
303 let mut g = Graph::with_vertices(4);
304 g.add_edge(0, 1).unwrap();
305 g.add_edge(1, 2).unwrap();
306 g.add_edge(2, 3).unwrap();
307 let r = get_all_shortest_paths(&g, 0).unwrap();
308 assert_eq!(r.paths[0], vec![vec![0]]);
309 assert_eq!(r.paths[1], vec![vec![0, 1]]);
310 assert_eq!(r.paths[2], vec![vec![0, 1, 2]]);
311 assert_eq!(r.paths[3], vec![vec![0, 1, 2, 3]]);
312 for v in 0..4 {
313 assert_eq!(r.nrgeo[v], 1);
314 }
315 }
316
317 #[test]
318 fn diamond_two_paths() {
319 let mut g = Graph::with_vertices(4);
321 g.add_edge(0, 1).unwrap();
322 g.add_edge(0, 2).unwrap();
323 g.add_edge(1, 3).unwrap();
324 g.add_edge(2, 3).unwrap();
325 let r = get_all_shortest_paths(&g, 0).unwrap();
326 assert_eq!(r.nrgeo[3], 2);
327 assert_eq!(r.paths[3].len(), 2);
328 let mut sorted_paths = r.paths[3].clone();
329 sorted_paths.sort();
330 assert_eq!(sorted_paths, vec![vec![0, 1, 3], vec![0, 2, 3]]);
331 }
332
333 #[test]
334 fn two_components_unreachable() {
335 let mut g = Graph::with_vertices(4);
336 g.add_edge(0, 1).unwrap();
337 g.add_edge(2, 3).unwrap();
338 let r = get_all_shortest_paths(&g, 0).unwrap();
339 assert_eq!(r.paths[1], vec![vec![0, 1]]);
340 assert!(r.paths[2].is_empty());
341 assert!(r.paths[3].is_empty());
342 assert_eq!(r.nrgeo[2], 0);
343 assert_eq!(r.nrgeo[3], 0);
344 }
345
346 #[test]
347 fn cycle_5_multiple_shortest() {
348 let mut g = Graph::with_vertices(5);
361 g.add_edge(0, 1).unwrap();
362 g.add_edge(1, 2).unwrap();
363 g.add_edge(2, 3).unwrap();
364 g.add_edge(3, 4).unwrap();
365 g.add_edge(4, 0).unwrap();
366 let r = get_all_shortest_paths(&g, 0).unwrap();
367 assert_eq!(r.nrgeo[1], 1);
368 assert_eq!(r.nrgeo[4], 1);
369 assert_eq!(r.nrgeo[2], 1); assert_eq!(r.nrgeo[3], 1); }
372
373 #[test]
374 fn grid_multiple_paths() {
375 let mut g = Graph::with_vertices(6);
386 g.add_edge(0, 1).unwrap();
387 g.add_edge(1, 2).unwrap();
388 g.add_edge(3, 4).unwrap();
389 g.add_edge(4, 5).unwrap();
390 g.add_edge(0, 3).unwrap();
391 g.add_edge(1, 4).unwrap();
392 g.add_edge(2, 5).unwrap();
393 let r = get_all_shortest_paths(&g, 0).unwrap();
394 assert_eq!(r.nrgeo[5], 3);
396 assert_eq!(r.paths[5].len(), 3);
397 let mut sorted = r.paths[5].clone();
398 sorted.sort();
399 assert_eq!(
400 sorted,
401 vec![vec![0, 1, 2, 5], vec![0, 1, 4, 5], vec![0, 3, 4, 5]]
402 );
403 }
404
405 #[test]
406 fn directed_out() {
407 let mut g = Graph::new(4, true).unwrap();
409 g.add_edge(0, 1).unwrap();
410 g.add_edge(0, 2).unwrap();
411 g.add_edge(1, 3).unwrap();
412 g.add_edge(2, 3).unwrap();
413 let r = get_all_shortest_paths(&g, 0).unwrap();
414 assert_eq!(r.nrgeo[3], 2);
415 assert_eq!(r.paths[3].len(), 2);
416 }
417
418 #[test]
419 fn directed_in() {
420 let mut g = Graph::new(4, true).unwrap();
422 g.add_edge(0, 1).unwrap();
423 g.add_edge(0, 2).unwrap();
424 g.add_edge(1, 3).unwrap();
425 g.add_edge(2, 3).unwrap();
426 let r = get_all_shortest_paths_with_mode(&g, 3, AllShortestPathsMode::In).unwrap();
427 assert_eq!(r.nrgeo[0], 2);
428 assert_eq!(r.paths[0].len(), 2);
429 let mut sorted = r.paths[0].clone();
430 sorted.sort();
431 assert_eq!(sorted, vec![vec![3, 1, 0], vec![3, 2, 0]]);
432 }
433
434 #[test]
435 fn directed_all() {
436 let mut g = Graph::new(3, true).unwrap();
438 g.add_edge(0, 1).unwrap();
439 g.add_edge(1, 2).unwrap();
440 let r = get_all_shortest_paths_with_mode(&g, 2, AllShortestPathsMode::All).unwrap();
441 assert_eq!(r.paths[0], vec![vec![2, 1, 0]]);
442 assert_eq!(r.paths[1], vec![vec![2, 1]]);
443 }
444
445 #[test]
446 fn directed_unreachable() {
447 let mut g = Graph::new(3, true).unwrap();
449 g.add_edge(0, 1).unwrap();
450 g.add_edge(1, 2).unwrap();
451 let r = get_all_shortest_paths(&g, 2).unwrap();
452 assert_eq!(r.paths[2], vec![vec![2]]);
453 assert!(r.paths[0].is_empty());
454 assert!(r.paths[1].is_empty());
455 }
456
457 #[test]
458 fn source_out_of_range() {
459 let g = Graph::with_vertices(3);
460 assert!(get_all_shortest_paths(&g, 5).is_err());
461 }
462
463 #[test]
464 fn self_loop_no_effect() {
465 let mut g = Graph::with_vertices(3);
466 g.add_edge(0, 1).unwrap();
467 g.add_edge(1, 1).unwrap();
468 g.add_edge(1, 2).unwrap();
469 let r = get_all_shortest_paths(&g, 0).unwrap();
470 assert_eq!(r.paths[2], vec![vec![0, 1, 2]]);
471 assert_eq!(r.nrgeo[2], 1);
472 }
473
474 #[test]
475 fn nrgeo_star() {
476 let mut g = Graph::with_vertices(4);
478 g.add_edge(0, 1).unwrap();
479 g.add_edge(0, 2).unwrap();
480 g.add_edge(0, 3).unwrap();
481 let r = get_all_shortest_paths(&g, 0).unwrap();
482 assert_eq!(r.nrgeo[0], 1);
483 for leaf in 1u32..4 {
484 assert_eq!(r.nrgeo[leaf as usize], 1);
485 assert_eq!(r.paths[leaf as usize], vec![vec![0, leaf]]);
486 }
487 let r1 = get_all_shortest_paths(&g, 1).unwrap();
489 assert_eq!(r1.nrgeo[2], 1);
490 assert_eq!(r1.paths[2], vec![vec![1, 0, 2]]);
491 }
492}