1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
|
\name{array selection}
\alias{array selection}
\alias{array_selection}
\alias{array selections}
\alias{array_selections}
\alias{L-index}
\alias{Lindex}
\alias{M-index}
\alias{Mindex}
\alias{N-index}
\alias{Nindex}
\alias{Lindex2Mindex}
\alias{Mindex2Lindex}
\title{Manipulation of array selections}
\description{
NOTE: The tools documented in this man page are primarily intended
for developers or advanced users curious about the internals of the
\pkg{SparseArray} or \pkg{DelayedArray} packages. End users typically
don't need them for their regular use of \link[SparseArray]{SparseArray}
or \link[DelayedArray]{DelayedArray} objects.
An \emph{array selection} is just an index into an array-like object that
contains the information of which array elements are selected. This index
can take various forms but 3 special forms are particularly useful and
extensively used in the context of the \pkg{SparseArray} and
\pkg{DelayedArray} packages:
\emph{linear index} (also referred to as \emph{L-index} or \emph{Lindex}),
\emph{matrix index} (also referred to as \emph{M-index} or \emph{Mindex}),
\emph{N-dimensional index} (also referred to as \emph{N-index} or
\emph{Nindex}). See Details section below for more information.
Two utility functions are provided at the moment to convert back and forth
between \emph{L-indices} and \emph{M-indices}. More will be added in the
future to convert between other types of array indices.
}
\usage{
## Convert back and forth between L-indices and M-indices:
Lindex2Mindex(Lindex, dim, use.names=FALSE)
Mindex2Lindex(Mindex, dim, use.names=FALSE, as.integer=FALSE)
}
\arguments{
\item{Lindex}{
An \emph{L-index}. See Details section below.
}
\item{Mindex}{
An \emph{M-index}. See Details section below.
For convenience, \code{Mindex} can also be specified as an integer vector
with one element per dimension in the underlying array, in which case it
will be treated like a 1-row matrix.
}
\item{dim}{
An integer vector containing the dimensions of the underlying array.
Note that \code{dim} can also be an integer matrix, in which case
it must have one row per element in \code{Lindex} (or per row in
\code{Mindex}) and one column per dimension in the underlying array.
}
\item{use.names}{
Should the names (or rownames) on the input be propagated to the output?
}
\item{as.integer}{
Set to \code{TRUE} to force \code{Mindex2Lindex} to return the L-index
as an integer vector. Dangerous!
By default, i.e. when \code{as.integer=FALSE}, \code{Mindex2Lindex} will
return the L-index either as an integer or numeric vector. It will choose
the former only if it's safe, that is, only if all the values in the
L-index "fit" in the integer type. More precisely:
\itemize{
\item If \code{dim} is not a matrix (i.e. is a vector) or if it's a
matrix with a single row: \code{Mindex2Lindex} returns an integer
or numeric vector depending on whether \code{prod(dim)} is <=
\code{.Machine$integer.max} (2^31 - 1) or not.
\item Otherwise \code{Mindex2Lindex} returns a numeric vector.
}
Note that with these rules, \code{Mindex2Lindex} can return a numeric
vector even if an integer vector could have been used.
Use \code{as.integer=TRUE} only in situations where you know that all
the L-index values are going to "fit" in the integer type.
\code{Mindex2Lindex} will return garbage if they don't.
}
}
\details{
The 3 special forms of array indices that are extensively used in the
context of the \pkg{SparseArray} and \pkg{DelayedArray} packages:
\enumerate{
\item \emph{Linear index} (or \emph{L-index} or \emph{Lindex}):
A numeric vector where each value is >= 1 and <= the length
of the array-like object. When using an L-index to subset an
array-like object, the returned value is a vector-like object
(i.e. no dimensions) of the same length as the L-index.
Example:
\preformatted{
a <- array(101:124, 4:2)
Lindex <- c(7, 2, 24, 2)
a[Lindex]
}
\item \emph{Matrix index} (or \emph{M-index} or \emph{Mindex}):
An integer matrix with one column per dimension in the array-like
object and one row per array element in the selection.
The values in each column must be >= 1 and <= the extent
of the array-like object along the corresponding dimension.
When using an M-index to subset an array-like object, the returned
value is a vector-like object (i.e. no dimensions) of length the
number of rows in the M-index.
Example:
\preformatted{
a <- array(101:124, 4:2)
Mindex <- rbind(c(3, 2, 1),
c(2, 1, 1),
c(4, 3, 2),
c(2, 1, 1))
a[Mindex]
}
Note that this is the type of index returned by
\code{base::\link[base]{arrayInd}}.
\item \emph{N-dimensional} (or \emph{N-index} or \emph{Nindex}):
A list with one list element per dimension in the array-like object.
Each list element must be a subscript describing the selection along
the corresponding dimension of the array-like object.
IMPORTANT: A \code{NULL} subscript is interpreted as a \emph{missing}
subscript ("missing" like in \code{a[ , , 1:2]}), that is, as a
subscript that runs along the full extend of the corresponding
dimension of the array-like object. This means that before an
N-index can be used in a call to \code{[}, \code{[<-}, \code{[[}
or \code{[[<-}, the \code{NULL} list elements in it must be
replaced with objects of class \code{"name"}.
When using an N-index to subset an array-like object, the returned
value is another array-like object of dimensions the lengths of the
selections along each dimensions.
Examples:
\preformatted{
a <- array(101:124, 4:2)
## Normalized N-index (i.e. non-NULL subscripts are integer
## vectors with positive values only):
Nindex <- list(c(1, 4, 1), NULL, 1)
## Same as a[c(1, 4, 1), , 1, drop=FALSE]:
S4Arrays:::subset_by_Nindex(a, Nindex)
Nindex <- list(integer(0), NULL, 1)
## Same as a[integer(0), , 1, drop=FALSE]:
S4Arrays:::subset_by_Nindex(a, Nindex)
## Non-normalized N-index:
Nindex <- list(-3, NULL, c(TRUE, FALSE, FALSE))
Nindex <- S4Arrays:::normalize_Nindex(Nindex, a)
## Same as a[-3, , 1, drop=FALSE]:
S4Arrays:::subset_by_Nindex(a, Nindex)
Nindex <- list(IRanges(2, 4), NULL, 1)
Nindex <- S4Arrays:::normalize_Nindex(Nindex, a)
## Same as a[2:4, , 1, drop=FALSE]:
S4Arrays:::subset_by_Nindex(a, Nindex)
dimnames(a)[[1]] <- LETTERS[1:4]
Nindex <- list(c("D", "B"), NULL, 1)
Nindex <- S4Arrays:::normalize_Nindex(Nindex, a)
## Same as a[c("D", "B"), , 1, drop=FALSE]:
S4Arrays:::subset_by_Nindex(a, Nindex)
}
}
}
\value{
\code{Lindex2Mindex} returns an M-index.
\code{Mindex2Lindex} returns an L-index.
}
\seealso{
\code{\link[base]{arrayInd}} in the \pkg{base} package.
}
\examples{
## ---------------------------------------------------------------------
## M-index vs L-index
## ---------------------------------------------------------------------
a <- array(101:124, 4:2)
## The same "array selection" can be represented by an M-index or
## an L-index. Here we use both representations to select the same
## 4 array elements:
Mindex <- rbind(c(3, 2, 1),
c(2, 1, 1),
c(4, 3, 2),
c(2, 1, 1))
a[Mindex]
Lindex <- c(7, 2, 24, 2)
a[Lindex]
## Sanity check:
stopifnot(identical(a[Mindex], a[Lindex]))
## ---------------------------------------------------------------------
## Convert back and forth between M-index and L-index representation
## ---------------------------------------------------------------------
Mindex2Lindex(Mindex, dim(a)) # L-index
Lindex2Mindex(Lindex, dim(a)) # M-index
## Sanity checks:
storage.mode(Mindex) <- storage.mode(Lindex) <- "integer"
stopifnot(identical(Mindex2Lindex(Mindex, dim(a)), Lindex))
stopifnot(identical(Lindex2Mindex(Lindex, dim(a)), Mindex))
## ---------------------------------------------------------------------
## More Mindex2Lindex() examples
## ---------------------------------------------------------------------
dim <- 4:2
Mindex2Lindex(c(4, 3, 1), dim)
Mindex2Lindex(c(4, 3, 2), dim)
Mindex <- rbind(c(1, 1, 1),
c(2, 1, 1),
c(3, 1, 1),
c(4, 1, 1),
c(1, 2, 1),
c(1, 1, 2),
c(4, 3, 2))
Mindex2Lindex(Mindex, dim)
## With a matrix of dimensions:
dims <- rbind(c(4L, 3L),
c(5L, 3L),
c(6L, 3L))
Mindex <- rbind(c(1, 2),
c(1, 2),
c(1, 2))
Mindex2Lindex(Mindex, dims)
## Sanity checks:
dim <- c(33:30, 45L, 30L)
stopifnot(Mindex2Lindex(rep(1, 6), dim) == 1)
stopifnot(Mindex2Lindex(dim, dim) == prod(dim))
stopifnot(identical(Mindex2Lindex(arrayInd(1:120, 6:4), 6:4), 1:120))
stopifnot(identical(Mindex2Lindex(arrayInd(840:1, 4:7), 4:7), 840:1))
}
\keyword{array}
\keyword{utilities}
|