Skip to content

Commit

Permalink
update src/toplevel/graphs.jl
Browse files Browse the repository at this point in the history
  • Loading branch information
aviatesk committed Jan 11, 2024
1 parent 1349a16 commit 9df31d9
Showing 1 changed file with 12 additions and 12 deletions.
24 changes: 12 additions & 12 deletions src/toplevel/graph.jl
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
# computes strongly connected components of a control flow graph `cfg`
# NOTE adapted from https://github.com/JuliaGraphs/LightGraphs.jl/blob/6134e21484f2312b33ba753d47dc2fc4d6b35fac/src/connectivity.jl#L221-L311
# since to load an entire LightGraphs.jl is a bit cost-ineffective in terms of a trade-off of latency vs. maintainability
# NOTE adapted from https://github.com/JuliaGraphs/Graphs.jl/blob/5878e7be4d68b2a1c179d1367aea670db115ebb5/src/connectivity.jl#L265-L357
# since to load an entire Graphs.jl is a bit cost-ineffective in terms of a trade-off of latency vs. maintainability
function strongly_connected_components(g::CFG)
T = Int
zero_t = zero(T)
one_t = one(T)
nvg = nv(g)
count = one_t


index = zeros(T, nvg) # first time in which vertex is discovered
stack = Vector{T}() # stores vertices which have been discovered and not yet assigned to any component
onstack = zeros(Bool, nvg) # false if a vertex is waiting in the stack to receive a component assignment
lowlink = zeros(T, nvg) # lowest index vertex that it can reach through back edge (index array not vertex id number)
parents = zeros(T, nvg) # parent of every vertex in dfs
components = Vector{Vector{T}}() # maintains a list of scc (order is not guaranteed in API)


dfs_stack = Vector{T}()

@inbounds for s in vertices(g)
Expand All @@ -32,14 +30,14 @@ function strongly_connected_components(g::CFG)
push!(dfs_stack, s)

while !isempty(dfs_stack)
v = dfs_stack[end] #end is the most recently added item
v = dfs_stack[end] # end is the most recently added item
u = zero_t
@inbounds for v_neighbor in outneighbors(g, v)
if index[v_neighbor] == zero_t
# unvisited neighbor found
u = v_neighbor
break
#GOTO A push u onto DFS stack and continue DFS
# GOTO A push u onto DFS stack and continue DFS
elseif onstack[v_neighbor]
# we have already seen n, but can update the lowlink of v
# which has the effect of possibly keeping v on the stack until n is ready to pop.
Expand All @@ -52,13 +50,15 @@ function strongly_connected_components(g::CFG)
# we have fully explored the DFS tree from v.
# time to start popping.
popped = pop!(dfs_stack)
lowlink[parents[popped]] = min(lowlink[parents[popped]], lowlink[popped])
lowlink[parents[popped]] = min(
lowlink[parents[popped]], lowlink[popped]
)

if index[v] == lowlink[v]
# found a cycle in a completed dfs tree.
component = Vector{T}()

while !isempty(stack) #break when popped == v
while !isempty(stack) # break when popped == v
# drain stack until we see v.
# everything on the stack until we see v is in the SCC rooted at v.
popped = pop!(stack)
Expand All @@ -75,7 +75,7 @@ function strongly_connected_components(g::CFG)
push!(components, component)
end

else #LABEL A
else # LABEL A
# add unvisited neighbor to dfs
index[u] = count
lowlink[u] = count
Expand All @@ -92,18 +92,18 @@ function strongly_connected_components(g::CFG)
end

# # assert with the original implementation
# components′ = LightGraphs.strongly_connected_components(cfg_to_sdg(g))
# components′ = Graphs.strongly_connected_components(cfg_to_sdg(g))
# @assert Set(Set.(components)) == Set(Set.(components′))

return components
end

# compatibility with LightGraphs.jl interfaces
# compatibility with Graphs.jl interfaces
@inline nv(cfg::CFG) = length(cfg.blocks)
@inline vertices(cfg::CFG) = 1:nv(cfg)
@inline outneighbors(cfg::CFG, v) = cfg.blocks[v].succs

# import LightGraphs: SimpleDiGraph, add_edge!, LightGraphs
# using Graphs: Graphs, SimpleDiGraph, add_edge!
# function cfg_to_sdg(cfg::CFG)
# g = SimpleDiGraph(length(cfg.blocks))
# for (v, block) in enumerate(cfg.blocks)
Expand Down

0 comments on commit 9df31d9

Please sign in to comment.