Current section

Files

Jump to
bitgraph lib algorithms scc kozaraju.ex
Raw

lib/algorithms/scc/kozaraju.ex

defmodule BitGraph.Algorithms.SCC.Kozaraju do
alias BitGraph.Dfs
import BitGraph.Algorithms.SCC.Utils
## Kozaraju's SCC algorithm
def run(graph,
opts \\ []
) do
BitGraph.num_vertices(graph) == 0 && [] ||
(
component_handler =
opts
|> Keyword.get(:component_handler, {fn component, acc -> [component | acc] end, []})
|> wrap_component_handler()
graph
|> Dfs.run(opts)
|> Dfs.order(:out, :desc)
|> Enum.reduce({nil, nil}, fn v, {state_acc, components_acc} ->
state =
Dfs.run(graph, vertices: v,
direction: :reverse,
state: state_acc,
process_vertex_fun: fn %{acc: acc} = _state, vertex ->
MapSet.put(acc || MapSet.new(), vertex)
end
)
component = state[:acc]
{Map.put(state, :acc, nil),
component && component_handler.(component, components_acc) || components_acc
}
end)
|> elem(1))
end
def strongly_connected?(graph, opts \\ []) do
try do
component_handler = fn component, _acc ->
throw({:single_scc?, component && (MapSet.size(component) == BitGraph.num_vertices(graph))})
end
run(graph,
Keyword.merge(opts,
component_handler: component_handler,
process_vertex_fun: fn(state, vertex, event) ->
event == :processed && state.dag && throw({:error, :dag, vertex}) || state[:acc] end)
)
catch
{:single_scc?, res} -> res
{:error, :dag, _vertex} -> false
end
end
end