-
New
nv_lower_tri()andnv_upper_tri()(withnv_lower_tri_like()/nv_upper_tri_like()) return a boolean triangular mask for a given shape, mirroring base R'slower.tri()/upper.tri(). As in base R, the main diagonal is excluded by default; passdiagonal = 0Lto include it. Usenv_tril()/nv_triu()to zero out a triangle of an existing array. -
trace_fn()gained anoptimizeargument controlling which graph optimization passes run on the traced graph.TRUEruns all passes,FALSE(default) runs none, and a character vector (e.g.c("inline_scalars", "remove_unused_constants")) selects a subset.jit()andxla()always trace with all passes enabled. -
New
nv_dnorm()computes the normal distribution's probability density function (or, withlog = TRUE, its log-density). -
nv_array(),nv_scalar(),as_array(), and theas.integer()/as.double()/as.logical()/as.vector()methods forAnvlArraygained acheckargument that opts into scanning forNAvalues during host -> device and device -> host transfers. See the "Gotchas" vignette. -
nv_var()andnv_sd()now default todims = NULL, which reduces over all dimensions and returns a scalar, consistent with the other reductions.
-
Most
nv_*()API functions are now JIT-compiled internally (via a new@jitroxygen roclet), speeding up eager-mode execution. -
Tracing (
trace_fn()) performance has been improved. -
Tracing now accumulates primitive calls in a
fastmap::fastqueue(amortised-O(1) append) instead of an R list grown withc()(copy-on-modify, O(n^2)). Tracing large unrolled graphs is substantially faster, e.g. ~1.36x for an 8000-op chain, with the gain growing with graph size. -
StableHLO lowering forwards the trace-time output types to the
hlo_*builders (via anoutput_typesargument passed to the lowering rules), so stablehlo skips redundant type inference when lowering the graph.
-
NULLis now treated as an empty node when flattening and unflattening trees. It contributes no leaves but is preserved structurally, so functions with optional arguments (e.g.function(x, y = NULL)) round-trip correctly. -
nv_argmax()/nv_argmin()andnv_cummax()/nv_cummin()now break ties order-independently, so they return the same result on GPU as on CPU (#368).nv_argmax()/nv_argmin()prefer the smallest index;nv_cummax()/nv_cummin()prefer the last occurrence. -
nv_diag()now errors on non-1-D input instead of silently producing an incorrect result.
nv_empty()/nv_empty_like()return arrays with unspecified contents (no longer zero-initialized).
- On CPU, jitted XLA functions now back every non-aliased output with
an R-owned RAWSXP. anvl appends a phantom donated input per
unaliased output during lowering, allocates
pjrt::pjrt_empty()buffers at execute time, andpjrtmigrates the keepalive onto the output XPtr. The output's host bytes are then managed by R's GC. - Renamed user-facing API functions to match base R names:
nv_sine()->nv_sin(),nv_cosine()->nv_cos(),nv_ceil()->nv_ceiling(),nv_cholesky()->nv_chol(). The corresponding primitives were renamed in step:prim_sine()->prim_sin(),prim_cosine()->prim_cos(),prim_cholesky()->prim_chol(). nv_reduce_mean()was renamed tonv_mean().nv_solve()no longer requiresato be symmetric positive-definite as it uses LU instead of Cholesky decomposition. Because of this, it is no longer differentiable, as the reverse rule for LU is not implemented yet.nv_chol()/prim_chol()now default tolower = FALSE(upper-triangular factor), matching base R'schol(). Previously defaulted tolower = TRUE.
- New matrix-decomposition primitives and corresponding
nv_*()functions:qr,lu,svd,eigh. None of them implement a reverse rule yet. - New API functions:
nv_triangular_solve()(wraps the already-existingprim_triangular_solve()).nv_det()andnv_determinant(). The latter can also be called via thedeterminant()generic.nv_inv(), which can also be called viasolve(operand)(missing second argument).
qr,chol, andsolvefrom base R now dispatch tonv_qr(),nv_chol(), andnv_solve()onAnvlArray/AnvlBoxinputs.
- New unary primitives and corresponding
nv_*()functions:acos,acosh,asin,asinh,atan,atanh,cosh,sinh,digamma,lgamma,polygamma,erf,erf_inv,erfc. - New API functions
nv_mod()(flooring remainder) andnv_trunc()(truncation toward zero).
- New primitives and corresponding
nv_*()functions:cumsum,cumprod,cummax,cummin.prim_cumprod()does not yet have a reverse rule.
- New primitives
prim_sort(),prim_top_k(),prim_reduce(),prim_argmax(),prim_argmin(). - New API functions:
nv_sort()/nv_argsort()-- sort along a dimension, or return the permutation that does.nv_top_k()-- theklargest values along a dimension.nv_median()/nv_quantile()-- median / quantiles along a dimension.median()dispatches tonv_median().nv_argmax()/nv_argmin()-- index of the maximum / minimum along a dimension (ties broken by smallest index).nv_select()-- select a slice along a dimension by index.
nv_array()gained abyrowargument that fills the array from an R object in row-major order, mirroringmatrix(byrow = TRUE)(#165).- New
nv_matrix(data, nrow, ncol, ...)which works like R'smatrix(). - New API functions
nv_rbind()andnv_cbind()and correspondingrbind()/cbind()generics. - New API function
nv_flatten()for flattening to 1-D.
- New
AnvlArray-> Rvectorconverters:as.numeric(),as.double(),as.integer(),as.logical(),as.vector(). - New function
await()that blocks until the underlying computation has finished. - New tree utilities
map_tree()andpmap_tree()for applying functions leaf-wise over (possibly nested) lists. - Added support for
rangegeneric. - Improved NaN handling across various primitives and API functions.
nv_reduce_sum(),nv_reduce_prod(),nv_reduce_max(),nv_reduce_min(),nv_reduce_any(),nv_reduce_all()andnv_mean()now defaultdims = NULL, which reduces over all dimensions and returns a scalar. Previously,dimswas required.
- The overloaded
%%operator now calls the newnv_mod()to be consistent with base R. - The reverse rule for
prim_reduce_prod()no longer producesNaN/Infgradients when the input contains zeros. - The CI now actually runs the torch-comparison tests.
nv_runif()not properly respects thelowerargument.
- The package was renamed from
anviltoanvlto avoid a conflict with the Bioconductor packageAnVIL. AnvilTensor/nv_tensorwere renamed toAnvlArrayandnv_arrayto be more in line with R'sarray(). Also,nv_aten()was renamed tonv_aval().- Subsetting with
list()(e.g.x[list(1, 3)]) is no longer supported. Usearray()to wrap the indices instead, e.g.x[array(c(1L, 3L))]. This mirrors the input convention used everywhere else in the package. - Removed debug mode.
- Remove NSE support for
nvl_if. It now requires passing 0-argument closures astrueandfalsearguments. - Primitives renamed from
nvl_*toprim_*. The underlying primitive object containing the rules and metadata is now part of theJitPrimitivefunction via theprimitiveattribute.
- Better composability:
jit()ted functions can now be used in otherjit()-calls. This is the mechanism underlying the new eager mode. - Eager mode was added:
This means, you can now do
nv_add(1, nv_array(1:2))and it will actually perform the computation and not only do type inference. - An experimental {quickr} backend was added
It only runs on CPU for now and supports a subset of available operations.
You can enable it via the
backendargument injit()andnv_array()or via theanvl.default_backendoption. - New primitives:
nvl_cholesky()to compute the Cholesky decomposition of a matrix.nvl_triangular_solve()to solve a system of linear equations with a triangular matrix.
- New API functions (+ corresponding R generic implementations):
nv_diag()to create a diagonal matrix from a 1-D tensor.nv_eye()to create an identity matrix.nv_solve()to solve a system of linear equations.nv_cholesky()to compute the Cholesky decomposition of a matrix.nv_device()constructs a backend-specific device object (e.g.nv_device("cpu")) that can be passed asdeviceto array constructors likenv_fill()ornv_iota().nv_crossprod()andnv_tcrossprod()for matrix cross-products.nv_outer()for the outer product.nv_extract_diag()to extract the diagonal of a matrix.nv_trace()to compute the trace of a matrix.nv_tril()andnv_triu()to extract lower/upper triangular parts.nv_squeeze()andnv_unsqueeze()to drop or add length-1 dimensions.nv_log2()andnv_log10().nv_is_infinite()andnv_is_nan().nv_sd()andnv_var()for standard deviation and variance.
jit()now accepts integer positions for thestaticargument.- New S3 methods
dim(),nrow(),ncol(), andlength()for anvl arrays. - Printing tensors via
nv_print()now also works on GPUs. - R vectors of length 1 and arrays are now auto-converted when being passed
to
jitted functions. - Improved device handling in
jit()
- Many operations are now done asynchronously, which improves performance, especially on GPUs.
- +-Inf/NaN are correctly created for
f64when inlined into the XLA exectuable (#182). This caused wrong results with e.g.nv_reduce_max()when working withf64. - Corrected argument checks in
nv_iota(). - Fix check that
wrtarguments ingradient()must be floats. nv_subset()andnv_subset_assign()now error on trailing-comma subscripts (#273).
- New vignette on implementing Gaussian Processes.
- New vignette on implementing Metropolis-Hastings sampling.
- An installation guide was added.
- Linux on ARM is now supported (CPU only).
- To use the CUDA backend, it is now possible to install the
cuda12.8package (see installation guide), which only requires a compatible CUDA driver.
Initial release