array_recycling: Multidimensional array recycling

array_recyclingR Documentation

Multidimensional array recycling

Description

Arithmetic and other binary operations in base R between a matrix or array and a vector don't let the user control how the latter should be recycled: it's always recycled along the first dimension of the matrix or array. This has led users to use various tricks when they need recycling along the second dimension (a.k.a. "horizontal recycling"), like the popular "double-transposition" trick: t(t(x) / cs). However this is inefficient and inelegant.

as_tile() is meant to address this.

It also allows arithmetic and other binary operations between two arrays of distinct dimensions (rejected as "non-conformable" by arithmetic operations in base R), typically between a small one (the tile) and a bigger one, as long as their geometries are compatible.

Usage

as_tile(x, along=1L, dim=NULL)

Arguments

x

An array-like object or a vector.

along

Can only be used when x is a vector. Must be a single positive integer indicating the "orientation" of the tile to be created, that is, the dimension along which x will be recycled by arithmetic operations and other binary operations.

dim

NULL or the dimensions (supplied as an integer vector) of the tile to be created.

Value

A tile object (tile is an extension of array).

See Also

  • base::colSums in the base package.

  • array and matrix objects in base R.

Examples

## ---------------------------------------------------------------------
## 2D EXAMPLES
## ---------------------------------------------------------------------
m0 <- matrix(1:54, nrow=6)
x <- c(-1, 0, 100)

## Arithmetic operations in base R recycle 'x' along the first dimension
## of the matrix ("vertical recycling"):
m0 * x

## To recycle 'x' along the second dimension of the matrix ("horizontal
## recycling"), we turn it into an "horizontal" tile:
t <- as_tile(x, along=2)
t

m0 * t

## The above produces the same result as the double-transposition trick
## but is more efficient (and also makes code easier to read):
stopifnot(identical(m0 * t, t(t(m0) * x)))

## A less artificial example:
cs0 <- colSums(m0)
m <- m0 / as_tile(cs0, along=2)

stopifnot(all(colSums(m) == 1))  # sanity check

## Using an arbitrary 2D tile:

t <- m0[1:2, 1:3]
t
## Unfortunately arithmetic operations in base R refuse to operate on
## arrays that don't have the same dimensions:
## Not run: 
  m0 / t  # ERROR! (non-conformable arrays)

## End(Not run)

## Wrapping 't' in a tile object makes this work:
m0 / as_tile(t)

## ---------------------------------------------------------------------
## 3D EXAMPLES
## ---------------------------------------------------------------------
## Note that colSums() supports multidimensional arrays. In this case
## the user can use the 'dims' argument to control how the array should
## be sliced into "columns". See '?base::colSums' for the details.

a <- array(runif(300), dim=c(10, 5, 6))

## Using 'dims=2' indicates that the columns are the 2D slices obtained
## by slicing the array along its 3rd dimension. With this slicing, each
## column is a 10 x 5 matrix.
cs2 <- colSums(a, dims=2)
cs2  # vector of length 6 (one value per 2D slice)

t <- as_tile(cs2, along=3)
a / t

stopifnot(all(colSums(a / t, dims=2) == 1))  # sanity check

## By default (i.e. when 'dims=1') the array is considered to be made
## of 5*6 columns of length 10.
cs1 <- colSums(a)
cs1  # 5 x 6 matrix

t <- as_tile(cs1, dim=c(1L, dim(cs1)))
a / t

stopifnot(all(colSums(a / t) == 1))  # sanity check

Bioconductor/S4Arrays documentation built on Feb. 8, 2025, 10:13 a.m.