Packages

Tastoids are a uniform abstraction of 'taste' and Algebra thereof.

Current section

Files

Jump to
tastoids src tastoids@taste.erl
Raw

src/tastoids@taste.erl

-module(tastoids@taste).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/tastoids/taste.gleam").
-export([from_one/1, from_tuples/1, scale/2, add/2, negate/1, multiply/2, length/1, indices/1, condense/1]).
-export_type([taste/1]).
-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(
" Tastes, broadly are any indexable sentiment (or lack thereof),\n"
" able to participate in the Tastoid algebra \n"
"\n"
" Apart from the 0-ideal/`Nil` taste (`tasteless`), Tastes must share a\n"
" given index(-space) i.e. strings, Ints, or sets/combinations thereof\n"
"\n"
" More algebraically:\n"
" \n"
" Consider that the set of all Vectors are a field ℝⁿ (aka 𝕍),\n"
" AND i is an enumerable (countable) set of indices (ⅈ) with\n"
" `imbed(a ∈ 𝔸) -> aᵢ` (a bijective imbedding of 'a' subject into 𝕍/ⅈ)\n"
"\n"
" Then, 𝛂aᵢ ∈ 𝔸 are the set of all 'unit' `tastes` (scaled by 𝛂)\n"
).
-opaque taste(DYH) :: nil |
{taste, DYH, float()} |
{tastes, gleam@dict:dict(DYH, float())}.
-file("src/tastoids/taste.gleam", 40).
?DOC(" Return a singular of 'index', a la `Taste(index, 1.0)`\n").
-spec from_one(DYI) -> taste(DYI).
from_one(Index) ->
{taste, Index, 1.0}.
-file("src/tastoids/taste.gleam", 45).
?DOC(" Return a `Tastes(index)` consisting of the provided #(index, value: Float) tuples.\n").
-spec from_tuples(list({DYK, float()})) -> taste(DYK).
from_tuples(Indexed_tastes) ->
_pipe = maps:from_list(Indexed_tastes),
{tastes, _pipe}.
-file("src/tastoids/taste.gleam", 50).
?DOC(" Internal: Short-hand for use in `scalar_multiply`; curries weight w/ float.multiply\n").
-spec scaling(float()) -> fun((float()) -> float()).
scaling(Weight) ->
fun(Taste) -> gleam@float:multiply(Weight, Taste) end.
-file("src/tastoids/taste.gleam", 55).
?DOC(" Internal: curry weight `scaling` further for `dict.map_values` to ignore the index\n").
-spec scaling_values(float()) -> fun((any(), float()) -> float()).
scaling_values(Weight) ->
Scaled = scaling(Weight),
fun(_, Sentiment) -> _pipe = Sentiment,
Scaled(_pipe) end.
-file("src/tastoids/taste.gleam", 66).
?DOC(
" Scale the given tastes by a portion (_weight_)–relative to its\n"
"'natural' values–a la scalar multiplication.\n"
"\n"
" _Note from Avery: While this could be accomplished via a Tastoid's\n"
" cardinality, I wanted keep the notion of a signal's 'worth' (the\n"
"_scale_ of its impression) distinct from its quantity.\n"
).
-spec scale(taste(DYP), float()) -> taste(DYP).
scale(Taste, Weight) ->
Scale_by_weight = fun(Sentiment) ->
gleam@float:multiply(Sentiment, Weight)
end,
case Taste of
{tastes, Ts} ->
_pipe = gleam@dict:map_values(Ts, scaling_values(Weight)),
{tastes, _pipe};
{taste, I, Sentiment@1} ->
{taste, I, Scale_by_weight(Sentiment@1)};
nil ->
Taste
end.
-file("src/tastoids/taste.gleam", 80).
?DOC(" Internal: Short-hand for `dict.filter` keeping only non-zero tastes\n").
-spec non_zeroes(any(), float()) -> boolean().
non_zeroes(_, T) ->
T /= +0.0.
-file("src/tastoids/taste.gleam", 86).
?DOC(
" Internal: Simplify a taste(s) by recursively excising zeroed tastes, collapsing\n"
" the smallest possible representation (ensuring direct equality when possible)\n"
).
-spec deflate(taste(DYU)) -> taste(DYU).
deflate(T) ->
case T of
{tastes, Ts} ->
Zeroless_ts = begin
_pipe = Ts,
gleam@dict:filter(_pipe, fun non_zeroes/2)
end,
case maps:size(Zeroless_ts) of
0 ->
nil;
N when N > 1 ->
_pipe@1 = Zeroless_ts,
{tastes, _pipe@1};
_ ->
case maps:to_list(Ts) of
[{Index, Sentiment}] ->
_pipe@2 = {taste, Index, Sentiment},
deflate(_pipe@2);
_ ->
T
end
end;
{taste, _, Sentiment@1} when Sentiment@1 =:= +0.0 ->
nil;
{taste, _, _} ->
T;
nil ->
nil
end.
-file("src/tastoids/taste.gleam", 110).
?DOC(
" Combine two tastes, linearly adding their sentiments (per index)\n"
" a la 'scalar addition'\n"
).
-spec add(taste(DYX), taste(DYX)) -> taste(DYX).
add(T, U) ->
Sum = case {T, U} of
{{taste, T_i, Sentiment_t}, {taste, Index_u, Sentiment_u}} when T_i =:= Index_u ->
_pipe = {taste, T_i, gleam@float:add(Sentiment_t, Sentiment_u)},
deflate(_pipe);
{{taste, T_i@1, Sentiment_t@1}, {taste, Index_u@1, Sentiment_u@1}} ->
_pipe@1 = maps:from_list(
[{T_i@1, Sentiment_t@1}, {Index_u@1, Sentiment_u@1}]
),
_pipe@2 = gleam@dict:filter(_pipe@1, fun non_zeroes/2),
{tastes, _pipe@2};
{{taste, _, _}, {tastes, _}} ->
add(U, T);
{{tastes, Ts}, {taste, Index_u@2, Sentiment_u@2}} ->
_pipe@3 = gleam@dict:upsert(
Ts,
Index_u@2,
fun(Sentiment_t@2) -> case Sentiment_t@2 of
{some, Sentiment_t@3} ->
gleam@float:add(Sentiment_t@3, Sentiment_u@2);
none ->
Sentiment_u@2
end end
),
_pipe@4 = gleam@dict:filter(_pipe@3, fun non_zeroes/2),
{tastes, _pipe@4};
{{tastes, T@1}, {tastes, U@1}} ->
_pipe@5 = gleam@dict:combine(
T@1,
U@1,
fun(Sentiment_t@4, Sentiment_u@3) ->
gleam@float:add(Sentiment_t@4, Sentiment_u@3)
end
),
_pipe@6 = gleam@dict:filter(_pipe@5, fun non_zeroes/2),
{tastes, _pipe@6};
{nil, _} ->
U;
{_, nil} ->
T
end,
_pipe@7 = Sum,
deflate(_pipe@7).
-file("src/tastoids/taste.gleam", 151).
?DOC(" Returns the 'negative' of a taste (like <-> dislike)\n").
-spec negate(taste(DZB)) -> taste(DZB).
negate(T) ->
case T of
{tastes, Ts} ->
_pipe = gleam@dict:map_values(
Ts,
fun(_, Sentiment) -> gleam@float:negate(Sentiment) end
),
{tastes, _pipe};
{taste, I, Sentiment@1} ->
{taste, I, gleam@float:negate(Sentiment@1)};
nil ->
T
end.
-file("src/tastoids/taste.gleam", 164).
?DOC(
" Return the _and_-ish product of two tastes. Multiplying the\n"
" indices between—possibly sparse—amplifying shared indices and\n"
" nullifying ones they don't (i.e. they were multiplied by zero).\n"
).
-spec multiply(taste(DZE), taste(DZE)) -> taste(DZE).
multiply(T, U) ->
case {T, U} of
{nil, _} ->
nil;
{_, nil} ->
nil;
{{taste, I1, _}, {taste, I2, _}} when I1 =/= I2 ->
nil;
{{taste, I, T1}, {taste, _, T2}} ->
{taste, I, gleam@float:multiply(T1, T2)};
{{taste, _, _}, {tastes, _}} ->
multiply(U, T);
{{tastes, Ts}, {taste, I@1, T1@1}} ->
case gleam_stdlib:map_get(Ts, I@1) of
{ok, T2@1} ->
case T2@1 of
+0.0 ->
nil;
_ ->
{taste, I@1, gleam@float:multiply(T1@1, T2@1)}
end;
{error, _} ->
nil
end;
{{tastes, Ts1}, {tastes, Ts2}} ->
_pipe = gleam@dict:combine(Ts1, Ts2, fun gleam@float:multiply/2),
_pipe@1 = gleam@dict:filter(_pipe, fun non_zeroes/2),
{tastes, _pipe@1}
end.
-file("src/tastoids/taste.gleam", 193).
?DOC(" Returns the combined sentiments of the entire Taste.\n").
-spec length(taste(any())) -> float().
length(Taste) ->
case Taste of
{tastes, Ts} ->
gleam@dict:fold(
Ts,
+0.0,
fun(Sum, _, Sentiment) -> _pipe = Sentiment,
_pipe@1 = gleam@float:absolute_value(_pipe),
gleam@float:add(_pipe@1, Sum) end
);
{taste, _, Sentiment@1} ->
Sentiment@1;
nil ->
+0.0
end.
-file("src/tastoids/taste.gleam", 205).
?DOC(" Returns the combined set of sentiment indices of a Taste\n").
-spec indices(taste(DZK)) -> gleam@set:set(DZK).
indices(Taste) ->
case Taste of
{tastes, Ts} ->
_pipe = Ts,
_pipe@1 = maps:keys(_pipe),
gleam@set:from_list(_pipe@1);
{taste, I, _} ->
gleam@set:from_list([I]);
nil ->
gleam@set:new()
end.
-file("src/tastoids/taste.gleam", 215).
?DOC(
" Returns a combined taste, where n taste indices become one set of its\n"
" indices, with its value representing the sum of their sentiments.\n"
).
-spec condense(taste(DZN)) -> taste(gleam@set:set(DZN)).
condense(Taste) ->
Sum = length(Taste),
{taste, indices(Taste), Sum}.