graphlib/iterators/
dfs.rs

1// Copyright 2019 Octavian Oncescu
2
3use crate::graph::Graph;
4use crate::iterators::VertexIter;
5use crate::vertex_id::VertexId;
6
7#[cfg(feature = "no_std")]
8use core::iter::{Chain, Cloned, Peekable};
9use hashbrown::HashSet;
10#[cfg(not(feature = "no_std"))]
11use std::iter::{Chain, Cloned, Peekable};
12
13#[cfg(feature = "no_std")]
14extern crate alloc;
15#[cfg(feature = "no_std")]
16use alloc::vec::Vec;
17
18#[cfg(feature = "no_std")]
19use core::fmt::Debug;
20
21#[cfg(not(feature = "no_std"))]
22use std::fmt::Debug;
23
24#[derive(Debug)]
25/// Depth-First Iterator
26pub struct Dfs<'a, T> {
27    /// All the vertices to be checked with the roots coming first.
28    unchecked: Peekable<Cloned<Chain<VertexIter<'a>, VertexIter<'a>>>>,
29    /// All black vertices.
30    black: HashSet<VertexId>,
31    /// All grey vertices.
32    grey: HashSet<VertexId>,
33    /// All vertices pending processing.
34    pending_stack: Vec<(VertexId, bool)>,
35    /// The Graph being iterated.
36    iterable: &'a Graph<T>,
37    /// A cached answer to the question: does this Graph contain cycles.
38    cached_cyclic: bool,
39}
40
41impl<'a, T> Dfs<'a, T> {
42    pub fn new(graph: &'a Graph<T>) -> Dfs<'_, T> {
43        let unchecked = graph.roots().chain(graph.vertices()).cloned().peekable();
44
45        Dfs {
46            unchecked,
47            iterable: graph,
48            cached_cyclic: false,
49            grey: HashSet::new(),
50            black: HashSet::new(),
51            pending_stack: Vec::new(),
52        }
53    }
54
55    /// Returns true if the iterated graph has a cycle.
56    ///
57    /// # Warning
58    ///
59    /// It is a logic error to use this iterator after calling this function.
60    pub fn is_cyclic(&mut self) -> bool {
61        //Check for a cached answer.
62        if self.cached_cyclic {
63            return self.cached_cyclic;
64        }
65
66        //Search until an answer is found.
67        while self.process_vertex().is_some() {}
68
69        self.cached_cyclic
70    }
71
72    /// Processes the next vertex.
73    ///
74    /// Will return None if:
75    ///
76    /// * No vertices are left.
77    /// * The next vertex forms a cycle.
78    fn process_vertex(&mut self) -> Option<&'a VertexId> {
79        if self.pending_stack.is_empty() {
80            //Spliting the borrows for the borrow checker.
81            let unchecked = &mut self.unchecked;
82            let black = &self.black;
83
84            //Search for an unprocessed vertex.
85            let next = unchecked.find(move |v| !black.contains(v));
86
87            //We found a new vertex.
88            if let Some(v) = next {
89                self.pending_stack.push((v, false));
90            }
91        }
92
93        // get next vertex
94        let mut should_return = true;
95        let n = self
96            .pending_stack
97            .pop()
98            .iter()
99            //Filter cycles.
100            .filter_map(|v| {
101                let (v, already_seen) = v;
102
103                // if we have seen the vertex before,
104                // we remove it from grey and add it to black
105                if *already_seen {
106                    self.grey.remove(v);
107                    self.black.insert(*v);
108                } else {
109                    // otherwise we remember that we have to
110                    // mark it as done (i.e. move it to black)
111                    // the next time we see it
112                    self.grey.insert(*v);
113                    self.pending_stack.push((*v, true));
114
115                    // add all successors that are not already marked
116                    // "under consideration", i.e. in grey
117                    for v in self.iterable.out_neighbors(v) {
118                        if self.grey.contains(v) {
119                            // if we do encounter such an edge,
120                            // there is a cycle
121                            self.cached_cyclic = true;
122                        } else if !self.black.contains(v) {
123                            self.pending_stack.push((*v, false));
124                        }
125                    }
126                }
127                // we don't want to return nodes twice so we only
128                // return a node when we haven't seen it yet
129                should_return = !*already_seen;
130                self.iterable.fetch_id_ref(v)
131            })
132            .next();
133        if should_return {
134            n
135        } else {
136            self.process_vertex()
137        }
138    }
139}
140
141impl<'a, T> Iterator for Dfs<'a, T> {
142    type Item = &'a VertexId;
143
144    fn size_hint(&self) -> (usize, Option<usize>) {
145        let remaining = self.iterable.vertex_count() - self.black.len();
146
147        (0, Some(remaining))
148    }
149    fn next(&mut self) -> Option<Self::Item> {
150        (0..self.size_hint().1.unwrap())
151            .filter_map(move |_| self.process_vertex())
152            .next()
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159
160    #[test]
161    fn is_cyclic() {
162        /*
163        A previous version of the function would fail if the iterator had passed through the last cycle.
164
165        The current version written 2019-03-23 caches if any cycles have been found as it
166        iterates to resolve this issue.
167        */
168
169        for _ in 0..100 {
170            let mut graph = Graph::new();
171
172            let v = graph.add_vertex(0);
173
174            assert!(graph.add_edge(&v, &v).is_ok(), "Failed to create cycle");
175
176            for _ in 0..100 {
177                graph.add_vertex(0);
178            }
179
180            let mut dfs = graph.dfs();
181
182            for _ in 0..99 {
183                dfs.next();
184            }
185
186            assert!(dfs.is_cyclic());
187        }
188    }
189    #[test]
190    fn not_cyclic() {
191        let mut graph = Graph::new();
192
193        let v1 = graph.add_vertex(());
194        let v2 = graph.add_vertex(());
195        let v3 = graph.add_vertex(());
196
197        graph.add_edge(&v1, &v2);
198        graph.add_edge(&v3, &v2);
199
200        graph.add_vertex(());
201
202        assert_eq!(graph.is_cyclic(), false);
203    }
204
205    #[test]
206    fn not_cyclic_edge_to_successor() {
207        let mut graph = Graph::new();
208
209        let v1 = graph.add_vertex(1);
210        let v2 = graph.add_vertex(2);
211        let v3 = graph.add_vertex(3);
212
213        graph.add_edge(&v1, &v2).unwrap();
214        graph.add_edge(&v2, &v3).unwrap();
215        graph.add_edge(&v1, &v3).unwrap();
216
217        assert_eq!(graph.is_cyclic(), false);
218    }
219
220    #[test]
221    fn not_cyclic_edge_split_merge() {
222        let mut graph = Graph::new();
223
224        let v1 = graph.add_vertex(1);
225        let v2 = graph.add_vertex(2);
226        let v3 = graph.add_vertex(3);
227        let v4 = graph.add_vertex(4);
228        let v5 = graph.add_vertex(5);
229        let v6 = graph.add_vertex(6);
230
231        graph.add_edge(&v1, &v2).unwrap();
232        graph.add_edge(&v2, &v3).unwrap();
233        graph.add_edge(&v3, &v4).unwrap();
234        graph.add_edge(&v3, &v5).unwrap();
235        graph.add_edge(&v4, &v6).unwrap();
236        graph.add_edge(&v5, &v6).unwrap();
237
238        assert_eq!(graph.is_cyclic(), false);
239    }
240
241    #[test]
242    fn not_cyclic_split_merge_continue() {
243        // TODO: rename that test
244
245        let mut graph = Graph::new();
246
247        let v1 = graph.add_vertex(1);
248        let v2 = graph.add_vertex(2);
249        let v3 = graph.add_vertex(3);
250        let v4 = graph.add_vertex(4);
251        let v5 = graph.add_vertex(5);
252        let v6 = graph.add_vertex(6);
253        let v7 = graph.add_vertex(7);
254
255        graph.add_edge(&v1, &v2).unwrap();
256        graph.add_edge(&v2, &v3).unwrap();
257        graph.add_edge(&v3, &v4).unwrap();
258        graph.add_edge(&v3, &v5).unwrap();
259        graph.add_edge(&v4, &v6).unwrap();
260        graph.add_edge(&v5, &v6).unwrap();
261        graph.add_edge(&v1, &v6).unwrap();
262        graph.add_edge(&v6, &v7).unwrap();
263
264        assert_eq!(graph.is_cyclic(), false);
265    }
266
267    #[test]
268    fn cycle_self_edge() {
269        let mut graph = Graph::new();
270
271        let v1 = graph.add_vertex(1);
272
273        graph.add_edge(&v1, &v1).unwrap();
274
275        assert!(graph.is_cyclic());
276    }
277}