-module(girard@internal@scc).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/girard/internal/scc.gleam").
-export([components/2]).
-export_type([tarjan/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.
?MODULEDOC(false).
-type tarjan() :: {tarjan,
integer(),
gleam@dict:dict(binary(), integer()),
gleam@dict:dict(binary(), integer()),
gleam@set:set(binary()),
list(binary()),
list(list(binary()))}.
-file("src/girard/internal/scc.gleam", 103).
?DOC(false).
-spec pop_component(tarjan(), binary(), list(binary())) -> tarjan().
pop_component(State, Root, Acc) ->
case erlang:element(6, State) of
[] ->
State;
[Top | Rest] ->
State@1 = {tarjan,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
gleam@set:delete(erlang:element(5, State), Top),
Rest,
erlang:element(7, State)},
Acc@1 = [Top | Acc],
case Top =:= Root of
true ->
{tarjan,
erlang:element(2, State@1),
erlang:element(3, State@1),
erlang:element(4, State@1),
erlang:element(5, State@1),
erlang:element(6, State@1),
[Acc@1 | erlang:element(7, State@1)]};
false ->
pop_component(State@1, Root, Acc@1)
end
end.
-file("src/girard/internal/scc.gleam", 120).
?DOC(false).
-spec get(gleam@dict:dict(binary(), integer()), binary()) -> integer().
get(D, Key) ->
case gleam_stdlib:map_get(D, Key) of
{ok, Value} ->
Value;
{error, _} ->
0
end.
-file("src/girard/internal/scc.gleam", 95).
?DOC(false).
-spec set_min_lowlink(tarjan(), binary(), integer()) -> tarjan().
set_min_lowlink(State, Node, Candidate) ->
Current = get(erlang:element(4, State), Node),
{tarjan,
erlang:element(2, State),
erlang:element(3, State),
gleam@dict:insert(
erlang:element(4, State),
Node,
gleam@int:min(Current, Candidate)
),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State)}.
-file("src/girard/internal/scc.gleam", 51).
?DOC(false).
-spec strong_connect(
tarjan(),
binary(),
gleam@dict:dict(binary(), list(binary()))
) -> tarjan().
strong_connect(State, Node, Edges) ->
Index = erlang:element(2, State),
State@1 = {tarjan,
Index + 1,
gleam@dict:insert(erlang:element(3, State), Node, Index),
gleam@dict:insert(erlang:element(4, State), Node, Index),
gleam@set:insert(erlang:element(5, State), Node),
[Node | erlang:element(6, State)],
erlang:element(7, State)},
Neighbours = case gleam_stdlib:map_get(Edges, Node) of
{ok, Ns} ->
Ns;
{error, _} ->
[]
end,
State@4 = gleam@list:fold(
Neighbours,
State@1,
fun(State@2, W) ->
case gleam_stdlib:map_get(erlang:element(3, State@2), W) of
{error, _} ->
State@3 = strong_connect(State@2, W, Edges),
set_min_lowlink(
State@3,
Node,
get(erlang:element(4, State@3), W)
);
{ok, W_index} ->
case gleam@set:contains(erlang:element(5, State@2), W) of
true ->
set_min_lowlink(State@2, Node, W_index);
false ->
State@2
end
end
end
),
case get(erlang:element(4, State@4), Node) =:= get(
erlang:element(3, State@4),
Node
) of
true ->
pop_component(State@4, Node, []);
false ->
State@4
end.
-file("src/girard/internal/scc.gleam", 26).
?DOC(false).
-spec components(list(binary()), gleam@dict:dict(binary(), list(binary()))) -> list(list(binary())).
components(Nodes, Edges) ->
Initial = {tarjan, 0, maps:new(), maps:new(), gleam@set:new(), [], []},
Final = gleam@list:fold(
Nodes,
Initial,
fun(State, Node) ->
case gleam@dict:has_key(erlang:element(3, State), Node) of
true ->
State;
false ->
strong_connect(State, Node, Edges)
end
end
),
lists:reverse(erlang:element(7, Final)).