Skip to main content

src/girard@internal@scc.erl

-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)).