Is there an abstract type that includes only absract arrays which have “standard” indexing, by which I mean the first valid index along each axis is 1, and the last valid index along the i
-th axis of A
is size(A, i)
?
I often write functions which have abstract arrays as arguments, and I don’t want to accommodate all possible array types, I just want to support, for example, Array
and SparseMatrixCSC
, and the like. I know you can in many cases be safe for all types by using tools like eachindex
and CartesianIndices
, but in many cases it’s not clear to me how to use those to solve my problems, and it is not worth the hassle to me.
So ideally I would like an abstract type that includes types with the “standard” indexing. That way, the types would be checked for the indexing at compile time. Second best would be an efficient function for checking that an array uses “standard” indexing. But this would have the disadvantage that the check would only happen at runtime.
You’ll have to settle for that second best here: Base.require_one_based_indexing
.
2 Likes
Thanks, I will use this solution.
But just to be 100% clear, Base.require_one_based_indexing
only checks that the indices along each axis start at one. It does not check that the indices for the i
-th axis of A
end at size(A,i)
. Granted, I cannot imagine any reasonable use case for having an axis that starts at 1 and ends at something other than size(A,i)
.
Source code from base:
"""
has_offset_axes(A)
has_offset_axes(A, B, ...)
Return `true` if the indices of `A` start with something other than 1 along any axis.
If multiple arguments are passed, equivalent to `has_offset_axes(A) || has_offset_axes(B) || ...`.
See also [`require_one_based_indexing`](@ref).
"""
has_offset_axes() = false
has_offset_axes(A) = _any_tuple(x->Int(first(x))::Int != 1, false, axes(A)...)
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
has_offset_axes(::Colon) = false
has_offset_axes(::Array) = false
# note: this could call `any` directly if the compiler can infer it. We don't use _any_tuple
# here because it stops full elision in some cases (#49332) and we don't need handling of
# `missing` (has_offset_axes(A) always returns a Bool)
has_offset_axes(A, As...) = has_offset_axes(A) || has_offset_axes(As...)
"""
require_one_based_indexing(A::AbstractArray)
require_one_based_indexing(A,B...)
Throw an `ArgumentError` if the indices of any argument start with something other than `1` along any axis.
See also [`has_offset_axes`](@ref).
!!! compat "Julia 1.2"
This function requires at least Julia 1.2.
"""
require_one_based_indexing(A...) = !has_offset_axes(A...) || throw(ArgumentError("offset arrays are not supported but got an array with index other than 1"))
All AbstractArray
s must have contiguous axes, whether offset or not. That is something the type itself requires. So you’re in the clear on the endpoints!
2 Likes