The main array object. Its type is determined by a data type and a shape and lives on a device, which can be a CPU or a GPU.
Usage
nv_array(data, shape = NULL, dtype = NULL, device = NULL, byrow = FALSE)
nv_scalar(data, dtype = NULL, device = NULL)
nv_matrix(
data,
nrow = NULL,
ncol = NULL,
dtype = NULL,
device = NULL,
byrow = FALSE
)
nv_empty(shape, dtype, device = NULL)
nv_array_like(like, data, shape = NULL, dtype = NULL, device = NULL)
nv_scalar_like(like, data, dtype = NULL, device = NULL)
nv_empty_like(like, shape = NULL, dtype = NULL, device = NULL)Arguments
- data
(any)
integer(),double(), orlogical()scalar, vector, or array. Alternatively araw()vector holding the native little-endian byte payload ofprod(shape)elements ofdtype; bothdtypeandshapeare then required (only supported on the"pjrt"backend). Raw payloads are read in column-major element order, or row-major withbyrow = TRUE. An existingAnvlArrayis returned unchanged if theshape,dtypeanddevicegiven agree with it, and is an error otherwise.- shape
(
NULL|integer())
The output shape of the array. The default (NULL) is to infer it from the data if possible. Note thatnv_arrayinterprets length 1 vectors as having shape(1). Empty data has no shape to infer –0,c(2, 0)andc(0, 3)all hold no elements – soshapeis required there. To create a "scalar" with no axes (shape()), usenv_scalaror explicitly specifyshape = integer().- dtype
(
NULL|character(1)|DataType)
The data type at which to create the array: axlamisc::DataTypeor one of bool, i8, i16, i32, i64, ui8, ui16, ui32, ui64, f32, f64. A value it cannot hold at all is an error (nv_array(3e9, dtype = "i32")overflows). Adoubleat an integer data type is truncated. The default (NULL) uses the default data type ofdata's category.nv_empty(), which has nodata, requires it.- device
(
NULL|character(1)| device)
The device the data lives on, given either as:a device string naming the platform (e.g.
"cpu","cuda","cuda:<n>"), which is resolved against the backend in use, ora device object as returned by
nv_device(): aPJRTDevicefor the"pjrt"backend or aquickr_devicefor the"quickr"backend. It must belong to the active backend (active_backend()); a device of another backend is an error.
The default (
NULL) usesdefault_device().- byrow
(
logical(1))
When constructing from an R object and the result has at least two axes, fill the array in row-major order rather than the default column-major order. Only allowed whendatais an R object — passing an existingAnvlArraytogether withbyrow = TRUEis an error.- nrow
(
NULL|integer(1))
Number of rows. Inferred fromncoland the data length ifNULL. Defaults to1whendatais a scalar.- ncol
(
NULL|integer(1))
Number of columns. Inferred fromnrowand the data length ifNULL. Defaults to1whendatais a scalar.- like
(
AnvlArray|GraphBox)
An existing array; an R value is an error. Any ofshape(whichnv_scalar_like()does not take),dtypeanddevicethat areNULL(the default) are taken fromlike.
Terminology
An array's axes are the indices that identify its directions, numbered
1, 2, 3, ... The size of an axis (its axis size) is the extent
along that axis, and the shape is the vector of all axis sizes. For
example, nv_array(1:6, shape = c(2, 3)) has two axes; the size of axis 1
is 2 and the size of axis 2 is 3, so its shape is c(2, 3). Use
naxes() for the number of axes, axes() for the axis
indices, and shape() for the axis sizes. We speak of the size of an
axis rather than an array's "dimensions", as the latter is generally
overloaded as it is used to refer to both the axis and its size.
Serialization
Arrays can be serialized to and from the safetensors format:
nv_serialize()/nv_unserialize(): Serialize/deserialize arrays to/from raw vectors.
An array can also be saved like any R object, e.g. with saveRDS().
Its device is not saved: an array of the pjrt backend loads onto the
default device at the time it is read, so an array saved
on a GPU also loads on a machine without one. anvl arranges this when it
is loaded, so load anvl before reading arrays.
Backend
An AnvlArray is backend-dependent: it belongs to exactly one backend
("pjrt" or the experimental "quickr") and lives on a device of that backend.
The supported data types and devices differ between backends.
Missing values
XLA, the compiler that is used by the "pjrt" (the default) backend
has no notion of a missing (NA) value.
When creating a new AnvlArray, the input is therefore checked for the
presence of such values.
NAs are always rejected, except when:
Creating
floatarrays where we convert theNAtoNaN.When creating an
i32from an Rinteger(). There, we throw a warning, but the resultingAnvlArraygets the bit representation ofNA_integer_, which isINT_MIN(-2147483648). Disallowing this would prevent round-trips between the data types.
See the Gotchas article for more information.
Out of Range values
Because base R has fewer data types than anvl, creating AnvlArrays from R often involves
type conversions.
When such conversions are performed, anvl performs a scan of the inputs to ensure that the
requested data type can actually hold the input data.
For example, trying to create an unsigned integer from a negative R integer() fails.
The same holds where an R value takes its data type from the array it meets
rather than from an argument: nv_scalar(1L, "ui8") + (-2L) is refused, where
converting an array with nv_convert() wraps around.
Examples
# a 1-d array (vector) with shape (4), at the default data type for integers
nv_array(1:4)
#> AnvlArray
#> 1
#> 2
#> 3
#> 4
#> [ CPUi32{4} ]
# specify a dtype
nv_array(c(1.5, 2.5, 3.5), dtype = "f64")
#> AnvlArray
#> 1.5000
#> 2.5000
#> 3.5000
#> [ CPUf64{3} ]
# a 2x3 matrix
nv_array(1:6, shape = c(2L, 3L))
#> AnvlArray
#> 1 3 5
#> 2 4 6
#> [ CPUi32{2,3} ]
# a 2x3 matrix filled by row, like `matrix(1:6, 2, 3, byrow = TRUE)`.
nv_array(1:6, shape = c(2L, 3L), byrow = TRUE)
#> AnvlArray
#> 1 2 3
#> 4 5 6
#> [ CPUi32{2,3} ]
# a scalar array
nv_scalar(3.14)
#> AnvlArray
#> 3.1400
#> [ CPUf32{} ]
# an uninitialized 2x3 array (contents are unspecified)
nv_empty(shape = c(2L, 3L), dtype = "f32")
#> AnvlArray
#> 7.4893e-17 3.5571e-41 7.4888e-17
#> 3.5571e-41 7.4888e-17 3.5571e-41
#> [ CPUf32{2,3} ]
# --- Extractors ---
x <- nv_array(1:6, shape = c(2L, 3L))
dtype(x)
#> <i32>
shape(x)
#> [1] 2 3
naxes(x)
#> [1] 2
device(x)
#> <CpuDevice(id=0)>
platform(x)
#> [1] "cpu"
# --- Transforming arrays with jit ---
add_one <- jit(function(x) x + 1L)
add_one(nv_array(1:4))
#> AnvlArray
#> 2
#> 3
#> 4
#> 5
#> [ CPUi32{4} ]
# --- Eager mode (calling operations directly) ---
nv_add(nv_array(1:3), nv_array(4:6))
#> AnvlArray
#> 5
#> 7
#> 9
#> [ CPUi32{3} ]