Packages

MLX machine learning framework bindings for Erlang

Current section

Files

Jump to
mlx src mlx.erl
Raw

src/mlx.erl

-module(mlx).
%% Type definitions
-type array() :: reference().
-type shape() :: [integer()].
-type dtype() :: atom().
%% Core array creation functions
-export([array/1, array/2, zeros/1, zeros/2, ones/1, ones/2, full/2, full/3, eye/1, eye/2, eye/3,
arange/1, arange/2, arange/3, linspace/2, linspace/3, linspace/4]).
%% Basic arithmetic operations
-export([add/2, subtract/2, multiply/2, divide/2, floor_divide/2, remainder/2,
divmod/2, power/2, abs/1, negative/1, reciprocal/1, sign/1]).
%% Trigonometric operations
-export([sin/1, cos/1, tan/1, arcsin/1, arccos/1, arctan/1, arctan2/2,
sinh/1, cosh/1, tanh/1, arcsinh/1, arccosh/1, arctanh/1]).
%% Exponential and logarithmic operations
-export([exp/1, expm1/1, log/1, log2/1, log10/1, log1p/1, logaddexp/2,
sqrt/1, square/1, rsqrt/1]).
%% Array manipulation operations
-export([reshape/2, transpose/1, transpose/2, squeeze/1, squeeze/2,
expand_dims/2, flatten/1, flatten/2, flatten/3, swapaxes/3,
moveaxis/3, roll/2, roll/3]).
%% Reduction operations
-export([sum/1, sum/2, sum/3, mean/1, mean/2, mean/3, max/1, max/2, max/3,
min/1, min/2, min/3, prod/1, prod/2, prod/3, std/1, std/2, std/3,
var/1, var/2, var/3]).
%% Cumulative operations
-export([cumsum/1, cumsum/2, cumprod/1, cumprod/2, cummax/1, cummax/2,
cummin/1, cummin/2]).
%% Linear algebra operations
-export([matmul/2, dot/2, inner/2, outer/2, tensordot/2, tensordot/3]).
%% Comparison operations
-export([equal/2, not_equal/2, less/2, less_equal/2, greater/2, greater_equal/2,
allclose/2, allclose/3, array_equal/2, isfinite/1, isinf/1, isnan/1]).
%% Logical operations
-export([logical_and/2, logical_or/2, logical_not/1, all/1, all/2, all/3,
any/1, any/2, any/3]).
%% Bitwise operations
-export([bitwise_and/2, bitwise_or/2, bitwise_xor/2, bitwise_invert/1,
left_shift/2, right_shift/2]).
%% Selection and indexing operations
-export([where/3, take/2, take/3, argmax/1, argmax/2, argmin/1, argmin/2,
sort/1, sort/2, argsort/1, argsort/2, topk/2, topk/3]).
%% Array concatenation and stacking
-export([concatenate/1, concatenate/2, stack/1, stack/2, split/2, split/3]).
%% Broadcasting operations
-export([broadcast_to/2, broadcast_arrays/1]).
%% Clipping and rounding operations
-export([clip/3, ceil/1, floor/1, round/1, round/2]).
%% Array properties and conversion
-export([shape/1, size/1, ndim/1, dtype/1, eval/1, to_list/1]).
%% Neural network operations
-export([softmax/1, softmax/2, sigmoid/1, conv1d/2, conv1d/3, conv2d/2, conv2d/3]).
%% Device management
-export([use_cpu/0, use_gpu/0]).
%% Testing and utilities
-export([test_basic/0, version/0]).
%% Array creation functions
-spec array(term()) -> {ok, array()} | {error, term()}.
array(Data) ->
array(Data, float32).
-spec array(term(), dtype()) -> {ok, array()} | {error, term()}.
array(Data, Dtype) ->
mlx_nif:array(Data, Dtype).
-spec zeros(shape()) -> {ok, array()} | {error, term()}.
zeros(Shape) ->
zeros(Shape, float32).
-spec zeros(shape(), dtype()) -> {ok, array()} | {error, term()}.
zeros(Shape, Dtype) ->
mlx_nif:zeros(Shape, Dtype).
-spec ones(shape()) -> {ok, array()} | {error, term()}.
ones(Shape) ->
ones(Shape, float32).
-spec ones(shape(), dtype()) -> {ok, array()} | {error, term()}.
ones(Shape, Dtype) ->
mlx_nif:ones(Shape, Dtype).
-spec full(shape(), number()) -> {ok, array()} | {error, term()}.
full(Shape, Value) ->
full(Shape, Value, float32).
-spec full(shape(), number(), dtype()) -> {ok, array()} | {error, term()}.
full(Shape, Value, Dtype) ->
mlx_nif:full(Shape, Value, Dtype).
-spec eye(integer()) -> {ok, array()} | {error, term()}.
eye(N) ->
eye(N, N, float32).
-spec eye(integer(), integer()) -> {ok, array()} | {error, term()}.
eye(N, M) ->
eye(N, M, float32).
-spec eye(integer(), integer(), dtype()) -> {ok, array()} | {error, term()}.
eye(N, M, Dtype) ->
case N of
M -> mlx_nif:eye(N, Dtype);
_ -> {error, non_square_matrix_not_supported}
end.
-spec arange(number()) -> {ok, array()} | {error, term()}.
arange(Stop) ->
arange(0, Stop, 1).
-spec arange(number(), number()) -> {ok, array()} | {error, term()}.
arange(Start, Stop) ->
arange(Start, Stop, 1).
-spec arange(number(), number(), number()) -> {ok, array()} | {error, term()}.
arange(Start, Stop, Step) ->
mlx_nif:arange(Start, Stop, Step).
-spec linspace(number(), number()) -> {ok, array()} | {error, term()}.
linspace(Start, Stop) ->
linspace(Start, Stop, 50).
-spec linspace(number(), number(), integer()) -> {ok, array()} | {error, term()}.
linspace(Start, Stop, Num) ->
linspace(Start, Stop, Num, float32).
-spec linspace(number(), number(), integer(), dtype()) -> {ok, array()} | {error, term()}.
linspace(Start, Stop, Num, Dtype) ->
case Dtype of
float32 -> mlx_nif:linspace(Start, Stop, Num);
_ -> {error, unsupported_dtype_use_float32}
end.
%% Basic arithmetic operations
-spec add(array(), array()) -> {ok, array()} | {error, term()}.
add(A, B) ->
mlx_nif:add(A, B).
-spec subtract(array(), array()) -> {ok, array()} | {error, term()}.
subtract(A, B) ->
mlx_nif:subtract(A, B).
-spec multiply(array(), array()) -> {ok, array()} | {error, term()}.
multiply(A, B) ->
mlx_nif:multiply(A, B).
-spec divide(array(), array()) -> {ok, array()} | {error, term()}.
divide(A, B) ->
mlx_nif:divide(A, B).
-spec floor_divide(array(), array()) -> {ok, array()} | {error, term()}.
floor_divide(A, B) ->
mlx_nif:floor_divide(A, B).
-spec remainder(array(), array()) -> {ok, array()} | {error, term()}.
remainder(A, B) ->
mlx_nif:remainder(A, B).
-spec divmod(array(), array()) -> {ok, {array(), array()}} | {error, term()}.
divmod(A, B) ->
mlx_nif:divmod(A, B).
-spec power(array(), array()) -> {ok, array()} | {error, term()}.
power(A, B) ->
mlx_nif:power(A, B).
-spec abs(array()) -> {ok, array()} | {error, term()}.
abs(A) ->
mlx_nif:abs(A).
-spec negative(array()) -> {ok, array()} | {error, term()}.
negative(A) ->
mlx_nif:negative(A).
-spec reciprocal(array()) -> {ok, array()} | {error, term()}.
reciprocal(A) ->
mlx_nif:reciprocal(A).
-spec sign(array()) -> {ok, array()} | {error, term()}.
sign(A) ->
mlx_nif:sign(A).
%% Trigonometric operations
-spec sin(array()) -> {ok, array()} | {error, term()}.
sin(A) ->
mlx_nif:sin(A).
-spec cos(array()) -> {ok, array()} | {error, term()}.
cos(A) ->
mlx_nif:cos(A).
-spec tan(array()) -> {ok, array()} | {error, term()}.
tan(A) ->
mlx_nif:tan(A).
-spec arcsin(array()) -> {ok, array()} | {error, term()}.
arcsin(A) ->
mlx_nif:arcsin(A).
-spec arccos(array()) -> {ok, array()} | {error, term()}.
arccos(A) ->
mlx_nif:arccos(A).
-spec arctan(array()) -> {ok, array()} | {error, term()}.
arctan(A) ->
mlx_nif:arctan(A).
-spec arctan2(array(), array()) -> {ok, array()} | {error, term()}.
arctan2(A, B) ->
mlx_nif:arctan2(A, B).
-spec sinh(array()) -> {ok, array()} | {error, term()}.
sinh(A) ->
mlx_nif:sinh(A).
-spec cosh(array()) -> {ok, array()} | {error, term()}.
cosh(A) ->
mlx_nif:cosh(A).
-spec tanh(array()) -> {ok, array()} | {error, term()}.
tanh(A) ->
mlx_nif:tanh(A).
-spec arcsinh(array()) -> {ok, array()} | {error, term()}.
arcsinh(A) ->
mlx_nif:arcsinh(A).
-spec arccosh(array()) -> {ok, array()} | {error, term()}.
arccosh(A) ->
mlx_nif:arccosh(A).
-spec arctanh(array()) -> {ok, array()} | {error, term()}.
arctanh(A) ->
mlx_nif:arctanh(A).
%% Exponential and logarithmic operations
-spec exp(array()) -> {ok, array()} | {error, term()}.
exp(A) ->
mlx_nif:exp(A).
-spec expm1(array()) -> {ok, array()} | {error, term()}.
expm1(A) ->
mlx_nif:expm1(A).
-spec log(array()) -> {ok, array()} | {error, term()}.
log(A) ->
mlx_nif:log(A).
-spec log2(array()) -> {ok, array()} | {error, term()}.
log2(A) ->
mlx_nif:log2(A).
-spec log10(array()) -> {ok, array()} | {error, term()}.
log10(A) ->
mlx_nif:log10(A).
-spec log1p(array()) -> {ok, array()} | {error, term()}.
log1p(A) ->
mlx_nif:log1p(A).
-spec logaddexp(array(), array()) -> {ok, array()} | {error, term()}.
logaddexp(A, B) ->
mlx_nif:logaddexp(A, B).
-spec sqrt(array()) -> {ok, array()} | {error, term()}.
sqrt(A) ->
mlx_nif:sqrt(A).
-spec square(array()) -> {ok, array()} | {error, term()}.
square(A) ->
mlx_nif:square(A).
-spec rsqrt(array()) -> {ok, array()} | {error, term()}.
rsqrt(A) ->
mlx_nif:rsqrt(A).
%% Array manipulation operations
-spec reshape(array(), shape()) -> {ok, array()} | {error, term()}.
reshape(A, Shape) ->
mlx_nif:reshape(A, Shape).
-spec transpose(array()) -> {ok, array()} | {error, term()}.
transpose(A) ->
transpose(A, []).
-spec transpose(array(), list()) -> {ok, array()} | {error, term()}.
transpose(A, Axes) ->
mlx_nif:transpose(A, Axes).
-spec squeeze(array()) -> {ok, array()} | {error, term()}.
squeeze(A) ->
squeeze(A, []).
-spec squeeze(array(), list()) -> {ok, array()} | {error, term()}.
squeeze(A, Axis) ->
mlx_nif:squeeze(A, Axis).
-spec expand_dims(array(), integer()) -> {ok, array()} | {error, term()}.
expand_dims(A, Axis) ->
mlx_nif:expand_dims(A, Axis).
-spec flatten(array()) -> {ok, array()} | {error, term()}.
flatten(A) ->
flatten(A, 0, -1).
-spec flatten(array(), integer()) -> {ok, array()} | {error, term()}.
flatten(A, StartAxis) ->
flatten(A, StartAxis, -1).
-spec flatten(array(), integer(), integer()) -> {ok, array()} | {error, term()}.
flatten(A, StartAxis, EndAxis) ->
mlx_nif:flatten(A, StartAxis, EndAxis).
-spec swapaxes(array(), integer(), integer()) -> {ok, array()} | {error, term()}.
swapaxes(A, Axis1, Axis2) ->
mlx_nif:swapaxes(A, Axis1, Axis2).
-spec moveaxis(array(), integer(), integer()) -> {ok, array()} | {error, term()}.
moveaxis(A, Source, Destination) ->
mlx_nif:moveaxis(A, Source, Destination).
-spec roll(array(), integer()) -> {ok, array()} | {error, term()}.
roll(A, Shift) ->
roll(A, Shift, []).
-spec roll(array(), integer(), list()) -> {ok, array()} | {error, term()}.
roll(A, Shift, Axis) ->
mlx_nif:roll(A, Shift, Axis).
%% Reduction operations
-spec sum(array()) -> {ok, array()} | {error, term()}.
sum(A) ->
mlx_nif:sum(A).
-spec sum(array(), list()) -> {ok, array()} | {error, term()}.
sum(A, Axis) ->
mlx_nif:sum(A, Axis).
-spec sum(array(), list(), boolean()) -> {ok, array()} | {error, term()}.
sum(A, Axis, Keepdims) ->
mlx_nif:sum(A, Axis, Keepdims).
-spec mean(array()) -> {ok, array()} | {error, term()}.
mean(A) ->
mlx_nif:mean(A).
-spec mean(array(), list()) -> {ok, array()} | {error, term()}.
mean(A, Axis) ->
mlx_nif:mean(A, Axis).
-spec mean(array(), list(), boolean()) -> {ok, array()} | {error, term()}.
mean(A, Axis, Keepdims) ->
mlx_nif:mean(A, Axis, Keepdims).
-spec max(array()) -> {ok, array()} | {error, term()}.
max(A) ->
mlx_nif:max(A).
-spec max(array(), list()) -> {ok, array()} | {error, term()}.
max(A, Axis) ->
mlx_nif:max(A, Axis).
-spec max(array(), list(), boolean()) -> {ok, array()} | {error, term()}.
max(A, Axis, Keepdims) ->
mlx_nif:max(A, Axis, Keepdims).
-spec min(array()) -> {ok, array()} | {error, term()}.
min(A) ->
mlx_nif:min(A).
-spec min(array(), list()) -> {ok, array()} | {error, term()}.
min(A, Axis) ->
mlx_nif:min(A, Axis).
-spec min(array(), list(), boolean()) -> {ok, array()} | {error, term()}.
min(A, Axis, Keepdims) ->
mlx_nif:min(A, Axis, Keepdims).
-spec prod(array()) -> {ok, array()} | {error, term()}.
prod(A) ->
prod(A, [], true).
-spec prod(array(), list()) -> {ok, array()} | {error, term()}.
prod(A, Axis) ->
prod(A, Axis, false).
-spec prod(array(), list(), boolean()) -> {ok, array()} | {error, term()}.
prod(A, Axis, Keepdims) ->
mlx_nif:prod(A, Axis, Keepdims).
-spec std(array()) -> {ok, array()} | {error, term()}.
std(A) ->
std(A, [], true).
-spec std(array(), list()) -> {ok, array()} | {error, term()}.
std(A, Axis) ->
std(A, Axis, false).
-spec std(array(), list(), boolean()) -> {ok, array()} | {error, term()}.
std(A, Axis, Keepdims) ->
mlx_nif:std(A, Axis, Keepdims).
-spec var(array()) -> {ok, array()} | {error, term()}.
var(A) ->
var(A, [], true).
-spec var(array(), list()) -> {ok, array()} | {error, term()}.
var(A, Axis) ->
var(A, Axis, false).
-spec var(array(), list(), boolean()) -> {ok, array()} | {error, term()}.
var(A, Axis, Keepdims) ->
mlx_nif:var(A, Axis, Keepdims).
%% Cumulative operations
-spec cumsum(array()) -> {ok, array()} | {error, term()}.
cumsum(A) ->
cumsum(A, 0).
-spec cumsum(array(), integer()) -> {ok, array()} | {error, term()}.
cumsum(A, Axis) ->
mlx_nif:cumsum(A, Axis).
-spec cumprod(array()) -> {ok, array()} | {error, term()}.
cumprod(A) ->
cumprod(A, 0).
-spec cumprod(array(), integer()) -> {ok, array()} | {error, term()}.
cumprod(A, Axis) ->
mlx_nif:cumprod(A, Axis).
-spec cummax(array()) -> {ok, array()} | {error, term()}.
cummax(A) ->
cummax(A, 0).
-spec cummax(array(), integer()) -> {ok, array()} | {error, term()}.
cummax(A, Axis) ->
mlx_nif:cummax(A, Axis).
-spec cummin(array()) -> {ok, array()} | {error, term()}.
cummin(A) ->
cummin(A, 0).
-spec cummin(array(), integer()) -> {ok, array()} | {error, term()}.
cummin(A, Axis) ->
mlx_nif:cummin(A, Axis).
%% Linear algebra operations
-spec matmul(array(), array()) -> {ok, array()} | {error, term()}.
matmul(A, B) ->
mlx_nif:matmul(A, B).
-spec dot(array(), array()) -> {ok, array()} | {error, term()}.
dot(A, B) ->
mlx_nif:dot(A, B).
-spec inner(array(), array()) -> {ok, array()} | {error, term()}.
inner(A, B) ->
mlx_nif:inner(A, B).
-spec outer(array(), array()) -> {ok, array()} | {error, term()}.
outer(A, B) ->
mlx_nif:outer(A, B).
-spec tensordot(array(), array()) -> {ok, array()} | {error, term()}.
tensordot(A, B) ->
tensordot(A, B, 2).
-spec tensordot(array(), array(), integer()) -> {ok, array()} | {error, term()}.
tensordot(A, B, Axes) ->
mlx_nif:tensordot(A, B, Axes).
%% Comparison operations
-spec equal(array(), array()) -> {ok, array()} | {error, term()}.
equal(A, B) ->
mlx_nif:equal(A, B).
-spec not_equal(array(), array()) -> {ok, array()} | {error, term()}.
not_equal(A, B) ->
mlx_nif:not_equal(A, B).
-spec less(array(), array()) -> {ok, array()} | {error, term()}.
less(A, B) ->
mlx_nif:less(A, B).
-spec less_equal(array(), array()) -> {ok, array()} | {error, term()}.
less_equal(A, B) ->
mlx_nif:less_equal(A, B).
-spec greater(array(), array()) -> {ok, array()} | {error, term()}.
greater(A, B) ->
mlx_nif:greater(A, B).
-spec greater_equal(array(), array()) -> {ok, array()} | {error, term()}.
greater_equal(A, B) ->
mlx_nif:greater_equal(A, B).
-spec maximum(array(), array()) -> {ok, array()} | {error, term()}.
maximum(A, B) ->
mlx_nif:maximum(A, B).
-spec minimum(array(), array()) -> {ok, array()} | {error, term()}.
minimum(A, B) ->
mlx_nif:minimum(A, B).
-spec allclose(array(), array()) -> {ok, boolean()} | {error, term()}.
allclose(A, B) ->
allclose(A, B, 1.0e-5).
-spec allclose(array(), array(), float()) -> {ok, boolean()} | {error, term()}.
allclose(A, B, Tolerance) ->
mlx_nif:allclose(A, B, Tolerance).
-spec array_equal(array(), array()) -> {ok, boolean()} | {error, term()}.
array_equal(A, B) ->
mlx_nif:array_equal(A, B).
-spec isfinite(array()) -> {ok, array()} | {error, term()}.
isfinite(A) ->
mlx_nif:isfinite(A).
-spec isinf(array()) -> {ok, array()} | {error, term()}.
isinf(A) ->
mlx_nif:isinf(A).
-spec isnan(array()) -> {ok, array()} | {error, term()}.
isnan(A) ->
mlx_nif:isnan(A).
%% Logical operations
-spec logical_and(array(), array()) -> {ok, array()} | {error, term()}.
logical_and(A, B) ->
mlx_nif:logical_and(A, B).
-spec logical_or(array(), array()) -> {ok, array()} | {error, term()}.
logical_or(A, B) ->
mlx_nif:logical_or(A, B).
-spec logical_not(array()) -> {ok, array()} | {error, term()}.
logical_not(A) ->
mlx_nif:logical_not(A).
-spec all(array()) -> {ok, array()} | {error, term()}.
all(A) ->
all(A, [], true).
-spec all(array(), list()) -> {ok, array()} | {error, term()}.
all(A, Axis) ->
all(A, Axis, false).
-spec all(array(), list(), boolean()) -> {ok, array()} | {error, term()}.
all(A, Axis, Keepdims) ->
mlx_nif:all(A, Axis, Keepdims).
-spec any(array()) -> {ok, array()} | {error, term()}.
any(A) ->
any(A, [], true).
-spec any(array(), list()) -> {ok, array()} | {error, term()}.
any(A, Axis) ->
any(A, Axis, false).
-spec any(array(), list(), boolean()) -> {ok, array()} | {error, term()}.
any(A, Axis, Keepdims) ->
mlx_nif:any(A, Axis, Keepdims).
%% Bitwise operations
-spec bitwise_and(array(), array()) -> {ok, array()} | {error, term()}.
bitwise_and(A, B) ->
mlx_nif:bitwise_and(A, B).
-spec bitwise_or(array(), array()) -> {ok, array()} | {error, term()}.
bitwise_or(A, B) ->
mlx_nif:bitwise_or(A, B).
-spec bitwise_xor(array(), array()) -> {ok, array()} | {error, term()}.
bitwise_xor(A, B) ->
mlx_nif:bitwise_xor(A, B).
-spec bitwise_invert(array()) -> {ok, array()} | {error, term()}.
bitwise_invert(A) ->
mlx_nif:bitwise_invert(A).
-spec left_shift(array(), array()) -> {ok, array()} | {error, term()}.
left_shift(A, B) ->
mlx_nif:left_shift(A, B).
-spec right_shift(array(), array()) -> {ok, array()} | {error, term()}.
right_shift(A, B) ->
mlx_nif:right_shift(A, B).
%% Selection and indexing operations
-spec where(array(), array(), array()) -> {ok, array()} | {error, term()}.
where(Condition, X, Y) ->
mlx_nif:where(Condition, X, Y).
-spec take(array(), array()) -> {ok, array()} | {error, term()}.
take(A, Indices) ->
take(A, Indices, 0).
-spec take(array(), array(), integer()) -> {ok, array()} | {error, term()}.
take(A, Indices, Axis) ->
mlx_nif:take(A, Indices, Axis).
-spec argmax(array()) -> {ok, array()} | {error, term()}.
argmax(A) ->
argmax(A, 0).
-spec argmax(array(), integer()) -> {ok, array()} | {error, term()}.
argmax(A, Axis) ->
mlx_nif:argmax(A, Axis).
-spec argmin(array()) -> {ok, array()} | {error, term()}.
argmin(A) ->
argmin(A, 0).
-spec argmin(array(), integer()) -> {ok, array()} | {error, term()}.
argmin(A, Axis) ->
mlx_nif:argmin(A, Axis).
-spec sort(array()) -> {ok, array()} | {error, term()}.
sort(A) ->
sort(A, -1).
-spec sort(array(), integer()) -> {ok, array()} | {error, term()}.
sort(A, Axis) ->
mlx_nif:sort(A, Axis).
-spec argsort(array()) -> {ok, array()} | {error, term()}.
argsort(A) ->
argsort(A, -1).
-spec argsort(array(), integer()) -> {ok, array()} | {error, term()}.
argsort(A, Axis) ->
mlx_nif:argsort(A, Axis).
-spec topk(array(), integer()) -> {ok, array()} | {error, term()}.
topk(A, K) ->
topk(A, K, -1).
-spec topk(array(), integer(), integer()) -> {ok, array()} | {error, term()}.
topk(A, K, Axis) ->
mlx_nif:topk(A, K, Axis).
%% Array concatenation and stacking
-spec concatenate(list()) -> {ok, array()} | {error, term()}.
concatenate(Arrays) ->
concatenate(Arrays, 0).
-spec concatenate(list(), integer()) -> {ok, array()} | {error, term()}.
concatenate(Arrays, Axis) ->
mlx_nif:concatenate(Arrays, Axis).
-spec stack(list()) -> {ok, array()} | {error, term()}.
stack(Arrays) ->
stack(Arrays, 0).
-spec stack(list(), integer()) -> {ok, array()} | {error, term()}.
stack(Arrays, Axis) ->
mlx_nif:stack(Arrays, Axis).
-spec split(array(), list()) -> {ok, list()} | {error, term()}.
split(A, Indices) ->
split(A, Indices, 0).
-spec split(array(), list(), integer()) -> {ok, list()} | {error, term()}.
split(A, Indices, Axis) ->
mlx_nif:split(A, Indices, Axis).
%% Broadcasting operations
-spec broadcast_to(array(), shape()) -> {ok, array()} | {error, term()}.
broadcast_to(A, Shape) ->
mlx_nif:broadcast_to(A, Shape).
-spec broadcast_arrays(list()) -> {ok, list()} | {error, term()}.
broadcast_arrays(Arrays) ->
mlx_nif:broadcast_arrays(Arrays).
%% Clipping and rounding operations
-spec clip(array(), number(), number()) -> {ok, array()} | {error, term()}.
clip(A, Min, Max) ->
mlx_nif:clip(A, Min, Max).
-spec ceil(array()) -> {ok, array()} | {error, term()}.
ceil(A) ->
mlx_nif:ceil(A).
-spec floor(array()) -> {ok, array()} | {error, term()}.
floor(A) ->
mlx_nif:floor(A).
-spec round(array()) -> {ok, array()} | {error, term()}.
round(A) ->
round(A, 0).
-spec round(array(), integer()) -> {ok, array()} | {error, term()}.
round(A, Decimals) ->
mlx_nif:round(A, Decimals).
%% Neural network operations
-spec softmax(array()) -> {ok, array()} | {error, term()}.
softmax(A) ->
softmax(A, -1).
-spec softmax(array(), integer()) -> {ok, array()} | {error, term()}.
softmax(A, Axis) ->
mlx_nif:softmax(A, Axis).
-spec sigmoid(array()) -> {ok, array()} | {error, term()}.
sigmoid(A) ->
mlx_nif:sigmoid(A).
-spec conv1d(array(), array()) -> {ok, array()} | {error, term()}.
conv1d(Input, Weight) ->
conv1d(Input, Weight, 1).
-spec conv1d(array(), array(), integer()) -> {ok, array()} | {error, term()}.
conv1d(Input, Weight, Stride) ->
mlx_nif:conv1d(Input, Weight, Stride).
-spec conv2d(array(), array()) -> {ok, array()} | {error, term()}.
conv2d(Input, Weight) ->
conv2d(Input, Weight, [1, 1]).
-spec conv2d(array(), array(), list()) -> {ok, array()} | {error, term()}.
conv2d(Input, Weight, Stride) ->
mlx_nif:conv2d(Input, Weight, Stride).
%% Array properties and conversion
-spec shape(array()) -> {ok, shape()} | {error, term()}.
shape(Array) ->
mlx_nif:shape(Array).
-spec size(array()) -> {ok, integer()} | {error, term()}.
size(Array) ->
mlx_nif:size(Array).
-spec ndim(array()) -> {ok, integer()} | {error, term()}.
ndim(Array) ->
mlx_nif:ndim(Array).
-spec dtype(array()) -> {ok, string()} | {error, term()}.
dtype(Array) ->
mlx_nif:dtype_str(Array).
-spec eval(array()) -> {ok, array()} | {error, term()}.
eval(Array) ->
mlx_nif:eval(Array).
-spec to_list(array()) -> {ok, list()} | {error, term()}.
to_list(Array) ->
mlx_nif:to_list(Array).
%% Device management
-spec use_cpu() -> ok | {error, term()}.
use_cpu() ->
mlx_nif:set_default_device(cpu).
-spec use_gpu() -> ok | {error, term()}.
use_gpu() ->
mlx_nif:set_default_device(gpu).
%% Testing and utilities
-spec test_basic() -> ok | {error, term()}.
test_basic() ->
mlx_nif:test_basic().
-spec version() -> {ok, string()} | {error, term()}.
version() ->
mlx_nif:version().