Current section

Files

Jump to
viva_tensor src viva_tensor@core@ops.erl
Raw

src/viva_tensor@core@ops.erl

-module(viva_tensor@core@ops).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/viva_tensor/core/ops.gleam").
-export([map/2, map_indexed/2, add/2, sub/2, mul/2, 'div'/2, scale/2, add_scalar/2, negate/1, abs/1, square/1, sqrt/1, exp/1, log/1, pow/2, sum/1, product/1, mean/1, max/1, min/1, argmax/1, argmin/1, variance/1, std/1, norm/1, normalize/1, dot/2, matmul_vec/2, matmul/2, dot_fast/2, matmul_fast/2, dot_auto/2, matmul_auto/2, backend_info/0, all_backends_info/0, sum_auto/1, add_auto/2, sub_auto/2, mul_auto/2, scale_auto/2, transpose/1, outer/2, clamp/3, relu/1, sigmoid/1, tanh/1, softmax/1, softmax_axis/2, can_broadcast/2, broadcast_shape/2, broadcast_to/2, add_broadcast/2, sub_broadcast/2, mul_broadcast/2, div_broadcast/2]).
-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(false).
-file("src/viva_tensor/core/ops.gleam", 27).
?DOC(false).
-spec map(viva_tensor@core@tensor:tensor(), fun((float()) -> float())) -> viva_tensor@core@tensor:tensor().
map(T, F) ->
Data = viva_tensor@core@tensor:to_list(T),
New_data = gleam@list:map(Data, F),
case viva_tensor@core@tensor:new(New_data, viva_tensor@core@tensor:shape(T)) of
{ok, Result} ->
Result;
{error, _} ->
T
end.
-file("src/viva_tensor/core/ops.gleam", 37).
?DOC(false).
-spec map_indexed(
viva_tensor@core@tensor:tensor(),
fun((float(), integer()) -> float())
) -> viva_tensor@core@tensor:tensor().
map_indexed(T, F) ->
Data = viva_tensor@core@tensor:to_list(T),
New_data = gleam@list:index_map(Data, fun(X, I) -> F(X, I) end),
case viva_tensor@core@tensor:new(New_data, viva_tensor@core@tensor:shape(T)) of
{ok, Result} ->
Result;
{error, _} ->
T
end.
-file("src/viva_tensor/core/ops.gleam", 47).
?DOC(false).
-spec add(viva_tensor@core@tensor:tensor(), viva_tensor@core@tensor:tensor()) -> {ok,
viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
add(A, B) ->
case viva_tensor@core@tensor:shape(A) =:= viva_tensor@core@tensor:shape(B) of
true ->
A_data = viva_tensor@core@tensor:to_list(A),
B_data = viva_tensor@core@tensor:to_list(B),
Data = gleam@list:map2(A_data, B_data, fun(X, Y) -> X + Y end),
viva_tensor@core@tensor:new(Data, viva_tensor@core@tensor:shape(A));
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 60).
?DOC(false).
-spec sub(viva_tensor@core@tensor:tensor(), viva_tensor@core@tensor:tensor()) -> {ok,
viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
sub(A, B) ->
case viva_tensor@core@tensor:shape(A) =:= viva_tensor@core@tensor:shape(B) of
true ->
A_data = viva_tensor@core@tensor:to_list(A),
B_data = viva_tensor@core@tensor:to_list(B),
Data = gleam@list:map2(A_data, B_data, fun(X, Y) -> X - Y end),
viva_tensor@core@tensor:new(Data, viva_tensor@core@tensor:shape(A));
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 73).
?DOC(false).
-spec mul(viva_tensor@core@tensor:tensor(), viva_tensor@core@tensor:tensor()) -> {ok,
viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
mul(A, B) ->
case viva_tensor@core@tensor:shape(A) =:= viva_tensor@core@tensor:shape(B) of
true ->
A_data = viva_tensor@core@tensor:to_list(A),
B_data = viva_tensor@core@tensor:to_list(B),
Data = gleam@list:map2(A_data, B_data, fun(X, Y) -> X * Y end),
viva_tensor@core@tensor:new(Data, viva_tensor@core@tensor:shape(A));
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 86).
?DOC(false).
-spec 'div'(viva_tensor@core@tensor:tensor(), viva_tensor@core@tensor:tensor()) -> {ok,
viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
'div'(A, B) ->
case viva_tensor@core@tensor:shape(A) =:= viva_tensor@core@tensor:shape(B) of
true ->
A_data = viva_tensor@core@tensor:to_list(A),
B_data = viva_tensor@core@tensor:to_list(B),
Data = gleam@list:map2(A_data, B_data, fun(X, Y) -> case Y of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> X / Gleam@denominator
end end),
viva_tensor@core@tensor:new(Data, viva_tensor@core@tensor:shape(A));
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 99).
?DOC(false).
-spec scale(viva_tensor@core@tensor:tensor(), float()) -> viva_tensor@core@tensor:tensor().
scale(T, S) ->
map(T, fun(X) -> X * S end).
-file("src/viva_tensor/core/ops.gleam", 104).
?DOC(false).
-spec add_scalar(viva_tensor@core@tensor:tensor(), float()) -> viva_tensor@core@tensor:tensor().
add_scalar(T, S) ->
map(T, fun(X) -> X + S end).
-file("src/viva_tensor/core/ops.gleam", 109).
?DOC(false).
-spec negate(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
negate(T) ->
scale(T, -1.0).
-file("src/viva_tensor/core/ops.gleam", 114).
?DOC(false).
-spec abs(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
abs(T) ->
map(T, fun(X) -> viva_tensor@core@ffi:abs(X) end).
-file("src/viva_tensor/core/ops.gleam", 119).
?DOC(false).
-spec square(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
square(T) ->
map(T, fun(X) -> X * X end).
-file("src/viva_tensor/core/ops.gleam", 124).
?DOC(false).
-spec sqrt(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
sqrt(T) ->
map(T, fun(X) -> viva_tensor@core@ffi:sqrt(X) end).
-file("src/viva_tensor/core/ops.gleam", 129).
?DOC(false).
-spec exp(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
exp(T) ->
map(T, fun(X) -> viva_tensor@core@ffi:exp(X) end).
-file("src/viva_tensor/core/ops.gleam", 134).
?DOC(false).
-spec log(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
log(T) ->
map(T, fun(X) -> viva_tensor@core@ffi:log(X) end).
-file("src/viva_tensor/core/ops.gleam", 139).
?DOC(false).
-spec pow(viva_tensor@core@tensor:tensor(), float()) -> viva_tensor@core@tensor:tensor().
pow(T, Exponent) ->
map(T, fun(X) -> viva_tensor@core@ffi:pow(X, Exponent) end).
-file("src/viva_tensor/core/ops.gleam", 153).
?DOC(false).
-spec sum(viva_tensor@core@tensor:tensor()) -> float().
sum(T) ->
Data = viva_tensor@core@tensor:to_list(T),
gleam@list:fold(Data, +0.0, fun(Acc, X) -> Acc + X end).
-file("src/viva_tensor/core/ops.gleam", 159).
?DOC(false).
-spec product(viva_tensor@core@tensor:tensor()) -> float().
product(T) ->
Data = viva_tensor@core@tensor:to_list(T),
gleam@list:fold(Data, 1.0, fun(Acc, X) -> Acc * X end).
-file("src/viva_tensor/core/ops.gleam", 165).
?DOC(false).
-spec mean(viva_tensor@core@tensor:tensor()) -> float().
mean(T) ->
S = sum(T),
N = erlang:float(viva_tensor@core@tensor:size(T)),
case N > +0.0 of
true ->
case N of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> S / Gleam@denominator
end;
false ->
+0.0
end.
-file("src/viva_tensor/core/ops.gleam", 175).
?DOC(false).
-spec max(viva_tensor@core@tensor:tensor()) -> float().
max(T) ->
Data = viva_tensor@core@tensor:to_list(T),
case Data of
[] ->
+0.0;
[First | Rest] ->
gleam@list:fold(
Rest,
First,
fun(Acc, X) -> gleam@float:max(Acc, X) end
)
end.
-file("src/viva_tensor/core/ops.gleam", 184).
?DOC(false).
-spec min(viva_tensor@core@tensor:tensor()) -> float().
min(T) ->
Data = viva_tensor@core@tensor:to_list(T),
case Data of
[] ->
+0.0;
[First | Rest] ->
gleam@list:fold(
Rest,
First,
fun(Acc, X) -> gleam@float:min(Acc, X) end
)
end.
-file("src/viva_tensor/core/ops.gleam", 193).
?DOC(false).
-spec argmax(viva_tensor@core@tensor:tensor()) -> integer().
argmax(T) ->
Data = viva_tensor@core@tensor:to_list(T),
case Data of
[] ->
0;
[First | Rest] ->
{Idx, _, _} = gleam@list:fold(
Rest,
{0, First, 1},
fun(Acc, X) ->
{Best_idx, Best_val, Curr_idx} = Acc,
case X > Best_val of
true ->
{Curr_idx, X, Curr_idx + 1};
false ->
{Best_idx, Best_val, Curr_idx + 1}
end
end
),
Idx
end.
-file("src/viva_tensor/core/ops.gleam", 213).
?DOC(false).
-spec argmin(viva_tensor@core@tensor:tensor()) -> integer().
argmin(T) ->
Data = viva_tensor@core@tensor:to_list(T),
case Data of
[] ->
0;
[First | Rest] ->
{Idx, _, _} = gleam@list:fold(
Rest,
{0, First, 1},
fun(Acc, X) ->
{Best_idx, Best_val, Curr_idx} = Acc,
case X < Best_val of
true ->
{Curr_idx, X, Curr_idx + 1};
false ->
{Best_idx, Best_val, Curr_idx + 1}
end
end
),
Idx
end.
-file("src/viva_tensor/core/ops.gleam", 232).
?DOC(false).
-spec variance(viva_tensor@core@tensor:tensor()) -> float().
variance(T) ->
Data = viva_tensor@core@tensor:to_list(T),
N = erlang:float(viva_tensor@core@tensor:size(T)),
case N > +0.0 of
true ->
{Total, Total_sq} = gleam@list:fold(
Data,
{+0.0, +0.0},
fun(Acc, X) ->
{S, Sq} = Acc,
{S + X, Sq + (X * X)}
end
),
M = case N of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> Total / Gleam@denominator
end,
(case N of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator@1 -> Total_sq / Gleam@denominator@1
end) - (M * M);
false ->
+0.0
end.
-file("src/viva_tensor/core/ops.gleam", 251).
?DOC(false).
-spec std(viva_tensor@core@tensor:tensor()) -> float().
std(T) ->
viva_tensor@core@ffi:sqrt(variance(T)).
-file("src/viva_tensor/core/ops.gleam", 256).
?DOC(false).
-spec norm(viva_tensor@core@tensor:tensor()) -> float().
norm(T) ->
Data = viva_tensor@core@tensor:to_list(T),
Sum_sq = gleam@list:fold(Data, +0.0, fun(Acc, X) -> Acc + (X * X) end),
viva_tensor@core@ffi:sqrt(Sum_sq).
-file("src/viva_tensor/core/ops.gleam", 263).
?DOC(false).
-spec normalize(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
normalize(T) ->
N = norm(T),
case N > 0.0001 of
true ->
scale(T, case N of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> 1.0 / Gleam@denominator
end);
false ->
T
end.
-file("src/viva_tensor/core/ops.gleam", 279).
?DOC(false).
-spec dot(viva_tensor@core@tensor:tensor(), viva_tensor@core@tensor:tensor()) -> {ok,
float()} |
{error, viva_tensor@core@error:tensor_error()}.
dot(A, B) ->
case ((viva_tensor@core@tensor:rank(A) =:= 1) andalso (viva_tensor@core@tensor:rank(
B
)
=:= 1))
andalso (viva_tensor@core@tensor:size(A) =:= viva_tensor@core@tensor:size(B)) of
true ->
A_data = viva_tensor@core@tensor:to_list(A),
B_data = viva_tensor@core@tensor:to_list(B),
Products = gleam@list:map2(A_data, B_data, fun(X, Y) -> X * Y end),
{ok,
gleam@list:fold(Products, +0.0, fun(Acc, X@1) -> Acc + X@1 end)};
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 994).
?DOC(false).
-spec range_loop(integer(), integer(), list(integer())) -> list(integer()).
range_loop(From, To, Acc) ->
case From > To of
true ->
lists:reverse(Acc);
false ->
range_loop(From + 1, To, [From | Acc])
end.
-file("src/viva_tensor/core/ops.gleam", 990).
?DOC(false).
-spec range_int(integer(), integer()) -> list(integer()).
range_int(From, To) ->
range_loop(From, To, []).
-file("src/viva_tensor/core/ops.gleam", 298).
?DOC(false).
-spec matmul_vec(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
matmul_vec(Mat, Vec) ->
case {viva_tensor@core@tensor:shape(Mat),
viva_tensor@core@tensor:shape(Vec)} of
{[M, N], [Vec_n]} when N =:= Vec_n ->
Mat_arr = viva_tensor@core@ffi:list_to_array(
viva_tensor@core@tensor:to_list(Mat)
),
Vec_arr = viva_tensor@core@ffi:list_to_array(
viva_tensor@core@tensor:to_list(Vec)
),
Result_data = begin
_pipe = range_int(0, M - 1),
gleam@list:map(
_pipe,
fun(Row_idx) ->
Start = Row_idx * N,
_pipe@1 = range_int(0, N - 1),
gleam@list:fold(
_pipe@1,
+0.0,
fun(Acc, K) ->
Acc + (viva_tensor@core@ffi:array_get(
Mat_arr,
Start + K
)
* viva_tensor@core@ffi:array_get(Vec_arr, K))
end
)
end
)
end,
viva_tensor@core@tensor:new(Result_data, [M]);
{[_, N@1], [Vec_n@1]} ->
{error, {shape_mismatch, [N@1], [Vec_n@1]}};
{_, _} ->
{error, {dimension_error, <<"Expected matrix and vector"/utf8>>}}
end.
-file("src/viva_tensor/core/ops.gleam", 326).
?DOC(false).
-spec matmul(viva_tensor@core@tensor:tensor(), viva_tensor@core@tensor:tensor()) -> {ok,
viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
matmul(A, B) ->
case {viva_tensor@core@tensor:shape(A), viva_tensor@core@tensor:shape(B)} of
{[M, N], [N2, P]} when N =:= N2 ->
A_arr = viva_tensor@core@ffi:list_to_array(
viva_tensor@core@tensor:to_list(A)
),
B_arr = viva_tensor@core@ffi:list_to_array(
viva_tensor@core@tensor:to_list(B)
),
Result_data = begin
_pipe = range_int(0, M - 1),
gleam@list:flat_map(
_pipe,
fun(I) ->
Row_start = I * N,
_pipe@1 = range_int(0, P - 1),
gleam@list:map(
_pipe@1,
fun(J) -> _pipe@2 = range_int(0, N - 1),
gleam@list:fold(
_pipe@2,
+0.0,
fun(Acc, K) ->
Acc + (viva_tensor@core@ffi:array_get(
A_arr,
Row_start + K
)
* viva_tensor@core@ffi:array_get(
B_arr,
(K * P) + J
))
end
) end
)
end
)
end,
viva_tensor@core@tensor:new(Result_data, [M, P]);
{[_, N@1], [N2@1, _]} ->
{error, {shape_mismatch, [N@1, -1], [N2@1, -1]}};
{_, _} ->
{error, {dimension_error, <<"Expected two matrices"/utf8>>}}
end.
-file("src/viva_tensor/core/ops.gleam", 357).
?DOC(false).
-spec dot_fast(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}.
dot_fast(A, B) ->
case ((viva_tensor@core@tensor:rank(A) =:= 1) andalso (viva_tensor@core@tensor:rank(
B
)
=:= 1))
andalso (viva_tensor@core@tensor:size(A) =:= viva_tensor@core@tensor:size(B)) of
true ->
A_arr = viva_tensor@core@ffi:list_to_array(
viva_tensor@core@tensor:to_list(A)
),
B_arr = viva_tensor@core@ffi:list_to_array(
viva_tensor@core@tensor:to_list(B)
),
{ok, viva_tensor@core@ffi:array_dot(A_arr, B_arr)};
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 373).
?DOC(false).
-spec matmul_fast(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
matmul_fast(A, B) ->
case {viva_tensor@core@tensor:shape(A), viva_tensor@core@tensor:shape(B)} of
{[M, K], [K2, N]} when K =:= K2 ->
A_arr = viva_tensor@core@ffi:list_to_array(
viva_tensor@core@tensor:to_list(A)
),
B_arr = viva_tensor@core@ffi:list_to_array(
viva_tensor@core@tensor:to_list(B)
),
Result_arr = viva_tensor@core@ffi:array_matmul(
A_arr,
B_arr,
M,
N,
K
),
Result_list = viva_tensor@core@ffi:array_to_list(Result_arr),
viva_tensor@core@tensor:new(Result_list, [M, N]);
{[_, K@1], [K2@1, _]} ->
{error, {shape_mismatch, [K@1, -1], [K2@1, -1]}};
{_, _} ->
{error, {dimension_error, <<"Expected two matrices"/utf8>>}}
end.
-file("src/viva_tensor/core/ops.gleam", 448).
?DOC(false).
-spec dot_with_zig_fallback(
list(float()),
list(float()),
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {{ok, float()} | {error, viva_tensor@core@error:tensor_error()}, binary()}.
dot_with_zig_fallback(A_list, B_list, A, B) ->
case viva_tensor@core@ffi:zig_is_loaded() of
true ->
case viva_tensor@core@ffi:zig_dot(A_list, B_list) of
{ok, R} ->
{{ok, R}, <<"zig"/utf8>>};
{error, _} ->
{dot_fast(A, B), <<"erlang"/utf8>>}
end;
false ->
{dot_fast(A, B), <<"erlang"/utf8>>}
end.
-file("src/viva_tensor/core/ops.gleam", 429).
?DOC(false).
-spec dot_list_fallback(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {{ok, float()} | {error, viva_tensor@core@error:tensor_error()}, binary()}.
dot_list_fallback(A, B) ->
case {viva_tensor@core@tensor:try_to_list(A),
viva_tensor@core@tensor:try_to_list(B)} of
{{ok, A_list}, {ok, B_list}} ->
case viva_tensor@core@ffi:is_nif_loaded() of
true ->
case viva_tensor@core@ffi:nif_dot(A_list, B_list) of
{ok, R} ->
{{ok, R}, <<"accelerate"/utf8>>};
{error, _} ->
dot_with_zig_fallback(A_list, B_list, A, B)
end;
false ->
dot_with_zig_fallback(A_list, B_list, A, B)
end;
{{error, E}, _} ->
{{error, E}, <<"materialize"/utf8>>};
{_, {error, E@1}} ->
{{error, E@1}, <<"materialize"/utf8>>}
end.
-file("src/viva_tensor/core/ops.gleam", 405).
?DOC(false).
-spec dot_auto(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}.
dot_auto(A, B) ->
case ((viva_tensor@core@tensor:rank(A) =:= 1) andalso (viva_tensor@core@tensor:rank(
B
)
=:= 1))
andalso (viva_tensor@core@tensor:size(A) =:= viva_tensor@core@tensor:size(B)) of
true ->
T0 = viva_tensor@core@ffi:now_microseconds(),
{Result, Backend} = case {viva_tensor@core@tensor:native_ref(A),
viva_tensor@core@tensor:native_ref(B)} of
{{ok, Ref_a}, {ok, Ref_b}} ->
case viva_tensor@core@ffi:nt_dot(Ref_a, Ref_b) of
{ok, R} ->
{{ok, R}, <<"native"/utf8>>};
{error, _} ->
dot_list_fallback(A, B)
end;
{_, _} ->
dot_list_fallback(A, B)
end,
viva_tensor@observability@telemetry:record_dot(
viva_tensor@core@tensor:size(A),
viva_tensor@core@ffi:now_microseconds() - T0,
Backend
),
Result;
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 511).
?DOC(false).
-spec matmul_with_zig_fallback(
list(float()),
list(float()),
integer(),
integer(),
integer(),
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {{ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()},
binary()}.
matmul_with_zig_fallback(A_list, B_list, M, N, K, A, B) ->
case viva_tensor@core@ffi:zig_is_loaded() of
true ->
case viva_tensor@core@ffi:zig_matmul(A_list, B_list, M, N, K) of
{ok, Result_list} ->
{viva_tensor@core@tensor:new(Result_list, [M, N]),
<<"zig"/utf8>>};
{error, _} ->
{matmul_fast(A, B), <<"erlang"/utf8>>}
end;
false ->
{matmul_fast(A, B), <<"erlang"/utf8>>}
end.
-file("src/viva_tensor/core/ops.gleam", 489).
?DOC(false).
-spec matmul_list_fallback(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor(),
integer(),
integer(),
integer()
) -> {{ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()},
binary()}.
matmul_list_fallback(A, B, M, N, K) ->
case {viva_tensor@core@tensor:try_to_list(A),
viva_tensor@core@tensor:try_to_list(B)} of
{{ok, A_list}, {ok, B_list}} ->
case viva_tensor@core@ffi:is_nif_loaded() of
true ->
case viva_tensor@core@ffi:nif_matmul(
A_list,
B_list,
M,
N,
K
) of
{ok, Result_list} ->
{viva_tensor@core@tensor:new(Result_list, [M, N]),
<<"accelerate"/utf8>>};
{error, _} ->
matmul_with_zig_fallback(
A_list,
B_list,
M,
N,
K,
A,
B
)
end;
false ->
matmul_with_zig_fallback(A_list, B_list, M, N, K, A, B)
end;
{{error, E}, _} ->
{{error, E}, <<"materialize"/utf8>>};
{_, {error, E@1}} ->
{{error, E@1}, <<"materialize"/utf8>>}
end.
-file("src/viva_tensor/core/ops.gleam", 468).
?DOC(false).
-spec matmul_auto(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
matmul_auto(A, B) ->
case {viva_tensor@core@tensor:shape(A), viva_tensor@core@tensor:shape(B)} of
{[M, K], [K2, N]} when K =:= K2 ->
T0 = viva_tensor@core@ffi:now_microseconds(),
{Result, Backend} = case {viva_tensor@core@tensor:native_ref(A),
viva_tensor@core@tensor:native_ref(B)} of
{{ok, Ref_a}, {ok, Ref_b}} ->
case viva_tensor@core@ffi:nt_matmul(Ref_a, Ref_b, M, N, K) of
{ok, Ref_c} ->
{{ok,
viva_tensor@core@tensor:from_native_ref(
Ref_c,
[M, N]
)},
<<"native"/utf8>>};
{error, _} ->
matmul_list_fallback(A, B, M, N, K)
end;
{_, _} ->
matmul_list_fallback(A, B, M, N, K)
end,
viva_tensor@observability@telemetry:record_matmul(
M,
N,
K,
viva_tensor@core@ffi:now_microseconds() - T0,
Backend
),
Result;
{[_, K@1], [K2@1, _]} ->
{error, {shape_mismatch, [K@1, -1], [K2@1, -1]}};
{_, _} ->
{error, {dimension_error, <<"Expected two matrices"/utf8>>}}
end.
-file("src/viva_tensor/core/ops.gleam", 534).
?DOC(false).
-spec backend_info() -> binary().
backend_info() ->
case viva_tensor@core@ffi:zig_is_loaded() of
true ->
<<(viva_tensor@core@ffi:zig_backend_info())/binary,
" + NIF Resources"/utf8>>;
false ->
case viva_tensor@core@ffi:is_nif_loaded() of
true ->
viva_tensor@core@ffi:nif_backend_info();
false ->
<<"Pure Erlang (O(1) array access)"/utf8>>
end
end.
-file("src/viva_tensor/core/ops.gleam", 546).
?DOC(false).
-spec all_backends_info() -> binary().
all_backends_info() ->
Zig_status = case viva_tensor@core@ffi:zig_is_loaded() of
true ->
<<"✓ "/utf8, (viva_tensor@core@ffi:zig_backend_info())/binary>>;
false ->
<<"✗ Not available"/utf8>>
end,
Accel_status = case viva_tensor@core@ffi:is_nif_loaded() of
true ->
<<"✓ "/utf8, (viva_tensor@core@ffi:nif_backend_info())/binary>>;
false ->
<<"✗ Not available"/utf8>>
end,
<<<<<<<<"Zig SIMD: "/utf8, Zig_status/binary>>/binary,
"\nApple Accelerate: "/utf8>>/binary,
Accel_status/binary>>/binary,
"\nPure Erlang: ✓ Always available"/utf8>>.
-file("src/viva_tensor/core/ops.gleam", 592).
?DOC(false).
-spec sum_with_accel_fallback(list(float())) -> float().
sum_with_accel_fallback(Data) ->
case viva_tensor@core@ffi:is_nif_loaded() of
true ->
case viva_tensor@core@ffi:nif_sum(Data) of
{ok, Result} ->
Result;
{error, _} ->
gleam@list:fold(Data, +0.0, fun(Acc, X) -> Acc + X end)
end;
false ->
gleam@list:fold(Data, +0.0, fun(Acc@1, X@1) -> Acc@1 + X@1 end)
end.
-file("src/viva_tensor/core/ops.gleam", 580).
?DOC(false).
-spec sum_list_fallback(viva_tensor@core@tensor:tensor()) -> float().
sum_list_fallback(T) ->
Data = viva_tensor@core@tensor:to_list(T),
case viva_tensor@core@ffi:zig_is_loaded() of
true ->
case viva_tensor@core@ffi:zig_sum(Data) of
{ok, R} ->
R;
{error, _} ->
sum_with_accel_fallback(Data)
end;
false ->
sum_with_accel_fallback(Data)
end.
-file("src/viva_tensor/core/ops.gleam", 565).
?DOC(false).
-spec sum_auto(viva_tensor@core@tensor:tensor()) -> float().
sum_auto(T) ->
T0 = viva_tensor@core@ffi:now_microseconds(),
Result = case viva_tensor@core@tensor:native_ref(T) of
{ok, Ref} ->
case viva_tensor@core@ffi:nt_sum(Ref) of
{ok, R} ->
R;
{error, _} ->
sum_list_fallback(T)
end;
{error, _} ->
sum_list_fallback(T)
end,
viva_tensor@observability@telemetry:record_op(
<<"sum"/utf8>>,
viva_tensor@core@ffi:now_microseconds() - T0
),
Result.
-file("src/viva_tensor/core/ops.gleam", 620).
?DOC(false).
-spec add_list_fallback(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
add_list_fallback(A, B) ->
gleam@result:'try'(
viva_tensor@core@tensor:try_to_list(A),
fun(A_data) ->
gleam@result:'try'(
viva_tensor@core@tensor:try_to_list(B),
fun(B_data) ->
Result_data = case viva_tensor@core@ffi:zig_is_loaded() of
true ->
case viva_tensor@core@ffi:zig_add(A_data, B_data) of
{ok, R} ->
R;
{error, _} ->
gleam@list:map2(
A_data,
B_data,
fun(X, Y) -> X + Y end
)
end;
false ->
gleam@list:map2(
A_data,
B_data,
fun(X@1, Y@1) -> X@1 + Y@1 end
)
end,
viva_tensor@core@tensor:new(
Result_data,
viva_tensor@core@tensor:shape(A)
)
end
)
end
).
-file("src/viva_tensor/core/ops.gleam", 605).
?DOC(false).
-spec add_auto(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
add_auto(A, B) ->
case viva_tensor@core@tensor:shape(A) =:= viva_tensor@core@tensor:shape(B) of
true ->
case {viva_tensor@core@tensor:native_ref(A),
viva_tensor@core@tensor:native_ref(B)} of
{{ok, Ref_a}, {ok, Ref_b}} ->
case viva_tensor@core@ffi:nt_add(Ref_a, Ref_b) of
{ok, Ref_c} ->
{ok,
viva_tensor@core@tensor:from_native_ref(
Ref_c,
viva_tensor@core@tensor:shape(A)
)};
{error, _} ->
add_list_fallback(A, B)
end;
{_, _} ->
add_list_fallback(A, B)
end;
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 650).
?DOC(false).
-spec sub_list_fallback(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
sub_list_fallback(A, B) ->
gleam@result:'try'(
viva_tensor@core@tensor:try_to_list(A),
fun(A_data) ->
gleam@result:'try'(
viva_tensor@core@tensor:try_to_list(B),
fun(B_data) ->
Result_data = case viva_tensor@core@ffi:zig_is_loaded() of
true ->
case viva_tensor@core@ffi:zig_scale(B_data, -1.0) of
{ok, Neg_b} ->
case viva_tensor@core@ffi:zig_add(
A_data,
Neg_b
) of
{ok, R} ->
R;
{error, _} ->
gleam@list:map2(
A_data,
B_data,
fun(X, Y) -> X - Y end
)
end;
{error, _} ->
gleam@list:map2(
A_data,
B_data,
fun(X@1, Y@1) -> X@1 - Y@1 end
)
end;
false ->
gleam@list:map2(
A_data,
B_data,
fun(X@2, Y@2) -> X@2 - Y@2 end
)
end,
viva_tensor@core@tensor:new(
Result_data,
viva_tensor@core@tensor:shape(A)
)
end
)
end
).
-file("src/viva_tensor/core/ops.gleam", 635).
?DOC(false).
-spec sub_auto(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
sub_auto(A, B) ->
case viva_tensor@core@tensor:shape(A) =:= viva_tensor@core@tensor:shape(B) of
true ->
case {viva_tensor@core@tensor:native_ref(A),
viva_tensor@core@tensor:native_ref(B)} of
{{ok, Ref_a}, {ok, Ref_b}} ->
case viva_tensor@core@ffi:nt_sub(Ref_a, Ref_b) of
{ok, Ref_c} ->
{ok,
viva_tensor@core@tensor:from_native_ref(
Ref_c,
viva_tensor@core@tensor:shape(A)
)};
{error, _} ->
sub_list_fallback(A, B)
end;
{_, _} ->
sub_list_fallback(A, B)
end;
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 684).
?DOC(false).
-spec mul_list_fallback(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
mul_list_fallback(A, B) ->
gleam@result:'try'(
viva_tensor@core@tensor:try_to_list(A),
fun(A_data) ->
gleam@result:'try'(
viva_tensor@core@tensor:try_to_list(B),
fun(B_data) ->
Result_data = case viva_tensor@core@ffi:zig_is_loaded() of
true ->
case viva_tensor@core@ffi:zig_mul(A_data, B_data) of
{ok, R} ->
R;
{error, _} ->
gleam@list:map2(
A_data,
B_data,
fun(X, Y) -> X * Y end
)
end;
false ->
gleam@list:map2(
A_data,
B_data,
fun(X@1, Y@1) -> X@1 * Y@1 end
)
end,
viva_tensor@core@tensor:new(
Result_data,
viva_tensor@core@tensor:shape(A)
)
end
)
end
).
-file("src/viva_tensor/core/ops.gleam", 669).
?DOC(false).
-spec mul_auto(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
mul_auto(A, B) ->
case viva_tensor@core@tensor:shape(A) =:= viva_tensor@core@tensor:shape(B) of
true ->
case {viva_tensor@core@tensor:native_ref(A),
viva_tensor@core@tensor:native_ref(B)} of
{{ok, Ref_a}, {ok, Ref_b}} ->
case viva_tensor@core@ffi:nt_mul(Ref_a, Ref_b) of
{ok, Ref_c} ->
{ok,
viva_tensor@core@tensor:from_native_ref(
Ref_c,
viva_tensor@core@tensor:shape(A)
)};
{error, _} ->
mul_list_fallback(A, B)
end;
{_, _} ->
mul_list_fallback(A, B)
end;
false ->
{error,
{shape_mismatch,
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)}}
end.
-file("src/viva_tensor/core/ops.gleam", 727).
?DOC(false).
-spec scale_with_accel_fallback(list(float()), float()) -> list(float()).
scale_with_accel_fallback(Data, S) ->
case viva_tensor@core@ffi:is_nif_loaded() of
true ->
case viva_tensor@core@ffi:nif_scale(Data, S) of
{ok, Result} ->
Result;
{error, _} ->
gleam@list:map(Data, fun(X) -> X * S end)
end;
false ->
gleam@list:map(Data, fun(X@1) -> X@1 * S end)
end.
-file("src/viva_tensor/core/ops.gleam", 711).
?DOC(false).
-spec scale_list_fallback(viva_tensor@core@tensor:tensor(), float()) -> viva_tensor@core@tensor:tensor().
scale_list_fallback(T, S) ->
Data = viva_tensor@core@tensor:to_list(T),
Result_data = case viva_tensor@core@ffi:zig_is_loaded() of
true ->
case viva_tensor@core@ffi:zig_scale(Data, S) of
{ok, R} ->
R;
{error, _} ->
scale_with_accel_fallback(Data, S)
end;
false ->
scale_with_accel_fallback(Data, S)
end,
case viva_tensor@core@tensor:new(
Result_data,
viva_tensor@core@tensor:shape(T)
) of
{ok, Result} ->
Result;
{error, _} ->
T
end.
-file("src/viva_tensor/core/ops.gleam", 699).
?DOC(false).
-spec scale_auto(viva_tensor@core@tensor:tensor(), float()) -> viva_tensor@core@tensor:tensor().
scale_auto(T, S) ->
case viva_tensor@core@tensor:native_ref(T) of
{ok, Ref} ->
case viva_tensor@core@ffi:nt_scale(Ref, S) of
{ok, Ref_c} ->
viva_tensor@core@tensor:from_native_ref(
Ref_c,
viva_tensor@core@tensor:shape(T)
);
{error, _} ->
scale_list_fallback(T, S)
end;
{error, _} ->
scale_list_fallback(T, S)
end.
-file("src/viva_tensor/core/ops.gleam", 740).
?DOC(false).
-spec transpose(viva_tensor@core@tensor:tensor()) -> {ok,
viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
transpose(T) ->
case viva_tensor@core@tensor:shape(T) of
[M, N] ->
Arr = viva_tensor@core@ffi:list_to_array(
viva_tensor@core@tensor:to_list(T)
),
Result_data = begin
_pipe = range_int(0, N - 1),
gleam@list:flat_map(
_pipe,
fun(J) -> _pipe@1 = range_int(0, M - 1),
gleam@list:map(
_pipe@1,
fun(I) ->
viva_tensor@core@ffi:array_get(Arr, (I * N) + J)
end
) end
)
end,
viva_tensor@core@tensor:new(Result_data, [N, M]);
_ ->
{error, {dimension_error, <<"Transpose requires 2D tensor"/utf8>>}}
end.
-file("src/viva_tensor/core/ops.gleam", 757).
?DOC(false).
-spec outer(viva_tensor@core@tensor:tensor(), viva_tensor@core@tensor:tensor()) -> {ok,
viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
outer(A, B) ->
case (viva_tensor@core@tensor:rank(A) =:= 1) andalso (viva_tensor@core@tensor:rank(
B
)
=:= 1) of
true ->
M = viva_tensor@core@tensor:size(A),
N = viva_tensor@core@tensor:size(B),
A_data = viva_tensor@core@tensor:to_list(A),
B_data = viva_tensor@core@tensor:to_list(B),
Result_data = gleam@list:flat_map(
A_data,
fun(Ai) -> gleam@list:map(B_data, fun(Bj) -> Ai * Bj end) end
),
viva_tensor@core@tensor:new(Result_data, [M, N]);
false ->
{error,
{dimension_error, <<"Outer product requires two vectors"/utf8>>}}
end.
-file("src/viva_tensor/core/ops.gleam", 775).
?DOC(false).
-spec clamp(viva_tensor@core@tensor:tensor(), float(), float()) -> viva_tensor@core@tensor:tensor().
clamp(T, Min_val, Max_val) ->
map(T, fun(X) -> gleam@float:min(gleam@float:max(X, Min_val), Max_val) end).
-file("src/viva_tensor/core/ops.gleam", 780).
?DOC(false).
-spec relu(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
relu(T) ->
map(T, fun(X) -> gleam@float:max(X, +0.0) end).
-file("src/viva_tensor/core/ops.gleam", 785).
?DOC(false).
-spec sigmoid(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
sigmoid(T) ->
map(T, fun(X) -> case (1.0 + viva_tensor@core@ffi:exp(+0.0 - X)) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> 1.0 / Gleam@denominator
end end).
-file("src/viva_tensor/core/ops.gleam", 790).
?DOC(false).
-spec tanh(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
tanh(T) ->
map(T, fun(X) -> viva_tensor@core@ffi:tanh(X) end).
-file("src/viva_tensor/core/ops.gleam", 802).
?DOC(false).
-spec softmax(viva_tensor@core@tensor:tensor()) -> viva_tensor@core@tensor:tensor().
softmax(T) ->
Data = viva_tensor@core@tensor:to_list(T),
Max_val = max(T),
Shifted = gleam@list:map(
Data,
fun(X) -> viva_tensor@core@ffi:exp(X - Max_val) end
),
Sum_exp = gleam@list:fold(Shifted, +0.0, fun(Acc, X@1) -> Acc + X@1 end),
Result = gleam@list:map(Shifted, fun(X@2) -> case Sum_exp of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> X@2 / Gleam@denominator
end end),
case viva_tensor@core@tensor:new(Result, viva_tensor@core@tensor:shape(T)) of
{ok, R} ->
R;
{error, _} ->
T
end.
-file("src/viva_tensor/core/ops.gleam", 982).
?DOC(false).
-spec value_at(list(float()), integer()) -> float().
value_at(Values, Index) ->
viva_tensor@core@layout_math:value_at(Values, Index).
-file("src/viva_tensor/core/ops.gleam", 986).
?DOC(false).
-spec indices(integer()) -> list(integer()).
indices(Size) ->
viva_tensor@core@layout_math:indices(Size).
-file("src/viva_tensor/core/ops.gleam", 890).
?DOC(false).
-spec softmax_values(list(float())) -> list(float()).
softmax_values(Values) ->
Max_value = gleam@list:fold(
Values,
value_at(Values, 0),
fun(Acc, Value) -> gleam@float:max(Acc, Value) end
),
Shifted = gleam@list:map(
Values,
fun(Value@1) -> viva_tensor@core@ffi:exp(Value@1 - Max_value) end
),
Total = gleam@list:fold(
Shifted,
+0.0,
fun(Acc@1, Value@2) -> Acc@1 + Value@2 end
),
gleam@list:map(Shifted, fun(Value@3) -> case Total of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> Value@3 / Gleam@denominator
end end).
-file("src/viva_tensor/core/ops.gleam", 877).
?DOC(false).
-spec softmax_axis_values(
list(float()),
integer(),
integer(),
integer(),
integer()
) -> list(float()).
softmax_axis_values(Data, Outer, Inner, Axis_size, Inner_size) ->
Base = ((Outer * Axis_size) * Inner_size) + Inner,
_pipe = indices(Axis_size),
gleam@list:map(
_pipe,
fun(Axis_pos) -> value_at(Data, Base + (Axis_pos * Inner_size)) end
).
-file("src/viva_tensor/core/ops.gleam", 857).
?DOC(false).
-spec softmax_axis_outer(list(float()), integer(), integer(), integer()) -> list(float()).
softmax_axis_outer(Data, Outer, Axis_size, Inner_size) ->
Groups = begin
_pipe = indices(Inner_size),
gleam@list:map(
_pipe,
fun(Inner) ->
Values = softmax_axis_values(
Data,
Outer,
Inner,
Axis_size,
Inner_size
),
softmax_values(Values)
end
)
end,
_pipe@1 = indices(Axis_size),
gleam@list:flat_map(
_pipe@1,
fun(Axis_pos) ->
gleam@list:map(Groups, fun(Group) -> value_at(Group, Axis_pos) end)
end
).
-file("src/viva_tensor/core/ops.gleam", 842).
?DOC(false).
-spec softmax_axis_data(list(float()), integer(), integer(), integer()) -> list(float()).
softmax_axis_data(Data, Total_size, Axis_size, Inner_size) ->
Group_width = Axis_size * Inner_size,
Outer_size = case Group_width of
0 -> 0;
Gleam@denominator -> Total_size div Gleam@denominator
end,
_pipe = indices(Outer_size),
gleam@list:flat_map(
_pipe,
fun(Outer) -> softmax_axis_outer(Data, Outer, Axis_size, Inner_size) end
).
-file("src/viva_tensor/core/ops.gleam", 978).
?DOC(false).
-spec dim_at(list(integer()), integer()) -> integer().
dim_at(Values, Index) ->
viva_tensor@core@layout_math:dim_at(Values, Index).
-file("src/viva_tensor/core/ops.gleam", 818).
?DOC(false).
-spec softmax_axis(viva_tensor@core@tensor:tensor(), integer()) -> {ok,
viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
softmax_axis(T, Axis) ->
Shp = viva_tensor@core@tensor:shape(T),
Rnk = erlang:length(Shp),
case (Axis >= 0) andalso (Axis < Rnk) of
false ->
{error, {dimension_error, <<"Invalid axis for softmax"/utf8>>}};
true ->
Data = viva_tensor@core@tensor:to_list(T),
Total_size = viva_tensor@core@tensor:size(T),
Axis_size = dim_at(Shp, Axis),
Inner_size = viva_tensor@core@layout_math:size(
gleam@list:drop(Shp, Axis + 1)
),
case Axis_size =< 0 of
true ->
viva_tensor@core@tensor:new([], Shp);
false ->
Result = softmax_axis_data(
Data,
Total_size,
Axis_size,
Inner_size
),
viva_tensor@core@tensor:new(Result, Shp)
end
end.
-file("src/viva_tensor/core/ops.gleam", 914).
?DOC(false).
-spec can_broadcast(list(integer()), list(integer())) -> boolean().
can_broadcast(A, B) ->
viva_tensor@core@tensor:can_broadcast(A, B).
-file("src/viva_tensor/core/ops.gleam", 919).
?DOC(false).
-spec broadcast_shape(list(integer()), list(integer())) -> {ok, list(integer())} |
{error, viva_tensor@core@error:tensor_error()}.
broadcast_shape(A, B) ->
viva_tensor@core@tensor:broadcast_shape(A, B).
-file("src/viva_tensor/core/ops.gleam", 971).
?DOC(false).
-spec broadcast_to(viva_tensor@core@tensor:tensor(), list(integer())) -> {ok,
viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
broadcast_to(T, Target_shape) ->
viva_tensor@core@tensor:broadcast_to(T, Target_shape).
-file("src/viva_tensor/core/ops.gleam", 927).
?DOC(false).
-spec add_broadcast(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
add_broadcast(A, B) ->
gleam@result:'try'(
broadcast_shape(
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)
),
fun(Result_shape) ->
gleam@result:'try'(
broadcast_to(A, Result_shape),
fun(A_bc) ->
gleam@result:'try'(
broadcast_to(B, Result_shape),
fun(B_bc) -> add(A_bc, B_bc) end
)
end
)
end
).
-file("src/viva_tensor/core/ops.gleam", 938).
?DOC(false).
-spec sub_broadcast(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
sub_broadcast(A, B) ->
gleam@result:'try'(
broadcast_shape(
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)
),
fun(Result_shape) ->
gleam@result:'try'(
broadcast_to(A, Result_shape),
fun(A_bc) ->
gleam@result:'try'(
broadcast_to(B, Result_shape),
fun(B_bc) -> sub(A_bc, B_bc) end
)
end
)
end
).
-file("src/viva_tensor/core/ops.gleam", 949).
?DOC(false).
-spec mul_broadcast(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
mul_broadcast(A, B) ->
gleam@result:'try'(
broadcast_shape(
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)
),
fun(Result_shape) ->
gleam@result:'try'(
broadcast_to(A, Result_shape),
fun(A_bc) ->
gleam@result:'try'(
broadcast_to(B, Result_shape),
fun(B_bc) -> mul(A_bc, B_bc) end
)
end
)
end
).
-file("src/viva_tensor/core/ops.gleam", 960).
?DOC(false).
-spec div_broadcast(
viva_tensor@core@tensor:tensor(),
viva_tensor@core@tensor:tensor()
) -> {ok, viva_tensor@core@tensor:tensor()} |
{error, viva_tensor@core@error:tensor_error()}.
div_broadcast(A, B) ->
gleam@result:'try'(
broadcast_shape(
viva_tensor@core@tensor:shape(A),
viva_tensor@core@tensor:shape(B)
),
fun(Result_shape) ->
gleam@result:'try'(
broadcast_to(A, Result_shape),
fun(A_bc) ->
gleam@result:'try'(
broadcast_to(B, Result_shape),
fun(B_bc) -> 'div'(A_bc, B_bc) end
)
end
)
end
).