Skip to content

Commit 57cd3ac

Browse files
authored
fix is_cyclic and topological_sort (#284)
* fix quadratic time in is_cyclic and topological_sort * Add comments * renaming queue to stack * fix topological_sort * fix is_cyclic * fix indentation * fix indentation * Update comment
1 parent d3b2706 commit 57cd3ac

File tree

2 files changed

+35
-16
lines changed

2 files changed

+35
-16
lines changed

src/traversals/dfs.jl

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,30 +32,30 @@ function is_cyclic end
3232
end
3333
# see https://github.com/mauro3/SimpleTraits.jl/issues/47#issuecomment-327880153 for syntax
3434
@traitfn function is_cyclic(g::AG::IsDirected) where {T,AG<:AbstractGraph{T}}
35-
# 0 if not visited, 1 if visited, 2 if in the current dfs path, 3 if fully explored
35+
# 0 if not visited, 1 if in the current dfs path, 2 if fully explored
3636
vcolor = zeros(UInt8, nv(g))
3737
vertex_stack = Vector{T}()
3838
for v in vertices(g)
3939
vcolor[v] != 0 && continue
4040
push!(vertex_stack, v)
41-
vcolor[v] = 1
4241
while !isempty(vertex_stack)
4342
u = vertex_stack[end]
44-
if vcolor[u] == 1
45-
vcolor[u] = 2
43+
if vcolor[u] == 0
44+
vcolor[u] = 1
4645
for n in outneighbors(g, u)
4746
# we hit a loop when reaching back a vertex of the main path
48-
if vcolor[n] == 2
47+
if vcolor[n] == 1
4948
return true
5049
elseif vcolor[n] == 0
5150
# we store neighbors, but these are not yet on the path
52-
vcolor[n] = 1
5351
push!(vertex_stack, n)
5452
end
5553
end
5654
else
57-
vcolor[u] = 3
5855
pop!(vertex_stack)
56+
if vcolor[u] == 1
57+
vcolor[u] = 2
58+
end
5959
end
6060
end
6161
end
@@ -87,32 +87,33 @@ graph `g` as a vector of vertices in topological order.
8787
function topological_sort_by_dfs end
8888
# see https://github.com/mauro3/SimpleTraits.jl/issues/47#issuecomment-327880153 for syntax
8989
@traitfn function topological_sort_by_dfs(g::AG::IsDirected) where {T,AG<:AbstractGraph{T}}
90-
# 0 if not visited, 1 if visited, 2 if in the current dfs path, 3 if fully explored
90+
# 0 if not visited, 1 if in the current dfs path, 2 if fully explored
9191
vcolor = zeros(UInt8, nv(g))
9292
verts = Vector{T}()
9393
vertex_stack = Vector{T}()
9494
for v in vertices(g)
9595
vcolor[v] != 0 && continue
9696
push!(vertex_stack, v)
97-
vcolor[v] = 1
9897
while !isempty(vertex_stack)
9998
u = vertex_stack[end]
100-
if vcolor[u] == 1
101-
vcolor[u] = 2
99+
if vcolor[u] == 0
100+
vcolor[u] = 1
102101
for n in outneighbors(g, u)
103102
# we hit a loop when reaching back a vertex of the main path
104-
if vcolor[n] == 2
103+
if vcolor[n] == 1
105104
error("The input graph contains at least one loop.") # TODO 0.7 should we use a different error?
106105
elseif vcolor[n] == 0
107106
# we store neighbors, but these are not yet on the path
108-
vcolor[n] = 1
109107
push!(vertex_stack, n)
110108
end
111109
end
112-
else
113-
vcolor[u] = 3
110+
else
114111
pop!(vertex_stack)
115-
pushfirst!(verts, u)
112+
# if vcolor[u] == 2, the vertex was already explored and added to verts
113+
if vcolor[u] == 1
114+
vcolor[u] = 2
115+
pushfirst!(verts, u)
116+
end
116117
end
117118
end
118119
end

test/traversals/dfs.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@
2323
0 0 0 1 0 0 0
2424
],
2525
)
26+
# non regression test following https://github.com/JuliaGraphs/Graphs.jl/pull/266#issuecomment-1621698039
27+
g6 = SimpleDiGraph(4)
28+
add_edge!(g6, 1, 2)
29+
add_edge!(g6, 2, 3)
30+
add_edge!(g6, 2, 4)
31+
add_edge!(g6, 4, 3)
32+
g7 = copy(g6)
33+
add_edge!(g7, 3, 4)
34+
2635
@testset "dfs_tree" begin
2736
for g in testdigraphs(g5)
2837
z = @inferred(dfs_tree(GenericDiGraph(g), 1))
@@ -45,6 +54,11 @@
4554
@test @inferred(is_cyclic(g))
4655
@test_throws ErrorException topological_sort(g)
4756
end
57+
58+
# non regression test following https://github.com/JuliaGraphs/Graphs.jl/pull/266#issuecomment-1621698039
59+
for g in testdigraphs(g6)
60+
@test @inferred(topological_sort(g)) == [1, 2, 4, 3]
61+
end
4862
end
4963

5064
@testset "topological_sort_by_dfs" begin
@@ -84,5 +98,9 @@
8498
for g in testgraphs(gloop_undirected)
8599
@test @inferred(is_cyclic(g))
86100
end
101+
# non regression test following https://github.com/JuliaGraphs/Graphs.jl/pull/266#issuecomment-1621698039
102+
for g in testdigraphs(g7)
103+
@test @inferred(is_cyclic(g))
104+
end
87105
end
88106
end

0 commit comments

Comments
 (0)