rustworkx_core/connectivity/
all_simple_paths.rs

1// Licensed under the Apache License, Version 2.0 (the "License"); you may
2// not use this file except in compliance with the License. You may obtain
3// a copy of the License at
4//
5//     http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10// License for the specific language governing permissions and limitations
11// under the License.
12
13// This module was forked from petgraph:
14//
15// https://github.com/petgraph/petgraph/blob/9ff688872b467d3e1b5adef19f5c52f519d3279c/src/algo/simple_paths.rs
16//
17// to add support for returning all simple paths to a list of targets instead
18// of just between a single node pair.
19
20use hashbrown::HashSet;
21use indexmap::map::Entry;
22use indexmap::IndexSet;
23use petgraph::visit::{IntoNeighborsDirected, NodeCount};
24use petgraph::Direction::Outgoing;
25use std::iter;
26use std::{hash::Hash, iter::FromIterator};
27
28use crate::dictmap::*;
29
30/// Returns a dictionary with all simple paths from `from` node to all nodes in `to`, which contains at least `min_intermediate_nodes` nodes
31/// and at most `max_intermediate_nodes`, if given, or limited by the graph's order otherwise. The simple path is a path without repetitions.
32///
33/// This algorithm is adapted from <https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.simple_paths.all_simple_paths.html>.
34///
35/// # Example
36/// ```
37/// use petgraph::prelude::*;
38/// use hashbrown::HashSet;
39/// use rustworkx_core::connectivity::all_simple_paths_multiple_targets;
40///
41/// let mut graph = DiGraph::<&str, i32>::new();
42///
43/// let a = graph.add_node("a");
44/// let b = graph.add_node("b");
45/// let c = graph.add_node("c");
46/// let d = graph.add_node("d");
47///
48/// graph.extend_with_edges(&[(a, b, 1), (b, c, 1), (c, d, 1), (a, b, 1), (b, d, 1)]);
49///
50/// let mut to_set = HashSet::new();
51/// to_set.insert(d);
52///
53/// let ways = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, None);
54///
55/// let d_path = ways.get(&d).unwrap();
56/// assert_eq!(4, d_path.len());
57/// ```
58pub fn all_simple_paths_multiple_targets<G>(
59    graph: G,
60    from: G::NodeId,
61    to: &HashSet<G::NodeId>,
62    min_intermediate_nodes: usize,
63    max_intermediate_nodes: Option<usize>,
64) -> DictMap<G::NodeId, Vec<Vec<G::NodeId>>>
65where
66    G: NodeCount,
67    G: IntoNeighborsDirected,
68    G::NodeId: Eq + Hash,
69{
70    // how many nodes are allowed in simple path up to target node
71    // it is min/max allowed path length minus one, because it is more appropriate when implementing lookahead
72    // than constantly add 1 to length of current path
73    let max_length = if let Some(l) = max_intermediate_nodes {
74        l + 1
75    } else {
76        graph.node_count() - 1
77    };
78
79    let min_length = min_intermediate_nodes + 1;
80
81    // list of visited nodes
82    let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
83    // list of children of currently exploring path nodes,
84    // last elem is list of children of last visited node
85    let mut stack = vec![graph.neighbors_directed(from, Outgoing)];
86
87    let mut output: DictMap<G::NodeId, Vec<Vec<G::NodeId>>> = DictMap::with_capacity(to.len());
88
89    while let Some(children) = stack.last_mut() {
90        if let Some(child) = children.next() {
91            if visited.len() < max_length {
92                if !visited.contains(&child) {
93                    if to.contains(&child) && visited.len() >= min_length {
94                        let new_path: Vec<G::NodeId> =
95                            visited.iter().chain(&[child]).copied().collect();
96                        match output.entry(child) {
97                            Entry::Vacant(e) => {
98                                e.insert(vec![new_path]);
99                            }
100                            Entry::Occupied(mut e) => {
101                                e.get_mut().push(new_path);
102                            }
103                        }
104                    }
105                    visited.insert(child);
106                    if to.iter().any(|n| !visited.contains(n)) {
107                        stack.push(graph.neighbors_directed(child, Outgoing));
108                    } else {
109                        visited.pop();
110                    }
111                }
112            // visited.len() == max_length
113            } else {
114                for c in children.chain(iter::once(child)) {
115                    if to.contains(&c) && !visited.contains(&c) && visited.len() >= min_length {
116                        let new_path: Vec<G::NodeId> =
117                            visited.iter().chain(&[c]).copied().collect();
118                        match output.entry(c) {
119                            Entry::Vacant(e) => {
120                                e.insert(vec![new_path]);
121                            }
122                            Entry::Occupied(mut e) => {
123                                e.get_mut().push(new_path);
124                            }
125                        }
126                    }
127                }
128                stack.pop();
129                visited.pop();
130            }
131        } else {
132            stack.pop();
133            visited.pop();
134        }
135    }
136    output
137}
138
139/// Returns the longest of all the simple paths from `from` node to all nodes in `to`, which contains at least `min_intermediate_nodes` nodes
140/// and at most `max_intermediate_nodes`, if given, or limited by the graph's order otherwise. The simple path is a path without repetitions.
141///
142/// # Example
143/// ```
144/// use petgraph::prelude::*;
145/// use hashbrown::HashSet;
146/// use rustworkx_core::connectivity::longest_simple_path_multiple_targets;
147///
148/// let mut graph = DiGraph::<&str, i32>::new();
149///
150/// let a = graph.add_node("a");
151/// let b = graph.add_node("b");
152/// let c = graph.add_node("c");
153/// let d = graph.add_node("d");
154///
155/// graph.extend_with_edges(&[(a, b, 1), (b, c, 1), (c, d, 1), (a, b, 1), (b, d, 1)]);
156///
157/// let mut to_set = HashSet::new();
158/// to_set.insert(d);
159///
160/// let path = longest_simple_path_multiple_targets(&graph, a, &to_set);
161///
162/// let expected = vec![a, b, c, d];
163/// assert_eq!(path.unwrap(), expected);
164/// ```
165pub fn longest_simple_path_multiple_targets<G>(
166    graph: G,
167    from: G::NodeId,
168    to: &HashSet<G::NodeId>,
169) -> Option<Vec<G::NodeId>>
170where
171    G: NodeCount,
172    G: IntoNeighborsDirected,
173    G::NodeId: Eq + Hash,
174{
175    // list of visited nodes
176    let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
177    // list of children of currently exploring path nodes,
178    // last elem is list of children of last visited node
179    let mut stack = vec![graph.neighbors_directed(from, Outgoing)];
180
181    let mut output_path: Option<Vec<G::NodeId>> = None;
182
183    let update_path = |new_path: Vec<G::NodeId>,
184                       output_path: &Option<Vec<G::NodeId>>|
185     -> Option<Vec<G::NodeId>> {
186        match output_path.as_ref() {
187            None => Some(new_path),
188            Some(path) => {
189                if path.len() < new_path.len() {
190                    Some(new_path)
191                } else {
192                    None
193                }
194            }
195        }
196    };
197
198    while let Some(children) = stack.last_mut() {
199        if let Some(child) = children.next() {
200            if !visited.contains(&child) {
201                if to.contains(&child) {
202                    let new_path: Vec<G::NodeId> =
203                        visited.iter().chain(&[child]).copied().collect();
204                    let temp = update_path(new_path, &output_path);
205                    if temp.is_some() {
206                        output_path = temp;
207                    }
208                }
209                visited.insert(child);
210                if to.iter().any(|n| !visited.contains(n)) {
211                    stack.push(graph.neighbors_directed(child, Outgoing));
212                } else {
213                    visited.pop();
214                }
215            }
216        } else {
217            stack.pop();
218            visited.pop();
219        }
220    }
221    output_path
222}
223
224#[cfg(test)]
225mod tests {
226    use crate::connectivity::{
227        all_simple_paths_multiple_targets, longest_simple_path_multiple_targets,
228    };
229    use hashbrown::HashSet;
230    use petgraph::prelude::*;
231
232    #[test]
233    fn test_all_simple_paths() {
234        // create a path graph
235        let mut graph = Graph::new_undirected();
236        let a = graph.add_node(0);
237        let b = graph.add_node(1);
238        let c = graph.add_node(2);
239        let d = graph.add_node(3);
240        let e = graph.add_node(4);
241
242        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1)]);
243
244        let mut to_set = HashSet::new();
245        to_set.insert(d);
246
247        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, None);
248
249        assert_eq!(paths.get(&d).unwrap(), &vec![vec![a, b, c, d]]);
250    }
251
252    #[test]
253    fn test_all_simple_paths_with_two_targets_emits_two_paths() {
254        // create a path graph
255        let mut graph = Graph::new_undirected();
256        let a = graph.add_node(0);
257        let b = graph.add_node(1);
258        let c = graph.add_node(2);
259        let d = graph.add_node(3);
260        let e = graph.add_node(4);
261
262        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1), (c, e, 1)]);
263
264        let mut to_set = HashSet::new();
265        to_set.insert(d);
266        to_set.insert(e);
267
268        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, None);
269
270        assert_eq!(
271            paths.get(&d).unwrap(),
272            &vec![vec![a, b, c, e, d], vec![a, b, c, d]]
273        );
274        assert_eq!(
275            paths.get(&e).unwrap(),
276            &vec![vec![a, b, c, e], vec![a, b, c, d, e]]
277        );
278    }
279
280    #[test]
281    fn test_digraph_all_simple_paths_with_two_targets_emits_two_paths() {
282        // create a path graph
283        let mut graph = Graph::new();
284        let a = graph.add_node(0);
285        let b = graph.add_node(1);
286        let c = graph.add_node(2);
287        let d = graph.add_node(3);
288        let e = graph.add_node(4);
289
290        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1), (c, e, 1)]);
291
292        let mut to_set = HashSet::new();
293        to_set.insert(d);
294        to_set.insert(e);
295
296        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, None);
297
298        assert_eq!(paths.get(&d).unwrap(), &vec![vec![a, b, c, d]]);
299        assert_eq!(
300            paths.get(&e).unwrap(),
301            &vec![vec![a, b, c, e], vec![a, b, c, d, e]]
302        );
303    }
304
305    #[test]
306    fn test_all_simple_paths_max_nodes() {
307        // create a complete graph
308        let mut graph = Graph::new_undirected();
309        let a = graph.add_node(0);
310        let b = graph.add_node(1);
311        let c = graph.add_node(2);
312        let d = graph.add_node(3);
313        let e = graph.add_node(4);
314
315        graph.extend_with_edges([
316            (a, b, 1),
317            (a, c, 1),
318            (a, d, 1),
319            (a, e, 1),
320            (b, c, 1),
321            (b, d, 1),
322            (b, e, 1),
323            (c, d, 1),
324            (c, e, 1),
325            (d, e, 1),
326        ]);
327
328        let mut to_set = HashSet::new();
329        to_set.insert(b);
330
331        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, Some(0));
332
333        assert_eq!(paths.get(&b).unwrap(), &vec![vec![a, b]]);
334
335        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, Some(1));
336
337        assert_eq!(
338            paths.get(&b).unwrap(),
339            &vec![vec![a, e, b], vec![a, d, b], vec![a, c, b], vec![a, b],]
340        );
341    }
342
343    #[test]
344    fn test_all_simple_paths_with_two_targets_max_nodes() {
345        // create a path graph
346        let mut graph = Graph::new_undirected();
347        let a = graph.add_node(0);
348        let b = graph.add_node(1);
349        let c = graph.add_node(2);
350        let d = graph.add_node(3);
351        let e = graph.add_node(4);
352
353        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1), (c, e, 1)]);
354
355        let mut to_set = HashSet::new();
356        to_set.insert(d);
357        to_set.insert(e);
358
359        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, Some(2));
360
361        assert_eq!(paths.get(&d).unwrap(), &vec![vec![a, b, c, d]]);
362        assert_eq!(paths.get(&e).unwrap(), &vec![vec![a, b, c, e]]);
363    }
364
365    #[test]
366    fn test_digraph_all_simple_paths_with_two_targets_max_nodes() {
367        // create a path graph
368        let mut graph = Graph::new();
369        let a = graph.add_node(0);
370        let b = graph.add_node(1);
371        let c = graph.add_node(2);
372        let d = graph.add_node(3);
373        let e = graph.add_node(4);
374
375        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1), (c, e, 1)]);
376
377        let mut to_set = HashSet::new();
378        to_set.insert(d);
379        to_set.insert(e);
380
381        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, Some(2));
382
383        assert_eq!(paths.get(&d).unwrap(), &vec![vec![a, b, c, d]]);
384        assert_eq!(paths.get(&e).unwrap(), &vec![vec![a, b, c, e]]);
385    }
386
387    #[test]
388    fn test_all_simple_paths_with_two_targets_in_line_emits_two_paths() {
389        // create a path graph
390        let mut graph = Graph::new_undirected();
391        let a = graph.add_node(0);
392        let b = graph.add_node(1);
393        let c = graph.add_node(2);
394        let d = graph.add_node(3);
395        let e = graph.add_node(4);
396
397        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1)]);
398
399        let mut to_set = HashSet::new();
400        to_set.insert(c);
401        to_set.insert(d);
402
403        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, None);
404
405        assert_eq!(paths.get(&c).unwrap(), &vec![vec![a, b, c]]);
406        assert_eq!(paths.get(&d).unwrap(), &vec![vec![a, b, c, d]]);
407    }
408
409    #[test]
410    fn test_all_simple_paths_min_nodes() {
411        // create a cycle graph
412        let mut graph = Graph::new();
413        let a = graph.add_node(0);
414        let b = graph.add_node(1);
415        let c = graph.add_node(2);
416        let d = graph.add_node(3);
417
418        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, a, 1), (b, d, 1)]);
419
420        let mut to_set = HashSet::new();
421        to_set.insert(d);
422
423        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 2, None);
424
425        assert_eq!(paths.get(&d).unwrap(), &vec![vec![a, b, c, d]]);
426    }
427
428    #[test]
429    fn test_all_simple_paths_with_two_targets_min_nodes() {
430        // create a cycle graph
431        let mut graph = Graph::new();
432        let a = graph.add_node(0);
433        let b = graph.add_node(1);
434        let c = graph.add_node(2);
435        let d = graph.add_node(3);
436
437        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, a, 1), (b, d, 1)]);
438
439        let mut to_set = HashSet::new();
440        to_set.insert(c);
441        to_set.insert(d);
442
443        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 2, None);
444
445        assert_eq!(paths.get(&c), None);
446        assert_eq!(paths.get(&d).unwrap(), &vec![vec![a, b, c, d]]);
447    }
448
449    #[test]
450    fn test_all_simple_paths_source_target() {
451        // create a path graph
452        let mut graph = Graph::new_undirected();
453        let a = graph.add_node(0);
454        let b = graph.add_node(1);
455        let c = graph.add_node(2);
456        let d = graph.add_node(3);
457        let e = graph.add_node(4);
458
459        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1)]);
460
461        let mut to_set = HashSet::new();
462        to_set.insert(a);
463
464        let paths = all_simple_paths_multiple_targets(&graph, a, &to_set, 0, None);
465
466        assert_eq!(paths.get(&a), None);
467    }
468
469    #[test]
470    fn test_all_simple_paths_on_non_trivial_graph() {
471        // create a path graph
472        let mut graph = Graph::new();
473        let a = graph.add_node(0);
474        let b = graph.add_node(1);
475        let c = graph.add_node(2);
476        let d = graph.add_node(3);
477        let e = graph.add_node(4);
478        let f = graph.add_node(5);
479
480        graph.extend_with_edges([
481            (a, b, 1),
482            (b, c, 1),
483            (c, d, 1),
484            (d, e, 1),
485            (e, f, 1),
486            (a, f, 1),
487            (b, f, 1),
488            (b, d, 1),
489            (f, e, 1),
490            (e, c, 1),
491            (e, d, 1),
492        ]);
493
494        let mut to_set = HashSet::new();
495        to_set.insert(c);
496        to_set.insert(d);
497
498        let paths = all_simple_paths_multiple_targets(&graph, b, &to_set, 0, None);
499
500        assert_eq!(
501            paths.get(&c).unwrap(),
502            &vec![vec![b, d, e, c], vec![b, f, e, c], vec![b, c]]
503        );
504        assert_eq!(
505            paths.get(&d).unwrap(),
506            &vec![
507                vec![b, d],
508                vec![b, f, e, d],
509                vec![b, f, e, c, d],
510                vec![b, c, d]
511            ]
512        );
513
514        let paths = all_simple_paths_multiple_targets(&graph, b, &to_set, 1, None);
515
516        assert_eq!(
517            paths.get(&c).unwrap(),
518            &vec![vec![b, d, e, c], vec![b, f, e, c]]
519        );
520        assert_eq!(
521            paths.get(&d).unwrap(),
522            &vec![vec![b, f, e, d], vec![b, f, e, c, d], vec![b, c, d]]
523        );
524
525        let paths = all_simple_paths_multiple_targets(&graph, b, &to_set, 0, Some(2));
526
527        assert_eq!(
528            paths.get(&c).unwrap(),
529            &vec![vec![b, d, e, c], vec![b, f, e, c], vec![b, c]]
530        );
531        assert_eq!(
532            paths.get(&d).unwrap(),
533            &vec![vec![b, d], vec![b, f, e, d], vec![b, c, d]]
534        );
535    }
536
537    #[test]
538    fn test_longest_simple_path() {
539        // create a path graph
540        let mut graph = Graph::new_undirected();
541        let a = graph.add_node(0);
542        let b = graph.add_node(1);
543        let c = graph.add_node(2);
544        let d = graph.add_node(3);
545        let e = graph.add_node(4);
546
547        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1)]);
548
549        let mut to_set = HashSet::new();
550        to_set.insert(d);
551
552        let path = longest_simple_path_multiple_targets(&graph, a, &to_set);
553
554        assert_eq!(path.unwrap(), vec![a, b, c, d]);
555    }
556
557    #[test]
558    fn test_longest_simple_path_with_two_targets_emits_two_paths() {
559        // create a path graph
560        let mut graph = Graph::new_undirected();
561        let a = graph.add_node(0);
562        let b = graph.add_node(1);
563        let c = graph.add_node(2);
564        let d = graph.add_node(3);
565        let e = graph.add_node(4);
566
567        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1), (c, e, 1)]);
568
569        let mut to_set = HashSet::new();
570        to_set.insert(d);
571        to_set.insert(e);
572
573        let path = longest_simple_path_multiple_targets(&graph, a, &to_set);
574
575        assert_eq!(path.unwrap(), vec![a, b, c, e, d]);
576    }
577
578    #[test]
579    fn test_digraph_longest_simple_path_with_two_targets_emits_two_paths() {
580        // create a path graph
581        let mut graph = Graph::new();
582        let a = graph.add_node(0);
583        let b = graph.add_node(1);
584        let c = graph.add_node(2);
585        let d = graph.add_node(3);
586        let e = graph.add_node(4);
587
588        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1), (c, e, 1)]);
589
590        let mut to_set = HashSet::new();
591        to_set.insert(d);
592        to_set.insert(e);
593
594        let path = longest_simple_path_multiple_targets(&graph, a, &to_set);
595
596        assert_eq!(path.unwrap(), vec![a, b, c, d, e]);
597    }
598
599    #[test]
600    fn test_longest_simple_paths_with_two_targets_in_line_emits_two_paths() {
601        // create a path graph
602        let mut graph = Graph::new_undirected();
603        let a = graph.add_node(0);
604        let b = graph.add_node(1);
605        let c = graph.add_node(2);
606        let d = graph.add_node(3);
607        let e = graph.add_node(4);
608
609        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1)]);
610
611        let mut to_set = HashSet::new();
612        to_set.insert(c);
613        to_set.insert(d);
614
615        let path = longest_simple_path_multiple_targets(&graph, a, &to_set);
616
617        assert_eq!(path.unwrap(), vec![a, b, c, d]);
618    }
619
620    #[test]
621    fn test_longest_simple_paths_source_target() {
622        // create a path graph
623        let mut graph = Graph::new_undirected();
624        let a = graph.add_node(0);
625        let b = graph.add_node(1);
626        let c = graph.add_node(2);
627        let d = graph.add_node(3);
628        let e = graph.add_node(4);
629
630        graph.extend_with_edges([(a, b, 1), (b, c, 1), (c, d, 1), (d, e, 1)]);
631
632        let mut to_set = HashSet::new();
633        to_set.insert(a);
634
635        let path = longest_simple_path_multiple_targets(&graph, a, &to_set);
636
637        assert_eq!(path, None);
638    }
639
640    #[test]
641    fn test_longest_simple_paths_on_non_trivial_graph() {
642        // create a path graph
643        let mut graph = Graph::new();
644        let a = graph.add_node(0);
645        let b = graph.add_node(1);
646        let c = graph.add_node(2);
647        let d = graph.add_node(3);
648        let e = graph.add_node(4);
649        let f = graph.add_node(5);
650
651        graph.extend_with_edges([
652            (a, b, 1),
653            (b, c, 1),
654            (c, d, 1),
655            (d, e, 1),
656            (e, f, 1),
657            (a, f, 1),
658            (b, f, 1),
659            (b, d, 1),
660            (f, e, 1),
661            (e, c, 1),
662            (e, d, 1),
663        ]);
664
665        let mut to_set = HashSet::new();
666        to_set.insert(c);
667        to_set.insert(d);
668
669        let path = longest_simple_path_multiple_targets(&graph, b, &to_set);
670
671        assert_eq!(path.unwrap(), vec![b, f, e, c, d],);
672    }
673}