Packages

A library for computing integer complexity.

Current section

Files

Jump to
integer_complexity src integer_complexity.erl
Raw

src/integer_complexity.erl

-module(integer_complexity).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([a000792/1, get_complexities_up_to/2, get_complexity/2, get_expressions_up_to/2, get_expression/2]).
-export_type([complexity_data/0, derived_expression/0]).
-opaque complexity_data() :: {complexity_data, integer(), derived_expression()}.
-type derived_expression() :: {derived_add,
derived_expression(),
derived_expression()} |
{derived_multiply, derived_expression(), derived_expression()} |
{derived, integer()} |
derived_one.
-spec a000792_rec(integer(), integer()) -> integer().
a000792_rec(N, Result) ->
case (N >= 5) orelse (N =:= 3) of
true ->
a000792_rec(N - 3, Result * 3);
false ->
erlang:'bsl'(Result, N div 2)
end.
-spec a000792(integer()) -> integer().
a000792(N) ->
a000792_rec(N, 1).
-spec calc_t(integer(), integer(), integer()) -> integer().
calc_t(T, Target, Index) ->
case (a000792(T) + a000792(Target - T)) < Index of
true ->
calc_t(T - 1, Target, Index);
false ->
T
end.
-spec products(
integer(),
integer(),
integer(),
gary:erlang_array(complexity_data())
) -> gary:erlang_array(complexity_data()).
products(K, Max, N, Complexity) ->
gleam@bool:guard(
K > Max,
Complexity,
fun() ->
Complexity_k = begin
_pipe = integer_complexity@internal@array:get(Complexity, K),
_pipe@1 = gleam@result:map(
_pipe,
fun(X) -> erlang:element(2, X) end
),
gleam@result:unwrap(_pipe@1, 2147483647)
end,
Complexity_n = begin
_pipe@2 = integer_complexity@internal@array:get(Complexity, N),
_pipe@3 = gleam@result:map(
_pipe@2,
fun(X@1) -> erlang:element(2, X@1) end
),
gleam@result:unwrap(_pipe@3, 2147483647)
end,
Complexity_k_n = integer_complexity@internal@array:get(
Complexity,
K * N
),
Prod_value = Complexity_k + Complexity_n,
_assert_subject = case Complexity_k_n of
{error, _} ->
integer_complexity@internal@array:set(
Complexity,
K * N,
{complexity_data,
Prod_value,
{derived_multiply, {derived, K}, {derived, N}}}
);
{ok, {complexity_data, K_n_value, _}} when Prod_value < K_n_value ->
integer_complexity@internal@array:set(
Complexity,
K * N,
{complexity_data,
Prod_value,
{derived_multiply, {derived, K}, {derived, N}}}
);
_ ->
{ok, Complexity}
end,
{ok, Updated_complexity} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"integer_complexity"/utf8>>,
function => <<"products"/utf8>>,
line => 222})
end,
products(K + 1, Max, N, Updated_complexity)
end
).
-spec sums(
carpenter@table:set(integer(), complexity_data()),
integer(),
integer()
) -> gleam@option:option(complexity_data()).
sums(Cache, N, Max) ->
gleam@bool:guard(Max < 6, none, fun() -> _pipe = gleam@list:range(6, Max),
gleam@list:fold(
_pipe,
none,
fun(Acc, M) ->
Complexity_m = erlang:element(2, complexity_rec(Cache, M)),
Complexity_n_m = erlang:element(
2,
complexity_rec(Cache, N - M)
),
Sum_value = Complexity_m + Complexity_n_m,
case Acc of
{some, {complexity_data, Complexity, _}} when Sum_value < Complexity ->
{some,
{complexity_data,
Sum_value,
{derived_add,
{derived, M},
{derived, N - M}}}};
none ->
{some,
{complexity_data,
Sum_value,
{derived_add,
{derived, M},
{derived, N - M}}}};
_ ->
Acc
end
end
) end).
-spec complexity_rec(
carpenter@table:set(integer(), complexity_data()),
integer()
) -> complexity_data().
complexity_rec(Cache, N) ->
fun rememo@ets@memo:memoize/3(
Cache,
N,
fun() ->
gleam@bool:guard(
N =:= 1,
{complexity_data, N, derived_one},
fun() ->
Base_complexity = {complexity_data,
erlang:element(2, complexity_rec(Cache, N - 1)) + 1,
{derived_add, {derived, N - 1}, derived_one}},
_assert_subject = erlang:element(
2,
complexity_rec(Cache, N - 1)
),
Target = case _assert_subject of
_ -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"integer_complexity"/utf8>>,
function => <<"complexity_rec"/utf8>>,
line => 122})
end,
T = calc_t(Target div 2, Target, N),
K_max = a000792(T),
Sum_test_result = begin
_pipe = sums(Cache, N, K_max),
gleam@option:unwrap(_pipe, Base_complexity)
end,
Divisor_test_result = begin
_pipe@1 = divisors(Cache, N),
gleam@option:unwrap(_pipe@1, Base_complexity)
end,
_assert_subject@1 = gleam_community@maths@piecewise:list_minimum(
[Base_complexity, Sum_test_result, Divisor_test_result],
fun(A, B) ->
gleam@int:compare(
erlang:element(2, A),
erlang:element(2, B)
)
end
),
{ok, Result} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"integer_complexity"/utf8>>,
function => <<"complexity_rec"/utf8>>,
line => 134})
end,
Result
end
)
end
).
-spec get_complexity_data_up_to(
carpenter@table:set(integer(), complexity_data()),
integer()
) -> list(complexity_data()).
get_complexity_data_up_to(Cache, Integer) ->
_pipe = gleam@list:range(1, Integer),
gleam@list:map(_pipe, fun(_capture) -> complexity_rec(Cache, _capture) end).
-spec get_complexities_up_to(
carpenter@table:set(integer(), complexity_data()),
integer()
) -> {ok, list(integer())} | {error, nil}.
get_complexities_up_to(Cache, Integer) ->
gleam@bool:guard(
Integer =< 0,
{error, nil},
fun() ->
_pipe = gleam@list:map(
get_complexity_data_up_to(Cache, Integer),
fun(X) -> erlang:element(2, X) end
),
{ok, _pipe}
end
).
-spec get_complexity_data(
carpenter@table:set(integer(), complexity_data()),
integer()
) -> complexity_data().
get_complexity_data(Cache, Integer) ->
complexity_rec(Cache, Integer).
-spec get_complexity(
carpenter@table:set(integer(), complexity_data()),
integer()
) -> integer().
get_complexity(Cache, Integer) ->
gleam@bool:guard(
Integer =:= 0,
0,
fun() ->
erlang:element(
2,
get_complexity_data(Cache, gleam@int:absolute_value(Integer))
)
end
).
-spec divisors(carpenter@table:set(integer(), complexity_data()), integer()) -> gleam@option:option(complexity_data()).
divisors(Cache, N) ->
Divisors = gleam_community@maths@arithmetics:divisors(N),
Smaller_divisors = begin
_pipe = gleam@list:take(
Divisors,
gleam@float:round(gleam@int:to_float(erlang:length(Divisors)) / 2.0)
),
gleam@list:drop(_pipe, 1)
end,
Sum_complexity = gleam@list:fold(
Smaller_divisors,
none,
fun(Acc, A) ->
Complexity_a = erlang:element(2, complexity_rec(Cache, A)),
Complexity_b = erlang:element(2, complexity_rec(Cache, case A of
0 -> 0;
Gleam@denominator -> N div Gleam@denominator
end)),
Prod_complexity = Complexity_a + Complexity_b,
case Acc of
none ->
{some,
{complexity_data,
Prod_complexity,
{derived_multiply, {derived, A}, {derived, case A of
0 -> 0;
Gleam@denominator@1 -> N div Gleam@denominator@1
end}}}};
{some, {complexity_data, Complexity, _}} when Prod_complexity < Complexity ->
{some,
{complexity_data,
Prod_complexity,
{derived_multiply, {derived, A}, {derived, case A of
0 -> 0;
Gleam@denominator@2 -> N div Gleam@denominator@2
end}}}};
_ ->
Acc
end
end
),
Sum_complexity.
-spec construct_expression(
carpenter@table:set(integer(), complexity_data()),
derived_expression()
) -> integer_complexity@expression:expression().
construct_expression(Cache, Derived_expression) ->
case Derived_expression of
derived_one ->
one;
{derived_add, Lhs, Rhs} ->
{add,
construct_expression(Cache, Lhs),
construct_expression(Cache, Rhs)};
{derived_multiply, Lhs@1, Rhs@1} ->
{multiply,
construct_expression(Cache, Lhs@1),
construct_expression(Cache, Rhs@1)};
{derived, N} ->
Data = complexity_rec(Cache, N),
construct_expression(Cache, erlang:element(3, Data))
end.
-spec get_expressions_up_to(
carpenter@table:set(integer(), complexity_data()),
integer()
) -> {ok, list(integer_complexity@expression:expression())} | {error, nil}.
get_expressions_up_to(Cache, Integer) ->
gleam@bool:guard(
Integer =< 0,
{error, nil},
fun() ->
_pipe = gleam@list:map(
get_complexity_data_up_to(Cache, Integer),
fun(X) -> construct_expression(Cache, erlang:element(3, X)) end
),
{ok, _pipe}
end
).
-spec get_expression(
carpenter@table:set(integer(), complexity_data()),
integer()
) -> {ok, integer_complexity@expression:expression()} | {error, nil}.
get_expression(Cache, Integer) ->
gleam@bool:guard(
Integer =:= 0,
{error, nil},
fun() ->
_pipe = erlang:element(
3,
get_complexity_data(Cache, gleam@int:absolute_value(Integer))
),
_pipe@1 = construct_expression(Cache, _pipe),
{ok, _pipe@1}
end
).