Current section
Files
Jump to
Current section
Files
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]).
-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"
" \n"
" AND i is an enumerable (countable) set of indices (ⅈ),\n"
" AND imbed: 𝔸(..) -> aᵢ is a bijective imbedding of 'a'\n"
" subject into 𝕍/ⅈ \n"
"\n"
" Then, 𝛂aᵢ ∈ 𝔸 are the set of all 'unit' `tastes` (scaled by 𝛂)\n"
).
-opaque taste(DTS) :: nil |
{taste, DTS, float()} |
{tastes, gleam@dict:dict(DTS, float())}.
-file("src/tastoids/taste.gleam", 44).
?DOC(" Return a singular of 'index', a la `Taste(index, 1.0)`\n").
-spec from_one(DTT) -> taste(DTT).
from_one(Index) ->
{taste, Index, 1.0}.
-file("src/tastoids/taste.gleam", 49).
?DOC(" Return a `Tastes(index)` consisting of the provided #(index, value: Float) tuples.\n").
-spec from_tuples(list({DTV, float()})) -> taste(DTV).
from_tuples(Indexed_tastes) ->
_pipe = maps:from_list(Indexed_tastes),
{tastes, _pipe}.
-file("src/tastoids/taste.gleam", 54).
?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", 59).
?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", 70).
?DOC(
" Scale the given tastes by its 'weight' (relative to its 'natural' values)\n"
" a la scalar multiplication.\n"
"\n"
" _Note from Avery: While this could be accomplished via a Tastoid's cardinality,\n"
" I wanted keep the notion of a signal's 'worth' (the _scale_ of its impression)\n"
" distinct from how many of them there are_\n"
).
-spec scale(taste(DUA), float()) -> taste(DUA).
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", 84).
?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", 90).
?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(DUF)) -> taste(DUF).
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", 114).
?DOC(
" Combine two tastes, linearly adding their sentiments (per index)\n"
" a la 'scalar addition'\n"
).
-spec add(taste(DUI), taste(DUI)) -> taste(DUI).
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", 155).
?DOC(" Returns the 'negative' of a taste (like <-> dislike)\n").
-spec negate(taste(DUM)) -> taste(DUM).
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.