Current section
Files
Jump to
Current section
Files
src/yog@components.erl
-module(yog@components).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/yog/components.gleam").
-export([strongly_connected_components/1]).
-export_type([tarjan_state/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type tarjan_state() :: {tarjan_state,
integer(),
list(integer()),
gleam@dict:dict(integer(), boolean()),
gleam@dict:dict(integer(), integer()),
gleam@dict:dict(integer(), integer()),
list(list(integer()))}.
-file("src/yog/components.gleam", 103).
-spec pop_stack_until(integer(), tarjan_state(), list(integer())) -> tarjan_state().
pop_stack_until(U, State, Component) ->
case erlang:element(3, State) of
[] ->
State;
[Head | Tail] ->
New_component = [Head | Component],
New_on_stack = gleam@dict:insert(
erlang:element(4, State),
Head,
false
),
Next_state = {tarjan_state,
erlang:element(2, State),
Tail,
New_on_stack,
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State)},
case Head =:= U of
true ->
{tarjan_state,
erlang:element(2, Next_state),
erlang:element(3, Next_state),
erlang:element(4, Next_state),
erlang:element(5, Next_state),
erlang:element(6, Next_state),
[New_component | erlang:element(7, State)]};
false ->
pop_stack_until(U, Next_state, New_component)
end
end.
-file("src/yog/components.gleam", 44).
-spec strong_connect(yog@model:graph(any(), any()), integer(), tarjan_state()) -> tarjan_state().
strong_connect(Graph, U, State) ->
State@1 = {tarjan_state,
erlang:element(2, State) + 1,
[U | erlang:element(3, State)],
gleam@dict:insert(erlang:element(4, State), U, true),
gleam@dict:insert(erlang:element(5, State), U, erlang:element(2, State)),
gleam@dict:insert(erlang:element(6, State), U, erlang:element(2, State)),
erlang:element(7, State)},
Successors = yog@model:successor_ids(Graph, U),
State@2 = gleam@list:fold(
Successors,
State@1,
fun(St, V) -> case gleam@dict:has_key(erlang:element(5, St), V) of
false ->
St@1 = strong_connect(Graph, V, St),
U_low = begin
_pipe = gleam_stdlib:map_get(erlang:element(6, St@1), U),
gleam@result:unwrap(_pipe, 0)
end,
V_low = begin
_pipe@1 = gleam_stdlib:map_get(
erlang:element(6, St@1),
V
),
gleam@result:unwrap(_pipe@1, 0)
end,
{tarjan_state,
erlang:element(2, St@1),
erlang:element(3, St@1),
erlang:element(4, St@1),
erlang:element(5, St@1),
gleam@dict:insert(
erlang:element(6, St@1),
U,
gleam@int:min(U_low, V_low)
),
erlang:element(7, St@1)};
true ->
case begin
_pipe@2 = gleam_stdlib:map_get(erlang:element(4, St), V),
gleam@result:unwrap(_pipe@2, false)
end of
true ->
U_low@1 = begin
_pipe@3 = gleam_stdlib:map_get(
erlang:element(6, St),
U
),
gleam@result:unwrap(_pipe@3, 0)
end,
V_index = begin
_pipe@4 = gleam_stdlib:map_get(
erlang:element(5, St),
V
),
gleam@result:unwrap(_pipe@4, 0)
end,
{tarjan_state,
erlang:element(2, St),
erlang:element(3, St),
erlang:element(4, St),
erlang:element(5, St),
gleam@dict:insert(
erlang:element(6, St),
U,
gleam@int:min(U_low@1, V_index)
),
erlang:element(7, St)};
false ->
St
end
end end
),
U_index = begin
_pipe@5 = gleam_stdlib:map_get(erlang:element(5, State@2), U),
gleam@result:unwrap(_pipe@5, 0)
end,
U_low@2 = begin
_pipe@6 = gleam_stdlib:map_get(erlang:element(6, State@2), U),
gleam@result:unwrap(_pipe@6, 0)
end,
case U_low@2 =:= U_index of
true ->
pop_stack_until(U, State@2, []);
false ->
State@2
end.
-file("src/yog/components.gleam", 20).
?DOC(
" Finds Strongly Connected Components (SCC) using Tarjan's Algorithm.\n"
" Returns a list of components, where each component is a list of NodeIds.\n"
).
-spec strongly_connected_components(yog@model:graph(any(), any())) -> list(list(integer())).
strongly_connected_components(Graph) ->
Nodes = yog@model:all_nodes(Graph),
Initial_state = {tarjan_state,
0,
[],
maps:new(),
maps:new(),
maps:new(),
[]},
Final_state = gleam@list:fold(
Nodes,
Initial_state,
fun(State, Node) ->
case gleam@dict:has_key(erlang:element(5, State), Node) of
true ->
State;
false ->
strong_connect(Graph, Node, State)
end
end
),
erlang:element(7, Final_state).