-module(viva_tensor@tensor). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/viva_tensor/tensor.gleam"). -export([zeros/1, ones/1, fill/2, from_list/1, from_list2d/1, vector/1, try_linspace/3, linspace/3, try_logspace/4, logspace/4, shape/1, zeros_like/1, ones_like/1, full_like/2, try_eye/1, eye/1, identity/1, try_to_list/1, rank/1, try_diag/1, diag/1, matrix/3, from_native_ref/2, native_ref/1, is_native/1, native_zeros/1, native_ones/1, native_fill/2, native_from_list/2, get_data/1, size/1, layout/1, dim/2, rows/1, cols/1, get/2, get2d/3, get_row/2, get_col/2, try_map/2, map/2, try_map_indexed/2, map_indexed/2, get_fast/2, map2/3, add/2, sub/2, mul/2, 'div'/2, add_into/3, sub_into/3, mul_into/3, scale_into/3, matmul_into/3, matmul/2, linear_relu/3, linear_relu_into/4, try_scale/2, scale/2, try_add_scalar/2, add_scalar/2, try_negate/1, negate/1, try_sum/1, sum/1, try_product/1, product/1, try_cumsum/1, cumsum/1, try_cumprod/1, cumprod/1, try_cumsum_axis/2, cumsum_axis/2, try_cumprod_axis/2, cumprod_axis/2, try_mean/1, mean/1, try_median/1, median/1, try_percentile/2, percentile/2, try_variance/1, variance/1, try_std/1, std/1, try_max/1, max/1, try_min/1, min/1, try_argmax/1, argmax/1, try_argmin/1, argmin/1, try_abs/1, abs/1, try_square/1, square/1, try_sqrt/1, sqrt/1, try_exp/1, exp/1, try_log/1, log/1, try_floor/1, floor/1, try_ceil/1, ceil/1, try_round/1, round/1, try_sign/1, sign/1, try_reciprocal/1, reciprocal/1, try_sum_axis/2, sum_axis/2, try_sum_axis_keepdims/2, sum_axis_keepdims/2, try_mean_axis/2, mean_axis/2, try_mean_axis_keepdims/2, mean_axis_keepdims/2, try_variance_axis/2, variance_axis/2, try_variance_axis_keepdims/2, variance_axis_keepdims/2, try_std_axis/2, std_axis/2, try_std_axis_keepdims/2, std_axis_keepdims/2, try_max_axis/2, max_axis/2, try_max_axis_keepdims/2, max_axis_keepdims/2, try_min_axis/2, min_axis/2, try_min_axis_keepdims/2, min_axis_keepdims/2, try_argmax_axis/2, argmax_axis/2, try_argmax_axis_keepdims/2, argmax_axis_keepdims/2, try_argmin_axis/2, argmin_axis/2, try_argmin_axis_keepdims/2, argmin_axis_keepdims/2, try_softmax_axis/2, softmax_axis/2, dot/2, matmul_vec/2, transpose/1, outer/2, to_list/1, to_list2d/1, try_clone/1, clone/1, reshape/2, try_flatten/1, flatten/1, try_concat/1, concat/1, concat_axis/2, try_unsqueeze/2, unsqueeze/2, stack/2, try_take_first/2, take_first/2, try_take_last/2, take_last/2, try_take_flat/2, take_flat/2, try_take/2, try_nonzero_flat/1, nonzero_flat/1, try_nonzero/1, take/3, gather/2, mask_select/2, nonzero/1, broadcast_to/2, broadcast_pair/2, try_masked_select/2, masked_select/2, slice/3, try_norm/1, norm/1, try_normalize/1, normalize/1, is_close/4, all_close/4, try_euclidean_distance/2, euclidean_distance/2, try_manhattan_distance/2, manhattan_distance/2, try_cosine_similarity/2, cosine_similarity/2, try_dot_similarity/2, dot_similarity/2, try_zscore/1, zscore/1, try_standardize/1, standardize/1, try_minmax_scale/3, minmax_scale/3, try_clip_by_norm/2, clip_by_norm/2, try_clamp/3, clamp/3, try_clip/3, clip/3, random_uniform/1, random_normal/3, xavier_init/2, he_init/2, can_broadcast/2, broadcast_shape/2, broadcast_shapes/1, add_broadcast/2, sub_broadcast/2, mul_broadcast/2, div_broadcast/2, maximum/2, try_maximum/2, minimum/2, try_minimum/2, equal/2, try_equal/2, not_equal/2, try_not_equal/2, greater/2, try_greater/2, greater_equal/2, try_greater_equal/2, less/2, try_less/2, less_equal/2, try_less_equal/2, where/3, try_where/3, try_logical_not/1, logical_not/1, logical_and/2, try_logical_and/2, logical_or/2, try_logical_or/2, logical_xor/2, try_logical_xor/2, try_any/1, any/1, try_all/1, all/1, try_count_nonzero/1, count_nonzero/1, try_any_axis/2, any_axis/2, try_any_axis_keepdims/2, any_axis_keepdims/2, try_all_axis/2, all_axis/2, try_all_axis_keepdims/2, all_axis_keepdims/2, try_count_nonzero_axis/2, count_nonzero_axis/2, try_count_nonzero_axis_keepdims/2, count_nonzero_axis_keepdims/2, squeeze/1, squeeze_axis/2, expand_dims/2, try_expand_dims/2, try_to_strided/1, to_strided/1, try_to_contiguous/1, to_contiguous/1, transpose_strided/1, is_contiguous/1, get2d_fast/3, conv2d_config/0, conv2d_same/2, pad2d/3, pad4d/3, conv2d/3, max_pool2d/5, avg_pool2d/5, global_avg_pool2d/1, einsum/2]). -export_type([tensor/0, conv2d_config/0]). -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). -type tensor() :: {tensor, list(float()), list(integer())} | {strided_tensor, viva_tensor@core@ffi:erlang_array(), list(integer()), list(integer()), integer()} | {native_tensor, viva_tensor@core@ffi:native_tensor_ref(), list(integer())}. -type conv2d_config() :: {conv2d_config, integer(), integer(), integer(), integer(), integer(), integer()}. -file("src/viva_tensor/tensor.gleam", 59). ?DOC(false). -spec zeros(list(integer())) -> tensor(). zeros(Shape) -> Size = gleam@list:fold(Shape, 1, fun(Acc, Dim) -> Acc * Dim end), {tensor, gleam@list:repeat(+0.0, Size), Shape}. -file("src/viva_tensor/tensor.gleam", 65). ?DOC(false). -spec ones(list(integer())) -> tensor(). ones(Shape) -> Size = gleam@list:fold(Shape, 1, fun(Acc, Dim) -> Acc * Dim end), {tensor, gleam@list:repeat(1.0, Size), Shape}. -file("src/viva_tensor/tensor.gleam", 71). ?DOC(false). -spec fill(list(integer()), float()) -> tensor(). fill(Shape, Value) -> Size = gleam@list:fold(Shape, 1, fun(Acc, Dim) -> Acc * Dim end), {tensor, gleam@list:repeat(Value, Size), Shape}. -file("src/viva_tensor/tensor.gleam", 77). ?DOC(false). -spec from_list(list(float())) -> tensor(). from_list(Data) -> {tensor, Data, [erlang:length(Data)]}. -file("src/viva_tensor/tensor.gleam", 82). ?DOC(false). -spec from_list2d(list(list(float()))) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. from_list2d(Rows) -> case Rows of [] -> {ok, {tensor, [], [0, 0]}}; [First | Rest] -> Cols = erlang:length(First), Valid = gleam@list:all( Rest, fun(Row) -> erlang:length(Row) =:= Cols end ), case Valid of false -> {error, {invalid_shape, <<"Rows have different lengths"/utf8>>}}; true -> Data = lists:append(Rows), Num_rows = erlang:length(Rows), {ok, {tensor, Data, [Num_rows, Cols]}} end end. -file("src/viva_tensor/tensor.gleam", 102). ?DOC(false). -spec vector(list(float())) -> tensor(). vector(Data) -> from_list(Data). -file("src/viva_tensor/tensor.gleam", 107). ?DOC(false). -spec try_linspace(float(), float(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_linspace(Start, Stop, Steps) -> case Steps of N when N =< 0 -> {error, {invalid_shape, <<"linspace requires steps > 0"/utf8>>}}; 1 -> {ok, from_list([Start])}; _ -> {ok, from_list( viva_math@statistics:linear_space(Start, Stop, Steps, true) )} end. -file("src/viva_tensor/tensor.gleam", 122). ?DOC(false). -spec linspace(float(), float(), integer()) -> tensor(). linspace(Start, Stop, Steps) -> _pipe = try_linspace(Start, Stop, Steps), gleam@result:unwrap(_pipe, from_list([])). -file("src/viva_tensor/tensor.gleam", 128). ?DOC(false). -spec try_logspace(float(), float(), integer(), float()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_logspace(Start, Stop, Steps, Base) -> case (Steps =< 0) orelse (Base =< +0.0) of true -> {error, {invalid_shape, <<"logspace requires steps > 0 and base > 0"/utf8>>}}; false -> {ok, from_list( viva_math@statistics:logarithmic_space( Start, Stop, Steps, true, Base ) )} end. -file("src/viva_tensor/tensor.gleam", 143). ?DOC(false). -spec logspace(float(), float(), integer(), float()) -> tensor(). logspace(Start, Stop, Steps, Base) -> _pipe = try_logspace(Start, Stop, Steps, Base), gleam@result:unwrap(_pipe, from_list([])). -file("src/viva_tensor/tensor.gleam", 343). ?DOC(false). -spec shape(tensor()) -> list(integer()). shape(T) -> case T of {tensor, _, S} -> S; {strided_tensor, _, S@1, _, _} -> S@1; {native_tensor, _, S@2} -> S@2 end. -file("src/viva_tensor/tensor.gleam", 149). ?DOC(false). -spec zeros_like(tensor()) -> tensor(). zeros_like(T) -> zeros(shape(T)). -file("src/viva_tensor/tensor.gleam", 154). ?DOC(false). -spec ones_like(tensor()) -> tensor(). ones_like(T) -> ones(shape(T)). -file("src/viva_tensor/tensor.gleam", 159). ?DOC(false). -spec full_like(tensor(), float()) -> tensor(). full_like(T, Value) -> fill(shape(T), Value). -file("src/viva_tensor/tensor.gleam", 5511). ?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/tensor.gleam", 5507). ?DOC(false). -spec range_int(integer(), integer()) -> list(integer()). range_int(From, To) -> range_loop(From, To, []). -file("src/viva_tensor/tensor.gleam", 164). ?DOC(false). -spec try_eye(integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_eye(N) -> case N =< 0 of true -> {error, {invalid_shape, <<"eye requires n > 0"/utf8>>}}; false -> Data = begin _pipe = range_int(0, (N * N) - 1), gleam@list:map(_pipe, fun(Index) -> case (case N of 0 -> 0; Gleam@denominator -> Index div Gleam@denominator end) =:= (case N of 0 -> 0; Gleam@denominator@1 -> Index rem Gleam@denominator@1 end) of true -> 1.0; false -> +0.0 end end) end, {ok, {tensor, Data, [N, N]}} end. -file("src/viva_tensor/tensor.gleam", 183). ?DOC(false). -spec eye(integer()) -> tensor(). eye(N) -> _pipe = try_eye(N), gleam@result:unwrap(_pipe, from_list([])). -file("src/viva_tensor/tensor.gleam", 189). ?DOC(false). -spec identity(integer()) -> tensor(). identity(N) -> eye(N). -file("src/viva_tensor/tensor.gleam", 3825). ?DOC(false). -spec list_at_float(list(float()), integer()) -> {ok, float()} | {error, nil}. list_at_float(Lst, Index) -> viva_tensor@core@layout_math:at(Lst, Index). -file("src/viva_tensor/tensor.gleam", 3865). ?DOC(false). -spec flat_to_multi(integer(), list(integer())) -> list(integer()). flat_to_multi(Flat, Shape) -> viva_tensor@core@layout_math:flat_to_multi(Flat, Shape). -file("src/viva_tensor/tensor.gleam", 352). ?DOC(false). -spec try_to_list(tensor()) -> {ok, list(float())} | {error, viva_tensor@core@error:tensor_error()}. try_to_list(T) -> case T of {tensor, Data, _} -> {ok, Data}; {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_to_list(Ref) of {ok, Data@1} -> {ok, Data@1}; {error, Reason} -> {error, {dimension_error, <<"Native tensor materialization failed: "/utf8, Reason/binary>>}} end; {strided_tensor, Storage, Shape, Strides, Offset} -> Total_size = gleam@list:fold( Shape, 1, fun(Acc, Dim) -> Acc * Dim end ), Data@2 = begin _pipe = range_int(0, Total_size - 1), gleam@list:map( _pipe, fun(Flat_idx) -> Indices = flat_to_multi(Flat_idx, Shape), Idx = begin _pipe@1 = gleam@list:zip(Indices, Strides), gleam@list:fold( _pipe@1, Offset, fun(Acc@1, Pair) -> {I, S} = Pair, Acc@1 + (I * S) end ) end, viva_tensor@core@ffi:array_get(Storage, Idx) end ) end, {ok, Data@2} end. -file("src/viva_tensor/tensor.gleam", 403). ?DOC(false). -spec rank(tensor()) -> integer(). rank(T) -> erlang:length(erlang:element(3, T)). -file("src/viva_tensor/tensor.gleam", 194). ?DOC(false). -spec try_diag(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_diag(T) -> case rank(T) =:= 1 of false -> {error, {dimension_error, <<"diag requires a 1D tensor"/utf8>>}}; true -> gleam@result:'try'( try_to_list(T), fun(Data) -> N = erlang:length(Data), case N =< 0 of true -> {error, {dimension_error, <<"diag requires a non-empty tensor"/utf8>>}}; false -> gleam@result:'try'( begin _pipe = range_int(0, (N * N) - 1), _pipe@2 = gleam@list:fold( _pipe, {ok, []}, fun(Acc, Index) -> gleam@result:'try'( Acc, fun(Values) -> Row = case N of 0 -> 0; Gleam@denominator -> Index div Gleam@denominator end, Col = case N of 0 -> 0; Gleam@denominator@1 -> Index rem Gleam@denominator@1 end, case Row =:= Col of true -> gleam@result:'try'( begin _pipe@1 = list_at_float( Data, Row ), gleam@result:map_error( _pipe@1, fun(_) -> {index_out_of_bounds, Row, erlang:length( Data )} end ) end, fun(Value) -> {ok, [Value | Values]} end ); false -> {ok, [+0.0 | Values]} end end ) end ), gleam@result:map( _pipe@2, fun lists:reverse/1 ) end, fun(Matrix_data) -> {ok, {tensor, Matrix_data, [N, N]}} end ) end end ) end. -file("src/viva_tensor/tensor.gleam", 235). ?DOC(false). -spec diag(tensor()) -> tensor(). diag(T) -> _pipe = try_diag(T), gleam@result:unwrap(_pipe, from_list([])). -file("src/viva_tensor/tensor.gleam", 241). ?DOC(false). -spec matrix(integer(), integer(), list(float())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. matrix(Rows, Cols, Data) -> Expected_size = Rows * Cols, Actual_size = erlang:length(Data), case Expected_size =:= Actual_size of true -> {ok, {tensor, Data, [Rows, Cols]}}; false -> {error, {invalid_shape, <<<<<<"Expected "/utf8, (erlang:integer_to_binary(Expected_size))/binary>>/binary, " elements, got "/utf8>>/binary, (erlang:integer_to_binary(Actual_size))/binary>>}} end. -file("src/viva_tensor/tensor.gleam", 264). ?DOC(false). -spec from_native_ref(viva_tensor@core@ffi:native_tensor_ref(), list(integer())) -> tensor(). from_native_ref(Ref, Shape) -> {native_tensor, Ref, Shape}. -file("src/viva_tensor/tensor.gleam", 269). ?DOC(false). -spec native_ref(tensor()) -> {ok, viva_tensor@core@ffi:native_tensor_ref()} | {error, nil}. native_ref(T) -> case T of {native_tensor, Ref, _} -> {ok, Ref}; _ -> {error, nil} end. -file("src/viva_tensor/tensor.gleam", 277). ?DOC(false). -spec is_native(tensor()) -> boolean(). is_native(T) -> case T of {native_tensor, _, _} -> true; _ -> false end. -file("src/viva_tensor/tensor.gleam", 285). ?DOC(false). -spec native_zeros(list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. native_zeros(Shape) -> case viva_tensor@core@ffi:nt_zeros(Shape) of {ok, Ref} -> {ok, {native_tensor, Ref, Shape}}; {error, <<"nif_not_loaded"/utf8>>} -> {error, {nif_not_loaded, <<"native_zeros"/utf8>>}}; {error, Reason} -> {error, {invalid_shape, Reason}} end. -file("src/viva_tensor/tensor.gleam", 294). ?DOC(false). -spec native_ones(list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. native_ones(Shape) -> case viva_tensor@core@ffi:nt_ones(Shape) of {ok, Ref} -> {ok, {native_tensor, Ref, Shape}}; {error, <<"nif_not_loaded"/utf8>>} -> {error, {nif_not_loaded, <<"native_ones"/utf8>>}}; {error, Reason} -> {error, {invalid_shape, Reason}} end. -file("src/viva_tensor/tensor.gleam", 303). ?DOC(false). -spec native_fill(list(integer()), float()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. native_fill(Shape, Value) -> case viva_tensor@core@ffi:nt_fill(Shape, Value) of {ok, Ref} -> {ok, {native_tensor, Ref, Shape}}; {error, <<"nif_not_loaded"/utf8>>} -> {error, {nif_not_loaded, <<"native_fill"/utf8>>}}; {error, Reason} -> {error, {invalid_shape, Reason}} end. -file("src/viva_tensor/tensor.gleam", 315). ?DOC(false). -spec native_from_list(list(float()), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. native_from_list(Data, Shape) -> Expected_size = gleam@list:fold(Shape, 1, fun(Acc, Dim) -> Acc * Dim end), Actual_size = erlang:length(Data), case Expected_size =:= Actual_size of false -> {error, {invalid_shape, <<<<<<"Expected "/utf8, (erlang:integer_to_binary(Expected_size))/binary>>/binary, " elements, got "/utf8>>/binary, (erlang:integer_to_binary(Actual_size))/binary>>}}; true -> case viva_tensor@core@ffi:nt_from_list(Data, Shape) of {ok, Ref} -> {ok, {native_tensor, Ref, Shape}}; {error, <<"nif_not_loaded"/utf8>>} -> {error, {nif_not_loaded, <<"native_from_list"/utf8>>}}; {error, Reason} -> {error, {invalid_shape, Reason}} end end. -file("src/viva_tensor/tensor.gleam", 387). ?DOC(false). -spec get_data(tensor()) -> list(float()). get_data(T) -> _pipe = try_to_list(T), gleam@result:unwrap(_pipe, []). -file("src/viva_tensor/tensor.gleam", 393). ?DOC(false). -spec size(tensor()) -> integer(). size(T) -> case T of {tensor, Data, _} -> erlang:length(Data); {native_tensor, _, Shape} -> gleam@list:fold(Shape, 1, fun(Acc, Dim) -> Acc * Dim end); {strided_tensor, _, Shape@1, _, _} -> gleam@list:fold(Shape@1, 1, fun(Acc@1, Dim@1) -> Acc@1 * Dim@1 end) end. -file("src/viva_tensor/tensor.gleam", 3869). ?DOC(false). -spec compute_strides(list(integer())) -> list(integer()). compute_strides(Shape) -> viva_tensor@core@layout_math:compute_strides(Shape). -file("src/viva_tensor/tensor.gleam", 408). ?DOC(false). -spec layout(tensor()) -> viva_tensor@layout:tensor_layout(). layout(T) -> case T of {tensor, _, Shape} -> {tensor_layout, dense_storage, beam_cpu, float64, Shape, compute_strides(Shape), 0, size(T), erlang:length(Shape), true}; {strided_tensor, _, Shape@1, Strides, Offset} -> {tensor_layout, strided_storage, beam_cpu, float64, Shape@1, Strides, Offset, size(T), erlang:length(Shape@1), Strides =:= compute_strides(Shape@1)}; {native_tensor, _, Shape@2} -> {tensor_layout, native_storage, native_cpu, float64, Shape@2, compute_strides(Shape@2), 0, size(T), erlang:length(Shape@2), true} end. -file("src/viva_tensor/tensor.gleam", 3821). ?DOC(false). -spec list_at_int(list(integer()), integer()) -> {ok, integer()} | {error, nil}. list_at_int(Lst, Index) -> viva_tensor@core@layout_math:at(Lst, Index). -file("src/viva_tensor/tensor.gleam", 452). ?DOC(false). -spec dim(tensor(), integer()) -> {ok, integer()} | {error, viva_tensor@core@error:tensor_error()}. dim(T, Axis) -> _pipe = list_at_int(erlang:element(3, T), Axis), gleam@result:map_error( _pipe, fun(_) -> {dimension_error, <<<<"Axis "/utf8, (erlang:integer_to_binary(Axis))/binary>>/binary, " out of bounds"/utf8>>} end ). -file("src/viva_tensor/tensor.gleam", 460). ?DOC(false). -spec rows(tensor()) -> integer(). rows(T) -> case erlang:element(3, T) of [R | _] -> R; [] -> 0 end. -file("src/viva_tensor/tensor.gleam", 468). ?DOC(false). -spec cols(tensor()) -> integer(). cols(T) -> case erlang:element(3, T) of [_, C | _] -> C; [N] -> N; [] -> 0 end. -file("src/viva_tensor/tensor.gleam", 479). ?DOC(false). -spec get(tensor(), integer()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. get(T, Index) -> case T of {tensor, Data, _} -> _pipe = list_at_float(Data, Index), gleam@result:map_error( _pipe, fun(_) -> {dimension_error, <<<<"Index "/utf8, (erlang:integer_to_binary(Index))/binary>>/binary, " out of bounds"/utf8>>} end ); {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_to_list(Ref) of {ok, Data@1} -> _pipe@1 = list_at_float(Data@1, Index), gleam@result:map_error( _pipe@1, fun(_) -> {dimension_error, <<<<"Index "/utf8, (erlang:integer_to_binary(Index))/binary>>/binary, " out of bounds"/utf8>>} end ); {error, Reason} -> {error, {dimension_error, Reason}} end; {strided_tensor, Storage, Shape, Strides, Offset} -> Indices = flat_to_multi(Index, Shape), Flat_idx = begin _pipe@2 = gleam@list:zip(Indices, Strides), gleam@list:fold( _pipe@2, Offset, fun(Acc, Pair) -> {I, S} = Pair, Acc + (I * S) end ) end, {ok, viva_tensor@core@ffi:array_get(Storage, Flat_idx)} end. -file("src/viva_tensor/tensor.gleam", 509). ?DOC(false). -spec get2d(tensor(), integer(), integer()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. get2d(T, Row, Col) -> case erlang:element(3, T) of [_, Num_cols] -> Index = (Row * Num_cols) + Col, get(T, Index); Other -> {error, {rank_mismatch, <<"get2d"/utf8>>, 2, Other}} end. -file("src/viva_tensor/tensor.gleam", 520). ?DOC(false). -spec get_row(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. get_row(T, Row_idx) -> case erlang:element(3, T) of [Num_rows, Num_cols] -> case (Row_idx >= 0) andalso (Row_idx < Num_rows) of true -> Data = get_data(T), Start = Row_idx * Num_cols, Row_data = begin _pipe = Data, _pipe@1 = gleam@list:drop(_pipe, Start), gleam@list:take(_pipe@1, Num_cols) end, {ok, from_list(Row_data)}; false -> {error, {dimension_error, <<"Row index out of bounds"/utf8>>}} end; Other -> {error, {rank_mismatch, <<"get_row"/utf8>>, 2, Other}} end. -file("src/viva_tensor/tensor.gleam", 541). ?DOC(false). -spec get_col(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. get_col(T, Col_idx) -> case erlang:element(3, T) of [Num_rows, Num_cols] -> case (Col_idx >= 0) andalso (Col_idx < Num_cols) of true -> Col_data = begin _pipe = range_int(0, Num_rows - 1), gleam@list:filter_map( _pipe, fun(Row) -> get2d(T, Row, Col_idx) end ) end, {ok, from_list(Col_data)}; false -> {error, {dimension_error, <<"Column index out of bounds"/utf8>>}} end; Other -> {error, {rank_mismatch, <<"get_col"/utf8>>, 2, Other}} end. -file("src/viva_tensor/tensor.gleam", 561). ?DOC(false). -spec try_map(tensor(), fun((float()) -> float())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_map(T, F) -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, {tensor, gleam@list:map(Data, F), erlang:element(3, T)}} end ). -file("src/viva_tensor/tensor.gleam", 570). ?DOC(false). -spec map(tensor(), fun((float()) -> float())) -> tensor(). map(T, F) -> _pipe = try_map(T, F), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 576). ?DOC(false). -spec try_map_indexed(tensor(), fun((float(), integer()) -> float())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_map_indexed(T, F) -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, {tensor, gleam@list:index_map(Data, fun(X, I) -> F(X, I) end), erlang:element(3, T)}} end ). -file("src/viva_tensor/tensor.gleam", 585). ?DOC(false). -spec map_indexed(tensor(), fun((float(), integer()) -> float())) -> tensor(). map_indexed(T, F) -> _pipe = try_map_indexed(T, F), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 3781). ?DOC(false). -spec get_fast(tensor(), integer()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. get_fast(T, Index) -> case T of {tensor, Data, _} -> _pipe = list_at_float(Data, Index), gleam@result:map_error( _pipe, fun(_) -> {dimension_error, <<<<"Index "/utf8, (erlang:integer_to_binary(Index))/binary>>/binary, " out of bounds"/utf8>>} end ); {native_tensor, _, _} -> get(T, Index); {strided_tensor, Storage, Shape, Strides, Offset} -> Indices = flat_to_multi(Index, Shape), Flat_idx = begin _pipe@1 = gleam@list:zip(Indices, Strides), gleam@list:fold( _pipe@1, Offset, fun(Acc, Pair) -> {Idx, Stride} = Pair, Acc + (Idx * Stride) end ) end, {ok, viva_tensor@core@ffi:array_get(Storage, Flat_idx)} end. -file("src/viva_tensor/tensor.gleam", 877). ?DOC(false). -spec indexed_elementwise( tensor(), tensor(), fun((float(), float()) -> float()) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. indexed_elementwise(A, B, F) -> Data_result = begin _pipe = range_int(0, size(A) - 1), gleam@list:fold( _pipe, {ok, []}, fun(Acc, I) -> gleam@result:'try'( Acc, fun(Values) -> gleam@result:'try'( get_fast(A, I), fun(X) -> gleam@result:'try'( get_fast(B, I), fun(Y) -> {ok, [F(X, Y) | Values]} end ) end ) end ) end ) end, gleam@result:'try'( Data_result, fun(Data) -> {ok, {tensor, lists:reverse(Data), erlang:element(3, A)}} end ). -file("src/viva_tensor/tensor.gleam", 866). ?DOC(false). -spec materialized_elementwise( tensor(), tensor(), fun((float(), float()) -> float()) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. materialized_elementwise(A, B, F) -> gleam@result:'try'( try_to_list(A), fun(A_data) -> gleam@result:'try'( try_to_list(B), fun(B_data) -> Data = gleam@list:map2(A_data, B_data, F), {ok, {tensor, Data, erlang:element(3, A)}} end ) end ). -file("src/viva_tensor/tensor.gleam", 847). ?DOC(false). -spec elementwise_fallback( tensor(), tensor(), fun((float(), float()) -> float()) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. elementwise_fallback(A, B, F) -> case is_native(A) orelse is_native(B) of true -> materialized_elementwise(A, B, F); false -> case {A, B} of {{tensor, A_data, _}, {tensor, B_data, _}} -> Data = gleam@list:map2(A_data, B_data, F), {ok, {tensor, Data, erlang:element(3, A)}}; {_, _} -> indexed_elementwise(A, B, F) end end. -file("src/viva_tensor/tensor.gleam", 591). ?DOC(false). -spec map2(tensor(), tensor(), fun((float(), float()) -> float())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. map2(A, B, F) -> case erlang:element(3, A) =:= erlang:element(3, B) of true -> elementwise_fallback(A, B, F); false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, B)}} end. -file("src/viva_tensor/tensor.gleam", 619). ?DOC(false). -spec add_dense(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. add_dense(A, B) -> map2(A, B, fun(X, Y) -> X + Y end). -file("src/viva_tensor/tensor.gleam", 603). ?DOC(false). -spec add(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. add(A, B) -> case erlang:element(3, A) =:= erlang:element(3, B) of true -> case {A, B} of {{native_tensor, A_ref, Shape}, {native_tensor, B_ref, _}} -> case viva_tensor@core@ffi:nt_add(A_ref, B_ref) of {ok, Ref} -> {ok, {native_tensor, Ref, Shape}}; {error, _} -> add_dense(A, B) end; {_, _} -> add_dense(A, B) end; false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, B)}} end. -file("src/viva_tensor/tensor.gleam", 640). ?DOC(false). -spec sub_dense(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. sub_dense(A, B) -> map2(A, B, fun(X, Y) -> X - Y end). -file("src/viva_tensor/tensor.gleam", 624). ?DOC(false). -spec sub(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. sub(A, B) -> case erlang:element(3, A) =:= erlang:element(3, B) of true -> case {A, B} of {{native_tensor, A_ref, Shape}, {native_tensor, B_ref, _}} -> case viva_tensor@core@ffi:nt_sub(A_ref, B_ref) of {ok, Ref} -> {ok, {native_tensor, Ref, Shape}}; {error, _} -> sub_dense(A, B) end; {_, _} -> sub_dense(A, B) end; false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, B)}} end. -file("src/viva_tensor/tensor.gleam", 662). ?DOC(false). -spec mul_dense(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. mul_dense(A, B) -> map2(A, B, fun(X, Y) -> X * Y end). -file("src/viva_tensor/tensor.gleam", 646). ?DOC(false). -spec mul(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. mul(A, B) -> case erlang:element(3, A) =:= erlang:element(3, B) of true -> case {A, B} of {{native_tensor, A_ref, Shape}, {native_tensor, B_ref, _}} -> case viva_tensor@core@ffi:nt_mul(A_ref, B_ref) of {ok, Ref} -> {ok, {native_tensor, Ref, Shape}}; {error, _} -> mul_dense(A, B) end; {_, _} -> mul_dense(A, B) end; false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, B)}} end. -file("src/viva_tensor/tensor.gleam", 674). ?DOC(false). -spec div_dense(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. div_dense(A, B) -> map2(A, B, fun(X, Y) -> case Y of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> X / Gleam@denominator end end). -file("src/viva_tensor/tensor.gleam", 667). ?DOC(false). -spec 'div'(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. 'div'(A, B) -> case erlang:element(3, A) =:= erlang:element(3, B) of true -> div_dense(A, B); false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, B)}} end. -file("src/viva_tensor/tensor.gleam", 825). ?DOC(false). -spec native_binary_into( tensor(), tensor(), tensor(), fun((viva_tensor@core@ffi:native_tensor_ref(), viva_tensor@core@ffi:native_tensor_ref(), viva_tensor@core@ffi:native_tensor_ref()) -> {ok, nil} | {error, binary()}) ) -> {ok, nil} | {error, viva_tensor@core@error:tensor_error()}. native_binary_into(Out, A, B, Op) -> case (erlang:element(3, A) =:= erlang:element(3, B)) andalso (erlang:element( 3, Out ) =:= erlang:element(3, A)) of false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, Out)}}; true -> case {Out, A, B} of {{native_tensor, Out_ref, _}, {native_tensor, A_ref, _}, {native_tensor, B_ref, _}} -> _pipe = Op(Out_ref, A_ref, B_ref), gleam@result:map_error( _pipe, fun(Reason) -> {dimension_error, Reason} end ); {_, _, _} -> {error, {dimension_error, <<"into operations require native tensors"/utf8>>}} end end. -file("src/viva_tensor/tensor.gleam", 679). ?DOC(false). -spec add_into(tensor(), tensor(), tensor()) -> {ok, nil} | {error, viva_tensor@core@error:tensor_error()}. add_into(Out, A, B) -> native_binary_into(Out, A, B, fun viva_tensor@core@ffi:nt_add_into/3). -file("src/viva_tensor/tensor.gleam", 684). ?DOC(false). -spec sub_into(tensor(), tensor(), tensor()) -> {ok, nil} | {error, viva_tensor@core@error:tensor_error()}. sub_into(Out, A, B) -> native_binary_into(Out, A, B, fun viva_tensor@core@ffi:nt_sub_into/3). -file("src/viva_tensor/tensor.gleam", 689). ?DOC(false). -spec mul_into(tensor(), tensor(), tensor()) -> {ok, nil} | {error, viva_tensor@core@error:tensor_error()}. mul_into(Out, A, B) -> native_binary_into(Out, A, B, fun viva_tensor@core@ffi:nt_mul_into/3). -file("src/viva_tensor/tensor.gleam", 694). ?DOC(false). -spec scale_into(tensor(), tensor(), float()) -> {ok, nil} | {error, viva_tensor@core@error:tensor_error()}. scale_into(Out, A, Scalar) -> case erlang:element(3, Out) =:= erlang:element(3, A) of false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, Out)}}; true -> case {Out, A} of {{native_tensor, Out_ref, _}, {native_tensor, A_ref, _}} -> _pipe = viva_tensor@core@ffi:nt_scale_into( Out_ref, A_ref, Scalar ), gleam@result:map_error( _pipe, fun(Reason) -> {dimension_error, Reason} end ); {_, _} -> {error, {dimension_error, <<"scale_into requires native tensors"/utf8>>}} end end. -file("src/viva_tensor/tensor.gleam", 713). ?DOC(false). -spec matmul_into(tensor(), tensor(), tensor()) -> {ok, nil} | {error, viva_tensor@core@error:tensor_error()}. matmul_into(Out, A, B) -> case {erlang:element(3, A), erlang:element(3, B), erlang:element(3, Out)} of {[M, N], [N2, P], [Out_m, Out_p]} when ((N =:= N2) andalso (M =:= Out_m)) andalso (P =:= Out_p) -> case {Out, A, B} of {{native_tensor, Out_ref, _}, {native_tensor, A_ref, _}, {native_tensor, B_ref, _}} -> _pipe = viva_tensor@core@ffi:nt_matmul_inplace( A_ref, B_ref, Out_ref, M, P, N ), gleam@result:map_error( _pipe, fun(Reason) -> {dimension_error, Reason} end ); {_, _, _} -> {error, {dimension_error, <<"matmul_into requires native tensors"/utf8>>}} end; {[M@1, _], [_, P@1], _} -> {error, {shape_mismatch, [M@1, P@1], erlang:element(3, Out)}}; {_, _, _} -> {error, {dimension_error, <<"Expected two matrices and matrix output"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 895). ?DOC(false). -spec get_element_or_zero(tensor(), integer()) -> float(). get_element_or_zero(T, Index) -> case get_fast(T, Index) of {ok, Value} -> Value; {error, _} -> +0.0 end. -file("src/viva_tensor/tensor.gleam", 1869). ?DOC(false). -spec matmul_dense(tensor(), tensor(), integer(), integer(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. matmul_dense(A, B, M, N, P) -> gleam@result:'try'( try_to_list(A), fun(A_data) -> gleam@result:'try'( try_to_list(B), fun(B_data) -> Result_data = viva_tensor@core@tensor_linalg:matmul_values( A_data, B_data, M, N, P ), {ok, {tensor, Result_data, [M, P]}} end ) end ). -file("src/viva_tensor/tensor.gleam", 1851). ?DOC(false). -spec matmul(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. matmul(A, B) -> case {erlang:element(3, A), erlang:element(3, B)} of {[M, N], [N2, P]} when N =:= N2 -> case {A, B} of {{native_tensor, A_ref, _}, {native_tensor, B_ref, _}} -> case viva_tensor@core@ffi:nt_matmul(A_ref, B_ref, M, P, N) of {ok, Ref} -> {ok, {native_tensor, Ref, [M, P]}}; {error, _} -> matmul_dense(A, B, M, N, P) end; {_, _} -> matmul_dense(A, B, M, N, P) end; {[_, 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/tensor.gleam", 804). ?DOC(false). -spec linear_relu_dense(tensor(), tensor(), tensor(), integer(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. linear_relu_dense(A, B, Bias, M, N) -> gleam@result:'try'( matmul(A, B), fun(Product) -> Data = begin _pipe = range_int(0, (M * N) - 1), gleam@list:map( _pipe, fun(I) -> Value = get_element_or_zero(Product, I) + get_element_or_zero( Bias, case N of 0 -> 0; Gleam@denominator -> I rem Gleam@denominator end ), case Value > +0.0 of true -> Value; false -> +0.0 end end ) end, {ok, {tensor, Data, [M, N]}} end ). -file("src/viva_tensor/tensor.gleam", 734). ?DOC(false). -spec linear_relu(tensor(), tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. linear_relu(A, B, Bias) -> case {erlang:element(3, A), erlang:element(3, B), erlang:element(3, Bias)} of {[M, K], [K2, N], [Bias_n]} when (K =:= K2) andalso (N =:= Bias_n) -> case {A, B, Bias} of {{native_tensor, A_ref, _}, {native_tensor, B_ref, _}, {native_tensor, Bias_ref, _}} -> case viva_tensor@core@ffi:nt_fused_linear_relu( A_ref, B_ref, Bias_ref, M, N, K ) of {ok, Result_ref} -> {ok, {native_tensor, Result_ref, [M, N]}}; {error, _} -> linear_relu_dense(A, B, Bias, M, N) end; {_, _, _} -> linear_relu_dense(A, B, Bias, M, N) end; {[_, _], [_, N@1], [Bias_n@1]} -> {error, {shape_mismatch, [N@1], [Bias_n@1]}}; {_, _, _} -> {error, {operand_shape_mismatch, <<"linear_relu"/utf8>>, <<"inputs"/utf8>>, <<"[m,k], [k,n], [n]"/utf8>>, erlang:element(3, A)}} end. -file("src/viva_tensor/tensor.gleam", 767). ?DOC(false). -spec linear_relu_into(tensor(), tensor(), tensor(), tensor()) -> {ok, nil} | {error, viva_tensor@core@error:tensor_error()}. linear_relu_into(Out, A, B, Bias) -> case {erlang:element(3, A), erlang:element(3, B), erlang:element(3, Bias), erlang:element(3, Out)} of {[M, K], [K2, N], [Bias_n], [Out_m, Out_n]} when (((K =:= K2) andalso (N =:= Bias_n)) andalso (M =:= Out_m)) andalso (N =:= Out_n) -> case {Out, A, B, Bias} of {{native_tensor, Out_ref, _}, {native_tensor, A_ref, _}, {native_tensor, B_ref, _}, {native_tensor, Bias_ref, _}} -> _pipe = viva_tensor@core@ffi:nt_fused_linear_relu_into( Out_ref, A_ref, B_ref, Bias_ref, M, N, K ), gleam@result:map_error( _pipe, fun(Reason) -> {dimension_error, Reason} end ); {_, _, _, _} -> {error, {dimension_error, <<"linear_relu_into requires native tensors"/utf8>>}} end; {[M@1, _], [_, N@1], _, _} -> {error, {shape_mismatch, [M@1, N@1], erlang:element(3, Out)}}; {_, _, _, _} -> {error, {dimension_error, <<"Expected [m,k], [k,n], [n], and [m,n] output"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 903). ?DOC(false). -spec try_scale(tensor(), float()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_scale(T, S) -> case T of {native_tensor, Ref, Shape} -> case viva_tensor@core@ffi:nt_scale(Ref, S) of {ok, Result_ref} -> {ok, {native_tensor, Result_ref, Shape}}; {error, _} -> try_map(T, fun(X) -> X * S end) end; _ -> try_map(T, fun(X@1) -> X@1 * S end) end. -file("src/viva_tensor/tensor.gleam", 916). ?DOC(false). -spec scale(tensor(), float()) -> tensor(). scale(T, S) -> _pipe = try_scale(T, S), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 922). ?DOC(false). -spec try_add_scalar(tensor(), float()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_add_scalar(T, S) -> try_map(T, fun(X) -> X + S end). -file("src/viva_tensor/tensor.gleam", 927). ?DOC(false). -spec add_scalar(tensor(), float()) -> tensor(). add_scalar(T, S) -> _pipe = try_add_scalar(T, S), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 933). ?DOC(false). -spec try_negate(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_negate(T) -> try_scale(T, -1.0). -file("src/viva_tensor/tensor.gleam", 938). ?DOC(false). -spec negate(tensor()) -> tensor(). negate(T) -> _pipe = try_negate(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 964). ?DOC(false). -spec sum_dense(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. sum_dense(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, gleam@list:fold(Data, +0.0, fun(Acc, X) -> Acc + X end)} end ). -file("src/viva_tensor/tensor.gleam", 946). ?DOC(false). -spec try_sum(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_sum(T) -> case T of {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_sum(Ref) of {ok, Value} -> {ok, Value}; {error, _} -> sum_dense(T) end; _ -> sum_dense(T) end. -file("src/viva_tensor/tensor.gleam", 959). ?DOC(false). -spec sum(tensor()) -> float(). sum(T) -> _pipe = try_sum(T), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 970). ?DOC(false). -spec try_product(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_product(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, gleam@list:fold(Data, 1.0, fun(Acc, X) -> Acc * X end)} end ). -file("src/viva_tensor/tensor.gleam", 976). ?DOC(false). -spec product(tensor()) -> float(). product(T) -> _pipe = try_product(T), gleam@result:unwrap(_pipe, 1.0). -file("src/viva_tensor/tensor.gleam", 982). ?DOC(false). -spec try_cumsum(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_cumsum(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, {tensor, viva_math@statistics:cumulative_sum(Data), shape(T)}} end ). -file("src/viva_tensor/tensor.gleam", 988). ?DOC(false). -spec cumsum(tensor()) -> tensor(). cumsum(T) -> _pipe = try_cumsum(T), gleam@result:unwrap(_pipe, from_list([])). -file("src/viva_tensor/tensor.gleam", 994). ?DOC(false). -spec try_cumprod(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_cumprod(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, {tensor, viva_math@statistics:cumulative_product(Data), shape(T)}} end ). -file("src/viva_tensor/tensor.gleam", 1000). ?DOC(false). -spec cumprod(tensor()) -> tensor(). cumprod(T) -> _pipe = try_cumprod(T), gleam@result:unwrap(_pipe, from_list([])). -file("src/viva_tensor/tensor.gleam", 1742). ?DOC(false). -spec cumulative_axis( binary(), tensor(), integer(), fun((list(float())) -> list(float())) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. cumulative_axis(Operation, T, Axis_idx, Transform) -> R = rank(T), case (Axis_idx >= 0) andalso (Axis_idx < R) of false -> {error, {axis_out_of_bounds, Operation, Axis_idx, R}}; true -> gleam@result:'try'( viva_tensor@core@tensor_axis:axis_size( erlang:element(3, T), Axis_idx ), fun(Axis_size) -> Inner_size = viva_tensor@core@layout_math:size( gleam@list:drop(erlang:element(3, T), Axis_idx + 1) ), case Axis_size =< 0 of true -> {ok, {tensor, [], erlang:element(3, T)}}; false -> gleam@result:'try'( try_to_list(T), fun(Data) -> gleam@result:'try'( viva_tensor@core@tensor_axis:axis_transform_data( Data, size(T), Axis_size, Inner_size, Transform ), fun(Result_data) -> {ok, {tensor, Result_data, erlang:element(3, T)}} end ) end ) end end ) end. -file("src/viva_tensor/tensor.gleam", 1006). ?DOC(false). -spec try_cumsum_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_cumsum_axis(T, Axis_idx) -> cumulative_axis( <<"cumsum"/utf8>>, T, Axis_idx, fun viva_math@statistics:cumulative_sum/1 ). -file("src/viva_tensor/tensor.gleam", 1014). ?DOC(false). -spec cumsum_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. cumsum_axis(T, Axis_idx) -> try_cumsum_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1019). ?DOC(false). -spec try_cumprod_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_cumprod_axis(T, Axis_idx) -> cumulative_axis( <<"cumprod"/utf8>>, T, Axis_idx, fun viva_math@statistics:cumulative_product/1 ). -file("src/viva_tensor/tensor.gleam", 1027). ?DOC(false). -spec cumprod_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. cumprod_axis(T, Axis_idx) -> try_cumprod_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1032). ?DOC(false). -spec try_mean(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_mean(T) -> gleam@result:'try'( try_sum(T), fun(Total) -> N = erlang:float(size(T)), case N > +0.0 of true -> {ok, case N of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> Total / Gleam@denominator end}; false -> {error, {dimension_error, <<"Cannot compute mean of an empty tensor"/utf8>>}} end end ). -file("src/viva_tensor/tensor.gleam", 1042). ?DOC(false). -spec mean(tensor()) -> float(). mean(T) -> _pipe = try_mean(T), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 1048). ?DOC(false). -spec try_median(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_median(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> case viva_math@statistics:median(Data) of {ok, Value} -> {ok, Value}; {error, _} -> {error, {dimension_error, <<"Cannot compute median of an empty tensor"/utf8>>}} end end ). -file("src/viva_tensor/tensor.gleam", 1058). ?DOC(false). -spec median(tensor()) -> float(). median(T) -> _pipe = try_median(T), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 1064). ?DOC(false). -spec try_percentile(tensor(), integer()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_percentile(T, Percentile) -> case (Percentile < 0) orelse (Percentile > 100) of true -> {error, {invalid_shape, <<"percentile must be between 0 and 100"/utf8>>}}; false -> gleam@result:'try'( try_to_list(T), fun(Data) -> case viva_math@statistics:percentile( Data, erlang:float(Percentile) / 100.0 ) of {ok, Value} -> {ok, Value}; {error, _} -> {error, {dimension_error, <<"Cannot compute percentile of an empty tensor"/utf8>>}} end end ) end. -file("src/viva_tensor/tensor.gleam", 1082). ?DOC(false). -spec percentile(tensor(), integer()) -> float(). percentile(T, Percentile) -> _pipe = try_percentile(T, Percentile), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 1087). ?DOC(false). -spec variance_dense(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. variance_dense(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> case viva_math@statistics:variance(Data) of {ok, Value} -> {ok, Value}; {error, _} -> {error, {dimension_error, <<"Cannot compute variance of an empty tensor"/utf8>>}} end end ). -file("src/viva_tensor/tensor.gleam", 1097). ?DOC(false). -spec try_variance(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_variance(T) -> variance_dense(T). -file("src/viva_tensor/tensor.gleam", 1102). ?DOC(false). -spec variance(tensor()) -> float(). variance(T) -> _pipe = try_variance(T), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 1108). ?DOC(false). -spec try_std(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_std(T) -> gleam@result:'try'( try_variance(T), fun(Value) -> {ok, viva_tensor@core@ffi:sqrt(Value)} end ). -file("src/viva_tensor/tensor.gleam", 1114). ?DOC(false). -spec std(tensor()) -> float(). std(T) -> _pipe = try_std(T), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 1138). ?DOC(false). -spec max_dense(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. max_dense(T) -> gleam@result:'try'(try_to_list(T), fun(Data) -> case Data of [] -> {error, {dimension_error, <<"Cannot compute max of an empty tensor"/utf8>>}}; [First | Rest] -> {ok, gleam@list:fold( Rest, First, fun(Acc, X) -> gleam@float:max(Acc, X) end )} end end). -file("src/viva_tensor/tensor.gleam", 1120). ?DOC(false). -spec try_max(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_max(T) -> case T of {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_max(Ref) of {ok, Value} -> {ok, Value}; {error, _} -> max_dense(T) end; _ -> max_dense(T) end. -file("src/viva_tensor/tensor.gleam", 1133). ?DOC(false). -spec max(tensor()) -> float(). max(T) -> _pipe = try_max(T), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 1166). ?DOC(false). -spec min_dense(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. min_dense(T) -> gleam@result:'try'(try_to_list(T), fun(Data) -> case Data of [] -> {error, {dimension_error, <<"Cannot compute min of an empty tensor"/utf8>>}}; [First | Rest] -> {ok, gleam@list:fold( Rest, First, fun(Acc, X) -> gleam@float:min(Acc, X) end )} end end). -file("src/viva_tensor/tensor.gleam", 1148). ?DOC(false). -spec try_min(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_min(T) -> case T of {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_min(Ref) of {ok, Value} -> {ok, Value}; {error, _} -> min_dense(T) end; _ -> min_dense(T) end. -file("src/viva_tensor/tensor.gleam", 1161). ?DOC(false). -spec min(tensor()) -> float(). min(T) -> _pipe = try_min(T), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 1176). ?DOC(false). -spec try_argmax(tensor()) -> {ok, integer()} | {error, viva_tensor@core@error:tensor_error()}. try_argmax(T) -> gleam@result:'try'(try_to_list(T), fun(Data) -> case Data of [] -> {error, {dimension_error, <<"Cannot compute argmax of an empty tensor"/utf8>>}}; [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 ), {ok, Idx} end end). -file("src/viva_tensor/tensor.gleam", 1195). ?DOC(false). -spec argmax(tensor()) -> integer(). argmax(T) -> _pipe = try_argmax(T), gleam@result:unwrap(_pipe, 0). -file("src/viva_tensor/tensor.gleam", 1201). ?DOC(false). -spec try_argmin(tensor()) -> {ok, integer()} | {error, viva_tensor@core@error:tensor_error()}. try_argmin(T) -> gleam@result:'try'(try_to_list(T), fun(Data) -> case Data of [] -> {error, {dimension_error, <<"Cannot compute argmin of an empty tensor"/utf8>>}}; [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 ), {ok, Idx} end end). -file("src/viva_tensor/tensor.gleam", 1220). ?DOC(false). -spec argmin(tensor()) -> integer(). argmin(T) -> _pipe = try_argmin(T), gleam@result:unwrap(_pipe, 0). -file("src/viva_tensor/tensor.gleam", 1226). ?DOC(false). -spec try_abs(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_abs(T) -> try_map(T, fun gleam@float:absolute_value/1). -file("src/viva_tensor/tensor.gleam", 1231). ?DOC(false). -spec abs(tensor()) -> tensor(). abs(T) -> _pipe = try_abs(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1237). ?DOC(false). -spec try_square(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_square(T) -> try_map(T, fun(X) -> X * X end). -file("src/viva_tensor/tensor.gleam", 1242). ?DOC(false). -spec square(tensor()) -> tensor(). square(T) -> _pipe = try_square(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1248). ?DOC(false). -spec try_sqrt(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_sqrt(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> case gleam@list:any(Data, fun(X) -> X < +0.0 end) of true -> {error, {invalid_shape, <<"sqrt requires all values >= 0"/utf8>>}}; false -> {ok, {tensor, gleam@list:map( Data, fun viva_tensor@core@ffi:sqrt/1 ), shape(T)}} end end ). -file("src/viva_tensor/tensor.gleam", 1257). ?DOC(false). -spec sqrt(tensor()) -> tensor(). sqrt(T) -> _pipe = try_sqrt(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1263). ?DOC(false). -spec try_exp(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_exp(T) -> try_map(T, fun viva_tensor@core@ffi:exp/1). -file("src/viva_tensor/tensor.gleam", 1268). ?DOC(false). -spec exp(tensor()) -> tensor(). exp(T) -> _pipe = try_exp(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1274). ?DOC(false). -spec try_log(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_log(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> case gleam@list:any(Data, fun(X) -> X =< +0.0 end) of true -> {error, {invalid_shape, <<"log requires all values > 0"/utf8>>}}; false -> {ok, {tensor, gleam@list:map(Data, fun viva_tensor@core@ffi:log/1), shape(T)}} end end ). -file("src/viva_tensor/tensor.gleam", 1283). ?DOC(false). -spec log(tensor()) -> tensor(). log(T) -> _pipe = try_log(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1289). ?DOC(false). -spec try_floor(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_floor(T) -> try_map(T, fun math:floor/1). -file("src/viva_tensor/tensor.gleam", 1294). ?DOC(false). -spec floor(tensor()) -> tensor(). floor(T) -> _pipe = try_floor(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1300). ?DOC(false). -spec try_ceil(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_ceil(T) -> try_map(T, fun math:ceil/1). -file("src/viva_tensor/tensor.gleam", 1305). ?DOC(false). -spec ceil(tensor()) -> tensor(). ceil(T) -> _pipe = try_ceil(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1311). ?DOC(false). -spec try_round(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_round(T) -> try_map(T, fun(X) -> erlang:float(erlang:round(X)) end). -file("src/viva_tensor/tensor.gleam", 1316). ?DOC(false). -spec round(tensor()) -> tensor(). round(T) -> _pipe = try_round(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1322). ?DOC(false). -spec try_sign(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_sign(T) -> try_map(T, fun(X) -> case X < +0.0 of true -> -1.0; false -> case X > +0.0 of true -> 1.0; false -> +0.0 end end end). -file("src/viva_tensor/tensor.gleam", 1336). ?DOC(false). -spec sign(tensor()) -> tensor(). sign(T) -> _pipe = try_sign(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1342). ?DOC(false). -spec try_reciprocal(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_reciprocal(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> case gleam@list:any(Data, fun(X) -> X =:= +0.0 end) of true -> {error, {invalid_shape, <<"reciprocal requires all values != 0"/utf8>>}}; false -> {ok, {tensor, gleam@list:map(Data, fun(X@1) -> case X@1 of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> 1.0 / Gleam@denominator end end), shape(T)}} end end ). -file("src/viva_tensor/tensor.gleam", 1352). ?DOC(false). -spec reciprocal(tensor()) -> tensor(). reciprocal(T) -> _pipe = try_reciprocal(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 1384). ?DOC(false). -spec sum_axis_with_keepdims(binary(), tensor(), integer(), boolean()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. sum_axis_with_keepdims(Operation, T, Axis_idx, Keepdims) -> R = rank(T), case (Axis_idx >= 0) andalso (Axis_idx < R) of false -> {error, {axis_out_of_bounds, Operation, Axis_idx, R}}; true -> case erlang:element(3, T) of [] -> {error, {dimension_error, <<"Cannot reduce scalar"/utf8>>}}; _ -> gleam@result:'try'( viva_tensor@core@tensor_axis:axis_size( erlang:element(3, T), Axis_idx ), fun(Axis_size) -> gleam@result:'try'( try_to_list(T), fun(Data) -> New_shape = viva_tensor@core@tensor_axis:reduced_shape( erlang:element(3, T), Axis_idx, Keepdims ), New_size = gleam@list:fold( New_shape, 1, fun(Acc, D) -> Acc * D end ), case New_size =< 0 of true -> {ok, {tensor, [], New_shape}}; false -> _pipe = viva_tensor@core@tensor_axis:reduce_sum_axis_data( Data, erlang:element(3, T), New_shape, Axis_idx, Axis_size ), gleam@result:map( _pipe, fun(Values) -> {tensor, Values, New_shape} end ) end end ) end ) end end. -file("src/viva_tensor/tensor.gleam", 1359). ?DOC(false). -spec try_sum_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_sum_axis(T, Axis_idx) -> sum_axis_with_keepdims(<<"sum_axis"/utf8>>, T, Axis_idx, false). -file("src/viva_tensor/tensor.gleam", 1364). ?DOC(false). -spec sum_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. sum_axis(T, Axis_idx) -> try_sum_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1369). ?DOC(false). -spec try_sum_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_sum_axis_keepdims(T, Axis_idx) -> sum_axis_with_keepdims(<<"sum_axis_keepdims"/utf8>>, T, Axis_idx, true). -file("src/viva_tensor/tensor.gleam", 1377). ?DOC(false). -spec sum_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. sum_axis_keepdims(T, Axis_idx) -> try_sum_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1449). ?DOC(false). -spec mean_axis_with_keepdims(binary(), tensor(), integer(), boolean()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. mean_axis_with_keepdims(Operation, T, Axis_idx, Keepdims) -> R = rank(T), case (Axis_idx >= 0) andalso (Axis_idx < R) of false -> {error, {axis_out_of_bounds, Operation, Axis_idx, R}}; true -> gleam@result:'try'( viva_tensor@core@tensor_axis:axis_size( erlang:element(3, T), Axis_idx ), fun(Axis_size) -> case Axis_size =< 0 of true -> {error, {dimension_error, <<"Cannot compute mean along empty axis"/utf8>>}}; false -> case sum_axis_with_keepdims( Operation, T, Axis_idx, Keepdims ) of {error, E} -> {error, E}; {ok, Summed} -> {ok, scale( Summed, case erlang:float(Axis_size) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> 1.0 / Gleam@denominator end )} end end end ) end. -file("src/viva_tensor/tensor.gleam", 1424). ?DOC(false). -spec try_mean_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_mean_axis(T, Axis_idx) -> mean_axis_with_keepdims(<<"mean_axis"/utf8>>, T, Axis_idx, false). -file("src/viva_tensor/tensor.gleam", 1429). ?DOC(false). -spec mean_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. mean_axis(T, Axis_idx) -> try_mean_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1434). ?DOC(false). -spec try_mean_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_mean_axis_keepdims(T, Axis_idx) -> mean_axis_with_keepdims(<<"mean_axis_keepdims"/utf8>>, T, Axis_idx, true). -file("src/viva_tensor/tensor.gleam", 1442). ?DOC(false). -spec mean_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. mean_axis_keepdims(T, Axis_idx) -> try_mean_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1773). ?DOC(false). -spec reduce_axis_with_keepdims( binary(), tensor(), integer(), boolean(), fun((list(float())) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. reduce_axis_with_keepdims(Operation, T, Axis_idx, Keepdims, Reducer) -> R = rank(T), case (Axis_idx >= 0) andalso (Axis_idx < R) of false -> {error, {axis_out_of_bounds, Operation, Axis_idx, R}}; true -> gleam@result:'try'( viva_tensor@core@tensor_axis:axis_size( erlang:element(3, T), Axis_idx ), fun(Axis_size) -> case Axis_size =< 0 of true -> {error, {dimension_error, <<"Cannot reduce along empty axis"/utf8>>}}; false -> gleam@result:'try'( try_to_list(T), fun(Data) -> Output_shape = viva_tensor@core@tensor_axis:reduced_shape( erlang:element(3, T), Axis_idx, Keepdims ), gleam@result:'try'( viva_tensor@core@tensor_axis:reduce_axis_data( Data, erlang:element(3, T), Output_shape, Axis_idx, Axis_size, Reducer ), fun(Values) -> {ok, {tensor, Values, Output_shape}} end ) end ) end end ) end. -file("src/viva_tensor/tensor.gleam", 1473). ?DOC(false). -spec try_variance_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_variance_axis(T, Axis_idx) -> reduce_axis_with_keepdims( <<"variance_axis"/utf8>>, T, Axis_idx, false, fun viva_tensor@core@tensor_axis:variance_list/1 ). -file("src/viva_tensor/tensor.gleam", 1487). ?DOC(false). -spec variance_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. variance_axis(T, Axis_idx) -> try_variance_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1492). ?DOC(false). -spec try_variance_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_variance_axis_keepdims(T, Axis_idx) -> reduce_axis_with_keepdims( <<"variance_axis_keepdims"/utf8>>, T, Axis_idx, true, fun viva_tensor@core@tensor_axis:variance_list/1 ). -file("src/viva_tensor/tensor.gleam", 1506). ?DOC(false). -spec variance_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. variance_axis_keepdims(T, Axis_idx) -> try_variance_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1514). ?DOC(false). -spec try_std_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_std_axis(T, Axis_idx) -> reduce_axis_with_keepdims( <<"std_axis"/utf8>>, T, Axis_idx, false, fun viva_tensor@core@tensor_axis:std_list/1 ). -file("src/viva_tensor/tensor.gleam", 1525). ?DOC(false). -spec std_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. std_axis(T, Axis_idx) -> try_std_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1530). ?DOC(false). -spec try_std_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_std_axis_keepdims(T, Axis_idx) -> reduce_axis_with_keepdims( <<"std_axis_keepdims"/utf8>>, T, Axis_idx, true, fun viva_tensor@core@tensor_axis:std_list/1 ). -file("src/viva_tensor/tensor.gleam", 1544). ?DOC(false). -spec std_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. std_axis_keepdims(T, Axis_idx) -> try_std_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1552). ?DOC(false). -spec try_max_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_max_axis(T, Axis_idx) -> reduce_axis_with_keepdims( <<"max_axis"/utf8>>, T, Axis_idx, false, fun viva_tensor@core@tensor_axis:max_list/1 ). -file("src/viva_tensor/tensor.gleam", 1563). ?DOC(false). -spec max_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. max_axis(T, Axis_idx) -> try_max_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1568). ?DOC(false). -spec try_max_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_max_axis_keepdims(T, Axis_idx) -> reduce_axis_with_keepdims( <<"max_axis_keepdims"/utf8>>, T, Axis_idx, true, fun viva_tensor@core@tensor_axis:max_list/1 ). -file("src/viva_tensor/tensor.gleam", 1582). ?DOC(false). -spec max_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. max_axis_keepdims(T, Axis_idx) -> try_max_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1590). ?DOC(false). -spec try_min_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_min_axis(T, Axis_idx) -> reduce_axis_with_keepdims( <<"min_axis"/utf8>>, T, Axis_idx, false, fun viva_tensor@core@tensor_axis:min_list/1 ). -file("src/viva_tensor/tensor.gleam", 1601). ?DOC(false). -spec min_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. min_axis(T, Axis_idx) -> try_min_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1606). ?DOC(false). -spec try_min_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_min_axis_keepdims(T, Axis_idx) -> reduce_axis_with_keepdims( <<"min_axis_keepdims"/utf8>>, T, Axis_idx, true, fun viva_tensor@core@tensor_axis:min_list/1 ). -file("src/viva_tensor/tensor.gleam", 1620). ?DOC(false). -spec min_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. min_axis_keepdims(T, Axis_idx) -> try_min_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1628). ?DOC(false). -spec try_argmax_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_argmax_axis(T, Axis_idx) -> reduce_axis_with_keepdims( <<"argmax_axis"/utf8>>, T, Axis_idx, false, fun viva_tensor@core@tensor_axis:argmax_list/1 ). -file("src/viva_tensor/tensor.gleam", 1642). ?DOC(false). -spec argmax_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. argmax_axis(T, Axis_idx) -> try_argmax_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1647). ?DOC(false). -spec try_argmax_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_argmax_axis_keepdims(T, Axis_idx) -> reduce_axis_with_keepdims( <<"argmax_axis_keepdims"/utf8>>, T, Axis_idx, true, fun viva_tensor@core@tensor_axis:argmax_list/1 ). -file("src/viva_tensor/tensor.gleam", 1661). ?DOC(false). -spec argmax_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. argmax_axis_keepdims(T, Axis_idx) -> try_argmax_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1669). ?DOC(false). -spec try_argmin_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_argmin_axis(T, Axis_idx) -> reduce_axis_with_keepdims( <<"argmin_axis"/utf8>>, T, Axis_idx, false, fun viva_tensor@core@tensor_axis:argmin_list/1 ). -file("src/viva_tensor/tensor.gleam", 1683). ?DOC(false). -spec argmin_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. argmin_axis(T, Axis_idx) -> try_argmin_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1688). ?DOC(false). -spec try_argmin_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_argmin_axis_keepdims(T, Axis_idx) -> reduce_axis_with_keepdims( <<"argmin_axis_keepdims"/utf8>>, T, Axis_idx, true, fun viva_tensor@core@tensor_axis:argmin_list/1 ). -file("src/viva_tensor/tensor.gleam", 1702). ?DOC(false). -spec argmin_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. argmin_axis_keepdims(T, Axis_idx) -> try_argmin_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 1710). ?DOC(false). -spec try_softmax_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_softmax_axis(T, Axis) -> Shp = erlang:element(3, T), Rnk = erlang:length(Shp), case (Axis >= 0) andalso (Axis < Rnk) of false -> {error, {dimension_error, <<"Invalid axis for softmax"/utf8>>}}; true -> gleam@result:'try'( viva_tensor@core@tensor_axis:axis_size(Shp, Axis), fun(Axis_size) -> Inner_size = viva_tensor@core@layout_math:size( gleam@list:drop(Shp, Axis + 1) ), case Axis_size =< 0 of true -> {ok, {tensor, [], Shp}}; false -> gleam@result:'try'( try_to_list(T), fun(Input) -> gleam@result:'try'( viva_tensor@core@tensor_axis:softmax_axis_data( Input, size(T), Axis_size, Inner_size ), fun(Data) -> {ok, {tensor, Data, Shp}} end ) end ) end end ) end. -file("src/viva_tensor/tensor.gleam", 1738). ?DOC(false). -spec softmax_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. softmax_axis(T, Axis) -> try_softmax_axis(T, Axis). -file("src/viva_tensor/tensor.gleam", 1825). ?DOC(false). -spec dot_dense(tensor(), tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. dot_dense(A, B) -> gleam@result:'try'( try_to_list(A), fun(A_data) -> gleam@result:'try'( try_to_list(B), fun(B_data) -> {ok, viva_tensor@core@tensor_linalg:dot_values( A_data, B_data )} end ) end ). -file("src/viva_tensor/tensor.gleam", 1809). ?DOC(false). -spec dot(tensor(), tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. dot(A, B) -> case ((rank(A) =:= 1) andalso (rank(B) =:= 1)) andalso (size(A) =:= size(B)) of true -> case {A, B} of {{native_tensor, A_ref, _}, {native_tensor, B_ref, _}} -> case viva_tensor@core@ffi:nt_dot(A_ref, B_ref) of {ok, Value} -> {ok, Value}; {error, _} -> dot_dense(A, B) end; {_, _} -> dot_dense(A, B) end; false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, B)}} end. -file("src/viva_tensor/tensor.gleam", 1833). ?DOC(false). -spec matmul_vec(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. matmul_vec(Mat, Vec) -> case {erlang:element(3, Mat), erlang:element(3, Vec)} of {[M, N], [Vec_n]} when N =:= Vec_n -> gleam@result:'try'( try_to_list(Mat), fun(Mat_data) -> gleam@result:'try'( try_to_list(Vec), fun(Vec_data) -> Result_data = viva_tensor@core@tensor_linalg:matmul_vec_values( Mat_data, Vec_data, M, N ), {ok, {tensor, Result_data, [M]}} end ) end ); {[_, 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/tensor.gleam", 1900). ?DOC(false). -spec transpose_dense(tensor(), integer(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. transpose_dense(T, M, N) -> gleam@result:'try'( try_to_list(T), fun(Data) -> gleam@result:'try'( viva_tensor@core@tensor_linalg:transpose_values(Data, M, N), fun(Result_data) -> {ok, {tensor, Result_data, [N, M]}} end ) end ). -file("src/viva_tensor/tensor.gleam", 1883). ?DOC(false). -spec transpose(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. transpose(T) -> case erlang:element(3, T) of [M, N] -> case T of {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_transpose(Ref) of {ok, Result_ref} -> {ok, {native_tensor, Result_ref, [N, M]}}; {error, _} -> transpose_dense(T, M, N) end; _ -> transpose_dense(T, M, N) end; _ -> {error, {dimension_error, <<"Transpose requires 2D tensor"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 1908). ?DOC(false). -spec outer(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. outer(A, B) -> case (rank(A) =:= 1) andalso (rank(B) =:= 1) of true -> M = size(A), N = size(B), gleam@result:'try'( try_to_list(A), fun(A_data) -> gleam@result:'try'( try_to_list(B), fun(B_data) -> Result_data = viva_tensor@core@tensor_linalg:outer_values( A_data, B_data ), {ok, {tensor, Result_data, [M, N]}} end ) end ); false -> {error, {dimension_error, <<"Outer product requires two vectors"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 1925). ?DOC(false). -spec to_list(tensor()) -> list(float()). to_list(T) -> get_data(T). -file("src/viva_tensor/tensor.gleam", 1930). ?DOC(false). -spec to_list2d(tensor()) -> {ok, list(list(float()))} | {error, viva_tensor@core@error:tensor_error()}. to_list2d(T) -> case erlang:element(3, T) of [Num_rows, Num_cols] -> gleam@result:'try'( try_to_list(T), fun(Data) -> Rows_list = begin _pipe = range_int(0, Num_rows - 1), gleam@list:map( _pipe, fun(I) -> Start = I * Num_cols, _pipe@1 = Data, _pipe@2 = gleam@list:drop(_pipe@1, Start), gleam@list:take(_pipe@2, Num_cols) end ) end, {ok, Rows_list} end ); Other -> {error, {rank_mismatch, <<"to_list2d"/utf8>>, 2, Other}} end. -file("src/viva_tensor/tensor.gleam", 1949). ?DOC(false). -spec try_clone(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_clone(T) -> case T of {native_tensor, Ref, Shape} -> case viva_tensor@core@ffi:nt_to_list(Ref) of {ok, Data} -> case viva_tensor@core@ffi:nt_from_list(Data, Shape) of {ok, Cloned_ref} -> {ok, {native_tensor, Cloned_ref, Shape}}; {error, _} -> {ok, {tensor, Data, Shape}} end; {error, _} -> {error, {dimension_error, <<"Could not materialize native tensor"/utf8>>}} end; _ -> gleam@result:'try'( try_to_list(T), fun(Data@1) -> {ok, {tensor, Data@1, erlang:element(3, T)}} end ) end. -file("src/viva_tensor/tensor.gleam", 1970). ?DOC(false). -spec clone(tensor()) -> tensor(). clone(T) -> _pipe = try_clone(T), gleam@result:unwrap(_pipe, {tensor, [], erlang:element(3, T)}). -file("src/viva_tensor/tensor.gleam", 1977). ?DOC(false). -spec reshape(tensor(), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. reshape(T, New_shape) -> Old_size = size(T), New_size = gleam@list:fold(New_shape, 1, fun(Acc, Dim) -> Acc * Dim end), case Old_size =:= New_size of true -> case T of {native_tensor, Ref, _} -> {ok, {native_tensor, Ref, New_shape}}; {tensor, Data, _} -> {ok, {tensor, Data, New_shape}}; {strided_tensor, Storage, Shape, Strides, Offset} -> case Strides =:= compute_strides(Shape) of true -> {ok, {strided_tensor, Storage, New_shape, compute_strides(New_shape), Offset}}; false -> gleam@result:'try'( try_to_list(T), fun(Data@1) -> {ok, {tensor, Data@1, New_shape}} end ) end end; false -> {error, {invalid_shape, <<<<<<<<"Cannot reshape: size mismatch ("/utf8, (erlang:integer_to_binary(Old_size))/binary>>/binary, " vs "/utf8>>/binary, (erlang:integer_to_binary(New_size))/binary>>/binary, ")"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 2013). ?DOC(false). -spec try_flatten(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_flatten(T) -> case T of {native_tensor, Ref, _} -> {ok, {native_tensor, Ref, [size(T)]}}; _ -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, {tensor, Data, [size(T)]}} end ) end. -file("src/viva_tensor/tensor.gleam", 2024). ?DOC(false). -spec flatten(tensor()) -> tensor(). flatten(T) -> _pipe = try_flatten(T), gleam@result:unwrap(_pipe, {tensor, [], [0]}). -file("src/viva_tensor/tensor.gleam", 3840). ?DOC(false). -spec materialize_many(list(tensor())) -> {ok, list(list(float()))} | {error, viva_tensor@core@error:tensor_error()}. materialize_many(Tensors) -> _pipe = Tensors, _pipe@1 = gleam@list:fold( _pipe, {ok, []}, fun(Acc, Tensor) -> gleam@result:'try'( Acc, fun(Values) -> gleam@result:'try'( try_to_list(Tensor), fun(Data) -> {ok, [Data | Values]} end ) end ) end ), gleam@result:map(_pipe@1, fun lists:reverse/1). -file("src/viva_tensor/tensor.gleam", 2030). ?DOC(false). -spec try_concat(list(tensor())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_concat(Tensors) -> gleam@result:'try'( materialize_many(Tensors), fun(Data) -> {ok, from_list(lists:append(Data))} end ). -file("src/viva_tensor/tensor.gleam", 2036). ?DOC(false). -spec concat(list(tensor())) -> tensor(). concat(Tensors) -> _pipe = try_concat(Tensors), gleam@result:unwrap(_pipe, from_list([])). -file("src/viva_tensor/tensor.gleam", 3833). ?DOC(false). -spec list_at_float_list(list(list(float())), integer()) -> {ok, list(float())} | {error, nil}. list_at_float_list(Lst, Index) -> viva_tensor@core@layout_math:at(Lst, Index). -file("src/viva_tensor/tensor.gleam", 3829). ?DOC(false). -spec list_at_tensor(list(tensor()), integer()) -> {ok, tensor()} | {error, nil}. list_at_tensor(Lst, Index) -> viva_tensor@core@layout_math:at(Lst, Index). -file("src/viva_tensor/tensor.gleam", 2044). ?DOC(false). -spec concat_axis(list(tensor()), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. concat_axis(Tensors, Axis) -> case Tensors of [] -> {error, {invalid_shape, <<"Cannot concatenate empty list"/utf8>>}}; [Single] -> {ok, Single}; [First | Rest] -> Base_shape = erlang:element(3, First), R = erlang:length(Base_shape), case (Axis >= 0) andalso (Axis < R) of false -> {error, {dimension_error, <<"Invalid axis for concatenation"/utf8>>}}; true -> Shapes_ok = gleam@list:all( Rest, fun(T) -> T_shape = erlang:element(3, T), case erlang:length(T_shape) =:= R of false -> false; true -> _pipe = gleam@list:zip(Base_shape, T_shape), _pipe@1 = gleam@list:index_map( _pipe, fun(Pair, I) -> {Pair, I} end ), gleam@list:all( _pipe@1, fun(X) -> {{Dim_a, Dim_b}, I@1} = X, (I@1 =:= Axis) orelse (Dim_a =:= Dim_b) end ) end end ), case Shapes_ok of false -> {error, {invalid_shape, <<"Shapes must match except on concat axis"/utf8>>}}; true -> Concat_dim = gleam@list:fold( Tensors, 0, fun(Acc, T@1) -> case viva_tensor@core@tensor_axis:axis_size( erlang:element(3, T@1), Axis ) of {ok, D} -> Acc + D; {error, _} -> Acc end end ), New_shape = begin _pipe@2 = Base_shape, gleam@list:index_map( _pipe@2, fun(D@1, I@2) -> case I@2 =:= Axis of true -> Concat_dim; false -> D@1 end end ) end, case Axis =:= 0 of true -> gleam@result:'try'( materialize_many(Tensors), fun(Chunks) -> Data = lists:append(Chunks), {ok, {tensor, Data, New_shape}} end ); false -> gleam@result:'try'( materialize_many(Tensors), fun(Materialized) -> Total_size = gleam@list:fold( New_shape, 1, fun(Acc@1, D@2) -> Acc@1 * D@2 end ), _ = compute_strides(New_shape), Result = begin _pipe@3 = range_int( 0, Total_size - 1 ), _pipe@8 = gleam@list:fold( _pipe@3, {ok, []}, fun(Acc@2, Flat_idx) -> gleam@result:'try'( Acc@2, fun(Values) -> Indices = flat_to_multi( Flat_idx, New_shape ), gleam@result:'try'( begin _pipe@4 = list_at_int( Indices, Axis ), gleam@result:map_error( _pipe@4, fun( _ ) -> {dimension_error, <<"Invalid axis for concatenation"/utf8>>} end ) end, fun( Axis_idx ) -> {Tensor_idx, Local_axis_idx, _} = gleam@list:fold( Tensors, {-1, Axis_idx, 0}, fun( Acc@3, T@2 ) -> {Found_t, Remaining, T_idx} = Acc@3, case Found_t >= 0 of true -> Acc@3; false -> T_axis_size = case viva_tensor@core@tensor_axis:axis_size( erlang:element( 3, T@2 ), Axis ) of {ok, D@3} -> D@3; {error, _} -> 0 end, case Remaining < T_axis_size of true -> {T_idx, Remaining, T_idx}; false -> {-1, Remaining - T_axis_size, T_idx + 1} end end end ), Local_indices = begin _pipe@5 = Indices, gleam@list:index_map( _pipe@5, fun( Idx, I@3 ) -> case I@3 =:= Axis of true -> Local_axis_idx; false -> Idx end end ) end, case {list_at_tensor( Tensors, Tensor_idx ), list_at_float_list( Materialized, Tensor_idx )} of {{ok, T@3}, {ok, T_data}} -> T_strides = compute_strides( erlang:element( 3, T@3 ) ), Local_flat = begin _pipe@6 = gleam@list:zip( Local_indices, T_strides ), gleam@list:fold( _pipe@6, 0, fun( A, P ) -> A + (erlang:element( 1, P ) * erlang:element( 2, P )) end ) end, gleam@result:'try'( begin _pipe@7 = list_at_float( T_data, Local_flat ), gleam@result:map_error( _pipe@7, fun( _ ) -> {index_out_of_bounds, Local_flat, erlang:length( T_data )} end ) end, fun( Value ) -> {ok, [Value | Values]} end ); {_, _} -> {error, {dimension_error, <<"Invalid tensor index for concatenation"/utf8>>}} end end ) end ) end ), gleam@result:map( _pipe@8, fun lists:reverse/1 ) end, case Result of {ok, Data@1} -> {ok, {tensor, Data@1, New_shape}}; {error, Error} -> {error, Error} end end ) end end end end. -file("src/viva_tensor/tensor.gleam", 3604). ?DOC(false). -spec insert_stride(list(integer()), integer(), integer()) -> list(integer()). insert_stride(Strides, Axis, Stride) -> {Before, After} = gleam@list:split(Strides, Axis), lists:append([Before, [Stride], After]). -file("src/viva_tensor/tensor.gleam", 3636). ?DOC(false). -spec try_unsqueeze(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_unsqueeze(T, Axis) -> Rnk = erlang:length(erlang:element(3, T)), Insert_at = case Axis < 0 of true -> (Rnk + Axis) + 1; false -> Axis end, case (Insert_at < 0) orelse (Insert_at > Rnk) of true -> {error, {dimension_error, <<"Axis out of bounds"/utf8>>}}; false -> {Before, After} = gleam@list:split(erlang:element(3, T), Insert_at), New_shape = lists:append([Before, [1], After]), case T of {tensor, Data, _} -> {ok, {tensor, Data, New_shape}}; {native_tensor, Ref, _} -> {ok, {native_tensor, Ref, New_shape}}; {strided_tensor, Storage, Shape, Strides, Offset} -> New_strides = case Strides =:= compute_strides(Shape) of true -> compute_strides(New_shape); false -> insert_stride(Strides, Insert_at, 0) end, {ok, {strided_tensor, Storage, New_shape, New_strides, Offset}} end end. -file("src/viva_tensor/tensor.gleam", 3669). ?DOC(false). -spec unsqueeze(tensor(), integer()) -> tensor(). unsqueeze(T, Axis) -> _pipe = try_unsqueeze(T, Axis), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 2203). ?DOC(false). -spec stack(list(tensor()), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. stack(Tensors, Axis) -> case Tensors of [] -> {error, {invalid_shape, <<"Cannot stack empty list"/utf8>>}}; [First | Rest] -> Base_shape = erlang:element(3, First), Shapes_ok = gleam@list:all( Rest, fun(T) -> erlang:element(3, T) =:= Base_shape end ), case Shapes_ok of false -> {error, {shape_mismatch, Base_shape, []}}; true -> N_tensors = erlang:length(Tensors), R = erlang:length(Base_shape), Insert_axis = case Axis < 0 of true -> (R + Axis) + 1; false -> Axis end, case (Insert_axis >= 0) andalso (Insert_axis =< R) of false -> {error, {dimension_error, <<"Invalid axis for stacking"/utf8>>}}; true -> {Before, After} = gleam@list:split( Base_shape, Insert_axis ), _ = lists:append([Before, [N_tensors], After]), Unsqueezed = begin _pipe = Tensors, gleam@list:map( _pipe, fun(T@1) -> unsqueeze(T@1, Insert_axis) end ) end, concat_axis(Unsqueezed, Insert_axis) end end end. -file("src/viva_tensor/tensor.gleam", 2242). ?DOC(false). -spec try_take_first(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_take_first(T, N) -> gleam@result:'try'(try_to_list(T), fun(Data) -> case erlang:element(3, T) of [] -> {ok, T}; [First_dim | Rest_dims] -> Take_n = gleam@int:min(N, First_dim), Stride = gleam@list:fold( Rest_dims, 1, fun(Acc, D) -> Acc * D end ), New_data = gleam@list:take(Data, Take_n * Stride), New_shape = [Take_n | Rest_dims], {ok, {tensor, New_data, New_shape}} end end). -file("src/viva_tensor/tensor.gleam", 2257). ?DOC(false). -spec take_first(tensor(), integer()) -> tensor(). take_first(T, N) -> _pipe = try_take_first(T, N), gleam@result:unwrap(_pipe, {tensor, [], [0]}). -file("src/viva_tensor/tensor.gleam", 2263). ?DOC(false). -spec try_take_last(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_take_last(T, N) -> gleam@result:'try'(try_to_list(T), fun(Data) -> case erlang:element(3, T) of [] -> {ok, T}; [First_dim | Rest_dims] -> Take_n = gleam@int:min(N, First_dim), Stride = gleam@list:fold( Rest_dims, 1, fun(Acc, D) -> Acc * D end ), Skip = (First_dim - Take_n) * Stride, New_data = gleam@list:drop(Data, Skip), New_shape = [Take_n | Rest_dims], {ok, {tensor, New_data, New_shape}} end end). -file("src/viva_tensor/tensor.gleam", 2279). ?DOC(false). -spec take_last(tensor(), integer()) -> tensor(). take_last(T, N) -> _pipe = try_take_last(T, N), gleam@result:unwrap(_pipe, {tensor, [], [0]}). -file("src/viva_tensor/tensor.gleam", 2285). ?DOC(false). -spec try_take_flat(tensor(), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_take_flat(T, Indices) -> gleam@result:'try'( try_to_list(T), fun(Data) -> Values_result = begin _pipe = Indices, gleam@list:fold( _pipe, {ok, []}, fun(Acc, Index) -> gleam@result:'try'( Acc, fun(Values) -> gleam@result:'try'( begin _pipe@1 = list_at_float(Data, Index), gleam@result:map_error( _pipe@1, fun(_) -> {index_out_of_bounds, Index, erlang:length(Data)} end ) end, fun(Value) -> {ok, [Value | Values]} end ) end ) end ) end, gleam@result:'try'( Values_result, fun(Values@1) -> {ok, {tensor, lists:reverse(Values@1), [erlang:length(Indices)]}} end ) end ). -file("src/viva_tensor/tensor.gleam", 2306). ?DOC(false). -spec take_flat(tensor(), list(integer())) -> tensor(). take_flat(T, Indices) -> _pipe = try_take_flat(T, Indices), gleam@result:unwrap(_pipe, {tensor, [], [0]}). -file("src/viva_tensor/tensor.gleam", 2312). ?DOC(false). -spec try_take(tensor(), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_take(T, Indices) -> try_take_flat(T, Indices). -file("src/viva_tensor/tensor.gleam", 2317). ?DOC(false). -spec try_nonzero_flat(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_nonzero_flat(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> Indices = begin _pipe = Data, _pipe@1 = gleam@list:index_map( _pipe, fun(Value, Index) -> {Value, Index} end ), _pipe@2 = gleam@list:filter( _pipe@1, fun(Pair) -> {Value@1, _} = Pair, Value@1 /= +0.0 end ), gleam@list:map( _pipe@2, fun(Pair@1) -> {_, Index@1} = Pair@1, erlang:float(Index@1) end ) end, {ok, {tensor, Indices, [erlang:length(Indices)]}} end ). -file("src/viva_tensor/tensor.gleam", 2335). ?DOC(false). -spec nonzero_flat(tensor()) -> tensor(). nonzero_flat(T) -> _pipe = try_nonzero_flat(T), gleam@result:unwrap(_pipe, {tensor, [], [0]}). -file("src/viva_tensor/tensor.gleam", 2341). ?DOC(false). -spec try_nonzero(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_nonzero(T) -> try_nonzero_flat(T). -file("src/viva_tensor/tensor.gleam", 2357). ?DOC(false). -spec take(tensor(), list(integer()), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. take(T, Indices, Axis) -> Shape = shape(T), R = erlang:length(Shape), case R of 0 -> {error, {dimension_error, <<"take requires a tensor with rank >= 1"/utf8>>}}; _ -> Normalized_axis = case Axis < 0 of true -> Axis + R; false -> Axis end, case (Normalized_axis < 0) orelse (Normalized_axis >= R) of true -> {error, {dimension_error, <<<<<<"take: axis "/utf8, (erlang:integer_to_binary(Axis))/binary>>/binary, " out of bounds for rank "/utf8>>/binary, (erlang:integer_to_binary(R))/binary>>}}; false -> Dim_size@1 = case list_at_int(Shape, Normalized_axis) of {ok, Dim_size} -> Dim_size; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"viva_tensor/tensor"/utf8>>, function => <<"take"/utf8>>, line => 2380, value => _assert_fail, start => 68478, 'end' => 68539, pattern_start => 68489, pattern_end => 68501}) end, gleam@result:'try'( begin _pipe = Indices, _pipe@1 = gleam@list:fold( _pipe, {ok, []}, fun(Acc, Idx) -> gleam@result:'try'( Acc, fun(Rev) -> Resolved = case Idx < 0 of true -> Idx + Dim_size@1; false -> Idx end, case (Resolved < 0) orelse (Resolved >= Dim_size@1) of true -> {error, {index_out_of_bounds, Idx, Dim_size@1}}; false -> {ok, [Resolved | Rev]} end end ) end ), gleam@result:map(_pipe@1, fun lists:reverse/1) end, fun(Normalized_indices) -> gleam@result:'try'( try_to_list(T), fun(Data) -> Strides = compute_strides(Shape), Axis_stride@1 = case list_at_int( Strides, Normalized_axis ) of {ok, Axis_stride} -> Axis_stride; _assert_fail@1 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"viva_tensor/tensor"/utf8>>, function => <<"take"/utf8>>, line => 2398, value => _assert_fail@1, start => 69183, 'end' => 69249, pattern_start => 69194, pattern_end => 69209} ) end, Outer_count = begin _pipe@2 = gleam@list:take( Shape, Normalized_axis ), gleam@list:fold( _pipe@2, 1, fun(Acc@1, D) -> Acc@1 * D end ) end, Outer_stride = case Normalized_axis of 0 -> gleam@list:fold( Shape, 1, fun(Acc@2, D@1) -> Acc@2 * D@1 end ); _ -> S@1 = case list_at_int( Strides, Normalized_axis - 1 ) of {ok, S} -> S; _assert_fail@2 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"viva_tensor/tensor"/utf8>>, function => <<"take"/utf8>>, line => 2405, value => _assert_fail@2, start => 69522, 'end' => 69582, pattern_start => 69533, pattern_end => 69538} ) end, S@1 end, Inner_size = Axis_stride@1, Out_data = begin _pipe@3 = range_int(0, Outer_count - 1), gleam@list:flat_map( _pipe@3, fun(Outer) -> _pipe@4 = Normalized_indices, gleam@list:flat_map( _pipe@4, fun(Idx@1) -> Base = (Outer * Outer_stride) + (Idx@1 * Axis_stride@1), _pipe@5 = range_int( 0, Inner_size - 1 ), gleam@list:map( _pipe@5, fun(K) -> case list_at_float( Data, Base + K ) of {ok, V} -> V; {error, _} -> +0.0 end end ) end ) end ) end, New_shape = begin _pipe@6 = Shape, gleam@list:index_map( _pipe@6, fun(D@2, I) -> case I =:= Normalized_axis of true -> erlang:length( Normalized_indices ); false -> D@2 end end ) end, {ok, {tensor, Out_data, New_shape}} end ) end ) end end. -file("src/viva_tensor/tensor.gleam", 5277). ?DOC(false). -spec string_join(list(binary()), binary()) -> binary(). string_join(Strings, Sep) -> case Strings of [] -> <<""/utf8>>; [S] -> S; [S@1 | Rest] -> <<<>/binary, (string_join(Rest, Sep))/binary>> end. -file("src/viva_tensor/tensor.gleam", 5273). ?DOC(false). -spec shape_to_string(list(integer())) -> binary(). shape_to_string(Shp) -> <<<<"["/utf8, (begin _pipe = gleam@list:map(Shp, fun erlang:integer_to_binary/1), string_join(_pipe, <<", "/utf8>>) end)/binary>>/binary, "]"/utf8>>. -file("src/viva_tensor/tensor.gleam", 2450). ?DOC(false). -spec gather(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. gather(T, Indices) -> case shape(Indices) of [_] -> gleam@result:'try'( try_to_list(Indices), fun(Idx_data) -> Int_indices = gleam@list:map(Idx_data, fun erlang:trunc/1), take(T, Int_indices, 0) end ); Other -> {error, {dimension_error, <<"gather requires a 1D index tensor, got shape "/utf8, (shape_to_string(Other))/binary>>}} end. -file("src/viva_tensor/tensor.gleam", 2476). ?DOC(false). -spec mask_select(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. mask_select(T, Mask) -> T_shape = shape(T), M_shape = shape(Mask), case T_shape =:= M_shape of false -> {error, {shape_mismatch, T_shape, M_shape}}; true -> gleam@result:'try'( try_to_list(T), fun(Data) -> gleam@result:'try'( try_to_list(Mask), fun(Mask_data) -> Selected = begin _pipe = gleam@list:zip(Data, Mask_data), gleam@list:filter_map( _pipe, fun(Pair) -> {V, M} = Pair, case M /= +0.0 of true -> {ok, V}; false -> {error, nil} end end ) end, {ok, {tensor, Selected, [erlang:length(Selected)]}} end ) end ) end. -file("src/viva_tensor/tensor.gleam", 2503). ?DOC(false). -spec nonzero(tensor()) -> {ok, list(list(integer()))} | {error, viva_tensor@core@error:tensor_error()}. nonzero(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> Shape = shape(T), Indices = begin _pipe = Data, _pipe@1 = gleam@list:index_map( _pipe, fun(Value, Flat_idx) -> {Value, Flat_idx} end ), _pipe@2 = gleam@list:filter( _pipe@1, fun(Pair) -> {Value@1, _} = Pair, Value@1 /= +0.0 end ), gleam@list:map( _pipe@2, fun(Pair@1) -> {_, Flat_idx@1} = Pair@1, flat_to_multi(Flat_idx@1, Shape) end ) end, {ok, Indices} end ). -file("src/viva_tensor/tensor.gleam", 3873). ?DOC(false). -spec broadcast_data(tensor(), list(integer())) -> {ok, list(float())} | {error, viva_tensor@core@error:tensor_error()}. broadcast_data(T, Target_shape) -> gleam@result:'try'( try_to_list(T), fun(Data) -> viva_tensor@core@tensor_broadcast:broadcast_data_values( Data, erlang:element(3, T), Target_shape ) end ). -file("src/viva_tensor/tensor.gleam", 2991). ?DOC(false). -spec broadcast_to(tensor(), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. broadcast_to(T, Target_shape) -> case viva_tensor@core@tensor_broadcast:can_broadcast( erlang:element(3, T), Target_shape ) of false -> {error, {broadcast_error, erlang:element(3, T), Target_shape}}; true -> case erlang:element(3, T) =:= Target_shape of true -> {ok, T}; false -> case T of {tensor, Data, Shape} -> Storage = viva_tensor@core@ffi:list_to_array(Data), Strides = viva_tensor@core@tensor_broadcast:broadcast_strides( Shape, compute_strides(Shape), Target_shape ), {ok, {strided_tensor, Storage, Target_shape, Strides, 0}}; {strided_tensor, Storage@1, Shape@1, Strides@1, Offset} -> View_strides = viva_tensor@core@tensor_broadcast:broadcast_strides( Shape@1, Strides@1, Target_shape ), {ok, {strided_tensor, Storage@1, Target_shape, View_strides, Offset}}; {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_broadcast_to( Ref, Target_shape ) of {ok, View_ref} -> {ok, {native_tensor, View_ref, Target_shape}}; {error, _} -> gleam@result:'try'( broadcast_data(T, Target_shape), fun(Data@1) -> {ok, {tensor, Data@1, Target_shape}} end ) end end end end. -file("src/viva_tensor/tensor.gleam", 3044). ?DOC(false). -spec broadcast_pair(tensor(), tensor()) -> {ok, {tensor(), tensor()}} | {error, viva_tensor@core@error:tensor_error()}. broadcast_pair(A, B) -> gleam@result:'try'( viva_tensor@core@tensor_broadcast:broadcast_shape( erlang:element(3, A), erlang:element(3, 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) -> {ok, {A_bc, B_bc}} end ) end ) end ). -file("src/viva_tensor/tensor.gleam", 2521). ?DOC(false). -spec try_masked_select(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_masked_select(T, Mask) -> gleam@result:'try'( broadcast_pair(T, Mask), fun(Pair) -> {Values_tensor, Mask_tensor} = Pair, gleam@result:'try'( try_to_list(Values_tensor), fun(Values) -> gleam@result:'try'( try_to_list(Mask_tensor), fun(Mask_values) -> Selected = begin _pipe = gleam@list:zip(Values, Mask_values), gleam@list:filter_map( _pipe, fun(Pair@1) -> {Value, Mask_value} = Pair@1, case Mask_value /= +0.0 of true -> {ok, Value}; false -> {error, nil} end end ) end, {ok, {tensor, Selected, [erlang:length(Selected)]}} end ) end ) end ). -file("src/viva_tensor/tensor.gleam", 2544). ?DOC(false). -spec masked_select(tensor(), tensor()) -> tensor(). masked_select(T, Mask) -> _pipe = try_masked_select(T, Mask), gleam@result:unwrap(_pipe, {tensor, [], [0]}). -file("src/viva_tensor/tensor.gleam", 3881). ?DOC(false). -spec multi_to_flat(list(integer()), list(integer())) -> integer(). multi_to_flat(Indices, Shape) -> viva_tensor@core@layout_math:multi_to_flat(Indices, Shape). -file("src/viva_tensor/tensor.gleam", 3852). ?DOC(false). -spec slice_bounds_valid(list(integer()), list(integer()), list(integer())) -> boolean(). slice_bounds_valid(Shape, Start, Lengths) -> _pipe = gleam@list:zip(Shape, gleam@list:zip(Start, Lengths)), gleam@list:all( _pipe, fun(Item) -> {Dim, Bounds} = Item, {Offset, Len} = Bounds, ((Offset >= 0) andalso (Len >= 0)) andalso ((Offset + Len) =< Dim) end ). -file("src/viva_tensor/tensor.gleam", 2551). ?DOC(false). -spec slice(tensor(), list(integer()), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. slice(T, Start, Lengths) -> gleam@result:'try'( try_to_list(T), fun(Data) -> R = rank(T), case (erlang:length(Start) =:= R) andalso (erlang:length(Lengths) =:= R) of false -> {error, {slice_arity_mismatch, erlang:element(3, T), Start, Lengths}}; true -> case R of 1 -> gleam@result:'try'( begin _pipe = list_at_int(Start, 0), gleam@result:map_error( _pipe, fun(_) -> {dimension_error, <<"Invalid slice start"/utf8>>} end ) end, fun(S) -> gleam@result:'try'( begin _pipe@1 = list_at_int(Lengths, 0), gleam@result:map_error( _pipe@1, fun(_) -> {dimension_error, <<"Invalid slice length"/utf8>>} end ) end, fun(Len) -> gleam@result:'try'( viva_tensor@core@tensor_axis:axis_size( erlang:element(3, T), 0 ), fun(Dim) -> case ((S < 0) orelse (Len < 0)) orelse ((S + Len) > Dim) of true -> {error, {index_out_of_bounds, S + Len, Dim}}; false -> Sliced = begin _pipe@2 = Data, _pipe@3 = gleam@list:drop( _pipe@2, S ), gleam@list:take( _pipe@3, Len ) end, {ok, {tensor, Sliced, [Len]}} end end ) end ) end ); _ -> case slice_bounds_valid( erlang:element(3, T), Start, Lengths ) of false -> {error, {dimension_error, <<"Slice bounds exceed tensor shape"/utf8>>}}; true -> New_size = gleam@list:fold( Lengths, 1, fun(Acc, D) -> Acc * D end ), Result = begin _pipe@4 = range_int(0, New_size - 1), _pipe@6 = gleam@list:fold( _pipe@4, {ok, []}, fun(Acc@1, Flat_idx) -> gleam@result:'try'( Acc@1, fun(Values) -> Local_indices = flat_to_multi( Flat_idx, Lengths ), Global_indices = gleam@list:map2( Local_indices, Start, fun(L, S@1) -> L + S@1 end ), Global_flat = multi_to_flat( Global_indices, erlang:element(3, T) ), gleam@result:'try'( begin _pipe@5 = list_at_float( Data, Global_flat ), gleam@result:map_error( _pipe@5, fun(_) -> {index_out_of_bounds, Global_flat, erlang:length( Data )} end ) end, fun(Value) -> {ok, [Value | Values]} end ) end ) end ), gleam@result:map( _pipe@6, fun lists:reverse/1 ) end, case Result of {ok, Values@1} -> {ok, {tensor, Values@1, Lengths}}; {error, Error} -> {error, Error} end end end end end ). -file("src/viva_tensor/tensor.gleam", 2620). ?DOC(false). -spec try_norm(tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_norm(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> Sum_sq = gleam@list:fold( Data, +0.0, fun(Acc, X) -> Acc + (X * X) end ), {ok, viva_tensor@core@ffi:sqrt(Sum_sq)} end ). -file("src/viva_tensor/tensor.gleam", 2627). ?DOC(false). -spec norm(tensor()) -> float(). norm(T) -> _pipe = try_norm(T), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 2633). ?DOC(false). -spec try_normalize(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_normalize(T) -> gleam@result:'try'(try_norm(T), fun(N) -> case N > 0.0001 of true -> try_scale(T, case N of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> 1.0 / Gleam@denominator end); false -> {ok, T} end end). -file("src/viva_tensor/tensor.gleam", 2642). ?DOC(false). -spec normalize(tensor()) -> tensor(). normalize(T) -> _pipe = try_normalize(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 2648). ?DOC(false). -spec is_close(float(), float(), float(), float()) -> boolean(). is_close(A, B, Rtol, Atol) -> viva_math@precision:is_close(A, B, Rtol, Atol). -file("src/viva_tensor/tensor.gleam", 2653). ?DOC(false). -spec all_close(tensor(), tensor(), float(), float()) -> {ok, boolean()} | {error, viva_tensor@core@error:tensor_error()}. all_close(A, B, Rtol, Atol) -> case erlang:element(3, A) =:= erlang:element(3, B) of false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, B)}}; true -> gleam@result:'try'( try_to_list(A), fun(A_data) -> gleam@result:'try'( try_to_list(B), fun(B_data) -> {ok, viva_math@precision:all_close( gleam@list:zip(A_data, B_data), Rtol, Atol )} end ) end ) end. -file("src/viva_tensor/tensor.gleam", 2765). ?DOC(false). -spec paired_unzipped_data(tensor(), tensor(), binary()) -> {ok, {list(float()), list(float())}} | {error, viva_tensor@core@error:tensor_error()}. paired_unzipped_data(A, B, Operation) -> case erlang:element(3, A) =:= erlang:element(3, B) of false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, B)}}; true -> gleam@result:'try'( try_to_list(A), fun(A_data) -> gleam@result:'try'( try_to_list(B), fun(B_data) -> case A_data of [] -> {error, {dimension_error, <>}}; _ -> {ok, {A_data, B_data}} end end ) end ) end. -file("src/viva_tensor/tensor.gleam", 2671). ?DOC(false). -spec try_euclidean_distance(tensor(), tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_euclidean_distance(A, B) -> gleam@result:'try'( paired_unzipped_data(A, B, <<"euclidean_distance"/utf8>>), fun(_use0) -> {Xs, Ys} = _use0, case viva_math@vecn:euclidean_distance(Xs, Ys) of {ok, Value} -> {ok, Value}; {error, _} -> {error, {dimension_error, <<"euclidean_distance requires non-empty tensors"/utf8>>}} end end ). -file("src/viva_tensor/tensor.gleam", 2684). ?DOC(false). -spec euclidean_distance(tensor(), tensor()) -> float(). euclidean_distance(A, B) -> _pipe = try_euclidean_distance(A, B), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 2690). ?DOC(false). -spec try_manhattan_distance(tensor(), tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_manhattan_distance(A, B) -> gleam@result:'try'( paired_unzipped_data(A, B, <<"manhattan_distance"/utf8>>), fun(_use0) -> {Xs, Ys} = _use0, case viva_math@vecn:manhattan_distance(Xs, Ys) of {ok, Value} -> {ok, Value}; {error, _} -> {error, {dimension_error, <<"manhattan_distance requires non-empty tensors"/utf8>>}} end end ). -file("src/viva_tensor/tensor.gleam", 2703). ?DOC(false). -spec manhattan_distance(tensor(), tensor()) -> float(). manhattan_distance(A, B) -> _pipe = try_manhattan_distance(A, B), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 2709). ?DOC(false). -spec try_cosine_similarity(tensor(), tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_cosine_similarity(A, B) -> gleam@result:'try'( paired_unzipped_data(A, B, <<"cosine_similarity"/utf8>>), fun(_use0) -> {Xs, Ys} = _use0, gleam@result:'try'( try_norm(A), fun(A_norm) -> gleam@result:'try'( try_norm(B), fun(B_norm) -> case (A_norm =< +0.0) orelse (B_norm =< +0.0) of true -> {error, {dimension_error, <<"cosine_similarity requires non-zero tensors"/utf8>>}}; false -> case viva_math@vecn:cosine_similarity( Xs, Ys ) of {ok, Value} -> {ok, Value}; {error, _} -> {error, {dimension_error, <<"cosine_similarity requires non-empty tensors"/utf8>>}} end end end ) end ) end ). -file("src/viva_tensor/tensor.gleam", 2730). ?DOC(false). -spec cosine_similarity(tensor(), tensor()) -> float(). cosine_similarity(A, B) -> _pipe = try_cosine_similarity(A, B), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 2747). ?DOC(false). -spec paired_tensor_data(tensor(), tensor(), binary()) -> {ok, list({float(), float()})} | {error, viva_tensor@core@error:tensor_error()}. paired_tensor_data(A, B, Operation) -> case erlang:element(3, A) =:= erlang:element(3, B) of false -> {error, {shape_mismatch, erlang:element(3, A), erlang:element(3, B)}}; true -> gleam@result:'try'( try_to_list(A), fun(A_data) -> gleam@result:'try'( try_to_list(B), fun(B_data) -> case A_data of [] -> {error, {dimension_error, <>}}; _ -> {ok, gleam@list:zip(A_data, B_data)} end end ) end ) end. -file("src/viva_tensor/tensor.gleam", 2736). ?DOC(false). -spec try_dot_similarity(tensor(), tensor()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. try_dot_similarity(A, B) -> gleam@result:'try'( paired_tensor_data(A, B, <<"dot_similarity"/utf8>>), fun(Pairs) -> {ok, gleam@list:fold( Pairs, +0.0, fun(Acc, Pair) -> Acc + (erlang:element(1, Pair) * erlang:element(2, Pair)) end )} end ). -file("src/viva_tensor/tensor.gleam", 2742). ?DOC(false). -spec dot_similarity(tensor(), tensor()) -> float(). dot_similarity(A, B) -> _pipe = try_dot_similarity(A, B), gleam@result:unwrap(_pipe, +0.0). -file("src/viva_tensor/tensor.gleam", 2784). ?DOC(false). -spec try_zscore(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_zscore(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> case viva_math@statistics:z_score(Data) of {ok, Values} -> {ok, {tensor, Values, shape(T)}}; {error, _} -> {error, {dimension_error, <<"zscore requires non-empty non-constant tensor"/utf8>>}} end end ). -file("src/viva_tensor/tensor.gleam", 2794). ?DOC(false). -spec zscore(tensor()) -> tensor(). zscore(T) -> _pipe = try_zscore(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 2800). ?DOC(false). -spec try_standardize(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_standardize(T) -> try_zscore(T). -file("src/viva_tensor/tensor.gleam", 2805). ?DOC(false). -spec standardize(tensor()) -> tensor(). standardize(T) -> zscore(T). -file("src/viva_tensor/tensor.gleam", 2810). ?DOC(false). -spec try_minmax_scale(tensor(), float(), float()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_minmax_scale(T, Feature_min, Feature_max) -> case Feature_max =< Feature_min of true -> {error, {invalid_shape, <<"minmax_scale requires feature_max > feature_min"/utf8>>}}; false -> gleam@result:'try'( try_min(T), fun(Min_value) -> gleam@result:'try'( try_max(T), fun(Max_value) -> Range = Max_value - Min_value, case Range =< +0.0 of true -> {error, {dimension_error, <<"minmax_scale requires a non-constant tensor"/utf8>>}}; false -> Target_range = Feature_max - Feature_min, try_map(T, fun(X) -> ((case Range of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> (X - Min_value) / Gleam@denominator end) * Target_range) + Feature_min end) end end ) end ) end. -file("src/viva_tensor/tensor.gleam", 2838). ?DOC(false). -spec minmax_scale(tensor(), float(), float()) -> tensor(). minmax_scale(T, Feature_min, Feature_max) -> _pipe = try_minmax_scale(T, Feature_min, Feature_max), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 2848). ?DOC(false). -spec try_clip_by_norm(tensor(), float()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_clip_by_norm(T, Max_norm) -> case Max_norm < +0.0 of true -> {error, {invalid_shape, <<"clip_by_norm requires max_norm >= 0"/utf8>>}}; false -> gleam@result:'try'( try_norm(T), fun(N) -> case (N > Max_norm) andalso (N > +0.0) of true -> try_scale(T, case N of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> Max_norm / Gleam@denominator end); false -> {ok, T} end end ) end. -file("src/viva_tensor/tensor.gleam", 2865). ?DOC(false). -spec clip_by_norm(tensor(), float()) -> tensor(). clip_by_norm(T, Max_norm) -> _pipe = try_clip_by_norm(T, Max_norm), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 2871). ?DOC(false). -spec try_clamp(tensor(), float(), float()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_clamp(T, Min_val, Max_val) -> case Min_val > Max_val of true -> {error, {invalid_shape, <<"clamp requires min <= max"/utf8>>}}; false -> try_map( T, fun(X) -> gleam@float:min(gleam@float:max(X, Min_val), Max_val) end ) end. -file("src/viva_tensor/tensor.gleam", 2883). ?DOC(false). -spec clamp(tensor(), float(), float()) -> tensor(). clamp(T, Min_val, Max_val) -> _pipe = try_clamp(T, Min_val, Max_val), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 2889). ?DOC(false). -spec try_clip(tensor(), float(), float()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_clip(T, Min_val, Max_val) -> try_clamp(T, Min_val, Max_val). -file("src/viva_tensor/tensor.gleam", 2898). ?DOC(false). -spec clip(tensor(), float(), float()) -> tensor(). clip(T, Min_val, Max_val) -> clamp(T, Min_val, Max_val). -file("src/viva_tensor/tensor.gleam", 2905). ?DOC(false). -spec random_uniform(list(integer())) -> tensor(). random_uniform(Shape) -> Size_val = gleam@list:fold(Shape, 1, fun(Acc, Dim) -> Acc * Dim end), Data = begin _pipe = range_int(1, Size_val), gleam@list:map( _pipe, fun(_) -> viva_tensor@core@ffi:random_uniform() end ) end, {tensor, Data, Shape}. -file("src/viva_tensor/tensor.gleam", 2915). ?DOC(false). -spec random_normal(list(integer()), float(), float()) -> tensor(). random_normal(Shape, Mean_val, Std_val) -> Size_val = gleam@list:fold(Shape, 1, fun(Acc, Dim) -> Acc * Dim end), Data = begin _pipe = range_int(1, Size_val), gleam@list:map( _pipe, fun(_) -> U1 = gleam@float:max( viva_tensor@core@ffi:random_uniform(), 0.0001 ), U2 = viva_tensor@core@ffi:random_uniform(), Z = viva_tensor@core@ffi:sqrt( -2.0 * viva_tensor@core@ffi:log(U1) ) * viva_tensor@core@ffi:cos((2.0 * 3.14159265359) * U2), Mean_val + (Z * Std_val) end ) end, {tensor, Data, Shape}. -file("src/viva_tensor/tensor.gleam", 2939). ?DOC(false). -spec xavier_init(integer(), integer()) -> tensor(). xavier_init(Fan_in, Fan_out) -> Limit = viva_tensor@core@ffi:sqrt(case erlang:float(Fan_in + Fan_out) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> 6.0 / Gleam@denominator end), Data = begin _pipe = range_int(1, Fan_in * Fan_out), gleam@list:map( _pipe, fun(_) -> R = viva_tensor@core@ffi:random_uniform(), ((R * 2.0) * Limit) - Limit end ) end, {tensor, Data, [Fan_out, Fan_in]}. -file("src/viva_tensor/tensor.gleam", 2956). ?DOC(false). -spec he_init(integer(), integer()) -> tensor(). he_init(Fan_in, Fan_out) -> Std_val = viva_tensor@core@ffi:sqrt(case erlang:float(Fan_in) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> 2.0 / Gleam@denominator end), random_normal([Fan_out, Fan_in], +0.0, Std_val). -file("src/viva_tensor/tensor.gleam", 2969). ?DOC(false). -spec can_broadcast(list(integer()), list(integer())) -> boolean(). can_broadcast(A, B) -> viva_tensor@core@tensor_broadcast:can_broadcast(A, B). -file("src/viva_tensor/tensor.gleam", 2974). ?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:broadcast_shape(A, B). -file("src/viva_tensor/tensor.gleam", 2982). ?DOC(false). -spec broadcast_shapes(list(list(integer()))) -> {ok, list(integer())} | {error, viva_tensor@core@error:tensor_error()}. broadcast_shapes(Shapes) -> viva_tensor@core@tensor_broadcast:broadcast_shapes(Shapes). -file("src/viva_tensor/tensor.gleam", 3058). ?DOC(false). -spec add_broadcast(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. add_broadcast(A, B) -> gleam@result:'try'( broadcast_pair(A, B), fun(Pair) -> {A_bc, B_bc} = Pair, add(A_bc, B_bc) end ). -file("src/viva_tensor/tensor.gleam", 3065). ?DOC(false). -spec sub_broadcast(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. sub_broadcast(A, B) -> gleam@result:'try'( broadcast_pair(A, B), fun(Pair) -> {A_bc, B_bc} = Pair, sub(A_bc, B_bc) end ). -file("src/viva_tensor/tensor.gleam", 3072). ?DOC(false). -spec mul_broadcast(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. mul_broadcast(A, B) -> gleam@result:'try'( broadcast_pair(A, B), fun(Pair) -> {A_bc, B_bc} = Pair, mul(A_bc, B_bc) end ). -file("src/viva_tensor/tensor.gleam", 3079). ?DOC(false). -spec div_broadcast(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. div_broadcast(A, B) -> gleam@result:'try'( broadcast_pair(A, B), fun(Pair) -> {A_bc, B_bc} = Pair, 'div'(A_bc, B_bc) end ). -file("src/viva_tensor/tensor.gleam", 3169). ?DOC(false). -spec native_binary_or_map2( tensor(), tensor(), fun((float(), float()) -> float()), fun((viva_tensor@core@ffi:native_tensor_ref(), viva_tensor@core@ffi:native_tensor_ref()) -> {ok, viva_tensor@core@ffi:native_tensor_ref()} | {error, binary()}) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. native_binary_or_map2(A_bc, B_bc, Fallback, Native_op) -> case {A_bc, B_bc} of {{native_tensor, A_ref, Shape}, {native_tensor, B_ref, _}} -> case Native_op(A_ref, B_ref) of {ok, Ref} -> {ok, {native_tensor, Ref, Shape}}; {error, _} -> map2(A_bc, B_bc, Fallback) end; {_, _} -> map2(A_bc, B_bc, Fallback) end. -file("src/viva_tensor/tensor.gleam", 3086). ?DOC(false). -spec maximum(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. maximum(A, B) -> gleam@result:'try'( broadcast_pair(A, B), fun(Pair) -> {A_bc, B_bc} = Pair, native_binary_or_map2( A_bc, B_bc, fun gleam@float:max/2, fun viva_tensor@core@ffi:nt_maximum/2 ) end ). -file("src/viva_tensor/tensor.gleam", 3093). ?DOC(false). -spec try_maximum(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_maximum(A, B) -> maximum(A, B). -file("src/viva_tensor/tensor.gleam", 3098). ?DOC(false). -spec minimum(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. minimum(A, B) -> gleam@result:'try'( broadcast_pair(A, B), fun(Pair) -> {A_bc, B_bc} = Pair, native_binary_or_map2( A_bc, B_bc, fun gleam@float:min/2, fun viva_tensor@core@ffi:nt_minimum/2 ) end ). -file("src/viva_tensor/tensor.gleam", 3105). ?DOC(false). -spec try_minimum(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_minimum(A, B) -> minimum(A, B). -file("src/viva_tensor/tensor.gleam", 3187). ?DOC(false). -spec compare_broadcast( tensor(), tensor(), fun((float(), float()) -> boolean()), fun((viva_tensor@core@ffi:native_tensor_ref(), viva_tensor@core@ffi:native_tensor_ref()) -> {ok, viva_tensor@core@ffi:native_tensor_ref()} | {error, binary()}) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. compare_broadcast(A, B, Predicate, Native_op) -> gleam@result:'try'( broadcast_pair(A, B), fun(Pair) -> {A_bc, B_bc} = Pair, native_binary_or_map2( A_bc, B_bc, fun(X, Y) -> case Predicate(X, Y) of true -> 1.0; false -> +0.0 end end, Native_op ) end ). -file("src/viva_tensor/tensor.gleam", 3110). ?DOC(false). -spec equal(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. equal(A, B) -> compare_broadcast( A, B, fun(X, Y) -> X =:= Y end, fun viva_tensor@core@ffi:nt_equal/2 ). -file("src/viva_tensor/tensor.gleam", 3115). ?DOC(false). -spec try_equal(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_equal(A, B) -> equal(A, B). -file("src/viva_tensor/tensor.gleam", 3120). ?DOC(false). -spec not_equal(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. not_equal(A, B) -> compare_broadcast( A, B, fun(X, Y) -> X /= Y end, fun viva_tensor@core@ffi:nt_not_equal/2 ). -file("src/viva_tensor/tensor.gleam", 3125). ?DOC(false). -spec try_not_equal(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_not_equal(A, B) -> not_equal(A, B). -file("src/viva_tensor/tensor.gleam", 3130). ?DOC(false). -spec greater(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. greater(A, B) -> compare_broadcast( A, B, fun(X, Y) -> X > Y end, fun viva_tensor@core@ffi:nt_greater/2 ). -file("src/viva_tensor/tensor.gleam", 3135). ?DOC(false). -spec try_greater(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_greater(A, B) -> greater(A, B). -file("src/viva_tensor/tensor.gleam", 3140). ?DOC(false). -spec greater_equal(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. greater_equal(A, B) -> compare_broadcast( A, B, fun(X, Y) -> X >= Y end, fun viva_tensor@core@ffi:nt_greater_equal/2 ). -file("src/viva_tensor/tensor.gleam", 3145). ?DOC(false). -spec try_greater_equal(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_greater_equal(A, B) -> greater_equal(A, B). -file("src/viva_tensor/tensor.gleam", 3150). ?DOC(false). -spec less(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. less(A, B) -> compare_broadcast( A, B, fun(X, Y) -> X < Y end, fun viva_tensor@core@ffi:nt_less/2 ). -file("src/viva_tensor/tensor.gleam", 3155). ?DOC(false). -spec try_less(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_less(A, B) -> less(A, B). -file("src/viva_tensor/tensor.gleam", 3160). ?DOC(false). -spec less_equal(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. less_equal(A, B) -> compare_broadcast( A, B, fun(X, Y) -> X =< Y end, fun viva_tensor@core@ffi:nt_less_equal/2 ). -file("src/viva_tensor/tensor.gleam", 3165). ?DOC(false). -spec try_less_equal(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_less_equal(A, B) -> less_equal(A, B). -file("src/viva_tensor/tensor.gleam", 3240). ?DOC(false). -spec where_materialized(tensor(), tensor(), tensor(), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. where_materialized(Condition_bc, True_bc, False_bc, Target_shape) -> gleam@result:'try'( try_to_list(Condition_bc), fun(Condition_data) -> gleam@result:'try'( try_to_list(True_bc), fun(True_data) -> gleam@result:'try'( try_to_list(False_bc), fun(False_data) -> Data = gleam@list:map2( gleam@list:zip(Condition_data, True_data), False_data, fun(Pair, F) -> {C, T} = Pair, case C /= +0.0 of true -> T; false -> F end end ), {ok, {tensor, Data, Target_shape}} end ) end ) end ). -file("src/viva_tensor/tensor.gleam", 3210). ?DOC(false). -spec where(tensor(), tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. where(Condition, When_true, When_false) -> gleam@result:'try'( broadcast_shapes( [shape(Condition), shape(When_true), shape(When_false)] ), fun(Target_shape) -> gleam@result:'try'( broadcast_to(Condition, Target_shape), fun(Condition_bc) -> gleam@result:'try'( broadcast_to(When_true, Target_shape), fun(True_bc) -> gleam@result:'try'( broadcast_to(When_false, Target_shape), fun(False_bc) -> case {Condition_bc, True_bc, False_bc} of {{native_tensor, Condition_ref, _}, {native_tensor, True_ref, _}, {native_tensor, False_ref, _}} -> case viva_tensor@core@ffi:nt_where( Condition_ref, True_ref, False_ref ) of {ok, Ref} -> {ok, {native_tensor, Ref, Target_shape}}; {error, _} -> where_materialized( Condition_bc, True_bc, False_bc, Target_shape ) end; {_, _, _} -> where_materialized( Condition_bc, True_bc, False_bc, Target_shape ) end end ) end ) end ) end ). -file("src/viva_tensor/tensor.gleam", 3263). ?DOC(false). -spec try_where(tensor(), tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_where(Condition, When_true, When_false) -> where(Condition, When_true, When_false). -file("src/viva_tensor/tensor.gleam", 3284). ?DOC(false). -spec logical_not_materialized(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. logical_not_materialized(T) -> try_map(T, fun(X) -> case X =:= +0.0 of true -> 1.0; false -> +0.0 end end). -file("src/viva_tensor/tensor.gleam", 3272). ?DOC(false). -spec try_logical_not(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_logical_not(T) -> case T of {native_tensor, Ref, Shape} -> case viva_tensor@core@ffi:nt_logical_not(Ref) of {ok, Out_ref} -> {ok, {native_tensor, Out_ref, Shape}}; {error, _} -> logical_not_materialized(T) end; _ -> logical_not_materialized(T) end. -file("src/viva_tensor/tensor.gleam", 3294). ?DOC(false). -spec logical_not(tensor()) -> tensor(). logical_not(T) -> _pipe = try_logical_not(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 3338). ?DOC(false). -spec logical_broadcast( tensor(), tensor(), fun((float(), float()) -> boolean()), fun((viva_tensor@core@ffi:native_tensor_ref(), viva_tensor@core@ffi:native_tensor_ref()) -> {ok, viva_tensor@core@ffi:native_tensor_ref()} | {error, binary()}) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. logical_broadcast(A, B, Predicate, Native_op) -> gleam@result:'try'( broadcast_pair(A, B), fun(Pair) -> {A_bc, B_bc} = Pair, native_binary_or_map2( A_bc, B_bc, fun(X, Y) -> case Predicate(X, Y) of true -> 1.0; false -> +0.0 end end, Native_op ) end ). -file("src/viva_tensor/tensor.gleam", 3300). ?DOC(false). -spec logical_and(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. logical_and(A, B) -> logical_broadcast( A, B, fun(X, Y) -> (X /= +0.0) andalso (Y /= +0.0) end, fun viva_tensor@core@ffi:nt_logical_and/2 ). -file("src/viva_tensor/tensor.gleam", 3305). ?DOC(false). -spec try_logical_and(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_logical_and(A, B) -> logical_and(A, B). -file("src/viva_tensor/tensor.gleam", 3310). ?DOC(false). -spec logical_or(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. logical_or(A, B) -> logical_broadcast( A, B, fun(X, Y) -> (X /= +0.0) orelse (Y /= +0.0) end, fun viva_tensor@core@ffi:nt_logical_or/2 ). -file("src/viva_tensor/tensor.gleam", 3315). ?DOC(false). -spec try_logical_or(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_logical_or(A, B) -> logical_or(A, B). -file("src/viva_tensor/tensor.gleam", 3320). ?DOC(false). -spec logical_xor(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. logical_xor(A, B) -> logical_broadcast( A, B, fun(X, Y) -> X_truthy = X /= +0.0, Y_truthy = Y /= +0.0, X_truthy /= Y_truthy end, fun viva_tensor@core@ffi:nt_logical_xor/2 ). -file("src/viva_tensor/tensor.gleam", 3334). ?DOC(false). -spec try_logical_xor(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_logical_xor(A, B) -> logical_xor(A, B). -file("src/viva_tensor/tensor.gleam", 3372). ?DOC(false). -spec any_materialized(tensor()) -> {ok, boolean()} | {error, viva_tensor@core@error:tensor_error()}. any_materialized(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, gleam@list:any(Data, fun(X) -> X /= +0.0 end)} end ). -file("src/viva_tensor/tensor.gleam", 3361). ?DOC(false). -spec try_any(tensor()) -> {ok, boolean()} | {error, viva_tensor@core@error:tensor_error()}. try_any(T) -> case T of {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_count_nonzero(Ref) of {ok, Count} -> {ok, Count > 0}; {error, _} -> any_materialized(T) end; _ -> any_materialized(T) end. -file("src/viva_tensor/tensor.gleam", 3378). ?DOC(false). -spec any(tensor()) -> boolean(). any(T) -> _pipe = try_any(T), gleam@result:unwrap(_pipe, false). -file("src/viva_tensor/tensor.gleam", 3395). ?DOC(false). -spec all_materialized(tensor()) -> {ok, boolean()} | {error, viva_tensor@core@error:tensor_error()}. all_materialized(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, gleam@list:all(Data, fun(X) -> X /= +0.0 end)} end ). -file("src/viva_tensor/tensor.gleam", 3384). ?DOC(false). -spec try_all(tensor()) -> {ok, boolean()} | {error, viva_tensor@core@error:tensor_error()}. try_all(T) -> case T of {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_count_nonzero(Ref) of {ok, Count} -> {ok, Count =:= size(T)}; {error, _} -> all_materialized(T) end; _ -> all_materialized(T) end. -file("src/viva_tensor/tensor.gleam", 3401). ?DOC(false). -spec all(tensor()) -> boolean(). all(T) -> _pipe = try_all(T), gleam@result:unwrap(_pipe, false). -file("src/viva_tensor/tensor.gleam", 3418). ?DOC(false). -spec count_nonzero_materialized(tensor()) -> {ok, integer()} | {error, viva_tensor@core@error:tensor_error()}. count_nonzero_materialized(T) -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, gleam@list:fold(Data, 0, fun(Count, X) -> case X /= +0.0 of true -> Count + 1; false -> Count end end)} end ). -file("src/viva_tensor/tensor.gleam", 3407). ?DOC(false). -spec try_count_nonzero(tensor()) -> {ok, integer()} | {error, viva_tensor@core@error:tensor_error()}. try_count_nonzero(T) -> case T of {native_tensor, Ref, _} -> case viva_tensor@core@ffi:nt_count_nonzero(Ref) of {ok, Count} -> {ok, Count}; {error, _} -> count_nonzero_materialized(T) end; _ -> count_nonzero_materialized(T) end. -file("src/viva_tensor/tensor.gleam", 3431). ?DOC(false). -spec count_nonzero(tensor()) -> integer(). count_nonzero(T) -> _pipe = try_count_nonzero(T), gleam@result:unwrap(_pipe, 0). -file("src/viva_tensor/tensor.gleam", 3437). ?DOC(false). -spec try_any_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_any_axis(T, Axis_idx) -> reduce_axis_with_keepdims( <<"any_axis"/utf8>>, T, Axis_idx, false, fun viva_tensor@core@tensor_axis:any_list/1 ). -file("src/viva_tensor/tensor.gleam", 3448). ?DOC(false). -spec any_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. any_axis(T, Axis_idx) -> try_any_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 3453). ?DOC(false). -spec try_any_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_any_axis_keepdims(T, Axis_idx) -> reduce_axis_with_keepdims( <<"any_axis_keepdims"/utf8>>, T, Axis_idx, true, fun viva_tensor@core@tensor_axis:any_list/1 ). -file("src/viva_tensor/tensor.gleam", 3467). ?DOC(false). -spec any_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. any_axis_keepdims(T, Axis_idx) -> try_any_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 3475). ?DOC(false). -spec try_all_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_all_axis(T, Axis_idx) -> reduce_axis_with_keepdims( <<"all_axis"/utf8>>, T, Axis_idx, false, fun viva_tensor@core@tensor_axis:all_list/1 ). -file("src/viva_tensor/tensor.gleam", 3486). ?DOC(false). -spec all_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. all_axis(T, Axis_idx) -> try_all_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 3491). ?DOC(false). -spec try_all_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_all_axis_keepdims(T, Axis_idx) -> reduce_axis_with_keepdims( <<"all_axis_keepdims"/utf8>>, T, Axis_idx, true, fun viva_tensor@core@tensor_axis:all_list/1 ). -file("src/viva_tensor/tensor.gleam", 3505). ?DOC(false). -spec all_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. all_axis_keepdims(T, Axis_idx) -> try_all_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 3513). ?DOC(false). -spec try_count_nonzero_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_count_nonzero_axis(T, Axis_idx) -> reduce_axis_with_keepdims( <<"count_nonzero_axis"/utf8>>, T, Axis_idx, false, fun viva_tensor@core@tensor_axis:count_nonzero_list/1 ). -file("src/viva_tensor/tensor.gleam", 3527). ?DOC(false). -spec count_nonzero_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. count_nonzero_axis(T, Axis_idx) -> try_count_nonzero_axis(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 3535). ?DOC(false). -spec try_count_nonzero_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_count_nonzero_axis_keepdims(T, Axis_idx) -> reduce_axis_with_keepdims( <<"count_nonzero_axis_keepdims"/utf8>>, T, Axis_idx, true, fun viva_tensor@core@tensor_axis:count_nonzero_list/1 ). -file("src/viva_tensor/tensor.gleam", 3549). ?DOC(false). -spec count_nonzero_axis_keepdims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. count_nonzero_axis_keepdims(T, Axis_idx) -> try_count_nonzero_axis_keepdims(T, Axis_idx). -file("src/viva_tensor/tensor.gleam", 3576). ?DOC(false). -spec squeezed_shape(list(integer())) -> list(integer()). squeezed_shape(Shape) -> case gleam@list:filter(Shape, fun(D) -> D /= 1 end) of [] -> [1]; Squeezed -> Squeezed end. -file("src/viva_tensor/tensor.gleam", 3583). ?DOC(false). -spec squeeze_shape_strides(list(integer()), list(integer())) -> {list(integer()), list(integer())}. squeeze_shape_strides(Shape, Strides) -> Kept = begin _pipe = gleam@list:zip(Shape, Strides), gleam@list:filter( _pipe, fun(Pair) -> {Dim, _} = Pair, Dim /= 1 end ) end, case Kept of [] -> {[1], [1]}; _ -> Final_shape = gleam@list:map( Kept, fun(Pair@1) -> erlang:element(1, Pair@1) end ), Final_strides = gleam@list:map( Kept, fun(Pair@2) -> erlang:element(2, Pair@2) end ), {Final_shape, Final_strides} end. -file("src/viva_tensor/tensor.gleam", 3559). ?DOC(false). -spec squeeze(tensor()) -> tensor(). squeeze(T) -> case T of {tensor, Data, Shape} -> {tensor, Data, squeezed_shape(Shape)}; {strided_tensor, Storage, Shape@1, Strides, Offset} -> {Final_shape, Final_strides} = squeeze_shape_strides( Shape@1, Strides ), {strided_tensor, Storage, Final_shape, Final_strides, Offset}; {native_tensor, Ref, Shape@2} -> {native_tensor, Ref, squeezed_shape(Shape@2)} end. -file("src/viva_tensor/tensor.gleam", 3610). ?DOC(false). -spec squeeze_axis(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. squeeze_axis(T, Axis) -> case list_at_int(erlang:element(3, T), Axis) of {error, _} -> {error, {dimension_error, <<"Axis out of bounds"/utf8>>}}; {ok, D} -> case D =:= 1 of false -> {error, {invalid_shape, <<"Dimension at axis is not 1"/utf8>>}}; true -> New_shape = viva_tensor@core@tensor_axis:remove_at_index( erlang:element(3, T), Axis ), case T of {tensor, Data, _} -> {ok, {tensor, Data, New_shape}}; {native_tensor, Ref, _} -> {ok, {native_tensor, Ref, New_shape}}; {strided_tensor, Storage, _, Strides, Offset} -> {ok, {strided_tensor, Storage, New_shape, viva_tensor@core@tensor_axis:remove_at_index( Strides, Axis ), Offset}} end end end. -file("src/viva_tensor/tensor.gleam", 3675). ?DOC(false). -spec expand_dims(tensor(), integer()) -> tensor(). expand_dims(T, Axis) -> unsqueeze(T, Axis). -file("src/viva_tensor/tensor.gleam", 3680). ?DOC(false). -spec try_expand_dims(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_expand_dims(T, Axis) -> try_unsqueeze(T, Axis). -file("src/viva_tensor/tensor.gleam", 3687). ?DOC(false). -spec try_to_strided(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_to_strided(T) -> case T of {strided_tensor, _, _, _, _} -> {ok, T}; {tensor, Data, Shape} -> Storage = viva_tensor@core@ffi:list_to_array(Data), Strides = compute_strides(Shape), {ok, {strided_tensor, Storage, Shape, Strides, 0}}; {native_tensor, _, _} -> gleam@result:'try'( try_to_list(T), fun(Data@1) -> Storage@1 = viva_tensor@core@ffi:list_to_array(Data@1), Strides@1 = compute_strides(erlang:element(3, T)), {ok, {strided_tensor, Storage@1, erlang:element(3, T), Strides@1, 0}} end ) end. -file("src/viva_tensor/tensor.gleam", 3715). ?DOC(false). -spec to_strided(tensor()) -> tensor(). to_strided(T) -> _pipe = try_to_strided(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 3721). ?DOC(false). -spec try_to_contiguous(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. try_to_contiguous(T) -> case T of {tensor, _, _} -> {ok, T}; {native_tensor, _, _} -> {ok, T}; {strided_tensor, _, _, _, _} -> gleam@result:'try'( try_to_list(T), fun(Data) -> {ok, {tensor, Data, erlang:element(3, T)}} end ) end. -file("src/viva_tensor/tensor.gleam", 3733). ?DOC(false). -spec to_contiguous(tensor()) -> tensor(). to_contiguous(T) -> _pipe = try_to_contiguous(T), gleam@result:unwrap(_pipe, T). -file("src/viva_tensor/tensor.gleam", 3740). ?DOC(false). -spec transpose_strided(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. transpose_strided(T) -> case T of {tensor, _, Shape} -> case Shape of [_, _] -> Strided = to_strided(T), transpose_strided(Strided); _ -> {error, {dimension_error, <<"Transpose requires 2D tensor"/utf8>>}} end; {native_tensor, _, _} -> transpose(T); {strided_tensor, Storage, Shape@1, Strides, Offset} -> case {Shape@1, Strides} of {[M, N], [S0, S1]} -> {ok, {strided_tensor, Storage, [N, M], [S1, S0], Offset}}; {_, _} -> {error, {dimension_error, <<"Transpose requires 2D tensor"/utf8>>}} end end. -file("src/viva_tensor/tensor.gleam", 3769). ?DOC(false). -spec is_contiguous(tensor()) -> boolean(). is_contiguous(T) -> case T of {tensor, _, _} -> true; {native_tensor, _, _} -> true; {strided_tensor, _, Shape, Strides, _} -> Expected_strides = compute_strides(Shape), Strides =:= Expected_strides end. -file("src/viva_tensor/tensor.gleam", 3803). ?DOC(false). -spec get2d_fast(tensor(), integer(), integer()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. get2d_fast(T, Row, Col) -> case T of {tensor, _, _} -> get2d(T, Row, Col); {native_tensor, _, _} -> get2d(T, Row, Col); {strided_tensor, Storage, Shape, Strides, Offset} -> case {Shape, Strides} of {[_, _], [S0, S1]} -> Flat_idx = (Offset + (Row * S0)) + (Col * S1), {ok, viva_tensor@core@ffi:array_get(Storage, Flat_idx)}; {Other, _} -> {error, {rank_mismatch, <<"get2d_fast"/utf8>>, 2, Other}} end end. -file("src/viva_tensor/tensor.gleam", 3905). ?DOC(false). -spec conv2d_config() -> conv2d_config(). conv2d_config() -> {conv2d_config, 3, 3, 1, 1, 0, 0}. -file("src/viva_tensor/tensor.gleam", 3917). ?DOC(false). -spec conv2d_same(integer(), integer()) -> conv2d_config(). conv2d_same(Kernel_h, Kernel_w) -> {conv2d_config, Kernel_h, Kernel_w, 1, 1, Kernel_h div 2, Kernel_w div 2}. -file("src/viva_tensor/tensor.gleam", 3930). ?DOC(false). -spec pad2d(tensor(), integer(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. pad2d(T, Pad_h, Pad_w) -> Shp = shape(T), case Shp of [H, W] -> New_h = H + (2 * Pad_h), New_w = W + (2 * Pad_w), Data = get_data(T), Padded = begin _pipe = range_int(0, New_h - 1), gleam@list:flat_map( _pipe, fun(Row) -> _pipe@1 = range_int(0, New_w - 1), gleam@list:map( _pipe@1, fun(Col) -> Src_row = Row - Pad_h, Src_col = Col - Pad_w, case (((Src_row >= 0) andalso (Src_row < H)) andalso (Src_col >= 0)) andalso (Src_col < W) of true -> Idx = (Src_row * W) + Src_col, case list_at_float(Data, Idx) of {ok, V} -> V; {error, _} -> +0.0 end; false -> +0.0 end end ) end ) end, {ok, {tensor, Padded, [New_h, New_w]}}; _ -> {error, {invalid_shape, <<"pad2d requires 2D tensor [H, W]"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 3967). ?DOC(false). -spec pad4d(tensor(), integer(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. pad4d(T, Pad_h, Pad_w) -> Shp = shape(T), case Shp of [N, C, H, W] -> New_h = H + (2 * Pad_h), New_w = W + (2 * Pad_w), Data = get_data(T), Spatial_size = H * W, _ = New_h * New_w, Padded = begin _pipe = range_int(0, N - 1), gleam@list:flat_map( _pipe, fun(Batch) -> _pipe@1 = range_int(0, C - 1), gleam@list:flat_map( _pipe@1, fun(Channel) -> Base_idx = ((Batch * C) * Spatial_size) + (Channel * Spatial_size), _pipe@2 = range_int(0, New_h - 1), gleam@list:flat_map( _pipe@2, fun(Row) -> _pipe@3 = range_int(0, New_w - 1), gleam@list:map( _pipe@3, fun(Col) -> Src_row = Row - Pad_h, Src_col = Col - Pad_w, case (((Src_row >= 0) andalso (Src_row < H)) andalso (Src_col >= 0)) andalso (Src_col < W) of true -> Idx = (Base_idx + (Src_row * W)) + Src_col, case list_at_float( Data, Idx ) of {ok, V} -> V; {error, _} -> +0.0 end; false -> +0.0 end end ) end ) end ) end ) end, {ok, {tensor, Padded, [N, C, New_h, New_w]}}; _ -> {error, {invalid_shape, <<"pad4d requires 4D tensor [N, C, H, W]"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 4421). ?DOC(false). -spec conv2d_kernel_sum( viva_tensor@core@ffi:erlang_array(), viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), float() ) -> float(). conv2d_kernel_sum( In_arr, K_arr, H, W, Kh, Kw, Ch_offset, K_offset, Row, Col, Kr, Kc, Acc ) -> case Kr >= Kh of true -> Acc; false -> case Kc >= Kw of true -> conv2d_kernel_sum( In_arr, K_arr, H, W, Kh, Kw, Ch_offset, K_offset, Row, Col, Kr + 1, 0, Acc ); false -> R = Row + Kr, C_pos = Col + Kc, In_val = case (((R >= 0) andalso (R < H)) andalso (C_pos >= 0)) andalso (C_pos < W) of true -> viva_tensor@core@ffi:array_get( In_arr, (Ch_offset + (R * W)) + C_pos ); false -> +0.0 end, K_val = viva_tensor@core@ffi:array_get( K_arr, (K_offset + (Kr * Kw)) + Kc ), conv2d_kernel_sum( In_arr, K_arr, H, W, Kh, Kw, Ch_offset, K_offset, Row, Col, Kr, Kc + 1, Acc + (In_val * K_val) ) end end. -file("src/viva_tensor/tensor.gleam", 4722). ?DOC(false). -spec conv2d_full_channels( viva_tensor@core@ffi:erlang_array(), viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), float() ) -> float(). conv2d_full_channels( In_arr, K_arr, C_in, H, W, Kh, Kw, In_spatial, K_spatial, Batch_offset, Filter_offset, Row, Col, Ic, Acc ) -> case Ic >= C_in of true -> Acc; false -> Ch_offset = Batch_offset + (Ic * In_spatial), K_ch_offset = Filter_offset + (Ic * K_spatial), Sum = conv2d_kernel_sum( In_arr, K_arr, H, W, Kh, Kw, Ch_offset, K_ch_offset, Row, Col, 0, 0, +0.0 ), conv2d_full_channels( In_arr, K_arr, C_in, H, W, Kh, Kw, In_spatial, K_spatial, Batch_offset, Filter_offset, Row, Col, Ic + 1, Acc + Sum ) end. -file("src/viva_tensor/tensor.gleam", 4544). ?DOC(false). -spec conv2d_full_loop( viva_tensor@core@ffi:erlang_array(), viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), list(float()) ) -> list(float()). conv2d_full_loop( In_arr, K_arr, N, C_in, C_out, H, W, Kh, Kw, In_spatial, In_batch_size, K_spatial, K_filter_size, Stride_h, Stride_w, Pad_h, Pad_w, Out_h, Out_w, Batch, Oc, Oh, Ow, Acc ) -> case Batch >= N of true -> Acc; false -> case Oc >= C_out of true -> conv2d_full_loop( In_arr, K_arr, N, C_in, C_out, H, W, Kh, Kw, In_spatial, In_batch_size, K_spatial, K_filter_size, Stride_h, Stride_w, Pad_h, Pad_w, Out_h, Out_w, Batch + 1, 0, 0, 0, Acc ); false -> case Oh >= Out_h of true -> conv2d_full_loop( In_arr, K_arr, N, C_in, C_out, H, W, Kh, Kw, In_spatial, In_batch_size, K_spatial, K_filter_size, Stride_h, Stride_w, Pad_h, Pad_w, Out_h, Out_w, Batch, Oc + 1, 0, 0, Acc ); false -> case Ow >= Out_w of true -> conv2d_full_loop( In_arr, K_arr, N, C_in, C_out, H, W, Kh, Kw, In_spatial, In_batch_size, K_spatial, K_filter_size, Stride_h, Stride_w, Pad_h, Pad_w, Out_h, Out_w, Batch, Oc, Oh + 1, 0, Acc ); false -> Batch_offset = Batch * In_batch_size, Filter_offset = Oc * K_filter_size, Row = (Oh * Stride_h) - Pad_h, Col = (Ow * Stride_w) - Pad_w, Val = conv2d_full_channels( In_arr, K_arr, C_in, H, W, Kh, Kw, In_spatial, K_spatial, Batch_offset, Filter_offset, Row, Col, 0, +0.0 ), conv2d_full_loop( In_arr, K_arr, N, C_in, C_out, H, W, Kh, Kw, In_spatial, In_batch_size, K_spatial, K_filter_size, Stride_h, Stride_w, Pad_h, Pad_w, Out_h, Out_w, Batch, Oc, Oh, Ow + 1, [Val | Acc] ) end end end end. -file("src/viva_tensor/tensor.gleam", 4489). ?DOC(false). -spec conv2d_full( tensor(), tensor(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), conv2d_config() ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. conv2d_full(Input, Kernel, N, C_in, C_out, H, W, Kh, Kw, Config) -> Out_h = (case erlang:element(4, Config) of 0 -> 0; Gleam@denominator -> ((H + (2 * erlang:element(6, Config))) - Kh) div Gleam@denominator end) + 1, Out_w = (case erlang:element(5, Config) of 0 -> 0; Gleam@denominator@1 -> ((W + (2 * erlang:element(7, Config))) - Kw) div Gleam@denominator@1 end) + 1, In_spatial = H * W, In_batch_size = C_in * In_spatial, K_spatial = Kh * Kw, K_filter_size = C_in * K_spatial, In_arr = viva_tensor@core@ffi:list_to_array(get_data(Input)), K_arr = viva_tensor@core@ffi:list_to_array(get_data(Kernel)), Output = conv2d_full_loop( In_arr, K_arr, N, C_in, C_out, H, W, Kh, Kw, In_spatial, In_batch_size, K_spatial, K_filter_size, erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), Out_h, Out_w, 0, 0, 0, 0, [] ), {ok, {tensor, lists:reverse(Output), [N, C_out, Out_h, Out_w]}}. -file("src/viva_tensor/tensor.gleam", 4363). ?DOC(false). -spec conv2d_mc_channels( viva_tensor@core@ffi:erlang_array(), viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), float() ) -> float(). conv2d_mc_channels( In_arr, K_arr, C_in, H, W, Kh, Kw, Spatial_size, K_spatial, Row, Col, C, Acc ) -> case C >= C_in of true -> Acc; false -> Ch_offset = C * Spatial_size, K_offset = C * K_spatial, Channel_sum = conv2d_kernel_sum( In_arr, K_arr, H, W, Kh, Kw, Ch_offset, K_offset, Row, Col, 0, 0, +0.0 ), conv2d_mc_channels( In_arr, K_arr, C_in, H, W, Kh, Kw, Spatial_size, K_spatial, Row, Col, C + 1, Acc + Channel_sum ) end. -file("src/viva_tensor/tensor.gleam", 4269). ?DOC(false). -spec conv2d_mc_loop( viva_tensor@core@ffi:erlang_array(), viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), list(float()) ) -> list(float()). conv2d_mc_loop( In_arr, K_arr, C_in, H, W, Kh, Kw, Spatial_size, K_spatial, Stride_h, Stride_w, Pad_h, Pad_w, Out_h, Out_w, Oh, Ow, Acc ) -> case Oh >= Out_h of true -> Acc; false -> case Ow >= Out_w of true -> conv2d_mc_loop( In_arr, K_arr, C_in, H, W, Kh, Kw, Spatial_size, K_spatial, Stride_h, Stride_w, Pad_h, Pad_w, Out_h, Out_w, Oh + 1, 0, Acc ); false -> Row = (Oh * Stride_h) - Pad_h, Col = (Ow * Stride_w) - Pad_w, Val = conv2d_mc_channels( In_arr, K_arr, C_in, H, W, Kh, Kw, Spatial_size, K_spatial, Row, Col, 0, +0.0 ), conv2d_mc_loop( In_arr, K_arr, C_in, H, W, Kh, Kw, Spatial_size, K_spatial, Stride_h, Stride_w, Pad_h, Pad_w, Out_h, Out_w, Oh, Ow + 1, [Val | Acc] ) end end. -file("src/viva_tensor/tensor.gleam", 4224). ?DOC(false). -spec conv2d_multichannel( tensor(), tensor(), integer(), integer(), integer(), integer(), integer(), conv2d_config() ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. conv2d_multichannel(Input, Kernel, C_in, H, W, Kh, Kw, Config) -> Out_h = (case erlang:element(4, Config) of 0 -> 0; Gleam@denominator -> ((H + (2 * erlang:element(6, Config))) - Kh) div Gleam@denominator end) + 1, Out_w = (case erlang:element(5, Config) of 0 -> 0; Gleam@denominator@1 -> ((W + (2 * erlang:element(7, Config))) - Kw) div Gleam@denominator@1 end) + 1, Spatial_size = H * W, K_spatial = Kh * Kw, In_arr = viva_tensor@core@ffi:list_to_array(get_data(Input)), K_arr = viva_tensor@core@ffi:list_to_array(get_data(Kernel)), Output = conv2d_mc_loop( In_arr, K_arr, C_in, H, W, Kh, Kw, Spatial_size, K_spatial, erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), Out_h, Out_w, 0, 0, [] ), {ok, {tensor, lists:reverse(Output), [Out_h, Out_w]}}. -file("src/viva_tensor/tensor.gleam", 4170). ?DOC(false). -spec conv2d_dot_product( viva_tensor@core@ffi:erlang_array(), viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), float() ) -> float(). conv2d_dot_product(In_arr, K_arr, In_w, Row, Col, Kh, Kw, Kr, Kc, Acc) -> case Kr >= Kh of true -> Acc; false -> case Kc >= Kw of true -> conv2d_dot_product( In_arr, K_arr, In_w, Row, Col, Kh, Kw, Kr + 1, 0, Acc ); false -> In_idx = ((Row + Kr) * In_w) + (Col + Kc), K_idx = (Kr * Kw) + Kc, In_val = viva_tensor@core@ffi:array_get(In_arr, In_idx), K_val = viva_tensor@core@ffi:array_get(K_arr, K_idx), conv2d_dot_product( In_arr, K_arr, In_w, Row, Col, Kh, Kw, Kr, Kc + 1, Acc + (In_val * K_val) ) end end. -file("src/viva_tensor/tensor.gleam", 4108). ?DOC(false). -spec conv2d_simple_loop( viva_tensor@core@ffi:erlang_array(), viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), list(float()) ) -> list(float()). conv2d_simple_loop( In_arr, K_arr, In_w, Kh, Kw, Stride_h, Stride_w, Out_h, Out_w, Oh, Ow, Acc ) -> case Oh >= Out_h of true -> Acc; false -> case Ow >= Out_w of true -> conv2d_simple_loop( In_arr, K_arr, In_w, Kh, Kw, Stride_h, Stride_w, Out_h, Out_w, Oh + 1, 0, Acc ); false -> Row = Oh * Stride_h, Col = Ow * Stride_w, Val = conv2d_dot_product( In_arr, K_arr, In_w, Row, Col, Kh, Kw, 0, 0, +0.0 ), conv2d_simple_loop( In_arr, K_arr, In_w, Kh, Kw, Stride_h, Stride_w, Out_h, Out_w, Oh, Ow + 1, [Val | Acc] ) end end. -file("src/viva_tensor/tensor.gleam", 4058). ?DOC(false). -spec conv2d_simple( tensor(), tensor(), integer(), integer(), integer(), integer(), conv2d_config() ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. conv2d_simple(Input, Kernel, H, W, Kh, Kw, Config) -> gleam@result:'try'( case (erlang:element(6, Config) > 0) orelse (erlang:element(7, Config) > 0) of true -> pad2d( Input, erlang:element(6, Config), erlang:element(7, Config) ); false -> {ok, Input} end, fun(Padded) -> Padded_shape = shape(Padded), {Ph@1, Pw@1} = case Padded_shape of [Ph, Pw] -> {Ph, Pw}; _ -> {H, W} end, Out_h = (case erlang:element(4, Config) of 0 -> 0; Gleam@denominator -> (Ph@1 - Kh) div Gleam@denominator end) + 1, Out_w = (case erlang:element(5, Config) of 0 -> 0; Gleam@denominator@1 -> (Pw@1 - Kw) div Gleam@denominator@1 end) + 1, In_arr = viva_tensor@core@ffi:list_to_array(get_data(Padded)), K_arr = viva_tensor@core@ffi:list_to_array(get_data(Kernel)), Output = conv2d_simple_loop( In_arr, K_arr, Pw@1, Kh, Kw, erlang:element(4, Config), erlang:element(5, Config), Out_h, Out_w, 0, 0, [] ), {ok, {tensor, lists:reverse(Output), [Out_h, Out_w]}} end ). -file("src/viva_tensor/tensor.gleam", 4023). ?DOC(false). -spec conv2d(tensor(), tensor(), conv2d_config()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. conv2d(Input, Kernel, Config) -> In_shape = shape(Input), K_shape = shape(Kernel), case {In_shape, K_shape} of {[H, W], [Kh, Kw]} -> conv2d_simple(Input, Kernel, H, W, Kh, Kw, Config); {[C_in, H@1, W@1], [C_k, Kh@1, Kw@1]} when C_in =:= C_k -> conv2d_multichannel( Input, Kernel, C_in, H@1, W@1, Kh@1, Kw@1, Config ); {[N, C_in@1, H@2, W@2], [C_out, C_k@1, Kh@2, Kw@2]} when C_in@1 =:= C_k@1 -> conv2d_full( Input, Kernel, N, C_in@1, C_out, H@2, W@2, Kh@2, Kw@2, Config ); {_, _} -> {error, {invalid_shape, <<<<<<"conv2d shape mismatch: input="/utf8, (shape_to_string(In_shape))/binary>>/binary, " kernel="/utf8>>/binary, (shape_to_string(K_shape))/binary>>}} end. -file("src/viva_tensor/tensor.gleam", 5095). ?DOC(false). -spec pool_window( viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), boolean(), float() ) -> float(). pool_window(Arr, W, Row, Col, Pool_h, Pool_w, Base, Pr, Pc, Is_max, Acc) -> case Pr >= Pool_h of true -> Acc; false -> case Pc >= Pool_w of true -> pool_window( Arr, W, Row, Col, Pool_h, Pool_w, Base, Pr + 1, 0, Is_max, Acc ); false -> Idx = (Base + ((Row + Pr) * W)) + (Col + Pc), Val = viva_tensor@core@ffi:array_get(Arr, Idx), New_acc = case Is_max of true -> case Val > Acc of true -> Val; false -> Acc end; false -> Acc + Val end, pool_window( Arr, W, Row, Col, Pool_h, Pool_w, Base, Pr, Pc + 1, Is_max, New_acc ) end end. -file("src/viva_tensor/tensor.gleam", 4945). ?DOC(false). -spec pool4d_loop( viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), boolean(), list(float()) ) -> list(float()). pool4d_loop( Arr, N, C, W, Pool_h, Pool_w, Stride_h, Stride_w, Spatial_size, Batch_size, Out_h, Out_w, Batch, Channel, Oh, Ow, Is_max, Acc ) -> case Batch >= N of true -> Acc; false -> case Channel >= C of true -> pool4d_loop( Arr, N, C, W, Pool_h, Pool_w, Stride_h, Stride_w, Spatial_size, Batch_size, Out_h, Out_w, Batch + 1, 0, 0, 0, Is_max, Acc ); false -> case Oh >= Out_h of true -> pool4d_loop( Arr, N, C, W, Pool_h, Pool_w, Stride_h, Stride_w, Spatial_size, Batch_size, Out_h, Out_w, Batch, Channel + 1, 0, 0, Is_max, Acc ); false -> case Ow >= Out_w of true -> pool4d_loop( Arr, N, C, W, Pool_h, Pool_w, Stride_h, Stride_w, Spatial_size, Batch_size, Out_h, Out_w, Batch, Channel, Oh + 1, 0, Is_max, Acc ); false -> Base = (Batch * Batch_size) + (Channel * Spatial_size), Row = Oh * Stride_h, Col = Ow * Stride_w, Val = pool_window( Arr, W, Row, Col, Pool_h, Pool_w, Base, 0, 0, Is_max, case Is_max of true -> -1.0e308; false -> +0.0 end ), Final_val = case Is_max of true -> Val; false -> case erlang:float(Pool_h * Pool_w) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> Val / Gleam@denominator end end, pool4d_loop( Arr, N, C, W, Pool_h, Pool_w, Stride_h, Stride_w, Spatial_size, Batch_size, Out_h, Out_w, Batch, Channel, Oh, Ow + 1, Is_max, [Final_val | Acc] ) end end end end. -file("src/viva_tensor/tensor.gleam", 4861). ?DOC(false). -spec pool2d_loop( viva_tensor@core@ffi:erlang_array(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), boolean(), list(float()) ) -> list(float()). pool2d_loop( Arr, W, Pool_h, Pool_w, Stride_h, Stride_w, Out_h, Out_w, Oh, Ow, Base, Is_max, Acc ) -> case Oh >= Out_h of true -> Acc; false -> case Ow >= Out_w of true -> pool2d_loop( Arr, W, Pool_h, Pool_w, Stride_h, Stride_w, Out_h, Out_w, Oh + 1, 0, Base, Is_max, Acc ); false -> Row = Oh * Stride_h, Col = Ow * Stride_w, Val = pool_window( Arr, W, Row, Col, Pool_h, Pool_w, Base, 0, 0, Is_max, case Is_max of true -> -1.0e308; false -> +0.0 end ), Final_val = case Is_max of true -> Val; false -> case erlang:float(Pool_h * Pool_w) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> Val / Gleam@denominator end end, pool2d_loop( Arr, W, Pool_h, Pool_w, Stride_h, Stride_w, Out_h, Out_w, Oh, Ow + 1, Base, Is_max, [Final_val | Acc] ) end end. -file("src/viva_tensor/tensor.gleam", 4790). ?DOC(false). -spec max_pool2d(tensor(), integer(), integer(), integer(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. max_pool2d(Input, Pool_h, Pool_w, Stride_h, Stride_w) -> Shp = shape(Input), Arr = viva_tensor@core@ffi:list_to_array(get_data(Input)), case Shp of [H, W] -> Out_h = (case Stride_h of 0 -> 0; Gleam@denominator -> (H - Pool_h) div Gleam@denominator end) + 1, Out_w = (case Stride_w of 0 -> 0; Gleam@denominator@1 -> (W - Pool_w) div Gleam@denominator@1 end) + 1, Output = pool2d_loop( Arr, W, Pool_h, Pool_w, Stride_h, Stride_w, Out_h, Out_w, 0, 0, 0, true, [] ), {ok, {tensor, lists:reverse(Output), [Out_h, Out_w]}}; [N, C, H@1, W@1] -> Out_h@1 = (case Stride_h of 0 -> 0; Gleam@denominator@2 -> (H@1 - Pool_h) div Gleam@denominator@2 end) + 1, Out_w@1 = (case Stride_w of 0 -> 0; Gleam@denominator@3 -> (W@1 - Pool_w) div Gleam@denominator@3 end) + 1, Spatial_size = H@1 * W@1, Batch_size = C * Spatial_size, Output@1 = pool4d_loop( Arr, N, C, W@1, Pool_h, Pool_w, Stride_h, Stride_w, Spatial_size, Batch_size, Out_h@1, Out_w@1, 0, 0, 0, 0, true, [] ), {ok, {tensor, lists:reverse(Output@1), [N, C, Out_h@1, Out_w@1]}}; _ -> {error, {invalid_shape, <<"max_pool2d requires 2D or 4D tensor"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 5159). ?DOC(false). -spec avg_pool2d(tensor(), integer(), integer(), integer(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. avg_pool2d(Input, Pool_h, Pool_w, Stride_h, Stride_w) -> Shp = shape(Input), Arr = viva_tensor@core@ffi:list_to_array(get_data(Input)), case Shp of [H, W] -> Out_h = (case Stride_h of 0 -> 0; Gleam@denominator -> (H - Pool_h) div Gleam@denominator end) + 1, Out_w = (case Stride_w of 0 -> 0; Gleam@denominator@1 -> (W - Pool_w) div Gleam@denominator@1 end) + 1, Output = pool2d_loop( Arr, W, Pool_h, Pool_w, Stride_h, Stride_w, Out_h, Out_w, 0, 0, 0, false, [] ), {ok, {tensor, lists:reverse(Output), [Out_h, Out_w]}}; [N, C, H@1, W@1] -> Out_h@1 = (case Stride_h of 0 -> 0; Gleam@denominator@2 -> (H@1 - Pool_h) div Gleam@denominator@2 end) + 1, Out_w@1 = (case Stride_w of 0 -> 0; Gleam@denominator@3 -> (W@1 - Pool_w) div Gleam@denominator@3 end) + 1, Spatial_size = H@1 * W@1, Batch_size = C * Spatial_size, Output@1 = pool4d_loop( Arr, N, C, W@1, Pool_h, Pool_w, Stride_h, Stride_w, Spatial_size, Batch_size, Out_h@1, Out_w@1, 0, 0, 0, 0, false, [] ), {ok, {tensor, lists:reverse(Output@1), [N, C, Out_h@1, Out_w@1]}}; _ -> {error, {invalid_shape, <<"avg_pool2d requires 2D or 4D tensor"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 5234). ?DOC(false). -spec global_avg_pool2d(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. global_avg_pool2d(Input) -> Shp = shape(Input), case Shp of [N, C, H, W] -> Spatial_size = H * W, Pool_size = erlang:float(Spatial_size), Batch_size = C * Spatial_size, Data = get_data(Input), Output = begin _pipe = range_int(0, N - 1), gleam@list:flat_map( _pipe, fun(Batch) -> _pipe@1 = range_int(0, C - 1), gleam@list:map( _pipe@1, fun(Channel) -> Base = (Batch * Batch_size) + (Channel * Spatial_size), _pipe@2 = range_int(0, Spatial_size - 1), _pipe@3 = gleam@list:fold( _pipe@2, +0.0, fun(Sum, I) -> case list_at_float(Data, Base + I) of {ok, V} -> Sum + V; {error, _} -> Sum end end ), (fun(S) -> case Pool_size of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> S / Gleam@denominator end end)(_pipe@3) end ) end ) end, {ok, {tensor, Output, [N, C, 1, 1]}}; _ -> {error, {invalid_shape, <<"global_avg_pool2d requires 4D tensor [N, C, H, W]"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 5339). ?DOC(false). -spec einsum_finish( {ok, viva_tensor@core@einsum:operand()} | {error, viva_tensor@core@error:tensor_error()} ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. einsum_finish(Op_result) -> gleam@result:'try'( Op_result, fun(Op) -> {ok, {tensor, erlang:element(2, Op), erlang:element(3, Op)}} end ). -file("src/viva_tensor/tensor.gleam", 5473). ?DOC(false). -spec einsum_elementwise_mul(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. einsum_elementwise_mul(A, B) -> Sa = shape(A), Sb = shape(B), case Sa =:= Sb of true -> Da = to_list(A), Db = to_list(B), Out = gleam@list:map2(Da, Db, fun(X, Y) -> X * Y end), {ok, {tensor, Out, Sa}}; false -> {error, {shape_mismatch, Sa, Sb}} end. -file("src/viva_tensor/tensor.gleam", 5487). ?DOC(false). -spec einsum_frobenius(tensor(), tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. einsum_frobenius(A, B) -> gleam@result:'try'( einsum_elementwise_mul(A, B), fun(Prod) -> {ok, {tensor, [sum(Prod)], []}} end ). -file("src/viva_tensor/tensor.gleam", 5374). ?DOC(false). -spec einsum_dispatch_two( tensor(), tensor(), list(binary()), list(binary()), list(binary()), list(viva_tensor@core@einsum:operand()), list({binary(), integer()}) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. einsum_dispatch_two(A, B, Labels_a, Labels_b, Rhs, Ops, Dims) -> case {Labels_a, Labels_b, Rhs} of {[I, J], [J2, K], [I2, K2]} when (((((I =:= I2) andalso (J =:= J2)) andalso (K =:= K2)) andalso (I =/= J)) andalso (J =/= K)) andalso (I =/= K) -> matmul(A, B); {[I@1], [I2@1], []} when I@1 =:= I2@1 -> gleam@result:'try'(dot(A, B), fun(V) -> {ok, {tensor, [V], []}} end); {[I@2], [J@1], [I2@2, J2@1]} when ((I@2 =:= I2@2) andalso (J@1 =:= J2@1)) andalso (I@2 =/= J@1) -> outer(A, B); {[I@3, J@2], [I2@3, J2@2], [I3, J3]} when ((((I@3 =:= I2@3) andalso (I@3 =:= I3)) andalso (J@2 =:= J2@2)) andalso (J@2 =:= J3)) andalso (I@3 =/= J@2) -> einsum_elementwise_mul(A, B); {[I@4, J@3], [I2@4, J2@3], []} when ((I@4 =:= I2@4) andalso (J@3 =:= J2@3)) andalso (I@4 =/= J@3) -> einsum_frobenius(A, B); {_, _, _} -> einsum_finish( viva_tensor@core@einsum:general( Ops, [Labels_a, Labels_b], Rhs, Dims ) ) end. -file("src/viva_tensor/tensor.gleam", 5499). ?DOC(false). -spec einsum_nth_loop(list(float()), integer()) -> {ok, float()} | {error, nil}. einsum_nth_loop(Items, Index) -> case {Items, Index} of {[], _} -> {error, nil}; {[X | _], 0} -> {ok, X}; {[_ | Rest], N} -> einsum_nth_loop(Rest, N - 1) end. -file("src/viva_tensor/tensor.gleam", 5492). ?DOC(false). -spec einsum_nth(list(float()), integer()) -> {ok, float()} | {error, nil}. einsum_nth(Items, Index) -> case Index < 0 of true -> {error, nil}; false -> einsum_nth_loop(Items, Index) end. -file("src/viva_tensor/tensor.gleam", 5431). ?DOC(false). -spec einsum_sum_axis_0(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. einsum_sum_axis_0(A) -> case shape(A) of [Rows, Cols] -> Data = to_list(A), Out = begin _pipe = range_int(0, Cols - 1), gleam@list:map( _pipe, fun(J) -> _pipe@1 = range_int(0, Rows - 1), gleam@list:fold( _pipe@1, +0.0, fun(Acc, I) -> case einsum_nth(Data, (I * Cols) + J) of {ok, V} -> Acc + V; {error, _} -> Acc end end ) end ) end, {ok, {tensor, Out, [Cols]}}; _ -> {error, {dimension_error, <<"einsum: axis sum requires a 2D tensor"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 5452). ?DOC(false). -spec einsum_sum_axis_1(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. einsum_sum_axis_1(A) -> case shape(A) of [Rows, Cols] -> Data = to_list(A), Out = begin _pipe = range_int(0, Rows - 1), gleam@list:map( _pipe, fun(I) -> _pipe@1 = range_int(0, Cols - 1), gleam@list:fold( _pipe@1, +0.0, fun(Acc, J) -> case einsum_nth(Data, (I * Cols) + J) of {ok, V} -> Acc + V; {error, _} -> Acc end end ) end ) end, {ok, {tensor, Out, [Rows]}}; _ -> {error, {dimension_error, <<"einsum: axis sum requires a 2D tensor"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 5413). ?DOC(false). -spec einsum_trace(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. einsum_trace(A) -> case shape(A) of [N, M] when N =:= M -> Data = to_list(A), S = begin _pipe = range_int(0, N - 1), gleam@list:fold( _pipe, +0.0, fun(Acc, I) -> case einsum_nth(Data, (I * N) + I) of {ok, V} -> Acc + V; {error, _} -> Acc end end ) end, {ok, {tensor, [S], []}}; _ -> {error, {dimension_error, <<"einsum: trace requires a square 2D tensor"/utf8>>}} end. -file("src/viva_tensor/tensor.gleam", 5346). ?DOC(false). -spec einsum_dispatch_one( tensor(), list(binary()), list(binary()), list(viva_tensor@core@einsum:operand()), list({binary(), integer()}) ) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. einsum_dispatch_one(A, Labels, Rhs, Ops, Dims) -> case {Labels, Rhs} of {[X, Y], [Y2, X2]} when ((X =:= X2) andalso (Y =:= Y2)) andalso (X =/= Y) -> transpose(A); {[X@1, Y@1], []} when X@1 =:= Y@1 -> einsum_trace(A); {_, []} -> {ok, {tensor, [sum(A)], []}}; {[X@2, Y@2], [X2@1]} when (X@2 =:= X2@1) andalso (Y@2 =/= X@2) -> einsum_sum_axis_1(A); {[X@3, Y@3], [Y2@1]} when (Y@3 =:= Y2@1) andalso (X@3 =/= Y@3) -> einsum_sum_axis_0(A); {_, _} -> einsum_finish( viva_tensor@core@einsum:general(Ops, [Labels], Rhs, Dims) ) end. -file("src/viva_tensor/tensor.gleam", 5335). ?DOC(false). -spec tensor_to_operand(tensor()) -> viva_tensor@core@einsum:operand(). tensor_to_operand(T) -> {operand, to_list(T), shape(T)}. -file("src/viva_tensor/tensor.gleam", 5314). ?DOC(false). -spec einsum(binary(), list(tensor())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. einsum(Equation, Operands) -> gleam@result:'try'( viva_tensor@core@einsum:parse(Equation), fun(Parsed) -> {Lhs_labels, Rhs_labels} = Parsed, Ops = gleam@list:map(Operands, fun(T) -> tensor_to_operand(T) end), gleam@result:'try'( viva_tensor@core@einsum:validate(Lhs_labels, Rhs_labels, Ops), fun(Dim_map) -> case {Operands, Lhs_labels} of {[A], [Labels_a]} -> einsum_dispatch_one( A, Labels_a, Rhs_labels, Ops, Dim_map ); {[A@1, B], [Labels_a@1, Labels_b]} -> einsum_dispatch_two( A@1, B, Labels_a@1, Labels_b, Rhs_labels, Ops, Dim_map ); {_, _} -> {error, {dimension_error, <<"einsum: feature not supported in v1: more than 2 input operands"/utf8>>}} end end ) end ).