From b06e7b95fe33dfe78b0d787aa7977e66e0b3b274 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Sat, 6 Jan 2018 16:41:50 +0100 Subject: [PATCH] Add CartesianIndices and LinearIndices Needed in particular to get linear indices once find() returns cartesian indices. --- README.md | 5 +++ src/Compat.jl | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 14 +++++++++ 3 files changed, 98 insertions(+) diff --git a/README.md b/README.md index 7cbf3a319..91d790818 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,10 @@ Currently, the `@compat` macro supports the following syntaxes: * `replace` accepts a pair of pattern and replacement, with the number of replacements as a keyword argument ([#25165]). +* `CartesianIndices` and `LinearIndices` types represent cartesian and linear indices of + an array (respectively), and indexing such objects allows translating from one kind of index + to the other ([#25113]). + ## Renaming @@ -431,3 +435,4 @@ includes this fix. Find the minimum version from there. [#25162]: https://github.com/JuliaLang/julia/issues/25162 [#25165]: https://github.com/JuliaLang/julia/issues/25165 [#25168]: https://github.com/JuliaLang/julia/issues/25168 +[#25113]: https://github.com/JuliaLang/julia/issues/25113 \ No newline at end of file diff --git a/src/Compat.jl b/src/Compat.jl index bc1d94acd..458bb7da5 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -1070,6 +1070,85 @@ end replace(s, first(pat_rep), last(pat_rep), count) end +@static if VERSION < v"0.7.0-DEV.3025" + import Base: convert, ndims, getindex + export CartesianIndices, LinearIndices + + struct CartesianIndices{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{CartesianIndex{N},N} + indices::R + end + + CartesianIndices(::Tuple{}) = CartesianIndices{0,typeof(())}(()) + CartesianIndices(inds::NTuple{N,AbstractUnitRange{Int}}) where {N} = + CartesianIndices{N,typeof(inds)}(inds) + CartesianIndices(inds::Vararg{AbstractUnitRange{Int},N}) where {N} = + CartesianIndices(inds) + CartesianIndices(inds::NTuple{N,AbstractUnitRange{<:Integer}}) where {N} = + CartesianIndices(map(r->convert(AbstractUnitRange{Int}, r), inds)) + CartesianIndices(inds::Vararg{AbstractUnitRange{<:Integer},N}) where {N} = + CartesianIndices(inds) + + CartesianIndices(index::CartesianIndex) = CartesianIndices(index.I) + CartesianIndices(sz::NTuple{N,<:Integer}) where {N} = CartesianIndices(map(Base.OneTo, sz)) + CartesianIndices(inds::NTuple{N,Union{<:Integer,AbstractUnitRange{<:Integer}}}) where {N} = + CartesianIndices(map(i->first(i):last(i), inds)) + + CartesianIndices(A::AbstractArray) = CartesianIndices(axes(A)) + + convert(::Type{Tuple{}}, R::CartesianIndices{0}) = () + convert(::Type{NTuple{N,AbstractUnitRange{Int}}}, R::CartesianIndices{N}) where {N} = + R.indices + + convert(::Type{NTuple{N,AbstractUnitRange}}, R::CartesianIndices{N}) where {N} = + convert(NTuple{N,AbstractUnitRange{Int}}, R) + convert(::Type{NTuple{N,UnitRange{Int}}}, R::CartesianIndices{N}) where {N} = + UnitRange{Int}.(convert(NTuple{N,AbstractUnitRange}, R)) + convert(::Type{NTuple{N,UnitRange}}, R::CartesianIndices{N}) where {N} = + UnitRange.(convert(NTuple{N,AbstractUnitRange}, R)) + convert(::Type{Tuple{Vararg{AbstractUnitRange{Int}}}}, R::CartesianIndices{N}) where {N} = + convert(NTuple{N,AbstractUnitRange{Int}}, R) + convert(::Type{Tuple{Vararg{AbstractUnitRange}}}, R::CartesianIndices) = + convert(Tuple{Vararg{AbstractUnitRange{Int}}}, R) + convert(::Type{Tuple{Vararg{UnitRange{Int}}}}, R::CartesianIndices{N}) where {N} = + convert(NTuple{N,UnitRange{Int}}, R) + convert(::Type{Tuple{Vararg{UnitRange}}}, R::CartesianIndices) = + convert(Tuple{Vararg{UnitRange{Int}}}, R) + + # AbstractArray implementation + Base.IndexStyle(::Type{CartesianIndices{N,R}}) where {N,R} = IndexCartesian() + @inline Base.getindex(iter::CartesianIndices{N,R}, I::Vararg{Int, N}) where {N,R} = CartesianIndex(first.(iter.indices) .- 1 .+ I) + + ndims(R::CartesianIndices) = ndims(typeof(R)) + ndims(::Type{CartesianIndices{N}}) where {N} = N + ndims(::Type{CartesianIndices{N,TT}}) where {N,TT} = N + + struct LinearIndices{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{Int,N} + indices::R + end + + LinearIndices(inds::CartesianIndices{N,R}) where {N,R} = LinearIndices{N,R}(inds.indices) + LinearIndices(::Tuple{}) = LinearIndices(CartesianIndices(())) + LinearIndices(inds::NTuple{N,AbstractUnitRange{Int}}) where {N} = LinearIndices(CartesianIndices(inds)) + LinearIndices(inds::Vararg{AbstractUnitRange{Int},N}) where {N} = LinearIndices(CartesianIndices(inds)) + LinearIndices(inds::NTuple{N,AbstractUnitRange{<:Integer}}) where {N} = LinearIndices(CartesianIndices(inds)) + LinearIndices(inds::Vararg{AbstractUnitRange{<:Integer},N}) where {N} = LinearIndices(CartesianIndices(inds)) + LinearIndices(index::CartesianIndex) = LinearIndices(CartesianIndices(index)) + LinearIndices(sz::NTuple{N,<:Integer}) where {N} = LinearIndices(CartesianIndices(sz)) + LinearIndices(inds::NTuple{N,Union{<:Integer,AbstractUnitRange{<:Integer}}}) where {N} = LinearIndices(CartesianIndices(inds)) + LinearIndices(A::AbstractArray) = LinearIndices(CartesianIndices(A)) + + # AbstractArray implementation + Base.IndexStyle(::Type{LinearIndices{N,R}}) where {N,R} = IndexCartesian() + Compat.axes(iter::LinearIndices{N,R}) where {N,R} = iter.indices + @inline function Base.getindex(iter::LinearIndices{N,R}, I::Vararg{Int, N}) where {N,R} + dims = length.(iter.indices) + #without the inbounds, this is slower than Base._sub2ind(iter.indices, I...) + @inbounds result = reshape(1:prod(dims), dims)[(I .- first.(iter.indices) .+ 1)...] + return result + end +end + + include("deprecated.jl") end # module Compat diff --git a/test/runtests.jl b/test/runtests.jl index b03fbde9a..5f89e8d7a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1076,6 +1076,20 @@ end @test replace("abcb", "b"=>"c") == "accc" @test replace("abcb", "b"=>"c", count=1) == "accb" +# 0.7.0-DEV.3025 +let c = CartesianIndices(1:3, 1:2), l = LinearIndices(1:3, 1:2) + @test LinearIndices(c) == collect(l) + @test CartesianIndices(l) == collect(c) + @test size(c) == (3, 2) + @test c == collect(c) == [CartesianIndex(1, 1) CartesianIndex(1, 2) + CartesianIndex(2, 1) CartesianIndex(2, 2) + CartesianIndex(3, 1) CartesianIndex(3, 2)] + @test l == collect(l) == reshape(1:6, 3, 2) + @test c[1:6] == vec(c) + @test l == l[c] == map(i -> l[i], c) + @test l[vec(c)] == collect(1:6) +end + if VERSION < v"0.6.0" include("deprecated.jl") end