-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 test_sums( complexity_data(), carpenter@table:set(integer(), complexity_data()), integer(), integer() ) -> complexity_data(). test_sums(Current_complexity_data, Cache, N, Max) -> gleam@bool:guard( Max < 6, Current_complexity_data, fun() -> _pipe = gleam@list:range(6, Max), gleam@list:fold( _pipe, Current_complexity_data, 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 Sum_value < erlang:element(2, Acc) of true -> {complexity_data, Sum_value, {derived_add, {derived, M}, {derived, N - M}}}; false -> 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}}, Target = erlang:element(2, complexity_rec(Cache, N - 1)), T = calc_t(Target div 2, Target, N), K_max = a000792(T), _pipe = Base_complexity, _pipe@1 = test_sums(_pipe, Cache, N, K_max), test_divisors(_pipe@1, Cache, N) 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 test_divisors( complexity_data(), carpenter@table:set(integer(), complexity_data()), integer() ) -> complexity_data(). test_divisors(Current_complexity_data, 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, Current_complexity_data, 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 Prod_complexity < erlang:element(2, Acc) of true -> {complexity_data, Prod_complexity, {derived_multiply, {derived, A}, {derived, case A of 0 -> 0; Gleam@denominator@1 -> N div Gleam@denominator@1 end}}}; false -> 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 ).