Idiomatic way to specialise method over array shape/dims

It seems that array dimensions is not included in the type definition (which is really reasonable). I was wondering if there was a mechanism in Julia to force method specialisation based on array dimensions.

Typically, the code would be fed with matrices of dimension (n, M) where n can be any number but M is a fixed integer my code is constantly looping over.

I could create my own type (or something similar) but:

  • Julia is not supporting inheritance and implementing proxy methods myself would be ludicrous (not a fan of introducing boilerplate and checking the Array interface hasn’t changed in each release).
  • I really don’t want to hardcode things. It would be a bit of a shame to manually create Matrix1D, Matrix2D, Matrix3D, etc. when the JIT can do it itself, especially if it involves manually creating methods with the only difference being the upper range in a single for loop.

The motivation for this is performance: my code involves a lot of looping over 1:M and knowing M from the start allows LLVM to perform more aggressive optimisations.

StaticArrays include the size in their type, so maybe use those? Not that you should not use them for arrays with more than ~ 100 elements. If this does not cut it for you, you could create a wrapper which contains M as type parameter and which is <:AbstractArray.

My usage is typically involving huge heap allocated arrays, so StaticArray looks like a bad idea in this case. That being said, is there a way to use a literal integer as a type parameter?

The doc seems to imply it there:

https://docs.julialang.org/en/v1/manual/types/#Parametric-Composite-Types-1

but without examples.

You might like https://github.com/mateuszbaran/HybridArrays.jl, which treats some dimensions like StaticArrays, while leaving others like ordinary Arrays.

1 Like

Quite like that. Thanks for the pointer.

Yes, type parameters can be any isbits value (plus also symbols). Your wrapper would look something like:

struct MyArr{M, T, N} <: AbstractArray{T,N}
  ar::Array{T,N}
end
MyArr(ar::Array{T,N}) where {T,N} = MyArr{size(ar,1), T, N}(ar)

Note, you will need to define the necessary interface functions for AbstractArrays, see the docs.

But the mentioned HybridArrays sound like well suited.

Wouldn’t it be better for performance to have the columns have a fixed size, instead of the rows? Then the innermost loop would be super fast. A version of this is quite common: to represent a matrix as a vector of StaticArrays.SVector.

1 Like

I’m very new to julia. About row vs. columns, yes: I’m still thinking/defaulting to C-like convention but that was definitely on my checklist.

The vector of static vector sounds like a very good idea! Thanks!

StaticArrays.Size can be used as a trait for dispatch, see also the SizedArray decorator.

https://juliaarrays.github.io/StaticArrays.jl/latest/pages/api/#The-Size-trait-1