Current section
Files
Jump to
Current section
Files
src/viva_math@vecn.erl
-module(viva_math@vecn).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/viva_math/vecn.gleam").
-export([zeros/1, ones/1, splat/2, add/2, sub/2, multiply/2, scale/2, add_scalar/2, dot/2, length_squared/1, length/1, distance/2, normalize/1, negate/1, clamp/3, lerp/3, sum/1, mean/1, zip_with/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(
" N-dimensional vectors as `List(Float)`.\n"
"\n"
" Pure functional, no NIF, no broadcasting beyond scalar/vector. For heavy\n"
" linear algebra, defer to `viva_tensor`.\n"
"\n"
" Most functions return `Result` when shapes mismatch.\n"
).
-file("src/viva_math/vecn.gleam", 14).
-spec zeros(integer()) -> list(float()).
zeros(N) ->
gleam@list:repeat(+0.0, N).
-file("src/viva_math/vecn.gleam", 18).
-spec ones(integer()) -> list(float()).
ones(N) ->
gleam@list:repeat(1.0, N).
-file("src/viva_math/vecn.gleam", 22).
-spec splat(float(), integer()) -> list(float()).
splat(Value, N) ->
gleam@list:repeat(Value, N).
-file("src/viva_math/vecn.gleam", 27).
?DOC(" Element-wise add. Errors on length mismatch.\n").
-spec add(list(float()), list(float())) -> {ok, list(float())} | {error, nil}.
add(A, B) ->
case erlang:length(A) =:= erlang:length(B) of
false ->
{error, nil};
true ->
{ok,
gleam@list:map(
gleam@list:zip(A, B),
fun(P) -> erlang:element(1, P) + erlang:element(2, P) end
)}
end.
-file("src/viva_math/vecn.gleam", 34).
-spec sub(list(float()), list(float())) -> {ok, list(float())} | {error, nil}.
sub(A, B) ->
case erlang:length(A) =:= erlang:length(B) of
false ->
{error, nil};
true ->
{ok,
gleam@list:map(
gleam@list:zip(A, B),
fun(P) -> erlang:element(1, P) - erlang:element(2, P) end
)}
end.
-file("src/viva_math/vecn.gleam", 41).
-spec multiply(list(float()), list(float())) -> {ok, list(float())} |
{error, nil}.
multiply(A, B) ->
case erlang:length(A) =:= erlang:length(B) of
false ->
{error, nil};
true ->
{ok,
gleam@list:map(
gleam@list:zip(A, B),
fun(P) -> erlang:element(1, P) * erlang:element(2, P) end
)}
end.
-file("src/viva_math/vecn.gleam", 49).
?DOC(" Scalar multiplication.\n").
-spec scale(list(float()), float()) -> list(float()).
scale(V, S) ->
gleam@list:map(V, fun(X) -> X * S end).
-file("src/viva_math/vecn.gleam", 53).
-spec add_scalar(list(float()), float()) -> list(float()).
add_scalar(V, S) ->
gleam@list:map(V, fun(X) -> X + S end).
-file("src/viva_math/vecn.gleam", 57).
-spec dot(list(float()), list(float())) -> {ok, float()} | {error, nil}.
dot(A, B) ->
case erlang:length(A) =:= erlang:length(B) of
false ->
{error, nil};
true ->
{ok,
gleam@list:fold(
gleam@list:zip(A, B),
+0.0,
fun(Acc, P) ->
Acc + (erlang:element(1, P) * erlang:element(2, P))
end
)}
end.
-file("src/viva_math/vecn.gleam", 64).
-spec length_squared(list(float())) -> float().
length_squared(V) ->
gleam@list:fold(V, +0.0, fun(Acc, X) -> Acc + (X * X) end).
-file("src/viva_math/vecn.gleam", 77).
-spec length_hypot(list(float()), float()) -> float().
length_hypot(Rest, Acc) ->
case Rest of
[] ->
Acc;
[X | Tail] ->
length_hypot(Tail, viva_math@scalar:hypot(Acc, X))
end.
-file("src/viva_math/vecn.gleam", 69).
?DOC(" Length using progressive `hypot` reduction to avoid overflow.\n").
-spec length(list(float())) -> float().
length(V) ->
case V of
[] ->
+0.0;
[X] ->
viva_math@scalar:safe_sqrt(X * X);
[A, B | Rest] ->
length_hypot(Rest, viva_math@scalar:hypot(A, B))
end.
-file("src/viva_math/vecn.gleam", 84).
-spec distance(list(float()), list(float())) -> {ok, float()} | {error, nil}.
distance(A, B) ->
case sub(A, B) of
{ok, Diff} ->
{ok, length(Diff)};
{error, _} ->
{error, nil}
end.
-file("src/viva_math/vecn.gleam", 91).
-spec normalize(list(float())) -> list(float()).
normalize(V) ->
L = length(V),
case L =:= +0.0 of
true ->
V;
false ->
scale(V, case L of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> 1.0 / Gleam@denominator
end)
end.
-file("src/viva_math/vecn.gleam", 99).
-spec negate(list(float())) -> list(float()).
negate(V) ->
gleam@list:map(V, fun(X) -> +0.0 - X end).
-file("src/viva_math/vecn.gleam", 103).
-spec clamp(list(float()), float(), float()) -> list(float()).
clamp(V, Lo, Hi) ->
gleam@list:map(V, fun(X) -> viva_math@scalar:clamp(X, Lo, Hi) end).
-file("src/viva_math/vecn.gleam", 107).
-spec lerp(list(float()), list(float()), float()) -> {ok, list(float())} |
{error, nil}.
lerp(A, B, T) ->
case erlang:length(A) =:= erlang:length(B) of
false ->
{error, nil};
true ->
{ok,
gleam@list:map(
gleam@list:zip(A, B),
fun(P) ->
viva_math@scalar:lerp(
erlang:element(1, P),
erlang:element(2, P),
T
)
end
)}
end.
-file("src/viva_math/vecn.gleam", 114).
-spec sum(list(float())) -> float().
sum(V) ->
gleam@list:fold(V, +0.0, fun(Acc, X) -> Acc + X end).
-file("src/viva_math/vecn.gleam", 118).
-spec mean(list(float())) -> {ok, float()} | {error, nil}.
mean(V) ->
case V of
[] ->
{error, nil};
_ ->
{ok, case erlang:float(erlang:length(V)) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> sum(V) / Gleam@denominator
end}
end.
-file("src/viva_math/vecn.gleam", 126).
?DOC(" Component-wise zip with a custom binary function.\n").
-spec zip_with(list(float()), list(float()), fun((float(), float()) -> float())) -> {ok,
list(float())} |
{error, nil}.
zip_with(A, B, F) ->
case erlang:length(A) =:= erlang:length(B) of
false ->
{error, nil};
true ->
{ok,
gleam@list:map(
gleam@list:zip(A, B),
fun(P) -> F(erlang:element(1, P), erlang:element(2, P)) end
)}
end.