JuliaArrays / JuliaArrays/OffsetArrays.jl

Preserving static size information in `no_offset_view`

Open
#301 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Julia
Stars
212
Forks
45
PR merge metrics
No merged PRs in 30d

Description

Currently, no_offst_view has special methods defined for Bsae.OneTo, but nothing for SOneTo axes that a StaticArray has. As a consequence, OffsetArrays doesn't realize that a SOneTo is 1-based. This leads to

julia> OffsetArrays.no_offset_view(SOneTo(4)) |> typeof
UnitRange{Int64}

that is, it loses the static size information. As a consequence,

julia> A = Float64.(reshape(1:16, 4, 4));

julia> B = @view A[SOneTo(4)];

julia> @code_warntype size(B) # size is constant-propagated
MethodInstance for size(::SubArray{Float64, 1, Vector{Float64}, Tuple{SOneTo{4}}, true})
  from size(V::SubArray) in Base at subarray.jl:63
Arguments
  #self#::Core.Const(size)
  V::SubArray{Float64, 1, Vector{Float64}, Tuple{SOneTo{4}}, true}
Body::Tuple{Int64}
1 ─      nothing
│   %2 = Base.axes(V)::Core.Const((SOneTo(4),))
│   %3 = Base.map(Base.length, %2)::Core.Const((4,))
└──      return %3


julia> @code_warntype size(OffsetArrays.no_offset_view(B)) # static size information is lost
MethodInstance for size(::SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true})
  from size(V::SubArray) in Base at subarray.jl:63
Arguments
  #self#::Core.Const(size)
  V::SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}
Body::Tuple{Int64}
1 ─      nothing
│   %2 = Base.axes(V)::Tuple{Base.OneTo{Int64}}
│   %3 = Base.map(Base.length, %2)::Tuple{Int64}
└──      return %3

julia> B = @view A[SOneTo(4)];

julia> C = OffsetArrays.no_offset_view(B);

julia> @btime sum($B);
  3.356 ns (0 allocations: 0 bytes)

julia> @btime sum($C);
  5.870 ns (0 allocations: 0 bytes)

One way to resolve this is to simply define _no_offset_view for Union{Base.OneTo, StaticArrays.SOneTo} over here, but this will require us to explicitly depend on StaticArrays. The second way might be something like https://github.com/JuliaLang/julia/issues/41946, where Base defines OneTo <: AbstractOneTo, and we define methods for AbstractOneTo in this package. However, it doesn't appear that there's a clear direction to this in Base at the moment. I wonder if there's another way to preserve the size, without one package explicitly depending on the other.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the _no_offset_view methods and compare their handling of Base.OneTo with StaticArrays.SOneTo; review the design discussed in Julia issue 41946 before choosing an approach. Reproduce the SOneTo examples with @code_warntype and @btime; done means no_offset_view preserves static size information without introducing an inappropriate dependency.

Written by the indexing model from the issue text.

Assessment

Tech stack
julia
Domain
performance
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.