View on GitHub

Flexiblearrays.jl

Multi-dimensional arrays with arbitrary upper and lower bounds that can be fixed or flexible

Download this project as a .zip file Download this project as a tar.gz file

FlexibleArrays

Build Status Build status codecov.io

Flexible multi-dimensional arrays, with arbitrary lower and upper bounds that can be fixed at compile time to improve efficiency

Background

Sometimes you really want arrays where the lower index bound is different from 1. This is not a question of performance, but of convenience -- for example, if you have quantum numbers ranging from 0 to k, then adding 1 every time you index an array looks tedious. This really should be part of the type declaration.

And sometimes, you know the size of a particular array dimension ahead of time. This is now a question of efficiency -- indexing into a multi-dimensional array is significantly more efficient if the sizes of the dimensions are known ahead of time.

This is just what this package FlexibleArrays provides: A way to define multi-dimensional array types where both lower and upper index bounds can be chosen freely, and which generates more efficient code if these bounds are known ahead of time.

Here is an example:

using FlexibleArrays

# A (10x10) fixed-size array
typealias Arr2d_10x10 FlexArray(1:10, 1:10)
a2 = Arr2d_10x10{Float64}(:,:)

# A 3d array with lower index bounds 0
typealias Arr3d_lb0 FlexArray(0, 0, 0)
a3 = Arr3d_lb0{Float64}(9, 9, 9)

# A generic array, all bounds determined at creation time
typealias Arr4d_generic FlexArray(:, :, :, :)
a4 = Arr4d_generic{Float64}(1:10, 0:10, -1:10, 15:15)

# These can be mixed: A (2x10) array
FlexArray(0:1, 1){Float64}(:, 10)

# Arrays can also be empty:
FlexArray(4:13, 10:9)
FlexArray(:){Int}(5:0)

# The trivial 0d array type, always holding one scalar value:
FlexArray(){Int}

Flexible arrays are accessed like regular arrays, using the [] notation or the getindex and setindex! functions.

You will have noticed the slightly unusual notation for flexible arrays. Implementation-wise, the set of all bounds that are kept fixed determine the (parameterized) type of the array; different choices for fixed array bounds correspond to different types. FlexArray is a function that returns the respective type, creating this type if necessary.

Currently, flexible arrays do not yet support resizing, reshaping, or subarrays; adding this would be straightforward.

I designed FlexibleArrays for the two reasons above -- I needed to model quantum numbers that have a range of 0:k, and I noticed that the C++ version of the respecived code became significantly faster when setting array sizes at compile time. In Julia, I confirmed that the generated machine code is also much simpler in this case. Of course, this provides a benefit only if array accessing is actually a bottleneck in the code.

Manual

Each array dimension has a lower and an upper bound. Both can either be fixed or flexible. Fixed bounds are the same for all objects of this type, flexible bounds have to be chosen when the array is allocated. Julia's Array types correspond to FlexArray types where all lower bounds are fixed to 1, and all upper bounds are flexible.

Internally, the fixed bounds are represented as a tuple of either nothing or integers: DimSpec = NTuple{2, Union{Void, Int}}.

For each dimension, the fixed bounds are set via:

When an array is allocated, the flexible bounds are set conversely:

Each flexible array type is subtype of AbstractFlexArray{T,N}, where T is the element type and N is the rank. This abstract is a subtype of DenseArray{T,N}.

Available array functions: