Skip to content

Commit 4f21348

Browse files
authored
Merge pull request #35 from hydrogenoxide/fixiscyclic2
Fixiscyclic2
2 parents 1c0fe0b + 51117dd commit 4f21348

1 file changed

Lines changed: 112 additions & 24 deletions

File tree

src/iterators/dfs.rs

Lines changed: 112 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)