Converting R data to integer and boolean arrays now uses less temporary memory. Suitable integer and logical inputs retain their R storage type, and conversion copies directly into MLX storage.
Embedding lookup now uses one native MLX take operation, preserving weight gradients and dtype and avoiding per-token transfers through R.
Axis validation and shape-based operations now recognize the single dimension of MLX vectors, including explicit axes, stacking, splitting, and neural layers.
Multi-axis reductions now use one native MLX operation, fixing variance and standard deviation over multiple axes and explicit reductions to scalars.
Converting R numeric vectors and arrays to float32 with as_mlx() is faster
and uses less temporary memory.
mlx_cross_entropy() is faster and uses less memory, especially with many
classes. It also improves numerical stability and gives clearer errors for
missing target indices.
Updated the bundled and minimum supported MLX version to 0.32.3 and
compilation to C++20. Fixed mlx_gather_qmm() for its new argument layout
while keeping the R interface unchanged.
.mlxfn examples now include both pre-metadata and current MLX
serialization formats, preserving import tests across MLX 0.31.1--0.32.1.scale() now preserves MLX-supplied center and scale vectors as MLX
attributes, avoiding a round trip through base R.mlx objects can now have row, column and dimnames, and vectors can have names.
These work much like base R. Names for any dimension may be NULL. Subsetting
with a non-existent name is an error. Many functions, e.g. solve(), %*%,
etc. preserve dimnames like their R analogues.mlx_device(), with_device() or local_device() to choose a
device to work on. This also makes irrelevant a bug in which
many/most operations were silently ignoring their operands' device.device argument which must be explicitly
set to "cpu". This is a teaching tool to help the user understand what
operations can take place on which device.rbind() and cbind() now accept 1D vectors.mlx_expand_dims() works with 1D vectors.[ subsetting by routing it through MLX take()
instead of the generic meshgrid gather path.mlx_take_along_axis(), mlx_put_along_axis(), and
mlx_scatter_add_axis() wrappers for MLX's axis-aligned indexed update ops.mlx_metal_kernel() to build custom Metal kernels from R and keep
inputs and outputs as MLX arrays.mlx_cast() for casting arrays between dtypes/devices (previously
internal .mlx_cast).%*% now requires both its arguments to be matrices (unlike base R).as_mlx(x) no longer returns scalars if x is a length-one vector.mlx_arange(start, stop, step) now matches seq()
behavior (stop included if reachable).mlx_device() to return device associated with x.mlx_get_device() to mlx_best_device().mlx_slice_update() now accepts 1-based (inclusive) start/stop indices to
match the rest of the R API; internal callers were updated accordingly.mlx_shape() to expose MLX-native shapes (never NULL) and aligned
dim.mlx() with base R semantics (returns NULL for 1-D vectors/scalars).mlx_rand_categorical(), mlx_rand_permutation(), mlx_cross_entropy(),
mlx_gather_qmm(), and mlx_embedding() now accept 1-based indices for
inputs/outputs, consistently with R.[/[<- on mlx arrays and
documented subsetting semantics.mlx_import_function() to import MLX functions from (e.g.) Python.mlx_array(), mlx_matrix(), mlx_vector(), and mlx_scalar() for
fast construction of MLX objects when data and dimensions are already known.mlx_array()/mlx_matrix() now recycle shorter payloads when they evenly divide the target shape.mlx_fft(), mlx_fft2(), and mlx_fftn() wrappers around MLX FFT
kernels.mlx_d/p/qnorm(), mlx_d/p/qunif() etc.mlx_quantile().mlx_coordinate_descent(), a coordinate descent algorithm.[/[<- bugs affecting non-contiguous, unsorted, and duplicate
subsetting patterns on mlx arrays.as_mlx() now takes a much faster path for large numeric matrices by letting
MLX handle column-major inputs directly.all() and any() applied to mlx arrays now return plain R
logical scalars; mlx_all()/mlx_any() continue to yield mlx booleans.row(), col(), asplit(), and backsolve().scale.mlx() to center/scale matrices entirely on the MLX backend (with
MLX arrays stored in the scaled:center / scaled:scale attributes).scale.mlx() now always records its scaled:center / scaled:scale
attributes as 1 x p MLX arrays, keeping them lazily evaluated even after
coercion.as.matrix.mlx() now preserves any user-set attributes (including the MLX
scaling metadata) when copying arrays back to base R.