specialize axes(S, dim) to return SOneTo#916
specialize axes(S, dim) to return SOneTo#916jishnub wants to merge 1 commit intoJuliaArrays:masterfrom
Conversation
mateuszbaran
left a comment
There was a problem hiding this comment.
Thanks, this looks like a good idea.
|
Gentle bump |
|
I'd prefer to have a second opinion here before merging this -- if the axis number isn't constant-propagated, this might be considered a less desirable behavior than the current one. |
|
For reference, the behavior of julia> using StrideArrays, Static, ArrayInterface
julia> A = @StrideArray rand(10, 10);
julia> B = @StrideArray rand(8, 10);
julia> ArrayInterface.axes(A,1)
Base.OneTo(static(10))
julia> ArrayInterface.axes(B,1)
Base.OneTo(8)
julia> ArrayInterface.axes(B,StaticInt(1))
Base.OneTo(static(8))
julia> ArrayInterface.axes(B,StaticInt(2))
Base.OneTo(static(10))For So one possibility is to return an |
|
Good point, restricting this to arrays where all axes have the same length removes the issue with type stability. |
|
The top message's case is for julia> ArrayInterface.axes(A,3) |> dump
ArrayInterface.OptionallyStaticUnitRange{StaticInt{1}, StaticInt{1}}
start: StaticInt{1} static(1)
stop: StaticInt{1} static(1)
julia> ArrayInterface.axes(A,2) |> dump
Base.OneTo{StaticInt{10}}
stop: StaticInt{10} static(10)I have a vague memory that this PR grew out of thinking about |
|
Yes indeed, this came out of Using the nightly build, julia> @code_warntype axes(a, 1)
MethodInstance for axes(::SMatrix{1, 2, Int64, 2}, ::Int64)
from axes(A::AbstractArray{T, N}, d) where {T, N} in Base at abstractarray.jl:72
Static Parameters
T = Int64
N = 2
Arguments
#self#::Core.Const(axes)
A::SMatrix{1, 2, Int64, 2}
d::Int64
Body::Union{SOneTo{1}, SOneTo{2}, Base.OneTo{Int64}}
1 ─ nothing
│ %2 = Core.typeassert(d, Base.Integer)::Int64
│ %3 = (%2 <= $(Expr(:static_parameter, 2)))::Bool
└── goto #3 if not %3
2 ─ %5 = Base.axes(A)::Core.Const((SOneTo(1), SOneTo(2)))
│ %6 = Base.getindex(%5, d)::Union{SOneTo{1}, SOneTo{2}}
└── return %6
3 ─ %8 = Base.OneTo(1)::Core.Const(Base.OneTo(1))
└── return %8
This PR julia> @code_warntype axes(a, 1)
MethodInstance for axes(::SMatrix{1, 2, Int64, 2}, ::Int64)
from axes(s::StaticArray, d) in StaticArrays at /home/jishnu/Dropbox/JuliaPackages/StaticArrays.jl/src/abstractarray.jl:15
Arguments
#self#::Core.Const(axes)
s::SMatrix{1, 2, Int64, 2}
d::Int64
Body::Union{SOneTo{1}, SOneTo{2}}
1 ─ %1 = StaticArrays.ndims(s)::Core.Const(2)
│ %2 = (d <= %1)::Bool
└── goto #3 if not %2
2 ─ %4 = StaticArrays.Size(s)::Core.Const(Size(1, 2))
│ %5 = StaticArrays._axes(%4)::Core.Const((SOneTo(1), SOneTo(2)))
│ %6 = Base.getindex(%5, d)::Union{SOneTo{1}, SOneTo{2}}
└── return %6
3 ─ %8 = Core.apply_type(StaticArrays.SOneTo, 1)::Core.Const(SOneTo{1})
│ %9 = (%8)()::Core.Const(SOneTo(1))
└── return %9The return type inferred is narrower in this case (as certain axes have the same type as the trivial ones). In general on master julia> @code_warntype axes(a, 1)
MethodInstance for axes(::SMatrix{3, 2, Int64, 6}, ::Int64)
from axes(A::AbstractArray{T, N}, d) where {T, N} in Base at abstractarray.jl:72
Static Parameters
T = Int64
N = 2
Arguments
#self#::Core.Const(axes)
A::SMatrix{3, 2, Int64, 6}
d::Int64
Body::Union{SOneTo{3}, SOneTo{2}, Base.OneTo{Int64}}
1 ─ nothing
│ %2 = Core.typeassert(d, Base.Integer)::Int64
│ %3 = (%2 <= $(Expr(:static_parameter, 2)))::Bool
└── goto #3 if not %3
2 ─ %5 = Base.axes(A)::Core.Const((SOneTo(3), SOneTo(2)))
│ %6 = Base.getindex(%5, d)::Union{SOneTo{3}, SOneTo{2}}
└── return %6
3 ─ %8 = Base.OneTo(1)::Core.Const(Base.OneTo(1))
└── return %8This PR julia> @code_warntype axes(a, 1)
MethodInstance for axes(::SMatrix{3, 2, Int64, 6}, ::Int64)
from axes(s::StaticArray, d) in StaticArrays at /home/jishnu/Dropbox/JuliaPackages/StaticArrays.jl/src/abstractarray.jl:15
Arguments
#self#::Core.Const(axes)
s::SMatrix{3, 2, Int64, 6}
d::Int64
Body::Union{SOneTo{3}, SOneTo{2}, SOneTo{1}}
1 ─ %1 = StaticArrays.ndims(s)::Core.Const(2)
│ %2 = (d <= %1)::Bool
└── goto #3 if not %2
2 ─ %4 = StaticArrays.Size(s)::Core.Const(Size(3, 2))
│ %5 = StaticArrays._axes(%4)::Core.Const((SOneTo(3), SOneTo(2)))
│ %6 = Base.getindex(%5, d)::Union{SOneTo{3}, SOneTo{2}}
└── return %6
3 ─ %8 = Core.apply_type(StaticArrays.SOneTo, 1)::Core.Const(SOneTo{1})
│ %9 = (%8)()::Core.Const(SOneTo(1))
└── return %9The type-instability is similar in both master and in this PR. |
Close #52373, or at least the part that may be addressed here. After
this, the first axis for an `Adjoint(parent::AbstractVector)` will be
the second axis of the `parent`. This will change the type of the axis
where the parent array type specializes `axes(A, d)`. In the short term,
this would improve type-stability in cases such as
```julia
julia> A = OffsetArray([1,2], 2);
julia> @code_typed axes(A')[1]
CodeInfo(
1 ─ %1 = $(Expr(:boundscheck))::Bool
│ %2 = Base.getfield(t, i, %1)::OffsetArrays.IdOffsetRange{Int64, Base.OneTo{Int64}}
└── return %2
) => OffsetArrays.IdOffsetRange{Int64, Base.OneTo{Int64}}
```
where the result is now concretely inferred instead of being a small
`Union`.
In principle, with
JuliaArrays/StaticArrays.jl#916, this would make
the axes of the adjoint of a `StaticVector` statically sized.
Close #52373, or at least the part that may be addressed here. After
this, the first axis for an `Adjoint(parent::AbstractVector)` will be
the second axis of the `parent`. This will change the type of the axis
where the parent array type specializes `axes(A, d)`. In the short term,
this would improve type-stability in cases such as
```julia
julia> A = OffsetArray([1,2], 2);
julia> @code_typed axes(A')[1]
CodeInfo(
1 ─ %1 = $(Expr(:boundscheck))::Bool
│ %2 = Base.getfield(t, i, %1)::OffsetArrays.IdOffsetRange{Int64, Base.OneTo{Int64}}
└── return %2
) => OffsetArrays.IdOffsetRange{Int64, Base.OneTo{Int64}}
```
where the result is now concretely inferred instead of being a small
`Union`.
In principle, with
JuliaArrays/StaticArrays.jl#916, this would make
the axes of the adjoint of a `StaticVector` statically sized.
Currently
After this PR
As a consequence,
returns a
StaticArray