/rust/registry/src/index.crates.io-1949cf8c6b5b557f/petgraph-0.8.3/src/visit/dfsvisit.rs
Line | Count | Source |
1 | | use crate::visit::IntoNeighbors; |
2 | | use crate::visit::{VisitMap, Visitable}; |
3 | | |
4 | | /// Strictly monotonically increasing event time for a depth first search. |
5 | | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Default, Hash)] |
6 | | pub struct Time(pub usize); |
7 | | |
8 | | /// A depth first search (DFS) visitor event. |
9 | | #[derive(Copy, Clone, Debug)] |
10 | | pub enum DfsEvent<N> { |
11 | | Discover(N, Time), |
12 | | /// An edge of the tree formed by the traversal. |
13 | | TreeEdge(N, N), |
14 | | /// An edge to an already visited node. |
15 | | BackEdge(N, N), |
16 | | /// A cross or forward edge. |
17 | | /// |
18 | | /// For an edge *(u, v)*, if the discover time of *v* is greater than *u*, |
19 | | /// then it is a forward edge, else a cross edge. |
20 | | CrossForwardEdge(N, N), |
21 | | /// All edges from a node have been reported. |
22 | | Finish(N, Time), |
23 | | } |
24 | | |
25 | | /// Return if the expression is a break value, execute the provided statement |
26 | | /// if it is a prune value. |
27 | | macro_rules! try_control { |
28 | | ($e:expr, $p:stmt) => { |
29 | | try_control!($e, $p, ()); |
30 | | }; |
31 | | ($e:expr, $p:stmt, $q:stmt) => { |
32 | | match $e { |
33 | | x => { |
34 | | if x.should_break() { |
35 | | return x; |
36 | | } else if x.should_prune() { |
37 | | $p |
38 | | } else { |
39 | | $q |
40 | | } |
41 | | } |
42 | | } |
43 | | }; |
44 | | } |
45 | | |
46 | | /// Control flow for `depth_first_search` callbacks. |
47 | | #[derive(Copy, Clone, Debug)] |
48 | | pub enum Control<B> { |
49 | | /// Continue the DFS traversal as normal. |
50 | | Continue, |
51 | | /// Prune the current node from the DFS traversal. No more edges from this |
52 | | /// node will be reported to the callback. A `DfsEvent::Finish` for this |
53 | | /// node will still be reported. This can be returned in response to any |
54 | | /// `DfsEvent`, except `Finish`, which will panic. |
55 | | Prune, |
56 | | /// Stop the DFS traversal and return the provided value. |
57 | | Break(B), |
58 | | } |
59 | | |
60 | | impl<B> Control<B> { |
61 | 0 | pub fn breaking() -> Control<()> { |
62 | 0 | Control::Break(()) |
63 | 0 | } |
64 | | /// Get the value in `Control::Break(_)`, if present. |
65 | 0 | pub fn break_value(self) -> Option<B> { |
66 | 0 | match self { |
67 | 0 | Control::Continue | Control::Prune => None, |
68 | 0 | Control::Break(b) => Some(b), |
69 | | } |
70 | 0 | } |
71 | | } |
72 | | |
73 | | /// Control flow for callbacks. |
74 | | /// |
75 | | /// The empty return value `()` is equivalent to continue. |
76 | | pub trait ControlFlow { |
77 | | fn continuing() -> Self; |
78 | | fn should_break(&self) -> bool; |
79 | | fn should_prune(&self) -> bool; |
80 | | } |
81 | | |
82 | | impl ControlFlow for () { |
83 | 0 | fn continuing() {} |
84 | | #[inline] |
85 | 0 | fn should_break(&self) -> bool { |
86 | 0 | false |
87 | 0 | } |
88 | | #[inline] |
89 | 0 | fn should_prune(&self) -> bool { |
90 | 0 | false |
91 | 0 | } |
92 | | } |
93 | | |
94 | | impl<B> ControlFlow for Control<B> { |
95 | 0 | fn continuing() -> Self { |
96 | 0 | Control::Continue |
97 | 0 | } |
98 | 0 | fn should_break(&self) -> bool { |
99 | 0 | matches!(*self, Control::Break(_)) |
100 | 0 | } |
101 | 0 | fn should_prune(&self) -> bool { |
102 | 0 | matches!(*self, Control::Prune) |
103 | 0 | } |
104 | | } |
105 | | |
106 | | impl<C: ControlFlow, E> ControlFlow for Result<C, E> { |
107 | 0 | fn continuing() -> Self { |
108 | 0 | Ok(C::continuing()) |
109 | 0 | } |
110 | 0 | fn should_break(&self) -> bool { |
111 | 0 | if let Ok(ref c) = *self { |
112 | 0 | c.should_break() |
113 | | } else { |
114 | 0 | true |
115 | | } |
116 | 0 | } |
117 | 0 | fn should_prune(&self) -> bool { |
118 | 0 | if let Ok(ref c) = *self { |
119 | 0 | c.should_prune() |
120 | | } else { |
121 | 0 | false |
122 | | } |
123 | 0 | } |
124 | | } |
125 | | |
126 | | /// The default is `Continue`. |
127 | | impl<B> Default for Control<B> { |
128 | 0 | fn default() -> Self { |
129 | 0 | Control::Continue |
130 | 0 | } |
131 | | } |
132 | | |
133 | | /// A recursive depth first search. |
134 | | /// |
135 | | /// Starting points are the nodes in the iterator `starts` (specify just one |
136 | | /// start node *x* by using `Some(x)`). |
137 | | /// |
138 | | /// The traversal emits discovery and finish events for each reachable node, |
139 | | /// and edge classification of each reachable edge. `visitor` is called for each |
140 | | /// event, see [`DfsEvent`][de] for possible values. |
141 | | /// |
142 | | /// The return value should implement the trait `ControlFlow`, and can be used to change |
143 | | /// the control flow of the search. |
144 | | /// |
145 | | /// `Control` Implements `ControlFlow` such that `Control::Continue` resumes the search. |
146 | | /// `Control::Break` will stop the visit early, returning the contained value. |
147 | | /// `Control::Prune` will stop traversing any additional edges from the current |
148 | | /// node and proceed immediately to the `Finish` event. |
149 | | /// |
150 | | /// There are implementations of `ControlFlow` for `()`, and `Result<C, E>` where |
151 | | /// `C: ControlFlow`. The implementation for `()` will continue until finished. |
152 | | /// For `Result`, upon encountering an `E` it will break, otherwise acting the same as `C`. |
153 | | /// |
154 | | /// **Panics** if you attempt to prune a node from its `Finish` event. |
155 | | /// |
156 | | /// [de]: enum.DfsEvent.html |
157 | | /// |
158 | | /// # Example returning `Control`. |
159 | | /// |
160 | | /// Find a path from node 0 to 5, and exit the visit as soon as we reach |
161 | | /// the goal node. |
162 | | /// |
163 | | /// ``` |
164 | | /// use petgraph::prelude::*; |
165 | | /// use petgraph::graph::node_index as n; |
166 | | /// use petgraph::visit::depth_first_search; |
167 | | /// use petgraph::visit::{DfsEvent, Control}; |
168 | | /// |
169 | | /// let gr: Graph<(), ()> = Graph::from_edges(&[ |
170 | | /// (0, 1), (0, 2), (0, 3), |
171 | | /// (1, 3), |
172 | | /// (2, 3), (2, 4), |
173 | | /// (4, 0), (4, 5), |
174 | | /// ]); |
175 | | /// |
176 | | /// // record each predecessor, mapping node → node |
177 | | /// let mut predecessor = vec![NodeIndex::end(); gr.node_count()]; |
178 | | /// let start = n(0); |
179 | | /// let goal = n(5); |
180 | | /// depth_first_search(&gr, Some(start), |event| { |
181 | | /// if let DfsEvent::TreeEdge(u, v) = event { |
182 | | /// predecessor[v.index()] = u; |
183 | | /// if v == goal { |
184 | | /// return Control::Break(v); |
185 | | /// } |
186 | | /// } |
187 | | /// Control::Continue |
188 | | /// }); |
189 | | /// |
190 | | /// let mut next = goal; |
191 | | /// let mut path = vec![next]; |
192 | | /// while next != start { |
193 | | /// let pred = predecessor[next.index()]; |
194 | | /// path.push(pred); |
195 | | /// next = pred; |
196 | | /// } |
197 | | /// path.reverse(); |
198 | | /// assert_eq!(&path, &[n(0), n(2), n(4), n(5)]); |
199 | | /// ``` |
200 | | /// |
201 | | /// # Example returning a `Result`. |
202 | | /// ``` |
203 | | /// use petgraph::graph::node_index as n; |
204 | | /// use petgraph::prelude::*; |
205 | | /// use petgraph::visit::depth_first_search; |
206 | | /// use petgraph::visit::{DfsEvent, Time}; |
207 | | /// |
208 | | /// let gr: Graph<(), ()> = Graph::from_edges(&[(0, 1), (1, 2), (1, 1), (2, 1)]); |
209 | | /// let start = n(0); |
210 | | /// let mut back_edges = 0; |
211 | | /// let mut discover_time = 0; |
212 | | /// // Stop the search, the first time a BackEdge is encountered. |
213 | | /// let result = depth_first_search(&gr, Some(start), |event| { |
214 | | /// match event { |
215 | | /// // In the cases where Ok(()) is returned, |
216 | | /// // Result falls back to the implementation of Control on the value (). |
217 | | /// // In the case of (), this is to always return Control::Continue. |
218 | | /// // continuing the search. |
219 | | /// DfsEvent::Discover(_, Time(t)) => { |
220 | | /// discover_time = t; |
221 | | /// Ok(()) |
222 | | /// } |
223 | | /// DfsEvent::BackEdge(_, _) => { |
224 | | /// back_edges += 1; |
225 | | /// // the implementation of ControlFlow for Result, |
226 | | /// // treats this Err value as Continue::Break |
227 | | /// Err(event) |
228 | | /// } |
229 | | /// _ => Ok(()), |
230 | | /// } |
231 | | /// }); |
232 | | /// |
233 | | /// // Even though the graph has more than one cycle, |
234 | | /// // The number of back_edges visited by the search should always be 1. |
235 | | /// assert_eq!(back_edges, 1); |
236 | | /// println!("discover time:{:?}", discover_time); |
237 | | /// println!("number of backedges encountered: {}", back_edges); |
238 | | /// println!("back edge: {:?}", result); |
239 | | /// ``` |
240 | | #[track_caller] |
241 | 0 | pub fn depth_first_search<G, I, F, C>(graph: G, starts: I, mut visitor: F) -> C |
242 | 0 | where |
243 | 0 | G: IntoNeighbors + Visitable, |
244 | 0 | I: IntoIterator<Item = G::NodeId>, |
245 | 0 | F: FnMut(DfsEvent<G::NodeId>) -> C, |
246 | 0 | C: ControlFlow, |
247 | | { |
248 | 0 | let time = &mut Time(0); |
249 | 0 | let discovered = &mut graph.visit_map(); |
250 | 0 | let finished = &mut graph.visit_map(); |
251 | | |
252 | 0 | for start in starts { |
253 | 0 | try_control!( |
254 | 0 | dfs_visitor(graph, start, &mut visitor, discovered, finished, time), |
255 | 0 | unreachable!() |
256 | | ); |
257 | | } |
258 | 0 | C::continuing() |
259 | 0 | } |
260 | | |
261 | 0 | pub(crate) fn dfs_visitor<G, F, C>( |
262 | 0 | graph: G, |
263 | 0 | u: G::NodeId, |
264 | 0 | visitor: &mut F, |
265 | 0 | discovered: &mut impl VisitMap<G::NodeId>, |
266 | 0 | finished: &mut impl VisitMap<G::NodeId>, |
267 | 0 | time: &mut Time, |
268 | 0 | ) -> C |
269 | 0 | where |
270 | 0 | G: IntoNeighbors + Visitable, |
271 | 0 | F: FnMut(DfsEvent<G::NodeId>) -> C, |
272 | 0 | C: ControlFlow, |
273 | | { |
274 | 0 | if !discovered.visit(u) { |
275 | 0 | return C::continuing(); |
276 | 0 | } |
277 | | |
278 | 0 | try_control!( |
279 | 0 | visitor(DfsEvent::Discover(u, time_post_inc(time))), |
280 | 0 | {}, |
281 | 0 | for v in graph.neighbors(u) { |
282 | 0 | if !discovered.is_visited(&v) { |
283 | 0 | try_control!(visitor(DfsEvent::TreeEdge(u, v)), continue); |
284 | 0 | try_control!( |
285 | 0 | dfs_visitor(graph, v, visitor, discovered, finished, time), |
286 | 0 | unreachable!() |
287 | | ); |
288 | 0 | } else if !finished.is_visited(&v) { |
289 | 0 | try_control!(visitor(DfsEvent::BackEdge(u, v)), continue); |
290 | | } else { |
291 | 0 | try_control!(visitor(DfsEvent::CrossForwardEdge(u, v)), continue); |
292 | | } |
293 | | } |
294 | | ); |
295 | 0 | let first_finish = finished.visit(u); |
296 | 0 | debug_assert!(first_finish); |
297 | 0 | try_control!( |
298 | 0 | visitor(DfsEvent::Finish(u, time_post_inc(time))), |
299 | 0 | panic!("Pruning on the `DfsEvent::Finish` is not supported!") |
300 | | ); |
301 | 0 | C::continuing() |
302 | 0 | } |
303 | | |
304 | 0 | fn time_post_inc(x: &mut Time) -> Time { |
305 | 0 | let v = *x; |
306 | 0 | x.0 += 1; |
307 | 0 | v |
308 | 0 | } |