-module(viva_tensor@core@tensor). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/viva_tensor/core/tensor.gleam"). -export([new/2, zeros/1, ones/1, fill/2, from_list/1, from_list2d/1, vector/1, matrix/3, eye/1, arange/3, linspace/3, random_uniform/1, random_normal/3, xavier_init/2, he_init/2, shape/1, try_to_list/1, to_list/1, size/1, rank/1, dim/2, rows/1, cols/1, can_broadcast/2, broadcast_shape/2, broadcast_to/2, get/2, get2d/3, get_row/2, get_col/2, to_strided/1, to_dense/1, to_contiguous/1, is_contiguous/1, transpose_strided/1, is_native/1, native_ref/1, from_native_ref/2, native_zeros/1, native_ones/1, native_fill/2, native_from_list/2]). -export_type([tensor/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). -opaque tensor() :: {dense, list(float()), list(integer())} | {strided, viva_tensor@core@ffi:erlang_array(), list(integer()), list(integer()), integer()} | {native, viva_tensor@core@ffi:native_tensor_ref(), list(integer())}. -file("src/viva_tensor/core/tensor.gleam", 599). ?DOC(false). -spec compute_size(list(integer())) -> integer(). compute_size(Shape) -> viva_tensor@core@layout_math:size(Shape). -file("src/viva_tensor/core/tensor.gleam", 54). ?DOC(false). -spec new(list(float()), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. new(Data, Shape) -> Expected_size = compute_size(Shape), Actual_size = erlang:length(Data), case Expected_size =:= Actual_size of true -> {ok, {dense, Data, Shape}}; false -> {error, {invalid_shape, <<<<<<<<<<<<"Data size "/utf8, (erlang:integer_to_binary( Actual_size ))/binary>>/binary, " doesn't match shape "/utf8>>/binary, (viva_tensor@core@error:shape_to_string( Shape ))/binary>>/binary, " (expected "/utf8>>/binary, (erlang:integer_to_binary(Expected_size))/binary>>/binary, ")"/utf8>>}} end. -file("src/viva_tensor/core/tensor.gleam", 74). ?DOC(false). -spec zeros(list(integer())) -> tensor(). zeros(Shape) -> Size = compute_size(Shape), {dense, gleam@list:repeat(+0.0, Size), Shape}. -file("src/viva_tensor/core/tensor.gleam", 80). ?DOC(false). -spec ones(list(integer())) -> tensor(). ones(Shape) -> Size = compute_size(Shape), {dense, gleam@list:repeat(1.0, Size), Shape}. -file("src/viva_tensor/core/tensor.gleam", 86). ?DOC(false). -spec fill(list(integer()), float()) -> tensor(). fill(Shape, Value) -> Size = compute_size(Shape), {dense, gleam@list:repeat(Value, Size), Shape}. -file("src/viva_tensor/core/tensor.gleam", 92). ?DOC(false). -spec from_list(list(float())) -> tensor(). from_list(Data) -> {dense, Data, [erlang:length(Data)]}. -file("src/viva_tensor/core/tensor.gleam", 97). ?DOC(false). -spec from_list2d(list(list(float()))) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. from_list2d(Rows) -> case Rows of [] -> {ok, {dense, [], [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, {dense, Data, [Num_rows, Cols]}} end end. -file("src/viva_tensor/core/tensor.gleam", 117). ?DOC(false). -spec vector(list(float())) -> tensor(). vector(Data) -> from_list(Data). -file("src/viva_tensor/core/tensor.gleam", 122). ?DOC(false). -spec matrix(integer(), integer(), list(float())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. matrix(Rows, Cols, Data) -> new(Data, [Rows, Cols]). -file("src/viva_tensor/core/tensor.gleam", 132). ?DOC(false). -spec eye(integer()) -> tensor(). eye(N) -> Data = begin _pipe = gleam@list:range(0, N - 1), gleam@list:flat_map( _pipe, fun(I) -> _pipe@1 = gleam@list:range(0, N - 1), gleam@list:map(_pipe@1, fun(J) -> case I =:= J of true -> 1.0; false -> +0.0 end end) end ) end, {dense, Data, [N, N]}. -file("src/viva_tensor/core/tensor.gleam", 154). ?DOC(false). -spec arange_loop(float(), float(), float(), list(float())) -> list(float()). arange_loop(Current, End, Step, Acc) -> case Current >= End of true -> Acc; false -> arange_loop(Current + Step, End, Step, [Current | Acc]) end. -file("src/viva_tensor/core/tensor.gleam", 149). ?DOC(false). -spec arange(float(), float(), float()) -> tensor(). arange(Start, End, Step) -> Data = arange_loop(Start, End, Step, []), from_list(lists:reverse(Data)). -file("src/viva_tensor/core/tensor.gleam", 167). ?DOC(false). -spec linspace(float(), float(), integer()) -> tensor(). linspace(Start, End, Num) -> case Num =< 1 of true -> from_list([Start]); false -> _pipe = gleam_community@maths:linear_space(Start, End, Num, true), _pipe@1 = gleam@result:unwrap(_pipe, []), from_list(_pipe@1) end. -file("src/viva_tensor/core/tensor.gleam", 184). ?DOC(false). -spec random_uniform(list(integer())) -> tensor(). random_uniform(Shape) -> Size = compute_size(Shape), Data = begin _pipe = gleam@list:range(1, Size), gleam@list:map( _pipe, fun(_) -> viva_tensor@core@ffi:random_uniform() end ) end, {dense, Data, Shape}. -file("src/viva_tensor/core/tensor.gleam", 195). ?DOC(false). -spec random_normal(list(integer()), float(), float()) -> tensor(). random_normal(Shape, Mean, Std) -> Size = compute_size(Shape), Data = begin _pipe = gleam@list:range(1, Size), 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.14159265358979323846) * U2), Mean + (Z * Std) end ) end, {dense, Data, Shape}. -file("src/viva_tensor/core/tensor.gleam", 215). ?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 = gleam@list:range(1, Fan_in * Fan_out), gleam@list:map( _pipe, fun(_) -> R = viva_tensor@core@ffi:random_uniform(), ((R * 2.0) * Limit) - Limit end ) end, {dense, Data, [Fan_out, Fan_in]}. -file("src/viva_tensor/core/tensor.gleam", 230). ?DOC(false). -spec he_init(integer(), integer()) -> tensor(). he_init(Fan_in, Fan_out) -> Std = 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). -file("src/viva_tensor/core/tensor.gleam", 238). ?DOC(false). -spec shape(tensor()) -> list(integer()). shape(T) -> case T of {dense, _, S} -> S; {strided, _, S@1, _, _} -> S@1; {native, _, S@2} -> S@2 end. -file("src/viva_tensor/core/tensor.gleam", 607). ?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/core/tensor.gleam", 247). ?DOC(false). -spec try_to_list(tensor()) -> {ok, list(float())} | {error, viva_tensor@core@error:tensor_error()}. try_to_list(T) -> case T of {dense, Data, _} -> {ok, Data}; {native, 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, Storage, Shp, Strides, Offset} -> Total_size = compute_size(Shp), Data@2 = begin _pipe = gleam@list:range(0, Total_size - 1), gleam@list:map( _pipe, fun(Flat_idx) -> Indices = flat_to_multi(Flat_idx, Shp), Idx = begin _pipe@1 = gleam@list:zip(Indices, Strides), gleam@list:fold( _pipe@1, Offset, fun(Acc, Pair) -> {I, S} = Pair, Acc + (I * S) end ) end, viva_tensor@core@ffi:array_get(Storage, Idx) end ) end, {ok, Data@2} end. -file("src/viva_tensor/core/tensor.gleam", 281). ?DOC(false). -spec to_list(tensor()) -> list(float()). to_list(T) -> _pipe = try_to_list(T), gleam@result:unwrap(_pipe, []). -file("src/viva_tensor/core/tensor.gleam", 287). ?DOC(false). -spec size(tensor()) -> integer(). size(T) -> compute_size(shape(T)). -file("src/viva_tensor/core/tensor.gleam", 292). ?DOC(false). -spec rank(tensor()) -> integer(). rank(T) -> erlang:length(shape(T)). -file("src/viva_tensor/core/tensor.gleam", 611). ?DOC(false). -spec list_at(list(RSX), integer()) -> {ok, RSX} | {error, nil}. list_at(Lst, Index) -> viva_tensor@core@layout_math:at(Lst, Index). -file("src/viva_tensor/core/tensor.gleam", 297). ?DOC(false). -spec dim(tensor(), integer()) -> {ok, integer()} | {error, viva_tensor@core@error:tensor_error()}. dim(T, Axis) -> _pipe = list_at(shape(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/core/tensor.gleam", 305). ?DOC(false). -spec rows(tensor()) -> integer(). rows(T) -> case shape(T) of [R | _] -> R; [] -> 0 end. -file("src/viva_tensor/core/tensor.gleam", 313). ?DOC(false). -spec cols(tensor()) -> integer(). cols(T) -> case shape(T) of [_, C | _] -> C; [N] -> N; [] -> 0 end. -file("src/viva_tensor/core/tensor.gleam", 324). ?DOC(false). -spec can_broadcast(list(integer()), list(integer())) -> boolean(). can_broadcast(A, B) -> {Longer, Shorter} = case erlang:length(A) >= erlang:length(B) of true -> {A, B}; false -> {B, A} end, Diff = erlang:length(Longer) - erlang:length(Shorter), Padded = lists:append(gleam@list:repeat(1, Diff), Shorter), _pipe = gleam@list:zip(Longer, Padded), gleam@list:all( _pipe, fun(Pair) -> {Dim_a, Dim_b} = Pair, ((Dim_a =:= Dim_b) orelse (Dim_a =:= 1)) orelse (Dim_b =:= 1) end ). -file("src/viva_tensor/core/tensor.gleam", 341). ?DOC(false). -spec broadcast_shape(list(integer()), list(integer())) -> {ok, list(integer())} | {error, viva_tensor@core@error:tensor_error()}. broadcast_shape(A, B) -> case can_broadcast(A, B) of false -> {error, {broadcast_error, A, B}}; true -> Max_rank = gleam@int:max(erlang:length(A), erlang:length(B)), Diff_a = Max_rank - erlang:length(A), Diff_b = Max_rank - erlang:length(B), Padded_a = lists:append(gleam@list:repeat(1, Diff_a), A), Padded_b = lists:append(gleam@list:repeat(1, Diff_b), B), Result_shape = begin _pipe = gleam@list:zip(Padded_a, Padded_b), gleam@list:map( _pipe, fun(Pair) -> {Dim_a, Dim_b} = Pair, gleam@int:max(Dim_a, Dim_b) end ) end, {ok, Result_shape} end. -file("src/viva_tensor/core/tensor.gleam", 615). ?DOC(false). -spec list_at_float(list(float()), integer()) -> {ok, float()} | {error, nil}. list_at_float(Lst, Index) -> list_at(Lst, Index). -file("src/viva_tensor/core/tensor.gleam", 619). ?DOC(false). -spec broadcast_data(tensor(), list(integer())) -> {ok, list(float())} | {error, viva_tensor@core@error:tensor_error()}. broadcast_data(T, Target_shape) -> Target_size = compute_size(Target_shape), Src_shape = shape(T), Src_rank = erlang:length(Src_shape), Target_rank = erlang:length(Target_shape), gleam@result:'try'( try_to_list(T), fun(Data) -> Diff = Target_rank - Src_rank, Padded_shape = lists:append(gleam@list:repeat(1, Diff), Src_shape), _pipe = viva_tensor@core@layout_math:indices(Target_size), _pipe@4 = gleam@list:fold( _pipe, {ok, []}, fun(Acc, Flat_idx) -> gleam@result:'try'( Acc, fun(Values) -> Target_indices = flat_to_multi( Flat_idx, Target_shape ), Src_indices = begin _pipe@1 = gleam@list:zip( Target_indices, Padded_shape ), _pipe@2 = gleam@list:map( _pipe@1, fun(Pair) -> {Idx, Dim} = Pair, case Dim =:= 1 of true -> 0; false -> Idx end end ), gleam@list:drop(_pipe@2, Diff) end, Src_flat = viva_tensor@core@layout_math:multi_to_flat( Src_indices, Src_shape ), gleam@result:'try'( begin _pipe@3 = list_at_float(Data, Src_flat), gleam@result:map_error( _pipe@3, fun(_) -> {index_out_of_bounds, Src_flat, erlang:length(Data)} end ) end, fun(Value) -> {ok, [Value | Values]} end ) end ) end ), gleam@result:map(_pipe@4, fun lists:reverse/1) end ). -file("src/viva_tensor/core/tensor.gleam", 603). ?DOC(false). -spec compute_strides(list(integer())) -> list(integer()). compute_strides(Shape) -> viva_tensor@core@layout_math:compute_strides(Shape). -file("src/viva_tensor/core/tensor.gleam", 370). ?DOC(false). -spec broadcast_to(tensor(), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. broadcast_to(T, Target_shape) -> Src_shape = shape(T), case can_broadcast(Src_shape, Target_shape) of false -> {error, {broadcast_error, Src_shape, Target_shape}}; true -> case Src_shape =:= Target_shape of true -> {ok, T}; false -> case T of {dense, Data, _} -> Storage = viva_tensor@core@ffi:list_to_array(Data), Strides = viva_tensor@core@layout_math:broadcast_strides( Src_shape, compute_strides(Src_shape), Target_shape ), {ok, {strided, Storage, Target_shape, Strides, 0}}; {strided, Storage@1, _, Strides@1, Offset} -> View_strides = viva_tensor@core@layout_math:broadcast_strides( Src_shape, Strides@1, Target_shape ), {ok, {strided, Storage@1, Target_shape, View_strides, Offset}}; {native, Ref, _} -> case viva_tensor@core@ffi:nt_broadcast_to( Ref, Target_shape ) of {ok, View_ref} -> {ok, {native, View_ref, Target_shape}}; {error, _} -> gleam@result:'try'( broadcast_data(T, Target_shape), fun(Data@1) -> new(Data@1, Target_shape) end ) end end end end. -file("src/viva_tensor/core/tensor.gleam", 429). ?DOC(false). -spec get(tensor(), integer()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. get(T, Index) -> case T of {dense, Data, _} -> _pipe = list_at_float(Data, Index), gleam@result:map_error( _pipe, fun(_) -> {index_out_of_bounds, Index, size(T)} end ); {native, Ref, _} -> case try_to_list({native, Ref, shape(T)}) of {ok, Data@1} -> _pipe@1 = list_at_float(Data@1, Index), gleam@result:map_error( _pipe@1, fun(_) -> {index_out_of_bounds, Index, size(T)} end ); {error, E} -> {error, E} end; {strided, Storage, Shp, Strides, Offset} -> Indices = flat_to_multi(Index, Shp), 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/core/tensor.gleam", 457). ?DOC(false). -spec get2d(tensor(), integer(), integer()) -> {ok, float()} | {error, viva_tensor@core@error:tensor_error()}. get2d(T, Row, Col) -> case shape(T) of [_, Num_cols] -> get(T, (Row * Num_cols) + Col); Other -> {error, {rank_mismatch, <<"get2d"/utf8>>, 2, Other}} end. -file("src/viva_tensor/core/tensor.gleam", 465). ?DOC(false). -spec get_row(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. get_row(T, Row_idx) -> case shape(T) of [Num_rows, Num_cols] -> case (Row_idx >= 0) andalso (Row_idx < Num_rows) of true -> Data = to_list(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, {index_out_of_bounds, Row_idx, Num_rows}} end; Other -> {error, {rank_mismatch, <<"get_row"/utf8>>, 2, Other}} end. -file("src/viva_tensor/core/tensor.gleam", 486). ?DOC(false). -spec get_col(tensor(), integer()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. get_col(T, Col_idx) -> case shape(T) of [Num_rows, Num_cols] -> case (Col_idx >= 0) andalso (Col_idx < Num_cols) of true -> Col_data = begin _pipe = gleam@list:range(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, {index_out_of_bounds, Col_idx, Num_cols}} end; Other -> {error, {rank_mismatch, <<"get_col"/utf8>>, 2, Other}} end. -file("src/viva_tensor/core/tensor.gleam", 512). ?DOC(false). -spec to_strided(tensor()) -> tensor(). to_strided(T) -> case T of {strided, _, _, _, _} -> T; {native, _, _} -> T; {dense, Data, Shp} -> Storage = viva_tensor@core@ffi:list_to_array(Data), Strides = compute_strides(Shp), {strided, Storage, Shp, Strides, 0} end. -file("src/viva_tensor/core/tensor.gleam", 525). ?DOC(false). -spec to_dense(tensor()) -> tensor(). to_dense(T) -> case T of {dense, _, _} -> T; {native, _, _} -> Data = to_list(T), {dense, Data, shape(T)}; {strided, _, _, _, _} -> Data@1 = to_list(T), {dense, Data@1, shape(T)} end. -file("src/viva_tensor/core/tensor.gleam", 540). ?DOC(false). -spec to_contiguous(tensor()) -> tensor(). to_contiguous(T) -> to_dense(T). -file("src/viva_tensor/core/tensor.gleam", 545). ?DOC(false). -spec is_contiguous(tensor()) -> boolean(). is_contiguous(T) -> case T of {dense, _, _} -> true; {native, _, _} -> true; {strided, _, Shp, Strides, _} -> Expected_strides = compute_strides(Shp), Strides =:= Expected_strides end. -file("src/viva_tensor/core/tensor.gleam", 557). ?DOC(false). -spec transpose_strided(tensor()) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. transpose_strided(T) -> case T of {native, Ref, Shp} -> case Shp of [_, _] -> case viva_tensor@core@ffi:nt_transpose(Ref) of {ok, Ref_t} -> {ok, {native, Ref_t, lists:reverse(Shp)}}; {error, _} -> Dense = to_dense(T), transpose_strided(Dense) end; _ -> {error, {dimension_error, <<"Transpose requires 2D tensor"/utf8>>}} end; {dense, _, Shp@1} -> case Shp@1 of [_, _] -> Strided = to_strided(T), transpose_strided(Strided); _ -> {error, {dimension_error, <<"Transpose requires 2D tensor"/utf8>>}} end; {strided, Storage, Shp@2, Strides, Offset} -> case {Shp@2, Strides} of {[M, N], [S0, S1]} -> {ok, {strided, Storage, [N, M], [S1, S0], Offset}}; {_, _} -> {error, {dimension_error, <<"Transpose requires 2D tensor"/utf8>>}} end end. -file("src/viva_tensor/core/tensor.gleam", 665). ?DOC(false). -spec is_native(tensor()) -> boolean(). is_native(T) -> case T of {native, _, _} -> true; _ -> false end. -file("src/viva_tensor/core/tensor.gleam", 673). ?DOC(false). -spec native_ref(tensor()) -> {ok, viva_tensor@core@ffi:native_tensor_ref()} | {error, nil}. native_ref(T) -> case T of {native, Ref, _} -> {ok, Ref}; _ -> {error, nil} end. -file("src/viva_tensor/core/tensor.gleam", 681). ?DOC(false). -spec from_native_ref(viva_tensor@core@ffi:native_tensor_ref(), list(integer())) -> tensor(). from_native_ref(Ref, Shape) -> {native, Ref, Shape}. -file("src/viva_tensor/core/tensor.gleam", 686). ?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, Ref, Shape}}; {error, <<"nif_not_loaded"/utf8>>} -> {error, {nif_not_loaded, <<"native_zeros"/utf8>>}}; {error, _} -> {error, {invalid_shape, <<"NIF resource allocation failed"/utf8>>}} end. -file("src/viva_tensor/core/tensor.gleam", 695). ?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, Ref, Shape}}; {error, <<"nif_not_loaded"/utf8>>} -> {error, {nif_not_loaded, <<"native_ones"/utf8>>}}; {error, _} -> {error, {invalid_shape, <<"NIF resource allocation failed"/utf8>>}} end. -file("src/viva_tensor/core/tensor.gleam", 704). ?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, Ref, Shape}}; {error, <<"nif_not_loaded"/utf8>>} -> {error, {nif_not_loaded, <<"native_fill"/utf8>>}}; {error, _} -> {error, {invalid_shape, <<"NIF resource allocation failed"/utf8>>}} end. -file("src/viva_tensor/core/tensor.gleam", 716). ?DOC(false). -spec native_from_list(list(float()), list(integer())) -> {ok, tensor()} | {error, viva_tensor@core@error:tensor_error()}. native_from_list(Data, Shape) -> case viva_tensor@core@ffi:nt_from_list(Data, Shape) of {ok, Ref} -> {ok, {native, Ref, Shape}}; {error, <<"nif_not_loaded"/utf8>>} -> {error, {nif_not_loaded, <<"native_from_list"/utf8>>}}; {error, _} -> Expected = compute_size(Shape), Actual = erlang:length(Data), case Expected =:= Actual of true -> {error, {invalid_shape, <<"NIF resource allocation failed"/utf8>>}}; false -> {error, {invalid_shape, <<<<<<"Data size "/utf8, (erlang:integer_to_binary(Actual))/binary>>/binary, " doesn't match shape "/utf8>>/binary, (viva_tensor@core@error:shape_to_string(Shape))/binary>>}} end end.