rs_graph/search.rs
1/*
2 * Copyright (c) 2019 Frank Fischer <frank-fischer@shadow-soft.de>
3 *
4 * This program is free software: you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation, either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>
16 */
17
18//! # Graph search algorithms.
19//!
20//! This module contains several standard search algorithms on graphs. These are
21//! algorithms that visit the nodes of a graph in some specific order.
22//!
23//! All search algorithms are implemented as iterators. The iterators produce a
24//! sequence of nodes (together with algorithm specific additional information)
25//! in the order in which they are visited by the particular search strategy.
26//! This allows search algorithms to be used on infinite graphs (represented by
27//! implementors of [`Adjacencies`][crate::adjacencies::Adjacencies]), in which
28//! case the iterator is infinite.
29
30pub mod astar;
31pub mod bfs;
32pub mod biastar;
33pub mod dfs;
34
35use std::iter::Iterator;
36use std::marker::PhantomData;
37
38/// Compute a path from a map of incoming edges for each node.
39///
40/// # Parameters
41/// - `dst`: the destination node
42/// - `incomings(v)`: return the incoming edge and preceding node for node `v`
43/// (or `None` if it does not exist)
44///
45/// # Return
46/// An iterator over the incoming edges starting from the last one.
47///
48/// # Example
49///
50/// ```
51/// // Breadth-first-search on a directed with 7 nodes.
52///
53/// use rs_graph::LinkedListGraph;
54/// use rs_graph::traits::*;
55/// use rs_graph::classes;
56/// use rs_graph::search::{path_from_incomings, bfs};
57/// use std::collections::{HashMap, VecDeque};
58///
59/// let g: LinkedListGraph = classes::cycle(7);
60///
61/// let mut incomings = HashMap::new();
62/// let mut bfs = bfs::start_with_data(g.outgoing(), g.id2node(0), (&mut incomings, VecDeque::new()));
63/// for _ in bfs {}
64///
65/// {
66/// let mut path = path_from_incomings(g.id2node(3), |u| incomings.get(&u).map(|&e| (e, g.src(e))));
67///
68/// assert_eq!(path.next().map(|e| g.edge_id(e)), Some(2));
69/// assert_eq!(path.next().map(|e| g.edge_id(e)), Some(1));
70/// assert_eq!(path.next().map(|e| g.edge_id(e)), Some(0));
71/// assert_eq!(path.next().map(|e| g.edge_id(e)), None);
72/// }
73///
74/// {
75/// let mut path = path_from_incomings(g.id2node(4), |u| incomings.get(&u).map(|&e| (e, g.src(e))));
76///
77/// assert_eq!(path.next().map(|e| g.edge_id(e)), Some(3));
78/// assert_eq!(path.next().map(|e| g.edge_id(e)), Some(2));
79/// assert_eq!(path.next().map(|e| g.edge_id(e)), Some(1));
80/// assert_eq!(path.next().map(|e| g.edge_id(e)), Some(0));
81/// assert_eq!(path.next().map(|e| g.edge_id(e)), None);
82/// }
83/// ```
84pub fn path_from_incomings<N, E, I>(dst: N, incomings: I) -> impl Iterator<Item = E>
85where
86 N: Copy,
87 E: Clone,
88 I: Fn(N) -> Option<(E, N)>,
89{
90 PathIter {
91 incomings,
92 u: dst,
93 phantom: PhantomData,
94 }
95}
96
97#[doc(hidden)]
98struct PathIter<N, E, I>
99where
100 I: Fn(N) -> Option<(E, N)>,
101{
102 incomings: I,
103 u: N,
104 phantom: PhantomData<E>,
105}
106
107impl<N, E, I> Iterator for PathIter<N, E, I>
108where
109 N: Clone,
110 I: Fn(N) -> Option<(E, N)>,
111{
112 type Item = E;
113
114 fn next(&mut self) -> Option<E> {
115 if let Some((e, v)) = (self.incomings)(self.u.clone()) {
116 self.u = v;
117 Some(e)
118 } else {
119 None
120 }
121 }
122}