@@ -33,7 +33,7 @@ pub struct Dfs<'a, T>
3333 /// All grey vertices.
3434 grey : HashSet < VertexId > ,
3535 /// All vertices pending processing.
36- pending_stack : Vec < VertexId > ,
36+ pending_stack : Vec < ( VertexId , bool ) > ,
3737 /// The Graph being iterated.
3838 iterable : & ' a Graph < T > ,
3939 /// A cached answer to the question: does this Graph contain cycles.
@@ -80,11 +80,7 @@ impl<'a, T> Dfs<'a, T>
8080 /// * No vertices are left.
8181 /// * The next vertex forms a cycle.
8282 fn process_vertex ( & mut self ) -> Option < & ' a VertexId > {
83- //We have traversed this partition of the graph, move on.
8483 if self . pending_stack . is_empty ( ) {
85- //Mark all the grey vertices black.
86- self . black . extend ( self . grey . drain ( ) ) ;
87-
8884 //Spliting the borrows for the borrow checker.
8985 let unchecked = & mut self . unchecked ;
9086 let black = & self . black ;
@@ -94,36 +90,55 @@ impl<'a, T> Dfs<'a, T>
9490
9591 //We found a new vertex.
9692 if let Some ( v) = next {
97- self . pending_stack . push ( v ) ;
93+ self . pending_stack . push ( ( v , false ) ) ;
9894 }
9995 }
10096
101- //Get the next pending vertex.
102- self . pending_stack
97+ // get next vertex
98+ let mut should_return = true ;
99+ let n = self
100+ . pending_stack
103101 . pop ( )
104102 . iter ( )
105103 //Filter cycles.
106104 . filter_map ( |v| {
107- //If this vertex forms a cycle do not return it.
108- if !self . grey . insert ( * v) {
109- self . cached_cyclic = true ;
110-
111- return None ;
112- }
113-
114- //Add all of its neighbours to be processed.
115- for v in self . iterable . out_neighbors ( v) {
116- //This neighbour forms a cycle don't process it.
117- if self . grey . contains ( v) {
118- self . cached_cyclic = true
119- } else {
120- self . pending_stack . push ( * v)
105+ let ( v, already_seen) = v;
106+
107+ // if we have seen the vertex before,
108+ // we remove it from grey and add it to black
109+ if * already_seen {
110+ self . grey . remove ( v) ;
111+ self . black . insert ( * v) ;
112+ } else {
113+ // otherwise we remember that we have to
114+ // mark it as done (i.e. move it to black)
115+ // the next time we see it
116+ self . grey . insert ( * v) ;
117+ self . pending_stack . push ( ( * v, true ) ) ;
118+
119+ // add all successors that are not already marked
120+ // "under consideration", i.e. in grey
121+ for v in self . iterable . out_neighbors ( v) {
122+ if self . grey . contains ( v) {
123+ // if we do encounter such an edge,
124+ // there is a cycle
125+ self . cached_cyclic = true ;
126+ } else if !self . black . contains ( v) {
127+ self . pending_stack . push ( ( * v, false ) ) ;
128+ }
121129 }
122130 }
123-
131+ // we don't want to return nodes twice so we only
132+ // return a node when we haven't seen it yet
133+ should_return = !* already_seen;
124134 self . iterable . fetch_id_ref ( v)
125135 } )
126- . next ( )
136+ . next ( ) ;
137+ if should_return {
138+ n
139+ } else {
140+ self . process_vertex ( )
141+ }
127142 }
128143}
129144
@@ -192,4 +207,77 @@ mod tests {
192207
193208 assert_eq ! ( graph. is_cyclic( ) , false ) ;
194209 }
210+
211+ #[ test]
212+ fn not_cyclic_edge_to_successor ( ) {
213+ let mut graph = Graph :: new ( ) ;
214+
215+ let v1 = graph. add_vertex ( 1 ) ;
216+ let v2 = graph. add_vertex ( 2 ) ;
217+ let v3 = graph. add_vertex ( 3 ) ;
218+
219+ graph. add_edge ( & v1, & v2) . unwrap ( ) ;
220+ graph. add_edge ( & v2, & v3) . unwrap ( ) ;
221+ graph. add_edge ( & v1, & v3) . unwrap ( ) ;
222+
223+ assert_eq ! ( graph. is_cyclic( ) , false ) ;
224+ }
225+
226+ #[ test]
227+ fn not_cyclic_edge_split_merge ( ) {
228+ let mut graph = Graph :: new ( ) ;
229+
230+ let v1 = graph. add_vertex ( 1 ) ;
231+ let v2 = graph. add_vertex ( 2 ) ;
232+ let v3 = graph. add_vertex ( 3 ) ;
233+ let v4 = graph. add_vertex ( 4 ) ;
234+ let v5 = graph. add_vertex ( 5 ) ;
235+ let v6 = graph. add_vertex ( 6 ) ;
236+
237+ graph. add_edge ( & v1, & v2) . unwrap ( ) ;
238+ graph. add_edge ( & v2, & v3) . unwrap ( ) ;
239+ graph. add_edge ( & v3, & v4) . unwrap ( ) ;
240+ graph. add_edge ( & v3, & v5) . unwrap ( ) ;
241+ graph. add_edge ( & v4, & v6) . unwrap ( ) ;
242+ graph. add_edge ( & v5, & v6) . unwrap ( ) ;
243+
244+ assert_eq ! ( graph. is_cyclic( ) , false ) ;
245+ }
246+
247+ #[ test]
248+ fn not_cyclic_split_merge_continue ( ) {
249+ // TODO: rename that test
250+
251+ let mut graph = Graph :: new ( ) ;
252+
253+ let v1 = graph. add_vertex ( 1 ) ;
254+ let v2 = graph. add_vertex ( 2 ) ;
255+ let v3 = graph. add_vertex ( 3 ) ;
256+ let v4 = graph. add_vertex ( 4 ) ;
257+ let v5 = graph. add_vertex ( 5 ) ;
258+ let v6 = graph. add_vertex ( 6 ) ;
259+ let v7 = graph. add_vertex ( 7 ) ;
260+
261+ graph. add_edge ( & v1, & v2) . unwrap ( ) ;
262+ graph. add_edge ( & v2, & v3) . unwrap ( ) ;
263+ graph. add_edge ( & v3, & v4) . unwrap ( ) ;
264+ graph. add_edge ( & v3, & v5) . unwrap ( ) ;
265+ graph. add_edge ( & v4, & v6) . unwrap ( ) ;
266+ graph. add_edge ( & v5, & v6) . unwrap ( ) ;
267+ graph. add_edge ( & v1, & v6) . unwrap ( ) ;
268+ graph. add_edge ( & v6, & v7) . unwrap ( ) ;
269+
270+ assert_eq ! ( graph. is_cyclic( ) , false ) ;
271+ }
272+
273+ #[ test]
274+ fn cycle_self_edge ( ) {
275+ let mut graph = Graph :: new ( ) ;
276+
277+ let v1 = graph. add_vertex ( 1 ) ;
278+
279+ graph. add_edge ( & v1, & v1) . unwrap ( ) ;
280+
281+ assert ! ( graph. is_cyclic( ) ) ;
282+ }
195283}
0 commit comments