# Reference

The following provides detailed documentation about types and methods provided by the `ArrayTools`

package. This information is also available from the REPL by typing `?`

followed by the name of a method or a type.

## Broadcasting

`ArrayTools.bcastlazy`

— Function`bcastlazy(A, [T=eltype(A),] dims...)`

yields a *flat* array of type `T`

and dimensions `dims`

whose values are given by `A`

according to type conversion and broadcasting rules (see `broadcast`

method). Compared to `bcastcopy`

, making a copy of `A`

is avoided if it is already an array with the correct type of elements and dimensions or if it can be reshaped (by the `reshape`

method) to the correct type and dimensions. This means that the result may share the same contents as `A`

. Argument `A`

can be a scalar or an array with 1-based indices. The result has 1-based indices and contiguous elements which is suitable for fast linear indexing.

`ArrayTools.bcastcopy`

— Function`bcastcopy(A, [T=eltype(A),] dims...)`

yields a new array of element type `T`

and dimensions `dims`

whose values are given by `A`

according to type conversion and broadcasting rules (like for the `broadcast`

method). Compared to `bcastlazy`

, it is guaranteed that the returned array does not share its contents with `A`

.

Argument `A`

can be a scalar value or an array.

`ArrayTools.bcastsize`

— Function`bcastsize(size(A), size(B), ...) -> siz`

yields the size `siz`

of the array that would result from applying broadcasting rules (see `broadcast`

method) to arguments `A`

, `B`

, etc. The result is a tuple of integers (of type `Int`

). Call `check_size`

if you want to also make sure that the result is a list of valid dimensions.

The method can also be applied to a single dimension:

`bcastsize(a, b) -> c`

to yield the dimension `c`

gievn by broadcasting dimensions `a`

and `b`

throwing an exception if dimensions are not compatible according to broadcasting rules. This is the same as `Base.Broadcasting._bcs1`

but it takes care of converting to `Int`

.

See also `standard_size`

, `check_size`

, `bcastcopy`

, `bcastlazy`

.

## Indexing

`ArrayTools.ArraySize`

— Type`ArraySize`

is the union of types eligible to define array size. Calling `[to_size](@ref)(dims)`

on any argument `dims`

such that `isa(dims,ArraySize)`

is true yields an array size in canonical form, that is an instance of `Dims{N}`

which is an alias for an `N`

-tuple of `Int`

.

`ArrayTools.RubberIndex`

— Type`RubberIndex`

is the singleron type that represents any number of indices. The constant `..`

is defined as `RubberIndex()`

and can be used in array indexation to left and/or right justify the other indices. For instance, assuming `A`

is a `3×4×5×6`

array, then all the following equalities hold:

```
A[..] == A[:,:,:,:]
A[..,3] == A[:,:,:,3]
A[2,..] == A[2,:,:,:]
A[..,2:4,5] == A[:,:,2:4,5]
A[2:3,..,1,2:4] == A[2:3,:,1,2:4]
```

As you can see, the advantage of the rubber index `..`

is that it automatically expands as the number of colons needed to have the correct number of indices. The expressions are also more readable.

The rubber index may also be used for setting values. For instance:

```
A[..] .= 1 # to fill A with ones
A[..,3] = A[..,2] # to copy A[:,:,:,2] in A[:,:,:,3]
A[..,3] .= A[..,2] # idem but faster
A[2,..] = A[3,..] # to copy A[3,:,:,:] in A[2,:,:,:]
A[..,2:4,5] .= 7 # to set all elements in A[:,:,2:4,5] to 7
```

Leading/trailing indices may be specified as Cartesian indices (of type `CartesianIndex`

).

There are two known limitations:

- The
`end`

reserved word can only be used in intervals specified*before*the rubber index but not*after*. This limitation is due to the Julia parser cannot be avoided. - At most 9 indices can be specified before the rubber index. This can be extended by editing the source code.

See also: `colons`

.

`ArrayTools.colons`

— Function`colons(n)`

yields a `n`

-tuple of colons `:`

(a.k.a. `Colon()`

).

When `n`

is known at compile time, it is faster to call:

`colons(Val(n))`

This method is suitable to extract sub-arrays of build views when some kind of rubber index is needed. For instance:

```
slice(A::AbstractArray{T,N}, i::Integer) where {T,N} =
A[colons(Val(N-1))..., i]
```

defines a function that returns the `i`

-th slice of `A`

assuming index `i`

refers the last index of `A`

. Using the rubber-index `..`

, a shorter definition is:

`slice(A::AbstractArray, i) = A[.., i]`

which is also able to deal with multiple trailing indices if `i`

is a `CartesianIndex`

.

See also: `..`

, `RubberIndex`

.

`ArrayTools.IndexingType`

— Type`IndexingType(A)`

yields one of the singletons `FastIndexing()`

or `AnyIndexing()`

to indicate whether or not array `A`

has standard 1-based indices and can be efficiently indexed by one integer (even if `A`

is multidimensional) and column-major ordering is used to access the elements of `A`

.

This method can be extended for custom array types to quickly return the correct answer.

See also `is_fast_array`

, `to_fast_array`

.

`ArrayTools.FastIndexing`

— Type`FastIndexing()`

yields the indexing type of *fast* arrays. See `IndexingType`

.

`ArrayTools.AnyIndexing`

— Type`AnyIndexing()`

yields the indexing type of *non-fast* arrays. See `IndexingType`

.

`ArrayTools.is_fast_array`

— Function`is_fast_array(A)`

yields whether array `A`

has standard 1-based indices and is efficiently indexed by linear indices.

Several arguments can be checked in a single call:

`is_fast_array(A, B, C, ...)`

is the same as:

`is_fast_array(A) && is_fast_array(B) && is_fast_array(C) && ...`

See also `IndexingType`

, `to_fast_array`

, `is_flat_array`

.

`ArrayTools.to_fast_array`

— Function`to_fast_array([T=eltype(A),] A)`

lazily yields a *fast array* equivalent to `A`

with element type `T`

. A *fast array* has standard 1-based indices and is efficiently indexed by linear indices. If `A`

is already a *fast array* with element type `T`

, `A`

is returned; otherwise, `A`

is converted into an `Array`

which is returned.

See also `is_fast_array`

, `IndexingType`

, `to_flat_array`

.

`ArrayTools.to_size`

— Function`to_size(dims)`

converts `dims`

to an instance of `Dims{N}`

which is an alias for an `N`

-tuple of `Int`

. Argument `dims`

can be a scalar integer or a tuple of integers. Argument `dims`

is returned if already of the correct type. This method may also be called as:

`to_size(dim1, dim2, ...)`

to let `to_size`

deal with a variable number of arguments.

The union `ArraySize`

matches the types of acceptable argument(s) for `to_size(arg)`

: scalar integers and tuples of integers.

This method is intended for fast conversion, call `check_size(dims)`

to verify that all dimensions in `dims`

are nonnegative.

`ArrayTools.check_size`

— Function` check_size(dims) -> len`

checks the validity of the array size `dims`

and yields the corresponding number of elements (throwing an `ArgumentError`

exception if this is not the case). To be a valid array size, the values of `dims`

must all be nonnegative.

See also `to_size`

.

`ArrayTools.same_size`

— Function`same_size(A, B...) -> size(A)`

checks whether arrays `A`

, `B`

, etc., all have the same size which is returned. A `DimensionMismatch`

exception is thrown if array sizes are not all identical.

See also `same_standard_size`

, `same_axes`

.

`ArrayTools.same_standard_size`

— Function`same_standard_size(A, B...) -> size(A)`

checks whether arrays `A`

, `B`

, etc., all have standard indexing and the same size which is returned. If array sizes are not all identical, a `DimensionMismatch`

exception is thrown. If arrays have non-standard indexing (that is indices not starting at index one), an `ArgumentError`

exception is thrown.

See also `standard_size`

, `has_standard_indexing`

.

`ArrayTools.standard_size`

— Function`standard_size(A) -> size(A)`

yields the list of dimensions of `A`

, that is `size(A)`

, throwing an `ArgmentError`

exception if `A`

does not have standard 1-based indices.

See also `has_standard_indexing`

, `same_standard_size`

.

`ArrayTools.same_axes`

— Function`same_axes(A, B...) -> axes(A)`

checks whether arrays `A`

, `B`

, etc., have the same axes and returns them. A `DimensionMismatch`

exception is thrown if axes are not all identical.

See also `same_size`

, `all_indices`

.

`ArrayTools.@assert_same_axes`

— Macro`@assert_same_axes A B ...`

throws a `DimensionMismatch`

exception if arrays `A`

, `B`

, etc. do not have the same axes.

`ArrayTools.all_indices`

— Function`all_indices(A...)`

yields an iterable object for visiting each index of array(s) `A`

in an efficient manner. For array types that have opted into fast linear indexing (like `Array`

), this is simply the range `1:length(A)`

. For other array types, return a specialized Cartesian range to efficiently index into the array(s) with indices specified for every dimension.

If more than one `AbstractArray`

argument are supplied, `all_indices`

will create an iterable object that is fast for all arguments (a `UnitRange`

if all inputs have fast linear indexing, a `CartesianIndices`

otherwise). A `DimensionMismatch`

exception is thrown if the arrays have different axes so that it is always safe to use `@inbounds`

in front of a loop like:

for i in all_indices(A, B, C, D) A[i] = B[i]*C[i] + D[i] end

when `A`

, `B`

etc. are all (abstract) arrays.

This method is similar to `eachindex`

except that a `DimensionMismatch`

exception is thrown if arrays have different axes. For linearly indexed arrays, `eachindex`

only checks that they have the same linear index range (that is the same number of elements, not the same shape).

`ArrayTools.cartesian_indices`

— Function```
cartesian_indices(A)
cartesian_indices((n1, n2, ...))
cartesian_indices((i1:j1, i2:j2, ...))
cartesian_indices(CartesianIndex(i1, i2, ...), CartesianIndex(j1, j2, ...))
cartesian_indices(R)
```

all yield an instance of `CartesianIndices`

suitable for multi-dimensional indexing of respectively: all the indices of array `A`

, a multi-dimensional array of dimensions `(n1,n2,...)`

, a multi-dimensional region whose first and last indices are `(i1,i2,...)`

and `(j1,j2,...)`

or a Cartesian region defined by `R`

, an instance of `CartesianIndices`

.

`ArrayTools.common_indices`

— FunctionAssuming `A`

and `B`

are arrays with `N`

dimensions:

`common_indices(A, B) -> inds`

yields the set of all the indices that are valid for both `A`

and `B`

. The result is similar to `axes(A)`

or `axes(B)`

, that is an `N`

-tuple of integer valued unit ranges.

An offset `k`

with a sign may be specified:

`common_indices(A, B, ±, k)`

to obtain the set of all indices `i`

such that `A[i]`

and `B[i ± k]`

are valid and where here and above `±`

is either `+`

or `-`

. Offset `k`

can be a tuple of integers or a Cartesian index.

Arguments `A`

and `B`

may be both tuples of indices or index ranges or both scalar or index range which specify the size or the axes of the arrays to be indexed. This is used in the following example, where we want to do `A[i] = B[i]*C[i + k]`

given the offset `k`

and for all valid indices `i`

:

```
I = common_indices(same_axes(A, B), axes(C), +, k)
@inbounds @simd for i in CartesianIndices(I)
A[i] = B[i]*C[i + k]
end
```

Note that `same_axes(A,B)`

is called to get the axes of `A`

and `B`

while asserting that they are the same, as a result no bound checking is necessary and the loop can be optimized for vectorization.

`ArrayTools.has_standard_indexing`

— Function`has_standard_indexing(A)`

return `true`

if the indices of `A`

start with 1 along all axes. Can be called with multiple arguments:

`has_standard_indexing(A, B, ...)`

is equivalent to:

`has_standard_indexing(A) && has_standard_indexing(B) && ...`

Opposite of `Base.has_offset_axes`

which is not available in version of Julia older than 0.7.

## Storage

`ArrayTools.StorageType`

— Type`StorageType(A)`

yields the type of storage of the elements of argument `A`

. If `A`

is a *flat* array, that is an array with contiguous elements in column-major order and first element at index 1, the singleton `FlatStorage()`

is returned; otherwise, the singleton `AnyStorage()`

is returned.

This method can be extended for custom array types to quickly return the correct answer.

See also `is_flat_array`

, `to_flat_array`

.

`ArrayTools.AnyStorage`

— Type`AnyStorage()`

yields the storage type of a *non-flat* arrays. See `StorageType`

.

`ArrayTools.FlatStorage`

— Type`FlatStorage()`

yields the storage type of *flat* arrays. See `StorageType`

.

`ArrayTools.is_flat_array`

— Function`is_flat_array(A) -> boolean`

yields whether array `A`

can be indexed as a *flat* array, that is an array with contiguous elements in column-major order and first element at index 1. This also means that `A`

has 1-based indices along all its dimensions.

Several arguments can be checked in a single call:

`is_flat_array(A, B, C, ...)`

is the same as:

`is_flat_array(A) && is_flat_array(B) && is_flat_array(C) && ...`

See also `StorageType`

, `to_flat_array`

, `is_fast_array`

, `has_standard_indexing`

.

`ArrayTools.to_flat_array`

— Function`to_flat_array([T=eltype(A),] A)`

lazily yields a *flat* array based on `A`

, that is an array with contiguous elements in column-major order and first element at index 1. Optional argument `T`

is to specify the element type of the result. Argument `A`

is returned if it is already a flat array with the requested element type; otherwise, `convert`

method is called to produce the result (an `Array{T}`

in that case).

See also `is_flat_array`

, `to_fast_array`

.

## Pseudo-arrays

`ArrayTools.PseudoArrays.PseudoArray`

— TypeAbstract type `PseudoArray{T,N,S}`

is to be derived by types that want to provide an array-like interface. Parameter `T`

is the element type, parameter `N`

is the number of dimensions and parameter `S`

is the index style: `IndexCartesian`

or `IndexLinear`

.

The indexing style must be part of the signature because it must be possible to call `IndexStyle()`

on the data type not the instance. Another possibility would have been to have the type of the embedded array be part of the signature but this is more restrictive.

Alias `LinearArray{T,N}`

is an abstract type that can be derived by types that want to provide an array-like interface with array values stored in an array whose index style is linear.

Usage can be as simple as:

```
struct CustomArray{T,N,...} <: LinearArray{T,N}
arr::Array{T,N} # can be any array type with linear index style
... # anything else
end
@inline Base.parent(A::CustomArray) = A.arr
```

As a result, instances of `CustomArray{T,N}`

will be seen as instances of `AbstractArray{T,N}`

and behave as if they implement linear indexing. Apart from the needs to extend the `Base.parent`

method, the interface to `LinearArray{T,N}`

should provide any necessary methods for indexation, getting the dimensions, the element type, *etc.* for the derived custom type. You may however override these definitions by more optimized or more suitable methods specialized for your custom array-like type.

Similarly, alias `CartesianArray{T,N}`

is an abstract type that can be derived by types that want to provide an array-like interface with array values stored in an array whose index style is Cartesian. For such array-like object, index checking requires an efficient implementation of the `Base.axes()`

method which you may have to specialize. The default implementation is:

`@inline Base.axes(A::PseudoArray) = axes(parent(A))`

## Utilities

`ArrayTools.all_match`

— Function`all_match(val, f, args...) -> bool`

yields as soon as possible (short-circuit) whether `f(arg) == val`

for each argument `arg`

in `args...`

. The returned value is `true`

if there are no arguments after `f`

.

`ArrayTools.allof`

— Function`allof(f, args...) -> Bool`

checks whether predicate function `f`

returns `true`

for all arguments in `args...`

, returning `false`

as soon as possible (short-circuiting).

`allof(args...) -> Bool`

checks whether all arguments `args...`

are `true`

, returning `false`

as soon as possible (short-circuiting). Arguments can be booleans or arrays of booleans. The latter are considered as `true`

if all their elements are `true`

and are considered as `false`

otherwise (if any of their elements are `false`

). Arguments can also be iterables to check whether all their values are `true`

. An empty iterable is considered as `true`

.

This method can be much faster than `all(f, args)`

or `all(args)`

because its result may be determined at compile time. However, `missing`

values are not considered as special.

`ArrayTools.anyof`

— Function`anyof(f, args...) -> bool`

checks whether predicate function `f`

returns `true`

for any argument `args...`

, returning `true`

as soon as possible (short-circuiting).

`anyof(args...) -> bool`

checks whether all arguments `args...`

are `true`

, returning `false`

as soon as possible (short-circuiting). Arguments can be booleans or arrays of booleans. The latter are considered as `true`

if any of their elements are `true`

and are considered as `false`

otherwise (if all their elements are `false`

). Arguments can also be iterables to check whether any of their values are `true`

. An empty iterable is considered as `false`

.

This method can be much faster than `any(f, args)`

or `any(args)`

because its result may be determined at compile time. However, `missing`

values are not considered as special.

`ArrayTools.axis_limits`

— Function`axis_limits(I) = (i0,i1)`

yields the limits `i0`

and `i1`

of index range `I`

as a 2-tuple of `Int`

's and such that `i0:i1`

represents the same indices as `I`

(although not in the same order if `step(I) < 0`

). If `step(I)`

is not equal to ±1, an `ArgumentError`

exception is thrown.

`ArrayTools.noneof`

— Function`TypeUtils.promote_eltype`

— Function`promote_eltype(args...)`

yields the promoted element type of its arguments. Arguments `args...`

may be anything implementing the `eltype`

method.

`ArrayTools.reversemap`

— Function`reversemap(f, args)`

applies the function `f`

to arguments `args`

in reverse order and return the result. For now, the arguments `args`

must be in the form of a simple tuple and the result is the tuple: `(f(args[end]),f(args[end-1]),...,f(args[1])`

.

Also see: `map`

, `ntuple`

.

`ArrayTools.split_interval`

— Function`split_interval(I, J, +/-, k) -> Ia, Ib, Ic`

given unit ranges `I`

and `J`

and offset `±k`

, yields 3 unit ranges, such that `Ia ∪ Ib ∪ Ic = I`

and:

`∀ i ∈ Ia`

,`i ± k < first(J)`

;`∀ i ∈ Ib`

,`i ± k ∈ J`

;`∀ i ∈ Ic`

,`i ± k > last(J)`

.

Unit ranges may be replaced by their first and last values:

`split_interval(first(I), last(I), first(J), last(J), +/-, k)`

yields the same result as above.

`ArrayTools.strictmap!`

— Function```
strictmap!(f, dst, src) -> dst
strictmap!(dst, f, src) -> dst
```

does `dst[i] = f(src[i])`

for all indices `i`

and returns `dst`

. Arguments `dst`

and `src`

must have the same axes.

Except for the strict condition on the axes, this method is similar to `map!(f,dst,src)`

.