-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 ).