Current section
Files
Jump to
Current section
Files
src/viva_math@common.erl
-module(viva_math@common).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/viva_math/common.gleam").
-export([clamp/3, clamp_unit/1, clamp_bipolar/1, lerp/3, inverse_lerp/3, sigmoid/2, sigmoid_standard/1, softmax/1, safe_div/3, smoothstep/3, exponential_decay/3]).
-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(
" Common mathematical utilities for VIVA.\n"
"\n"
" Functions not found in gleam_community_maths:\n"
" - clamp, lerp, sigmoid, softmax, safe_div\n"
).
-file("src/viva_math/common.gleam", 19).
?DOC(
" Clamp a value to a range [min, max].\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" clamp(5.0, 0.0, 10.0) // -> 5.0\n"
" clamp(-1.0, 0.0, 10.0) // -> 0.0\n"
" clamp(15.0, 0.0, 10.0) // -> 10.0\n"
" ```\n"
).
-spec clamp(float(), float(), float()) -> float().
clamp(Value, Min, Max) ->
_pipe = Value,
_pipe@1 = gleam@float:max(_pipe, Min),
gleam@float:min(_pipe@1, Max).
-file("src/viva_math/common.gleam", 34).
?DOC(
" Clamp a value to the unit interval [0, 1].\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" clamp_unit(0.5) // -> 0.5\n"
" clamp_unit(-0.5) // -> 0.0\n"
" clamp_unit(1.5) // -> 1.0\n"
" ```\n"
).
-spec clamp_unit(float()) -> float().
clamp_unit(Value) ->
clamp(Value, +0.0, 1.0).
-file("src/viva_math/common.gleam", 48).
?DOC(
" Clamp a value to the bipolar interval [-1, 1].\n"
" Used for PAD dimensions.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" clamp_bipolar(0.5) // -> 0.5\n"
" clamp_bipolar(-1.5) // -> -1.0\n"
" clamp_bipolar(1.5) // -> 1.0\n"
" ```\n"
).
-spec clamp_bipolar(float()) -> float().
clamp_bipolar(Value) ->
clamp(Value, -1.0, 1.0).
-file("src/viva_math/common.gleam", 64).
?DOC(
" Linear interpolation between two values.\n"
"\n"
" lerp(a, b, 0.0) = a\n"
" lerp(a, b, 1.0) = b\n"
" lerp(a, b, 0.5) = (a + b) / 2\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" lerp(0.0, 10.0, 0.5) // -> 5.0\n"
" lerp(0.0, 10.0, 0.25) // -> 2.5\n"
" ```\n"
).
-spec lerp(float(), float(), float()) -> float().
lerp(A, B, T) ->
A + (T * (B - A)).
-file("src/viva_math/common.gleam", 77).
?DOC(
" Inverse linear interpolation - find t given value in range [a, b].\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" inverse_lerp(0.0, 10.0, 5.0) // -> Ok(0.5)\n"
" inverse_lerp(0.0, 10.0, 2.5) // -> Ok(0.25)\n"
" inverse_lerp(0.0, 0.0, 5.0) // -> Error(Nil) (division by zero)\n"
" ```\n"
).
-spec inverse_lerp(float(), float(), float()) -> {ok, float()} | {error, nil}.
inverse_lerp(A, B, Value) ->
Range = B - A,
case Range =:= +0.0 of
true ->
{error, nil};
false ->
{ok, case Range of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> (Value - A) / Gleam@denominator
end}
end.
-file("src/viva_math/common.gleam", 97).
?DOC(
" Sigmoid function: 1 / (1 + exp(-k * x))\n"
"\n"
" Maps any real number to (0, 1).\n"
" k controls steepness (k=1 is standard sigmoid).\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" sigmoid(0.0, 1.0) // -> 0.5\n"
" sigmoid(100.0, 1.0) // -> ~1.0\n"
" sigmoid(-100.0, 1.0) // -> ~0.0\n"
" ```\n"
).
-spec sigmoid(float(), float()) -> float().
sigmoid(X, K) ->
Neg_kx = +0.0 - (K * X),
case (1.0 + gleam_community@maths:exponential(Neg_kx)) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> 1.0 / Gleam@denominator
end.
-file("src/viva_math/common.gleam", 103).
?DOC(" Standard sigmoid with k=1.\n").
-spec sigmoid_standard(float()) -> float().
sigmoid_standard(X) ->
sigmoid(X, 1.0).
-file("src/viva_math/common.gleam", 118).
?DOC(
" Softmax function: converts a list of values to probabilities.\n"
"\n"
" softmax([x1, x2, ...]) = [exp(x1)/sum, exp(x2)/sum, ...]\n"
" where sum = exp(x1) + exp(x2) + ...\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" softmax([1.0, 2.0, 3.0]) // -> [0.09, 0.24, 0.67] (approx)\n"
" softmax([0.0, 0.0]) // -> [0.5, 0.5]\n"
" ```\n"
).
-spec softmax(list(float())) -> {ok, list(float())} | {error, nil}.
softmax(Values) ->
case Values of
[] ->
{error, nil};
_ ->
Max_val = gleam@list:fold(Values, +0.0, fun gleam@float:max/2),
Exps = gleam@list:map(
Values,
fun(X) -> gleam_community@maths:exponential(X - Max_val) end
),
Sum = gleam@list:fold(Exps, +0.0, fun(Acc, X@1) -> Acc + X@1 end),
case Sum =:= +0.0 of
true ->
{error, nil};
false ->
{ok, gleam@list:map(Exps, fun(X@2) -> case Sum of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> X@2 / Gleam@denominator
end end)}
end
end.
-file("src/viva_math/common.gleam", 147).
?DOC(
" Safe division with default value on division by zero.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" safe_div(10.0, 2.0, 0.0) // -> 5.0\n"
" safe_div(10.0, 0.0, -1.0) // -> -1.0\n"
" ```\n"
).
-spec safe_div(float(), float(), float()) -> float().
safe_div(A, B, Default) ->
case B =:= +0.0 of
true ->
Default;
false ->
case B of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> A / Gleam@denominator
end
end.
-file("src/viva_math/common.gleam", 164).
?DOC(
" Smooth step function (Hermite interpolation).\n"
" Returns 0 if x < edge0, 1 if x > edge1, smooth transition otherwise.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" smoothstep(0.0, 1.0, 0.5) // -> 0.5 (roughly)\n"
" smoothstep(0.0, 1.0, 0.0) // -> 0.0\n"
" smoothstep(0.0, 1.0, 1.0) // -> 1.0\n"
" ```\n"
).
-spec smoothstep(float(), float(), float()) -> float().
smoothstep(Edge0, Edge1, X) ->
T = clamp_unit(case (Edge1 - Edge0) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> (X - Edge0) / Gleam@denominator
end),
(T * T) * (3.0 - (2.0 * T)).
-file("src/viva_math/common.gleam", 177).
?DOC(
" Exponential decay: value * exp(-rate * time)\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" exponential_decay(1.0, 0.5, 1.0) // -> ~0.606\n"
" exponential_decay(1.0, 0.0, 10.0) // -> 1.0 (no decay)\n"
" ```\n"
).
-spec exponential_decay(float(), float(), float()) -> float().
exponential_decay(Value, Rate, Time) ->
Neg_rt = +0.0 - (Rate * Time),
Value * gleam_community@maths:exponential(Neg_rt).