From f06b91cdeae00abfc490b0a9da5388086d9e5450 Mon Sep 17 00:00:00 2001 From: Bart Janssens Date: Wed, 22 Nov 2017 23:50:02 +0100 Subject: [PATCH 1/3] Make CartesianRange an AbstractArray and deprecate sub2ind and ind2sub --- NEWS.md | 15 ++++ base/abstractarray.jl | 143 +++++++++--------------------- base/array.jl | 2 +- base/deprecated.jl | 21 +++++ base/exports.jl | 3 +- base/multidimensional.jl | 85 +++++++++++++++++- base/precompile.jl | 6 +- base/reshapedarray.jl | 4 +- base/sparse/sparsematrix.jl | 10 +-- base/sparse/sparsevector.jl | 8 +- base/subarray.jl | 2 +- doc/src/devdocs/offset-arrays.md | 2 +- doc/src/devdocs/subarrays.md | 5 +- doc/src/manual/metaprogramming.md | 2 +- doc/src/stdlib/arrays.md | 3 +- test/abstractarray.jl | 94 ++++++++++++-------- test/arrayops.jl | 2 +- test/euler.jl | 7 +- 18 files changed, 245 insertions(+), 169 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1baa1294bcd2c..0a6feb53ced2d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -211,6 +211,13 @@ This section lists changes that do not have deprecation warnings. longer present. Use `first(R)` and `last(R)` to obtain start/stop. ([#20974]) + * `CartesianRange` inherits from AbstractArray and construction with an + `AbstractArray` argument constructs the indices for that array. Consequently, + linear indexing can be used to provide linear-to-cartesian conversion ([#24715]) + + * The type `CartesianToLinear` has been added, providing conversion from + cartesian incices to linear indices using the normal indexing operation. ([#24715]) + * The `Diagonal`, `Bidiagonal`, `Tridiagonal` and `SymTridiagonal` type definitions have changed from `Diagonal{T}`, `Bidiagonal{T}`, `Tridiagonal{T}` and `SymTridiagonal{T}` to `Diagonal{T,V<:AbstractVector{T}}`, `Bidiagonal{T,V<:AbstractVector{T}}`, @@ -445,6 +452,11 @@ Library improvements defined, linear-algebra function `transpose`. Similarly, `permutedims(v::AbstractVector)` will create a row matrix ([#24839]). + * `CartesianRange` changes ([#24715]): + - Inherits from `AbstractArray` + - Constructor taking an array + - `eachindex` returns the linear indices into a reshaped array, as `sub2ind` alternative + Compiler/Runtime improvements ----------------------------- @@ -792,6 +804,8 @@ Deprecated or removed and `unsafe_get`/`get` can be dropped or replaced with `coalesce`. `NullException` has been removed. + * `sub2ind` and `ind2sub` are deprecated in favor of using `CartesianRange` and `CartesianToLinear` ([#24715]). + Command-line option changes --------------------------- @@ -1768,6 +1782,7 @@ Command-line option changes [#24413]: https://github.com/JuliaLang/julia/issues/24413 [#24653]: https://github.com/JuliaLang/julia/issues/24653 [#24714]: https://github.com/JuliaLang/julia/issues/24714 +[#24715]: https://github.com/JuliaLang/julia/issues/24715 [#24869]: https://github.com/JuliaLang/julia/issues/24869 [#25021]: https://github.com/JuliaLang/julia/issues/25021 [#25088]: https://github.com/JuliaLang/julia/issues/25088 diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 9e1e9bd370d2f..c393f3fed70d7 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -308,9 +308,8 @@ type: The default is `IndexCartesian()`. Julia's internal indexing machinery will automatically (and invisibly) -convert all indexing operations into the preferred style using -[`sub2ind`](@ref) or [`ind2sub`](@ref). This allows users to access -elements of your array using any indexing style, even when explicit +convert all indexing operations into the preferred style. This allows users +to access elements of your array using any indexing style, even when explicit methods have not been provided. If you define both styles of indexing for your `AbstractArray`, this @@ -959,7 +958,7 @@ end _to_linear_index(A::AbstractArray, i::Int) = i _to_linear_index(A::AbstractVector, i::Int, I::Int...) = i _to_linear_index(A::AbstractArray) = 1 -_to_linear_index(A::AbstractArray, I::Int...) = (@_inline_meta; sub2ind(A, I...)) +_to_linear_index(A::AbstractArray, I::Int...) = (@_inline_meta; _sub2ind(A, I...)) ## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M @@ -993,8 +992,8 @@ _to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, sa _to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I _remaining_size(::Tuple{Any}, t::Tuple) = t _remaining_size(h::Tuple, t::Tuple) = (@_inline_meta; _remaining_size(tail(h), tail(t))) -_unsafe_ind2sub(::Tuple{}, i) = () # ind2sub may throw(BoundsError()) in this case -_unsafe_ind2sub(sz, i) = (@_inline_meta; ind2sub(sz, i)) +_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case +_unsafe_ind2sub(sz, i) = (@_inline_meta; _ind2sub(sz, i)) ## Setindex! is defined similarly. We first dispatch to an internal _setindex! # function that allows dispatch on array storage @@ -1581,73 +1580,43 @@ function (==)(A::AbstractArray, B::AbstractArray) return anymissing ? missing : true end -# sub2ind and ind2sub +# _sub2ind and _ind2sub # fallbacks -function sub2ind(A::AbstractArray, I...) +function _sub2ind(A::AbstractArray, I...) @_inline_meta - sub2ind(axes(A), I...) + _sub2ind(axes(A), I...) end -""" - ind2sub(a, index) -> subscripts - -Return a tuple of subscripts into array `a` corresponding to the linear index `index`. - -# Examples -```jldoctest -julia> A = ones(5,6,7); - -julia> ind2sub(A,35) -(5, 1, 2) - -julia> ind2sub(A,70) -(5, 2, 3) -``` -""" -function ind2sub(A::AbstractArray, ind) +function _ind2sub(A::AbstractArray, ind) @_inline_meta - ind2sub(axes(A), ind) + _ind2sub(axes(A), ind) end # 0-dimensional arrays and indexing with [] -sub2ind(::Tuple{}) = 1 -sub2ind(::DimsInteger) = 1 -sub2ind(::Indices) = 1 -sub2ind(::Tuple{}, I::Integer...) = (@_inline_meta; _sub2ind((), 1, 1, I...)) -# Generic cases - -""" - sub2ind(dims, i, j, k...) -> index - -The inverse of [`ind2sub`](@ref), return the linear index corresponding to the provided subscripts. - -# Examples -```jldoctest -julia> sub2ind((5,6,7),1,2,3) -66 +_sub2ind(::Tuple{}) = 1 +_sub2ind(::DimsInteger) = 1 +_sub2ind(::Indices) = 1 +_sub2ind(::Tuple{}, I::Integer...) = (@_inline_meta; _sub2ind_recurse((), 1, 1, I...)) -julia> sub2ind((5,6,7),1,6,3) -86 -``` -""" -sub2ind(dims::DimsInteger, I::Integer...) = (@_inline_meta; _sub2ind(dims, 1, 1, I...)) -sub2ind(inds::Indices, I::Integer...) = (@_inline_meta; _sub2ind(inds, 1, 1, I...)) +# Generic cases +_sub2ind(dims::DimsInteger, I::Integer...) = (@_inline_meta; _sub2ind_recurse(dims, 1, 1, I...)) +_sub2ind(inds::Indices, I::Integer...) = (@_inline_meta; _sub2ind_recurse(inds, 1, 1, I...)) # In 1d, there's a question of whether we're doing cartesian indexing # or linear indexing. Support only the former. -sub2ind(inds::Indices{1}, I::Integer...) = +_sub2ind(inds::Indices{1}, I::Integer...) = throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays")) -sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@_inline_meta; _sub2ind(inds, 1, 1, I...)) # only OneTo is safe -sub2ind(inds::Tuple{OneTo}, i::Integer) = i +_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@_inline_meta; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe +_sub2ind(inds::Tuple{OneTo}, i::Integer) = i -_sub2ind(::Any, L, ind) = ind -function _sub2ind(::Tuple{}, L, ind, i::Integer, I::Integer...) +_sub2ind_recurse(::Any, L, ind) = ind +function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...) @_inline_meta - _sub2ind((), L, ind+(i-1)*L, I...) + _sub2ind_recurse((), L, ind+(i-1)*L, I...) end -function _sub2ind(inds, L, ind, i::Integer, I::Integer...) +function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...) @_inline_meta r1 = inds[1] - _sub2ind(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...) + _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...) end nextL(L, l::Integer) = L*l @@ -1655,42 +1624,23 @@ nextL(L, r::AbstractUnitRange) = L*unsafe_length(r) offsetin(i, l::Integer) = i-1 offsetin(i, r::AbstractUnitRange) = i-first(r) -ind2sub(::Tuple{}, ind::Integer) = (@_inline_meta; ind == 1 ? () : throw(BoundsError())) - -""" - ind2sub(dims, index) -> subscripts - -Return a tuple of subscripts into an array with dimensions `dims`, -corresponding to the linear index `index`. - -# Examples -```jldoctest -julia> ind2sub((3,4),2) -(2, 1) - -julia> ind2sub((3,4),3) -(3, 1) - -julia> ind2sub((3,4),4) -(1, 2) -``` -""" -ind2sub(dims::DimsInteger, ind::Integer) = (@_inline_meta; _ind2sub(dims, ind-1)) -ind2sub(inds::Indices, ind::Integer) = (@_inline_meta; _ind2sub(inds, ind-1)) -ind2sub(inds::Indices{1}, ind::Integer) = +_ind2sub(::Tuple{}, ind::Integer) = (@_inline_meta; ind == 1 ? () : throw(BoundsError())) +_ind2sub(dims::DimsInteger, ind::Integer) = (@_inline_meta; _ind2sub_recurse(dims, ind-1)) +_ind2sub(inds::Indices, ind::Integer) = (@_inline_meta; _ind2sub_recurse(inds, ind-1)) +_ind2sub(inds::Indices{1}, ind::Integer) = throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays")) -ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,) +_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,) -_ind2sub(::Tuple{}, ind) = (ind+1,) -function _ind2sub(indslast::NTuple{1}, ind) +_ind2sub_recurse(::Tuple{}, ind) = (ind+1,) +function _ind2sub_recurse(indslast::NTuple{1}, ind) @_inline_meta (_lookup(ind, indslast[1]),) end -function _ind2sub(inds, ind) +function _ind2sub_recurse(inds, ind) @_inline_meta r1 = inds[1] indnext, f, l = _div(ind, r1) - (ind-l*indnext+f, _ind2sub(tail(inds), indnext)...) + (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...) end _lookup(ind, d::Integer) = ind+1 @@ -1699,12 +1649,12 @@ _div(ind, d::Integer) = div(ind, d), 1, d _div(ind, r::AbstractUnitRange) = (d = unsafe_length(r); (div(ind, d), first(r), d)) # Vectorized forms -function sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer +function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays")) end -sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} = +_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} = _sub2ind_vecs(inds, I1, I...) -sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} = +_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} = _sub2ind_vecs(inds, I1, I...) function _sub2ind_vecs(inds, I::AbstractVector...) I1 = I[1] @@ -1720,21 +1670,21 @@ end function _sub2ind!(Iout, inds, Iinds, I) @_noinline_meta for i in Iinds - # Iout[i] = sub2ind(inds, map(Ij -> Ij[i], I)...) + # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...) Iout[i] = sub2ind_vec(inds, i, I) end Iout end -sub2ind_vec(inds, i, I) = (@_inline_meta; sub2ind(inds, _sub2ind_vec(i, I...)...)) +sub2ind_vec(inds, i, I) = (@_inline_meta; _sub2ind(inds, _sub2ind_vec(i, I...)...)) _sub2ind_vec(i, I1, I...) = (@_inline_meta; (I1[i], _sub2ind_vec(i, I...)...)) _sub2ind_vec(i) = () -function ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N +function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N M = length(ind) t = ntuple(n->similar(ind),Val(N)) for (i,idx) in pairs(IndexLinear(), ind) - sub = ind2sub(inds, idx) + sub = _ind2sub(inds, idx) for j = 1:N t[j][i] = sub[j] end @@ -1742,17 +1692,6 @@ function ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:I t end -function ind2sub!(sub::Array{T}, dims::Tuple{Vararg{T}}, ind::T) where T<:Integer - ndims = length(dims) - for i=1:ndims-1 - ind2 = div(ind-1,dims[i])+1 - sub[i] = ind - dims[i]*(ind2-1) - ind = ind2 - end - sub[ndims] = ind - return sub -end - ## iteration utilities ## """ diff --git a/base/array.jl b/base/array.jl index c3ee01b4a4ad3..289382bc7ae04 100644 --- a/base/array.jl +++ b/base/array.jl @@ -135,7 +135,7 @@ sizeof(a::Array) = Core.sizeof(a) function isassigned(a::Array, i::Int...) @_inline_meta - ii = (sub2ind(size(a), i...) % UInt) - 1 + ii = (_sub2ind(size(a), i...) % UInt) - 1 @boundscheck ii < length(a) % UInt || return false ccall(:jl_array_isassigned, Cint, (Any, UInt), a, ii) == 1 end diff --git a/base/deprecated.jl b/base/deprecated.jl index 87e29088041a6..558d2b7acb08f 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -3262,6 +3262,27 @@ end @deprecate_moved isnull "Nullables" @deprecate_moved unsafe_get "Nullables" +# sub2ind and ind2sub deprecation (PR #24715) +@deprecate ind2sub(A::AbstractArray, ind) CartesianRange(A)[ind] +@deprecate ind2sub(::Tuple{}, ind::Integer) CartesianRange()[ind] +@deprecate ind2sub(dims::Tuple{Vararg{Integer,N}} where N, ind::Integer) CartesianRange(dims)[ind] +@deprecate ind2sub(inds::Tuple{Base.OneTo}, ind::Integer) CartesianRange(inds)[ind] +@deprecate ind2sub(inds::Tuple{AbstractUnitRange}, ind::Integer) CartesianRange(inds)[ind] +@deprecate ind2sub(inds::Tuple{Vararg{AbstractUnitRange,N}} where N, ind::Integer) CartesianRange(inds)[ind] +@deprecate ind2sub(inds::Union{DimsInteger{N},Indices{N}} where N, ind::AbstractVector{<:Integer}) CartesianRange(inds)[ind] + +@deprecate sub2ind(A::AbstractArray, I...) CartesianToLinear(A)[I...] +@deprecate sub2ind(dims::Tuple{}) CartesianToLinear(dims)[] +@deprecate sub2ind(dims::DimsInteger) CartesianToLinear(dims)[] +@deprecate sub2ind(dims::Indices) CartesianToLinear(dims)[] +@deprecate sub2ind(dims::Tuple{}, I::Integer...) CartesianToLinear(dims)[I...] +@deprecate sub2ind(dims::DimsInteger, I::Integer...) CartesianToLinear(dims)[I...] +@deprecate sub2ind(inds::Indices, I::Integer...) CartesianToLinear(inds)[I...] +@deprecate sub2ind(inds::Tuple{OneTo}, I::Integer...) CartesianToLinear(inds)[I...] +@deprecate sub2ind(inds::Tuple{OneTo}, i::Integer) CartesianToLinear(inds)[i] +@deprecate sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} CartesianToLinear(inds)[CartesianIndex.(I1, I...)] +@deprecate sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} CartesianToLinear(inds)[CartesianIndex.(I1, I...)] + # END 0.7 deprecations # BEGIN 1.0 deprecations diff --git a/base/exports.jl b/base/exports.jl index 29b110cebfdc7..0eb27e0866f27 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -39,6 +39,7 @@ export BufferStream, CartesianIndex, CartesianRange, + CartesianToLinear, Channel, Cmd, Colon, @@ -452,7 +453,6 @@ export flipdim, hcat, hvcat, - ind2sub, indexin, indmax, indmin, @@ -521,7 +521,6 @@ export step, stride, strides, - sub2ind, sum!, sum, to_indices, diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 5e6039ab08a57..3b008a6699b75 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -11,7 +11,7 @@ module IteratorsMD using Base: IndexLinear, IndexCartesian, AbstractCartesianIndex, fill_to_length, tail using Base.Iterators: Reverse - export CartesianIndex, CartesianRange + export CartesianIndex, CartesianRange, CartesianToLinear """ CartesianIndex(i, j, k...) -> I @@ -172,6 +172,11 @@ module IteratorsMD Consequently these can be useful for writing algorithms that work in arbitrary dimensions. + CartesianRange(A::AbstractArray) -> R + + As a convenience, constructing a CartesianRange from an array makes a + range of its indices. + # Examples ```jldoctest julia> foreach(println, CartesianRange((2, 2, 2))) @@ -183,9 +188,32 @@ module IteratorsMD CartesianIndex(2, 1, 2) CartesianIndex(1, 2, 2) CartesianIndex(2, 2, 2) + + julia> CartesianRange(ones(2,3)) + 2×3 CartesianRange{2,Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}}: + CartesianIndex(1, 1) CartesianIndex(1, 2) CartesianIndex(1, 3) + CartesianIndex(2, 1) CartesianIndex(2, 2) CartesianIndex(2, 3) + ``` + + ## Conversion between linear and cartesian indices + + Linear index to cartesian index conversion exploits the fact that a + `CartesianRange` is an `AbstractArray` and can be indexed linearly: + + ```jldoctest subarray + julia> cartesian = CartesianRange(1:3,1:2) + 3×2 CartesianRange{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}: + CartesianIndex(1, 1) CartesianIndex(1, 2) + CartesianIndex(2, 1) CartesianIndex(2, 2) + CartesianIndex(3, 1) CartesianIndex(3, 2) + + julia> cartesian[4] + CartesianIndex(1, 2) ``` + + For cartesian to linear index conversion, see [`CartesianToLinear`](@ref). """ - struct CartesianRange{N,R<:NTuple{N,AbstractUnitRange{Int}}} + struct CartesianRange{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{CartesianIndex{N},N} indices::R end @@ -204,6 +232,8 @@ module IteratorsMD CartesianRange(inds::NTuple{N,Union{<:Integer,AbstractUnitRange{<:Integer}}}) where {N} = CartesianRange(map(i->first(i):last(i), inds)) + CartesianRange(A::AbstractArray) = CartesianRange(axes(A)) + convert(::Type{Tuple{}}, R::CartesianRange{0}) = () convert(::Type{NTuple{N,AbstractUnitRange{Int}}}, R::CartesianRange{N}) where {N} = R.indices @@ -222,6 +252,10 @@ module IteratorsMD convert(::Type{Tuple{Vararg{UnitRange}}}, R::CartesianRange) = convert(Tuple{Vararg{UnitRange{Int}}}, R) + # AbstractArray implementation + Base.IndexStyle(::Type{CartesianRange{N,R}}) where {N,R} = IndexCartesian() + @inline Base.getindex(iter::CartesianRange{N,R}, I::Vararg{Int, N}) where {N,R} = CartesianIndex(first.(iter.indices) .- 1 .+ I) + ndims(R::CartesianRange) = ndims(typeof(R)) ndims(::Type{CartesianRange{N}}) where {N} = N ndims(::Type{CartesianRange{N,TT}}) where {N,TT} = N @@ -343,6 +377,53 @@ module IteratorsMD start(iter::Reverse{<:CartesianRange{0}}) = false next(iter::Reverse{<:CartesianRange{0}}, state) = CartesianIndex(), true done(iter::Reverse{<:CartesianRange{0}}, state) = state + + """ + CartesianToLinear(inds::CartesianRange) -> R + CartesianToLinear(sz::Dims) -> R + CartesianToLinear(istart:istop, jstart:jstop, ...) -> R + + Define a mapping between cartesian indices and the corresponding linear index into a CartesianRange + + # Example + + The main purpose of this type is intuitive conversion from cartesian to linear indexing: + + ```jldoctest subarray + julia> linear = CartesianToLinear(1:3,1:2) + CartesianToLinear{2,Tuple{UnitRange{Int64},UnitRange{Int64}}} with indices 1:3×1:2: + 1 4 + 2 5 + 3 6 + + julia> linear[1,2] + 4 + ``` + """ + struct CartesianToLinear{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{Int,N} + indices::R + end + + CartesianToLinear(inds::CartesianRange{N,R}) where {N,R} = CartesianToLinear{N,R}(inds.indices) + CartesianToLinear(::Tuple{}) = CartesianToLinear(CartesianRange(())) + CartesianToLinear(inds::NTuple{N,AbstractUnitRange{Int}}) where {N} = CartesianToLinear(CartesianRange(inds)) + CartesianToLinear(inds::Vararg{AbstractUnitRange{Int},N}) where {N} = CartesianToLinear(CartesianRange(inds)) + CartesianToLinear(inds::NTuple{N,AbstractUnitRange{<:Integer}}) where {N} = CartesianToLinear(CartesianRange(inds)) + CartesianToLinear(inds::Vararg{AbstractUnitRange{<:Integer},N}) where {N} = CartesianToLinear(CartesianRange(inds)) + CartesianToLinear(index::CartesianIndex) = CartesianToLinear(CartesianRange(index)) + CartesianToLinear(sz::NTuple{N,<:Integer}) where {N} = CartesianToLinear(CartesianRange(sz)) + CartesianToLinear(inds::NTuple{N,Union{<:Integer,AbstractUnitRange{<:Integer}}}) where {N} = CartesianToLinear(CartesianRange(inds)) + CartesianToLinear(A::AbstractArray) = CartesianToLinear(CartesianRange(A)) + + # AbstractArray implementation + Base.IndexStyle(::Type{CartesianToLinear{N,R}}) where {N,R} = IndexCartesian() + Base.axes(iter::CartesianToLinear{N,R}) where {N,R} = iter.indices + @inline function Base.getindex(iter::CartesianToLinear{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 # IteratorsMD diff --git a/base/precompile.jl b/base/precompile.jl index 1be887564e958..fec501e2bf697 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -1367,9 +1367,9 @@ precompile(Tuple{typeof(Base.print_matrix_vdots), Base.IOContext{Base.Terminals. precompile(Tuple{typeof(Base.print_matrix), Base.IOContext{Base.Terminals.TTYTerminal}, Array{Int64, 1}, String, String, String, String, String, String, Int64, Int64}) precompile(Tuple{typeof(Base.alignment), Base.IOContext{Base.Terminals.TTYTerminal}, Array{Int64, 1}, Array{Int64, 1}, Array{Int64, 1}, Int64, Int64, Int64}) precompile(Tuple{getfield(Base, Symbol("#kw##sprint")), Array{Any, 1}, typeof(Base.sprint), Int64, typeof(Base.show), Int64}) -precompile(Tuple{typeof(Base.sub2ind), Tuple{Int64}, Int64, Int64}) -precompile(Tuple{typeof(Base._sub2ind), Tuple{Int64}, Int64, Int64, Int64, Int64}) -precompile(Tuple{typeof(Base._sub2ind), Tuple{}, Int64, Int64, Int64}) +precompile(Tuple{typeof(Base._sub2ind), Tuple{Int64}, Int64, Int64}) +precompile(Tuple{typeof(Base._sub2ind_recurse), Tuple{Int64}, Int64, Int64, Int64, Int64}) +precompile(Tuple{typeof(Base._sub2ind_recurse), Tuple{}, Int64, Int64, Int64}) precompile(Tuple{typeof(Base.first), Array{Int64, 1}}) precompile(Tuple{typeof(Base.print_matrix_row), Base.IOContext{Base.Terminals.TTYTerminal}, Array{Int64, 1}, Array{Tuple{Int64, Int64}, 1}, Int64, Array{Int64, 1}, String}) precompile(Tuple{typeof(Base.print), Base.GenericIOBuffer{Array{UInt8, 1}}, Base.OneTo{Int64}}) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index 070d25ffc20b7..005be471253b4 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -204,7 +204,7 @@ end end @inline function _unsafe_getindex(A::ReshapedArray{T,N}, indices::Vararg{Int,N}) where {T,N} - i = sub2ind(size(A), indices...) + i = Base._sub2ind(size(A), indices...) I = ind2sub_rs(A.mi, i) _unsafe_getindex_rs(parent(A), I) end @@ -227,7 +227,7 @@ end end @inline function _unsafe_setindex!(A::ReshapedArray{T,N}, val, indices::Vararg{Int,N}) where {T,N} - @inbounds parent(A)[ind2sub_rs(A.mi, sub2ind(size(A), indices...))...] = val + @inbounds parent(A)[ind2sub_rs(A.mi, Base._sub2ind(size(A), indices...))...] = val val end diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 4d726ab4bf581..11ac69ab72b59 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -1279,7 +1279,7 @@ function find(p::Function, S::SparseMatrixCSC) end sz = size(S) I, J = _findn(p, S) - return sub2ind(sz, I, J) + return Base._sub2ind(sz, I, J) end findn(S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = _findn(x->true, S) @@ -2249,10 +2249,10 @@ function getindex(A::SparseMatrixCSC{Tv,Ti}, I::AbstractArray) where {Tv,Ti} for i in 1:n ((I[i] < 1) | (I[i] > nA)) && throw(BoundsError()) - row,col = ind2sub(szA, I[i]) + row,col = Base._ind2sub(szA, I[i]) for r in colptrA[col]:(colptrA[col+1]-1) @inbounds if rowvalA[r] == row - rowB,colB = ind2sub(szB, i) + rowB,colB = Base._ind2sub(szB, i) colptrB[colB+1] += 1 rowvalB[idxB] = rowB nzvalB[idxB] = nzvalA[r] @@ -2754,7 +2754,7 @@ function setindex!(A::SparseMatrixCSC, x, I::AbstractVector{<:Real}) sxidx = S[xidx] (sxidx < n) && (I[sxidx] == I[sxidx+1]) && continue - row,col = ind2sub(szA, I[sxidx]) + row,col = Base._ind2sub(szA, I[sxidx]) v = isa(x, AbstractArray) ? x[sxidx] : x if col > lastcol @@ -3447,7 +3447,7 @@ function hash(A::SparseMatrixCSC{T}, h::UInt) where T for j = colptr[col]:colptr[col+1]-1 nz = nzval[j] isequal(nz, zero(T)) && continue - idx = sub2ind(sz, rowval[j], col) + idx = Base._sub2ind(sz, rowval[j], col) if idx != lastidx+1 || !isequal(nz, lastnz) # Run is over h = hashrun(lastnz, runlength, h) # Hash previous run h = hashrun(0, idx-lastidx-1, h) # Hash intervening zeros diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index c08b1cd2eeab1..83af34955370e 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -617,8 +617,8 @@ function getindex(A::SparseMatrixCSC{Tv}, I::AbstractUnitRange) where Tv rowvalB = Vector{Int}(uninitialized, nnzB) nzvalB = Vector{Tv}(uninitialized, nnzB) - rowstart,colstart = ind2sub(szA, first(I)) - rowend,colend = ind2sub(szA, last(I)) + rowstart,colstart = Base._ind2sub(szA, first(I)) + rowend,colend = Base._ind2sub(szA, last(I)) idxB = 1 @inbounds for col in colstart:colend @@ -627,7 +627,7 @@ function getindex(A::SparseMatrixCSC{Tv}, I::AbstractUnitRange) where Tv for r in colptrA[col]:(colptrA[col+1]-1) rowA = rowvalA[r] if minrow <= rowA <= maxrow - rowvalB[idxB] = sub2ind(szA, rowA, col) - first(I) + 1 + rowvalB[idxB] = Base._sub2ind(szA, rowA, col) - first(I) + 1 nzvalB[idxB] = nzvalA[r] idxB += 1 end @@ -655,7 +655,7 @@ function getindex(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVector) where {Tv,Ti} idxB = 1 for i in 1:n ((I[i] < 1) | (I[i] > nA)) && throw(BoundsError(A, I)) - row,col = ind2sub(szA, I[i]) + row,col = Base._ind2sub(szA, I[i]) for r in colptrA[col]:(colptrA[col+1]-1) @inbounds if rowvalA[r] == row if idxB <= nnzB diff --git a/base/subarray.jl b/base/subarray.jl index 97afeddeaaf17..3dd49f66a7d44 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -329,7 +329,7 @@ pointer(V::FastSubArray, i::Int) = pointer(V.parent, V.offset1 + V.stride1*i) pointer(V::FastContiguousSubArray, i::Int) = pointer(V.parent, V.offset1 + i) pointer(V::SubArray, i::Int) = _pointer(V, i) _pointer(V::SubArray{<:Any,1}, i::Int) = pointer(V, (i,)) -_pointer(V::SubArray, i::Int) = pointer(V, ind2sub(axes(V), i)) +_pointer(V::SubArray, i::Int) = pointer(V, Base._ind2sub(axes(V), i)) function pointer(V::SubArray{T,N,<:Array,<:Tuple{Vararg{RangeIndex}}}, is::Tuple{Vararg{Int}}) where {T,N} index = first_index(V) diff --git a/doc/src/devdocs/offset-arrays.md b/doc/src/devdocs/offset-arrays.md index 4e6f77224faa1..c26ac5870372e 100644 --- a/doc/src/devdocs/offset-arrays.md +++ b/doc/src/devdocs/offset-arrays.md @@ -81,7 +81,7 @@ Some algorithms are most conveniently (or efficiently) written in terms of a sin For this reason, your best option may be to iterate over the array with `eachindex(A)`, or, if you require the indices to be sequential integers, to get the index range by calling `linearindices(A)`. This will return `axes(A, 1)` if A is an AbstractVector, and the equivalent of `1:length(A)` otherwise. -By this definition, 1-dimensional arrays always use Cartesian indexing with the array's native indices. To help enforce this, it's worth noting that sub2ind(shape, i...) and ind2sub(shape, ind) will throw an error if shape indicates a 1-dimensional array with unconventional indexing (i.e., is a `Tuple{UnitRange}` rather than a tuple of `OneTo`). For arrays with conventional indexing, these functions continue to work the same as always. +By this definition, 1-dimensional arrays always use Cartesian indexing with the array's native indices. To help enforce this, it's worth noting that the index conversion functions will throw an error if shape indicates a 1-dimensional array with unconventional indexing (i.e., is a `Tuple{UnitRange}` rather than a tuple of `OneTo`). For arrays with conventional indexing, these functions continue to work the same as always. Using `indices` and `linearindices`, here is one way you could rewrite `mycopy!`: diff --git a/doc/src/devdocs/subarrays.md b/doc/src/devdocs/subarrays.md index ac69ef0f151c9..62fc64413a39a 100644 --- a/doc/src/devdocs/subarrays.md +++ b/doc/src/devdocs/subarrays.md @@ -22,9 +22,8 @@ computation (such as interpolation), and the type under discussion here, `SubArr For these types, the underlying information is more naturally described in terms of cartesian indices. -You can manually convert from a cartesian index to a linear index with `sub2ind`, and vice versa -using `ind2sub`. `getindex` and `setindex!` functions for `AbstractArray` types may include similar -operations. +The `getindex` and `setindex!` functions for `AbstractArray` types may include automatic conversion +between indexing types. For explicit conversion, [`CartesianRange`](@ref) can be used. While converting from a cartesian index to a linear index is fast (it's just multiplication and addition), converting from a linear index to a cartesian index is very slow: it relies on the diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index b14ace6264800..e11f111d95e54 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -1264,7 +1264,7 @@ to build some more advanced (and valid) functionality... ### An advanced example -Julia's base library has a [`sub2ind`](@ref) function to calculate a linear index into an n-dimensional +Julia's base library has a an internal `sub2ind` function to calculate a linear index into an n-dimensional array, based on a set of n multilinear indices - in other words, to calculate the index `i` that can be used to index into an array `A` using `A[i]`, instead of `A[x,y,z,...]`. One possible implementation is the following: diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index ec4bdd2b4f1c4..b546a62a79b37 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -48,8 +48,6 @@ Base.IndexStyle Base.conj! Base.stride Base.strides -Base.ind2sub -Base.sub2ind Base.LinAlg.checksquare ``` @@ -89,6 +87,7 @@ Base.isassigned Base.Colon Base.CartesianIndex Base.CartesianRange +Base.CartesianToLinear Base.to_indices Base.checkbounds Base.checkindex diff --git a/test/abstractarray.jl b/test/abstractarray.jl index e894850f4f23d..2a5bf5f6d69d1 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -112,62 +112,64 @@ end @test checkbounds(Bool, A, [CartesianIndex((5, 4))], 4) == false end -@testset "sub2ind & ind2sub" begin +@testset "index conversion" begin @testset "0-dimensional" begin - for i = 1:4 - @test sub2ind((), i) == i - end - @test sub2ind((), 2, 2) == 3 - @test ind2sub((), 1) == () - @test_throws BoundsError ind2sub((), 2) + @test CartesianToLinear()[1] == 1 + @test_throws BoundsError CartesianToLinear()[2] + @test CartesianToLinear()[1,1] == 1 + @test CartesianRange()[1] == CartesianIndex() + @test_throws BoundsError CartesianRange()[2] end @testset "1-dimensional" begin - for i = 1:4 - @test sub2ind((3,), i) == i - @test ind2sub((3,), i) == (i,) + for i = 1:3 + @test CartesianToLinear((3,))[i] == i + @test CartesianRange((3,))[i] == CartesianIndex(i,) end - @test sub2ind((3,), 2, 2) == 5 - @test_throws MethodError ind2sub((3,), 2, 2) + @test CartesianToLinear((3,))[2,1] == 2 + @test_throws BoundsError CartesianRange((3,))[2,2] # ambiguity btw cartesian indexing and linear indexing in 1d when # indices may be nontraditional - @test_throws ArgumentError sub2ind((1:3,), 2) - @test_throws ArgumentError ind2sub((1:3,), 2) + @test_throws ArgumentError Base._sub2ind((1:3,), 2) + @test_throws ArgumentError Base._ind2sub((1:3,), 2) end @testset "2-dimensional" begin k = 0 + cartesian = CartesianRange((4,3)) + linear = CartesianToLinear(cartesian) for j = 1:3, i = 1:4 - @test sub2ind((4,3), i, j) == (k+=1) - @test ind2sub((4,3), k) == (i,j) - @test sub2ind((1:4,1:3), i, j) == k - @test ind2sub((1:4,1:3), k) == (i,j) - @test sub2ind((0:3,3:5), i-1, j+2) == k - @test ind2sub((0:3,3:5), k) == (i-1, j+2) + @test linear[i,j] == (k+=1) + @test cartesian[k] == CartesianIndex(i,j) + @test CartesianToLinear(0:3,3:5)[i-1,j+2] == k + @test CartesianRange(0:3,3:5)[k] == CartesianIndex(i-1,j+2) end end @testset "3-dimensional" begin l = 0 for k = 1:2, j = 1:3, i = 1:4 - @test sub2ind((4,3,2), i, j, k) == (l+=1) - @test ind2sub((4,3,2), l) == (i,j,k) - @test sub2ind((1:4,1:3,1:2), i, j, k) == l - @test ind2sub((1:4,1:3,1:2), l) == (i,j,k) - @test sub2ind((0:3,3:5,-101:-100), i-1, j+2, k-102) == l - @test ind2sub((0:3,3:5,-101:-100), l) == (i-1, j+2, k-102) + @test CartesianToLinear((4,3,2))[i,j,k] == (l+=1) + @test CartesianRange((4,3,2))[l] == CartesianIndex(i,j,k) + @test CartesianToLinear(1:4,1:3,1:2)[i,j,k] == l + @test CartesianRange(1:4,1:3,1:2)[l] == CartesianIndex(i,j,k) + @test CartesianToLinear(0:3,3:5,-101:-100)[i-1,j+2,k-102] == l + @test CartesianRange(0:3,3:5,-101:-100)[l] == CartesianIndex(i-1, j+2, k-102) end local A = reshape(collect(1:9), (3,3)) - @test ind2sub(size(A), 6) == (3,2) - @test sub2ind(size(A), 3, 2) == 6 - @test ind2sub(A, 6) == (3,2) - @test sub2ind(A, 3, 2) == 6 + @test CartesianRange(size(A))[6] == CartesianIndex(3,2) + @test CartesianToLinear(size(A))[3, 2] == 6 + @test CartesianRange(A)[6] == CartesianIndex(3,2) + @test CartesianToLinear(A)[3, 2] == 6 + for i in 1:length(A) + @test CartesianToLinear(A)[CartesianRange(A)[i]] == i + end @testset "PR #9256" begin function pr9256() m = [1 2 3; 4 5 6; 7 8 9] - ind2sub(m, 6) + Base._ind2sub(m, 6) end @test pr9256() == (3,2) end @@ -616,10 +618,9 @@ function test_ind2sub(::Type{TestAbstractArray}) dims = tuple(rand(1:5, n)...) len = prod(dims) A = reshape(collect(1:len), dims...) - I = ind2sub(dims, [1:len...]) + I = CartesianRange(dims) for i in 1:len - idx = [ I[j][i] for j in 1:n ] - @test A[idx...] == A[i] + @test A[I[i]] == A[i] end end @@ -762,8 +763,8 @@ end @test Base.copymutable((1,2,3)) == [1,2,3] end -@testset "sub2ind for empty tuple" begin - @test sub2ind(()) == 1 +@testset "_sub2ind for empty tuple" begin + @test Base._sub2ind(()) == 1 end @testset "to_shape" begin @@ -826,3 +827,24 @@ end @test isempty(v2::Vector{Int}) @test isempty(v3::Vector{Float64}) end + +@testset "CartesianRange" begin + xrng = 2:4 + yrng = 1:5 + CR = CartesianRange((xrng,yrng)) + + for (i,i_idx) in enumerate(xrng) + for (j,j_idx) in enumerate(yrng) + @test CR[i,j] == CartesianIndex(i_idx,j_idx) + end + end + + for i_lin in linearindices(CR) + i = (i_lin-1) % length(xrng) + 1 + j = (i_lin-i) ÷ length(xrng) + 1 + @test CR[i_lin] == CartesianIndex(xrng[i],yrng[j]) + end + + @test CartesianRange(ones(2,3)) == CartesianRange((2,3)) + @test CartesianToLinear((2,3)) == [1 3 5; 2 4 6] +end diff --git a/test/arrayops.jl b/test/arrayops.jl index a49eef100f142..2165bcdef2eb4 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -1358,7 +1358,7 @@ end # issue #7197 function i7197() S = [1 2 3; 4 5 6; 7 8 9] - ind2sub(size(S), 5) + Base._ind2sub(size(S), 5) end @test i7197() == (2,2) diff --git a/test/euler.jl b/test/euler.jl index 52b9bd0a3702c..7e81d05b635a2 100644 --- a/test/euler.jl +++ b/test/euler.jl @@ -65,13 +65,14 @@ end #11: 70600674 function euler11(grid,n) m = typemin(eltype(grid)) + tolinear = CartesianToLinear(size(grid)) for i = n:size(grid,1)-n+1, j = n:size(grid,2)-n+1, di = -1:1, dj = -1:1 di == dj == 0 && continue - idx = sub2ind(size(grid), - di==0 ? fill(i,n) : range(i,di,n), - dj==0 ? fill(j,n) : range(j,dj,n)) + i_idxs = di==0 ? fill(i,n) : range(i,di,n) + j_idxs = dj==0 ? fill(j,n) : range(j,dj,n) + idx = tolinear[CartesianIndex.(i_idxs, j_idxs)] m = max(m,prod(grid[idx])) end return m From e261a40ee8b5ec935f4c2cdb17d5cdb7cdfce72f Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 16 Dec 2017 06:17:29 -0600 Subject: [PATCH 2/3] Rename CartesianRange->CartesianIndices --- base/abstractarray.jl | 8 +- base/abstractarraymath.jl | 2 +- base/array.jl | 2 +- base/arrayshow.jl | 2 +- base/bitarray.jl | 2 +- base/broadcast.jl | 4 +- base/deprecated.jl | 47 ++++---- base/exports.jl | 4 +- base/io.jl | 4 +- base/iterators.jl | 2 +- base/multidimensional.jl | 222 +++++++++++++++++------------------ base/permuteddimsarray.jl | 8 +- base/reducedim.jl | 8 +- base/statistics.jl | 4 +- doc/src/devdocs/subarrays.md | 2 +- doc/src/stdlib/arrays.md | 6 +- test/TestHelpers.jl | 2 +- test/abstractarray.jl | 60 +++++----- test/arrayops.jl | 22 ++-- test/copy.jl | 8 +- test/euler.jl | 2 +- test/offsetarray.jl | 2 +- test/perf/array/indexing.jl | 2 +- test/perf/array/perf.jl | 8 +- test/simdloop.jl | 10 +- test/subarray.jl | 2 +- 26 files changed, 224 insertions(+), 221 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index c393f3fed70d7..9dd5f1165a6f6 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -104,7 +104,7 @@ julia> extrema(b) linearindices(A::AbstractArray) = (@_inline_meta; OneTo(_length(A))) linearindices(A::AbstractVector) = (@_inline_meta; indices1(A)) -keys(a::AbstractArray) = CartesianRange(axes(a)) +keys(a::AbstractArray) = CartesianIndices(axes(a)) keys(a::AbstractVector) = linearindices(a) prevind(::AbstractArray, i::Integer) = Int(i)-1 @@ -773,7 +773,7 @@ zero(x::AbstractArray{T}) where {T} = fill!(similar(x), zero(T)) # Allows fast iteration by default for both IndexLinear and IndexCartesian arrays # While the definitions for IndexLinear are all simple enough to inline on their -# own, IndexCartesian's CartesianRange is more complicated and requires explicit +# own, IndexCartesian's CartesianIndices is more complicated and requires explicit # inlining. start(A::AbstractArray) = (@_inline_meta; itr = eachindex(A); (itr, start(itr))) next(A::AbstractArray, i) = (@_propagate_inbounds_meta; (idx, s) = next(i[1], i[2]); (A[idx], (i[1], s))) @@ -824,7 +824,7 @@ A[iter] = 0 If you supply more than one `AbstractArray` argument, `eachindex` will create an iterable object that is fast for all arguments (a `UnitRange` -if all inputs have fast linear indexing, a [`CartesianRange`](@ref) +if all inputs have fast linear indexing, a [`CartesianIndices`](@ref) otherwise). If the arrays have different sizes and/or dimensionalities, `eachindex` will return an iterable that spans the largest range along each dimension. @@ -1815,7 +1815,7 @@ function mapslices(f, A::AbstractArray, dims::AbstractVector) R[ridx...] = r1 nidx = length(otherdims) - indices = Iterators.drop(CartesianRange(itershape), 1) + indices = Iterators.drop(CartesianIndices(itershape), 1) inner_mapslices!(safe_for_reuse, indices, nidx, idx, otherdims, ridx, Aslice, A, f, R) end diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 8a8650da28485..ee208780fffa2 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -374,7 +374,7 @@ cat_fill!(R, X::AbstractArray, inds) = fill!(view(R, inds...), X) R[axes(A)...] = A else inner_indices = [1:n for n in inner] - for c in CartesianRange(axes(A)) + for c in CartesianIndices(axes(A)) for i in 1:ndims(A) n = inner[i] inner_indices[i] = (1:n) .+ ((c[i] - 1) * n) diff --git a/base/array.jl b/base/array.jl index 289382bc7ae04..dfb427963ae9d 100644 --- a/base/array.jl +++ b/base/array.jl @@ -490,7 +490,7 @@ _collect_indices(indsA::Tuple{Vararg{OneTo}}, A) = copy!(Array{eltype(A)}(uninitialized, length.(indsA)), A) function _collect_indices(indsA, A) B = Array{eltype(A)}(uninitialized, length.(indsA)) - copy!(B, CartesianRange(axes(B)), A, CartesianRange(indsA)) + copy!(B, CartesianIndices(axes(B)), A, CartesianIndices(indsA)) end # define this as a macro so that the call to Inference diff --git a/base/arrayshow.jl b/base/arrayshow.jl index b5e1f20f04ae9..b20f9286c86a8 100644 --- a/base/arrayshow.jl +++ b/base/arrayshow.jl @@ -261,7 +261,7 @@ function show_nd(io::IO, a::AbstractArray, print_matrix::Function, label_slices: end tailinds = tail(tail(axes(a))) nd = ndims(a)-2 - for I in CartesianRange(tailinds) + for I in CartesianIndices(tailinds) idxs = I.I if limit for i = 1:nd diff --git a/base/bitarray.jl b/base/bitarray.jl index 4b95491fa6f08..031b30c44f8d7 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -548,7 +548,7 @@ gen_bitarray(isz::IteratorSize, itr) = gen_bitarray_from_itr(itr, start(itr)) # generic iterable with known shape function gen_bitarray(::HasShape, itr) B = BitArray(uninitialized, size(itr)) - for (I,x) in zip(CartesianRange(axes(itr)), itr) + for (I,x) in zip(CartesianIndices(axes(itr)), itr) B[I] = x end return B diff --git a/base/broadcast.jl b/base/broadcast.jl index a3d6d57547d4c..afa4285f5609d 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -454,7 +454,7 @@ as in `broadcast!(f, A, A, B)` to perform `A[:] = broadcast(f, A, B)`. shape = broadcast_indices(C) @boundscheck check_broadcast_indices(shape, A, Bs...) keeps, Idefaults = map_newindexer(shape, A, Bs) - iter = CartesianRange(shape) + iter = CartesianIndices(shape) _broadcast!(f, C, keeps, Idefaults, A, Bs, Val(N), iter) return C end @@ -616,7 +616,7 @@ end # accommodate later values. function broadcast_nonleaf(f, s::NonleafHandlingTypes, ::Type{ElType}, shape::Indices, As...) where ElType nargs = length(As) - iter = CartesianRange(shape) + iter = CartesianIndices(shape) if isempty(iter) return Base.similar(Array{ElType}, shape) end diff --git a/base/deprecated.jl b/base/deprecated.jl index 558d2b7acb08f..229fa8dcdab8a 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1381,10 +1381,10 @@ import .LinAlg: lufact, lufact!, qrfact, qrfact!, cholfact, cholfact! @deprecate read(s::IO, t::Type, d1::Integer, dims::Integer...) read!(s, Array{t}(uninitialized, convert(Tuple{Vararg{Int}},tuple(d1,dims...)))) @deprecate read(s::IO, t::Type, dims::Dims) read!(s, Array{t}(uninitialized, dims)) -function CartesianRange(start::CartesianIndex{N}, stop::CartesianIndex{N}) where N +function CartesianIndices(start::CartesianIndex{N}, stop::CartesianIndex{N}) where N inds = map((f,l)->f:l, start.I, stop.I) - depwarn("the internal representation of CartesianRange has changed, use CartesianRange($inds) (or other more approriate AbstractUnitRange type) instead.", :CartesianRange) - CartesianRange(inds) + depwarn("the internal representation of CartesianIndices has changed, use CartesianIndices($inds) (or other more approriate AbstractUnitRange type) instead.", :CartesianIndices) + CartesianIndices(inds) end # PR #20005 @@ -3263,25 +3263,28 @@ end @deprecate_moved unsafe_get "Nullables" # sub2ind and ind2sub deprecation (PR #24715) -@deprecate ind2sub(A::AbstractArray, ind) CartesianRange(A)[ind] -@deprecate ind2sub(::Tuple{}, ind::Integer) CartesianRange()[ind] -@deprecate ind2sub(dims::Tuple{Vararg{Integer,N}} where N, ind::Integer) CartesianRange(dims)[ind] -@deprecate ind2sub(inds::Tuple{Base.OneTo}, ind::Integer) CartesianRange(inds)[ind] -@deprecate ind2sub(inds::Tuple{AbstractUnitRange}, ind::Integer) CartesianRange(inds)[ind] -@deprecate ind2sub(inds::Tuple{Vararg{AbstractUnitRange,N}} where N, ind::Integer) CartesianRange(inds)[ind] -@deprecate ind2sub(inds::Union{DimsInteger{N},Indices{N}} where N, ind::AbstractVector{<:Integer}) CartesianRange(inds)[ind] - -@deprecate sub2ind(A::AbstractArray, I...) CartesianToLinear(A)[I...] -@deprecate sub2ind(dims::Tuple{}) CartesianToLinear(dims)[] -@deprecate sub2ind(dims::DimsInteger) CartesianToLinear(dims)[] -@deprecate sub2ind(dims::Indices) CartesianToLinear(dims)[] -@deprecate sub2ind(dims::Tuple{}, I::Integer...) CartesianToLinear(dims)[I...] -@deprecate sub2ind(dims::DimsInteger, I::Integer...) CartesianToLinear(dims)[I...] -@deprecate sub2ind(inds::Indices, I::Integer...) CartesianToLinear(inds)[I...] -@deprecate sub2ind(inds::Tuple{OneTo}, I::Integer...) CartesianToLinear(inds)[I...] -@deprecate sub2ind(inds::Tuple{OneTo}, i::Integer) CartesianToLinear(inds)[i] -@deprecate sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} CartesianToLinear(inds)[CartesianIndex.(I1, I...)] -@deprecate sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} CartesianToLinear(inds)[CartesianIndex.(I1, I...)] +@deprecate ind2sub(A::AbstractArray, ind) CartesianIndices(A)[ind] +@deprecate ind2sub(::Tuple{}, ind::Integer) CartesianIndices()[ind] +@deprecate ind2sub(dims::Tuple{Vararg{Integer,N}} where N, ind::Integer) CartesianIndices(dims)[ind] +@deprecate ind2sub(inds::Tuple{Base.OneTo}, ind::Integer) CartesianIndices(inds)[ind] +@deprecate ind2sub(inds::Tuple{AbstractUnitRange}, ind::Integer) CartesianIndices(inds)[ind] +@deprecate ind2sub(inds::Tuple{Vararg{AbstractUnitRange,N}} where N, ind::Integer) CartesianIndices(inds)[ind] +@deprecate ind2sub(inds::Union{DimsInteger{N},Indices{N}} where N, ind::AbstractVector{<:Integer}) CartesianIndices(inds)[ind] + +@deprecate sub2ind(A::AbstractArray, I...) LinearIndices(A)[I...] +@deprecate sub2ind(dims::Tuple{}) LinearIndices(dims)[] +@deprecate sub2ind(dims::DimsInteger) LinearIndices(dims)[] +@deprecate sub2ind(dims::Indices) LinearIndices(dims)[] +@deprecate sub2ind(dims::Tuple{}, I::Integer...) LinearIndices(dims)[I...] +@deprecate sub2ind(dims::DimsInteger, I::Integer...) LinearIndices(dims)[I...] +@deprecate sub2ind(inds::Indices, I::Integer...) LinearIndices(inds)[I...] +@deprecate sub2ind(inds::Tuple{OneTo}, I::Integer...) LinearIndices(inds)[I...] +@deprecate sub2ind(inds::Tuple{OneTo}, i::Integer) LinearIndices(inds)[i] +@deprecate sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} LinearIndices(inds)[CartesianIndex.(I1, I...)] +@deprecate sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} LinearIndices(inds)[CartesianIndex.(I1, I...)] + +# PR #25113 +@deprecate_binding CartesianRange CartesianIndices # END 0.7 deprecations diff --git a/base/exports.jl b/base/exports.jl index 0eb27e0866f27..8d3f77f7961c4 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -38,8 +38,8 @@ export BitVector, BufferStream, CartesianIndex, - CartesianRange, - CartesianToLinear, + CartesianIndices, + LinearIndices, Channel, Cmd, Colon, diff --git a/base/io.jl b/base/io.jl index 961975cce4bf2..6f3424c7f0bf2 100644 --- a/base/io.jl +++ b/base/io.jl @@ -535,14 +535,14 @@ function write(s::IO, a::SubArray{T,N,<:Array}) where {T,N} elsz = sizeof(T) colsz = size(a,1) * elsz @gc_preserve a if stride(a,1) != 1 - for idxs in CartesianRange(size(a)) + for idxs in CartesianIndices(size(a)) unsafe_write(s, pointer(a, idxs.I), elsz) end return elsz * length(a) elseif N <= 1 return unsafe_write(s, pointer(a, 1), colsz) else - for idxs in CartesianRange((1, size(a)[2:end]...)) + for idxs in CartesianIndices((1, size(a)[2:end]...)) unsafe_write(s, pointer(a, idxs.I), colsz) end return colsz * trailingsize(a,2) diff --git a/base/iterators.jl b/base/iterators.jl index ce2517bb29c0f..2daaa49ae497e 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -191,7 +191,7 @@ CartesianIndex(2, 2) e See also: [`IndexStyle`](@ref), [`axes`](@ref). """ pairs(::IndexLinear, A::AbstractArray) = IndexValue(A, linearindices(A)) -pairs(::IndexCartesian, A::AbstractArray) = IndexValue(A, CartesianRange(axes(A))) +pairs(::IndexCartesian, A::AbstractArray) = IndexValue(A, CartesianIndices(axes(A))) # faster than zip(keys(a), values(a)) for arrays pairs(A::AbstractArray) = pairs(IndexCartesian(), A) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 3b008a6699b75..3417e9fa68515 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -11,7 +11,7 @@ module IteratorsMD using Base: IndexLinear, IndexCartesian, AbstractCartesianIndex, fill_to_length, tail using Base.Iterators: Reverse - export CartesianIndex, CartesianRange, CartesianToLinear + export CartesianIndex, CartesianIndices, LinearIndices """ CartesianIndex(i, j, k...) -> I @@ -27,7 +27,7 @@ module IteratorsMD dimensionality. A `CartesianIndex` is sometimes produced by [`eachindex`](@ref), and - always when iterating with an explicit [`CartesianRange`](@ref). + always when iterating with an explicit [`CartesianIndices`](@ref). # Examples ```jldoctest @@ -144,7 +144,7 @@ module IteratorsMD # nextind with CartesianIndex function Base.nextind(a::AbstractArray{<:Any,N}, i::CartesianIndex{N}) where {N} - _, ni = next(CartesianRange(axes(a)), i) + _, ni = next(CartesianIndices(axes(a)), i) return ni end @@ -155,8 +155,8 @@ module IteratorsMD # Iteration """ - CartesianRange(sz::Dims) -> R - CartesianRange(istart:istop, jstart:jstop, ...) -> R + CartesianIndices(sz::Dims) -> R + CartesianIndices(istart:istop, jstart:jstop, ...) -> R Define a region `R` spanning a multidimensional rectangular range of integer indices. These are most commonly encountered in the @@ -172,14 +172,14 @@ module IteratorsMD Consequently these can be useful for writing algorithms that work in arbitrary dimensions. - CartesianRange(A::AbstractArray) -> R + CartesianIndices(A::AbstractArray) -> R - As a convenience, constructing a CartesianRange from an array makes a + As a convenience, constructing a CartesianIndices from an array makes a range of its indices. # Examples ```jldoctest - julia> foreach(println, CartesianRange((2, 2, 2))) + julia> foreach(println, CartesianIndices((2, 2, 2))) CartesianIndex(1, 1, 1) CartesianIndex(2, 1, 1) CartesianIndex(1, 2, 1) @@ -189,8 +189,8 @@ module IteratorsMD CartesianIndex(1, 2, 2) CartesianIndex(2, 2, 2) - julia> CartesianRange(ones(2,3)) - 2×3 CartesianRange{2,Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}}: + julia> CartesianIndices(ones(2,3)) + 2×3 CartesianIndices{2,Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}}: CartesianIndex(1, 1) CartesianIndex(1, 2) CartesianIndex(1, 3) CartesianIndex(2, 1) CartesianIndex(2, 2) CartesianIndex(2, 3) ``` @@ -198,11 +198,11 @@ module IteratorsMD ## Conversion between linear and cartesian indices Linear index to cartesian index conversion exploits the fact that a - `CartesianRange` is an `AbstractArray` and can be indexed linearly: + `CartesianIndices` is an `AbstractArray` and can be indexed linearly: ```jldoctest subarray - julia> cartesian = CartesianRange(1:3,1:2) - 3×2 CartesianRange{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}: + julia> cartesian = CartesianIndices(1:3,1:2) + 3×2 CartesianIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}: CartesianIndex(1, 1) CartesianIndex(1, 2) CartesianIndex(2, 1) CartesianIndex(2, 2) CartesianIndex(3, 1) CartesianIndex(3, 2) @@ -211,76 +211,76 @@ module IteratorsMD CartesianIndex(1, 2) ``` - For cartesian to linear index conversion, see [`CartesianToLinear`](@ref). + For cartesian to linear index conversion, see [`LinearIndices`](@ref). """ - struct CartesianRange{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{CartesianIndex{N},N} + struct CartesianIndices{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{CartesianIndex{N},N} indices::R end - CartesianRange(::Tuple{}) = CartesianRange{0,typeof(())}(()) - CartesianRange(inds::NTuple{N,AbstractUnitRange{Int}}) where {N} = - CartesianRange{N,typeof(inds)}(inds) - CartesianRange(inds::Vararg{AbstractUnitRange{Int},N}) where {N} = - CartesianRange(inds) - CartesianRange(inds::NTuple{N,AbstractUnitRange{<:Integer}}) where {N} = - CartesianRange(map(r->convert(AbstractUnitRange{Int}, r), inds)) - CartesianRange(inds::Vararg{AbstractUnitRange{<:Integer},N}) where {N} = - CartesianRange(inds) - - CartesianRange(index::CartesianIndex) = CartesianRange(index.I) - CartesianRange(sz::NTuple{N,<:Integer}) where {N} = CartesianRange(map(Base.OneTo, sz)) - CartesianRange(inds::NTuple{N,Union{<:Integer,AbstractUnitRange{<:Integer}}}) where {N} = - CartesianRange(map(i->first(i):last(i), inds)) - - CartesianRange(A::AbstractArray) = CartesianRange(axes(A)) - - convert(::Type{Tuple{}}, R::CartesianRange{0}) = () - convert(::Type{NTuple{N,AbstractUnitRange{Int}}}, R::CartesianRange{N}) where {N} = + 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::CartesianRange{N}) where {N} = + convert(::Type{NTuple{N,AbstractUnitRange}}, R::CartesianIndices{N}) where {N} = convert(NTuple{N,AbstractUnitRange{Int}}, R) - convert(::Type{NTuple{N,UnitRange{Int}}}, R::CartesianRange{N}) where {N} = + convert(::Type{NTuple{N,UnitRange{Int}}}, R::CartesianIndices{N}) where {N} = UnitRange{Int}.(convert(NTuple{N,AbstractUnitRange}, R)) - convert(::Type{NTuple{N,UnitRange}}, R::CartesianRange{N}) where {N} = + convert(::Type{NTuple{N,UnitRange}}, R::CartesianIndices{N}) where {N} = UnitRange.(convert(NTuple{N,AbstractUnitRange}, R)) - convert(::Type{Tuple{Vararg{AbstractUnitRange{Int}}}}, R::CartesianRange{N}) where {N} = + convert(::Type{Tuple{Vararg{AbstractUnitRange{Int}}}}, R::CartesianIndices{N}) where {N} = convert(NTuple{N,AbstractUnitRange{Int}}, R) - convert(::Type{Tuple{Vararg{AbstractUnitRange}}}, R::CartesianRange) = + convert(::Type{Tuple{Vararg{AbstractUnitRange}}}, R::CartesianIndices) = convert(Tuple{Vararg{AbstractUnitRange{Int}}}, R) - convert(::Type{Tuple{Vararg{UnitRange{Int}}}}, R::CartesianRange{N}) where {N} = + convert(::Type{Tuple{Vararg{UnitRange{Int}}}}, R::CartesianIndices{N}) where {N} = convert(NTuple{N,UnitRange{Int}}, R) - convert(::Type{Tuple{Vararg{UnitRange}}}, R::CartesianRange) = + convert(::Type{Tuple{Vararg{UnitRange}}}, R::CartesianIndices) = convert(Tuple{Vararg{UnitRange{Int}}}, R) # AbstractArray implementation - Base.IndexStyle(::Type{CartesianRange{N,R}}) where {N,R} = IndexCartesian() - @inline Base.getindex(iter::CartesianRange{N,R}, I::Vararg{Int, N}) where {N,R} = CartesianIndex(first.(iter.indices) .- 1 .+ I) + 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::CartesianRange) = ndims(typeof(R)) - ndims(::Type{CartesianRange{N}}) where {N} = N - ndims(::Type{CartesianRange{N,TT}}) where {N,TT} = N + ndims(R::CartesianIndices) = ndims(typeof(R)) + ndims(::Type{CartesianIndices{N}}) where {N} = N + ndims(::Type{CartesianIndices{N,TT}}) where {N,TT} = N - eachindex(::IndexCartesian, A::AbstractArray) = CartesianRange(axes(A)) + eachindex(::IndexCartesian, A::AbstractArray) = CartesianIndices(axes(A)) @inline function eachindex(::IndexCartesian, A::AbstractArray, B::AbstractArray...) axsA = axes(A) all(x->axes(x) == axsA, B) || Base.throw_eachindex_mismatch(IndexCartesian(), A, B...) - CartesianRange(axsA) + CartesianIndices(axsA) end - eltype(R::CartesianRange) = eltype(typeof(R)) - eltype(::Type{CartesianRange{N}}) where {N} = CartesianIndex{N} - eltype(::Type{CartesianRange{N,TT}}) where {N,TT} = CartesianIndex{N} - iteratorsize(::Type{<:CartesianRange}) = Base.HasShape() + eltype(R::CartesianIndices) = eltype(typeof(R)) + eltype(::Type{CartesianIndices{N}}) where {N} = CartesianIndex{N} + eltype(::Type{CartesianIndices{N,TT}}) where {N,TT} = CartesianIndex{N} + iteratorsize(::Type{<:CartesianIndices}) = Base.HasShape() - @inline function start(iter::CartesianRange) + @inline function start(iter::CartesianIndices) iterfirst, iterlast = first(iter), last(iter) if any(map(>, iterfirst.I, iterlast.I)) return iterlast+1 end iterfirst end - @inline function next(iter::CartesianRange, state) + @inline function next(iter::CartesianIndices, state) state, CartesianIndex(inc(state.I, first(iter).I, last(iter).I)) end # increment & carry @@ -293,37 +293,37 @@ module IteratorsMD newtail = inc(tail(state), tail(start), tail(stop)) (start[1], newtail...) end - @inline done(iter::CartesianRange, state) = state.I[end] > last(iter.indices[end]) + @inline done(iter::CartesianIndices, state) = state.I[end] > last(iter.indices[end]) # 0-d cartesian ranges are special-cased to iterate once and only once - start(iter::CartesianRange{0}) = false - next(iter::CartesianRange{0}, state) = CartesianIndex(), true - done(iter::CartesianRange{0}, state) = state + start(iter::CartesianIndices{0}) = false + next(iter::CartesianIndices{0}, state) = CartesianIndex(), true + done(iter::CartesianIndices{0}, state) = state - size(iter::CartesianRange) = map(dimlength, first(iter).I, last(iter).I) + size(iter::CartesianIndices) = map(dimlength, first(iter).I, last(iter).I) dimlength(start, stop) = stop-start+1 - length(iter::CartesianRange) = prod(size(iter)) + length(iter::CartesianIndices) = prod(size(iter)) - first(iter::CartesianRange) = CartesianIndex(map(first, iter.indices)) - last(iter::CartesianRange) = CartesianIndex(map(last, iter.indices)) + first(iter::CartesianIndices) = CartesianIndex(map(first, iter.indices)) + last(iter::CartesianIndices) = CartesianIndex(map(last, iter.indices)) - @inline function in(i::CartesianIndex{N}, r::CartesianRange{N}) where {N} + @inline function in(i::CartesianIndex{N}, r::CartesianIndices{N}) where {N} _in(true, i.I, first(r).I, last(r).I) end _in(b, ::Tuple{}, ::Tuple{}, ::Tuple{}) = b @inline _in(b, i, start, stop) = _in(b & (start[1] <= i[1] <= stop[1]), tail(i), tail(start), tail(stop)) - simd_outer_range(iter::CartesianRange{0}) = iter - function simd_outer_range(iter::CartesianRange) - CartesianRange(tail(iter.indices)) + simd_outer_range(iter::CartesianIndices{0}) = iter + function simd_outer_range(iter::CartesianIndices) + CartesianIndices(tail(iter.indices)) end - simd_inner_length(iter::CartesianRange{0}, ::CartesianIndex) = 1 - simd_inner_length(iter::CartesianRange, I::CartesianIndex) = length(iter.indices[1]) + simd_inner_length(iter::CartesianIndices{0}, ::CartesianIndex) = 1 + simd_inner_length(iter::CartesianIndices, I::CartesianIndex) = length(iter.indices[1]) - simd_index(iter::CartesianRange{0}, ::CartesianIndex, I1::Int) = first(iter) - @inline function simd_index(iter::CartesianRange, Ilast::CartesianIndex, I1::Int) + simd_index(iter::CartesianIndices{0}, ::CartesianIndex, I1::Int) = first(iter) + @inline function simd_index(iter::CartesianIndices, Ilast::CartesianIndex, I1::Int) CartesianIndex((I1+first(iter.indices[1]), Ilast.I...)) end @@ -346,20 +346,20 @@ module IteratorsMD i, j = split(I.I, V) CartesianIndex(i), CartesianIndex(j) end - function split(R::CartesianRange, V::Val) + function split(R::CartesianIndices, V::Val) i, j = split(R.indices, V) - CartesianRange(i), CartesianRange(j) + CartesianIndices(i), CartesianIndices(j) end - # reversed CartesianRange iteration - @inline function start(r::Reverse{<:CartesianRange}) + # reversed CartesianIndices iteration + @inline function start(r::Reverse{<:CartesianIndices}) iterfirst, iterlast = last(r.itr), first(r.itr) if any(map(<, iterfirst.I, iterlast.I)) return iterlast-1 end iterfirst end - @inline function next(r::Reverse{<:CartesianRange}, state) + @inline function next(r::Reverse{<:CartesianIndices}, state) state, CartesianIndex(dec(state.I, last(r.itr).I, first(r.itr).I)) end # decrement & carry @@ -372,26 +372,26 @@ module IteratorsMD newtail = dec(tail(state), tail(start), tail(stop)) (start[1], newtail...) end - @inline done(r::Reverse{<:CartesianRange}, state) = state.I[end] < first(r.itr.indices[end]) + @inline done(r::Reverse{<:CartesianIndices}, state) = state.I[end] < first(r.itr.indices[end]) # 0-d cartesian ranges are special-cased to iterate once and only once - start(iter::Reverse{<:CartesianRange{0}}) = false - next(iter::Reverse{<:CartesianRange{0}}, state) = CartesianIndex(), true - done(iter::Reverse{<:CartesianRange{0}}, state) = state + start(iter::Reverse{<:CartesianIndices{0}}) = false + next(iter::Reverse{<:CartesianIndices{0}}, state) = CartesianIndex(), true + done(iter::Reverse{<:CartesianIndices{0}}, state) = state """ - CartesianToLinear(inds::CartesianRange) -> R - CartesianToLinear(sz::Dims) -> R - CartesianToLinear(istart:istop, jstart:jstop, ...) -> R + LinearIndices(inds::CartesianIndices) -> R + LinearIndices(sz::Dims) -> R + LinearIndices(istart:istop, jstart:jstop, ...) -> R - Define a mapping between cartesian indices and the corresponding linear index into a CartesianRange + Define a mapping between cartesian indices and the corresponding linear index into a CartesianIndices # Example The main purpose of this type is intuitive conversion from cartesian to linear indexing: ```jldoctest subarray - julia> linear = CartesianToLinear(1:3,1:2) - CartesianToLinear{2,Tuple{UnitRange{Int64},UnitRange{Int64}}} with indices 1:3×1:2: + julia> linear = LinearIndices(1:3,1:2) + LinearIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}} with indices 1:3×1:2: 1 4 2 5 3 6 @@ -400,25 +400,25 @@ module IteratorsMD 4 ``` """ - struct CartesianToLinear{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{Int,N} + struct LinearIndices{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{Int,N} indices::R end - CartesianToLinear(inds::CartesianRange{N,R}) where {N,R} = CartesianToLinear{N,R}(inds.indices) - CartesianToLinear(::Tuple{}) = CartesianToLinear(CartesianRange(())) - CartesianToLinear(inds::NTuple{N,AbstractUnitRange{Int}}) where {N} = CartesianToLinear(CartesianRange(inds)) - CartesianToLinear(inds::Vararg{AbstractUnitRange{Int},N}) where {N} = CartesianToLinear(CartesianRange(inds)) - CartesianToLinear(inds::NTuple{N,AbstractUnitRange{<:Integer}}) where {N} = CartesianToLinear(CartesianRange(inds)) - CartesianToLinear(inds::Vararg{AbstractUnitRange{<:Integer},N}) where {N} = CartesianToLinear(CartesianRange(inds)) - CartesianToLinear(index::CartesianIndex) = CartesianToLinear(CartesianRange(index)) - CartesianToLinear(sz::NTuple{N,<:Integer}) where {N} = CartesianToLinear(CartesianRange(sz)) - CartesianToLinear(inds::NTuple{N,Union{<:Integer,AbstractUnitRange{<:Integer}}}) where {N} = CartesianToLinear(CartesianRange(inds)) - CartesianToLinear(A::AbstractArray) = CartesianToLinear(CartesianRange(A)) + 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{CartesianToLinear{N,R}}) where {N,R} = IndexCartesian() - Base.axes(iter::CartesianToLinear{N,R}) where {N,R} = iter.indices - @inline function Base.getindex(iter::CartesianToLinear{N,R}, I::Vararg{Int, N}) where {N,R} + Base.IndexStyle(::Type{LinearIndices{N,R}}) where {N,R} = IndexCartesian() + Base.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)...] @@ -544,7 +544,7 @@ show(io::IO, r::LogicalIndex) = print(io, "Base.LogicalIndex(", r.mask, ")") return (r, start(r), 1) end @inline function start(L::LogicalIndex{<:CartesianIndex}) - r = CartesianRange(axes(L.mask)) + r = CartesianIndices(axes(L.mask)) return (r, start(r), 1) end @propagate_inbounds function next(L::LogicalIndex, s) @@ -967,7 +967,7 @@ function accumulate!(op, B, A, dim::Integer) # We can accumulate to a temporary variable, which allows # register usage and will be slightly faster ind1 = inds_t[1] - @inbounds for I in CartesianRange(tail(inds_t)) + @inbounds for I in CartesianIndices(tail(inds_t)) tmp = convert(eltype(B), A[first(ind1), I]) B[first(ind1), I] = tmp for i_1 = first(ind1)+1:last(ind1) @@ -976,8 +976,8 @@ function accumulate!(op, B, A, dim::Integer) end end else - R1 = CartesianRange(axes(A)[1:dim-1]) # not type-stable - R2 = CartesianRange(axes(A)[dim+1:end]) + R1 = CartesianIndices(axes(A)[1:dim-1]) # not type-stable + R2 = CartesianIndices(axes(A)[dim+1:end]) _accumulate!(op, B, A, R1, inds_t[dim], R2) # use function barrier end return B @@ -1113,8 +1113,8 @@ function copy!(dest::AbstractArray{T,N}, src::AbstractArray{T,N}) where {T,N} dest end -function copy!(dest::AbstractArray{T1,N}, Rdest::CartesianRange{N}, - src::AbstractArray{T2,N}, Rsrc::CartesianRange{N}) where {T1,T2,N} +function copy!(dest::AbstractArray{T1,N}, Rdest::CartesianIndices{N}, + src::AbstractArray{T2,N}, Rsrc::CartesianIndices{N}) where {T1,T2,N} isempty(Rdest) && return dest if size(Rdest) != size(Rsrc) throw(ArgumentError("source and destination must have same size (got $(size(Rsrc)) and $(size(Rdest)))")) @@ -1139,12 +1139,12 @@ function copy!(dest::AbstractArray{T1,N}, Rdest::CartesianRange{N}, end """ - copy!(dest, Rdest::CartesianRange, src, Rsrc::CartesianRange) -> dest + copy!(dest, Rdest::CartesianIndices, src, Rsrc::CartesianIndices) -> dest Copy the block of `src` in the range of `Rsrc` to the block of `dest` in the range of `Rdest`. The sizes of the two regions must match. """ -copy!(::AbstractArray, ::CartesianRange, ::AbstractArray, ::CartesianRange) +copy!(::AbstractArray, ::CartesianIndices, ::AbstractArray, ::CartesianIndices) # circshift! circshift!(dest::AbstractArray, src, ::Tuple{}) = copy!(dest, src) @@ -1197,7 +1197,7 @@ circshift!(dest::AbstractArray, src, shiftamt) = circshift!(dest, src, (shiftamt end # At least one of inds, shiftamt is empty function _circshift!(dest, rdest, src, rsrc, inds, shiftamt) - copy!(dest, CartesianRange(rdest), src, CartesianRange(rsrc)) + copy!(dest, CartesianIndices(rdest), src, CartesianIndices(rsrc)) end # circcopy! @@ -1260,7 +1260,7 @@ end # At least one of indsdest, indssrc are empty (and both should be, since we've checked) function _circcopy!(dest, rdest, indsdest, src, rsrc, indssrc) - copy!(dest, CartesianRange(rdest), src, CartesianRange(rsrc)) + copy!(dest, CartesianIndices(rdest), src, CartesianIndices(rsrc)) end ### BitArrays @@ -1751,12 +1751,12 @@ end @noinline function extrema!(B, A) sA = size(A) sB = size(B) - for I in CartesianRange(sB) + for I in CartesianIndices(sB) AI = A[I] B[I] = (AI, AI) end Bmax = CartesianIndex(sB) - @inbounds @simd for I in CartesianRange(sA) + @inbounds @simd for I in CartesianIndices(sA) J = min(Bmax,I) BJ = B[J] AI = A[I] diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index 20e5fba8579ae..211d6155f7ae4 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -162,16 +162,16 @@ function _copy!(P::PermutedDimsArray{T,N,perm}, src) where {T,N,perm} if d == ndims(src) copy!(parent(P), src) # it's not permuted else - R1 = CartesianRange(axes(src)[1:d]) + R1 = CartesianIndices(axes(src)[1:d]) d1 = findfirst(equalto(d+1), perm) # first permuted dim of dest - R2 = CartesianRange(axes(src)[d+2:d1-1]) - R3 = CartesianRange(axes(src)[d1+1:end]) + R2 = CartesianIndices(axes(src)[d+2:d1-1]) + R3 = CartesianIndices(axes(src)[d1+1:end]) _permutedims!(P, src, R1, R2, R3, d+1, d1) end return P end -@noinline function _permutedims!(P::PermutedDimsArray, src, R1::CartesianRange{0}, R2, R3, ds, dp) +@noinline function _permutedims!(P::PermutedDimsArray, src, R1::CartesianIndices{0}, R2, R3, ds, dp) ip, is = axes(src, dp), axes(src, ds) for jo in first(ip):8:last(ip), io in first(is):8:last(is) for I3 in R3, I2 in R2 diff --git a/base/reducedim.jl b/base/reducedim.jl index 7c5bcb1e3c45a..28ea3895b40d1 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -228,7 +228,7 @@ function _mapreducedim!(f, op, R::AbstractArray, A::AbstractArray) if reducedim1(R, A) # keep the accumulator as a local variable when reducing along the first dimension i1 = first(indices1(R)) - @inbounds for IA in CartesianRange(indsAt) + @inbounds for IA in CartesianIndices(indsAt) IR = Broadcast.newindex(IA, keep, Idefault) r = R[i1,IR] @simd for i in axes(A, 1) @@ -237,7 +237,7 @@ function _mapreducedim!(f, op, R::AbstractArray, A::AbstractArray) R[i1,IR] = r end else - @inbounds for IA in CartesianRange(indsAt) + @inbounds for IA in CartesianIndices(indsAt) IR = Broadcast.newindex(IA, keep, Idefault) @simd for i in axes(A, 1) R[i,IR] = op(R[i,IR], f(A[i,IA])) @@ -652,7 +652,7 @@ function findminmax!(f, Rval, Rind, A::AbstractArray{T,N}) where {T,N} zi = zero(eltype(ks)) if reducedim1(Rval, A) i1 = first(indices1(Rval)) - @inbounds for IA in CartesianRange(indsAt) + @inbounds for IA in CartesianIndices(indsAt) IR = Broadcast.newindex(IA, keep, Idefault) tmpRv = Rval[i1,IR] tmpRi = Rind[i1,IR] @@ -668,7 +668,7 @@ function findminmax!(f, Rval, Rind, A::AbstractArray{T,N}) where {T,N} Rind[i1,IR] = tmpRi end else - @inbounds for IA in CartesianRange(indsAt) + @inbounds for IA in CartesianIndices(indsAt) IR = Broadcast.newindex(IA, keep, Idefault) for i in axes(A, 1) tmpAv = A[i,IA] diff --git a/base/statistics.jl b/base/statistics.jl index 593f7c3743053..85f5026a18b10 100644 --- a/base/statistics.jl +++ b/base/statistics.jl @@ -144,7 +144,7 @@ function centralize_sumabs2!(R::AbstractArray{S}, A::AbstractArray, means::Abstr keep, Idefault = Broadcast.shapeindexer(indsAt, indsRt) if reducedim1(R, A) i1 = first(indices1(R)) - @inbounds for IA in CartesianRange(indsAt) + @inbounds for IA in CartesianIndices(indsAt) IR = Broadcast.newindex(IA, keep, Idefault) r = R[i1,IR] m = means[i1,IR] @@ -154,7 +154,7 @@ function centralize_sumabs2!(R::AbstractArray{S}, A::AbstractArray, means::Abstr R[i1,IR] = r end else - @inbounds for IA in CartesianRange(indsAt) + @inbounds for IA in CartesianIndices(indsAt) IR = Broadcast.newindex(IA, keep, Idefault) @simd for i in axes(A, 1) R[i,IR] += abs2(A[i,IA] - means[i,IR]) diff --git a/doc/src/devdocs/subarrays.md b/doc/src/devdocs/subarrays.md index 62fc64413a39a..dd82daf382e38 100644 --- a/doc/src/devdocs/subarrays.md +++ b/doc/src/devdocs/subarrays.md @@ -23,7 +23,7 @@ For these types, the underlying information is more naturally described in terms cartesian indices. The `getindex` and `setindex!` functions for `AbstractArray` types may include automatic conversion -between indexing types. For explicit conversion, [`CartesianRange`](@ref) can be used. +between indexing types. For explicit conversion, [`CartesianIndices`](@ref) can be used. While converting from a cartesian index to a linear index is fast (it's just multiplication and addition), converting from a linear index to a cartesian index is very slow: it relies on the diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index b546a62a79b37..c14d95335520e 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -82,12 +82,12 @@ Base.Broadcast.DefaultArrayStyle ```@docs Base.getindex(::AbstractArray, ::Any...) Base.setindex!(::AbstractArray, ::Any, ::Any...) -Base.copy!(::AbstractArray, ::CartesianRange, ::AbstractArray, ::CartesianRange) +Base.copy!(::AbstractArray, ::CartesianIndices, ::AbstractArray, ::CartesianIndices) Base.isassigned Base.Colon Base.CartesianIndex -Base.CartesianRange -Base.CartesianToLinear +Base.CartesianIndices +Base.LinearIndices Base.to_indices Base.checkbounds Base.checkindex diff --git a/test/TestHelpers.jl b/test/TestHelpers.jl index ef6d5610bc200..f10a10bf1dfaf 100644 --- a/test/TestHelpers.jl +++ b/test/TestHelpers.jl @@ -162,7 +162,7 @@ Base.parent(A::OffsetArray) = A.parent errmsg(A) = error("size not supported for arrays with indices $(axes(A)); see https://docs.julialang.org/en/latest/devdocs/offset-arrays/") Base.size(A::OffsetArray) = errmsg(A) Base.size(A::OffsetArray, d) = errmsg(A) -Base.eachindex(::IndexCartesian, A::OffsetArray) = CartesianRange(axes(A)) +Base.eachindex(::IndexCartesian, A::OffsetArray) = CartesianIndices(axes(A)) Base.eachindex(::IndexLinear, A::OffsetVector) = axes(A, 1) # Implementations of indices and indices1. Since bounds-checking is diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 2a5bf5f6d69d1..baf3d40e67ae4 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -114,20 +114,20 @@ end @testset "index conversion" begin @testset "0-dimensional" begin - @test CartesianToLinear()[1] == 1 - @test_throws BoundsError CartesianToLinear()[2] - @test CartesianToLinear()[1,1] == 1 - @test CartesianRange()[1] == CartesianIndex() - @test_throws BoundsError CartesianRange()[2] + @test LinearIndices()[1] == 1 + @test_throws BoundsError LinearIndices()[2] + @test LinearIndices()[1,1] == 1 + @test CartesianIndices()[1] == CartesianIndex() + @test_throws BoundsError CartesianIndices()[2] end @testset "1-dimensional" begin for i = 1:3 - @test CartesianToLinear((3,))[i] == i - @test CartesianRange((3,))[i] == CartesianIndex(i,) + @test LinearIndices((3,))[i] == i + @test CartesianIndices((3,))[i] == CartesianIndex(i,) end - @test CartesianToLinear((3,))[2,1] == 2 - @test_throws BoundsError CartesianRange((3,))[2,2] + @test LinearIndices((3,))[2,1] == 2 + @test_throws BoundsError CartesianIndices((3,))[2,2] # ambiguity btw cartesian indexing and linear indexing in 1d when # indices may be nontraditional @test_throws ArgumentError Base._sub2ind((1:3,), 2) @@ -136,34 +136,34 @@ end @testset "2-dimensional" begin k = 0 - cartesian = CartesianRange((4,3)) - linear = CartesianToLinear(cartesian) + cartesian = CartesianIndices((4,3)) + linear = LinearIndices(cartesian) for j = 1:3, i = 1:4 @test linear[i,j] == (k+=1) @test cartesian[k] == CartesianIndex(i,j) - @test CartesianToLinear(0:3,3:5)[i-1,j+2] == k - @test CartesianRange(0:3,3:5)[k] == CartesianIndex(i-1,j+2) + @test LinearIndices(0:3,3:5)[i-1,j+2] == k + @test CartesianIndices(0:3,3:5)[k] == CartesianIndex(i-1,j+2) end end @testset "3-dimensional" begin l = 0 for k = 1:2, j = 1:3, i = 1:4 - @test CartesianToLinear((4,3,2))[i,j,k] == (l+=1) - @test CartesianRange((4,3,2))[l] == CartesianIndex(i,j,k) - @test CartesianToLinear(1:4,1:3,1:2)[i,j,k] == l - @test CartesianRange(1:4,1:3,1:2)[l] == CartesianIndex(i,j,k) - @test CartesianToLinear(0:3,3:5,-101:-100)[i-1,j+2,k-102] == l - @test CartesianRange(0:3,3:5,-101:-100)[l] == CartesianIndex(i-1, j+2, k-102) + @test LinearIndices((4,3,2))[i,j,k] == (l+=1) + @test CartesianIndices((4,3,2))[l] == CartesianIndex(i,j,k) + @test LinearIndices(1:4,1:3,1:2)[i,j,k] == l + @test CartesianIndices(1:4,1:3,1:2)[l] == CartesianIndex(i,j,k) + @test LinearIndices(0:3,3:5,-101:-100)[i-1,j+2,k-102] == l + @test CartesianIndices(0:3,3:5,-101:-100)[l] == CartesianIndex(i-1, j+2, k-102) end local A = reshape(collect(1:9), (3,3)) - @test CartesianRange(size(A))[6] == CartesianIndex(3,2) - @test CartesianToLinear(size(A))[3, 2] == 6 - @test CartesianRange(A)[6] == CartesianIndex(3,2) - @test CartesianToLinear(A)[3, 2] == 6 + @test CartesianIndices(size(A))[6] == CartesianIndex(3,2) + @test LinearIndices(size(A))[3, 2] == 6 + @test CartesianIndices(A)[6] == CartesianIndex(3,2) + @test LinearIndices(A)[3, 2] == 6 for i in 1:length(A) - @test CartesianToLinear(A)[CartesianRange(A)[i]] == i + @test LinearIndices(A)[CartesianIndices(A)[i]] == i end @testset "PR #9256" begin @@ -222,7 +222,7 @@ Base.convert(::Type{TSlow }, X::AbstractArray{T,N}) where {T,N } = convert( Base.convert(::Type{TSlow{T }}, X::AbstractArray{_,N}) where {T,N,_} = convert(TSlow{T,N}, X) Base.convert(::Type{TSlow{T,N}}, X::AbstractArray ) where {T,N } = begin A = TSlow(T, size(X)) - for I in CartesianRange(size(X)) + for I in CartesianIndices(size(X)) A[I.I...] = X[I.I...] end A @@ -618,7 +618,7 @@ function test_ind2sub(::Type{TestAbstractArray}) dims = tuple(rand(1:5, n)...) len = prod(dims) A = reshape(collect(1:len), dims...) - I = CartesianRange(dims) + I = CartesianIndices(dims) for i in 1:len @test A[I[i]] == A[i] end @@ -828,10 +828,10 @@ end @test isempty(v3::Vector{Float64}) end -@testset "CartesianRange" begin +@testset "CartesianIndices" begin xrng = 2:4 yrng = 1:5 - CR = CartesianRange((xrng,yrng)) + CR = CartesianIndices((xrng,yrng)) for (i,i_idx) in enumerate(xrng) for (j,j_idx) in enumerate(yrng) @@ -845,6 +845,6 @@ end @test CR[i_lin] == CartesianIndex(xrng[i],yrng[j]) end - @test CartesianRange(ones(2,3)) == CartesianRange((2,3)) - @test CartesianToLinear((2,3)) == [1 3 5; 2 4 6] + @test CartesianIndices(ones(2,3)) == CartesianIndices((2,3)) + @test LinearIndices((2,3)) == [1 3 5; 2 4 6] end diff --git a/test/arrayops.jl b/test/arrayops.jl index 2165bcdef2eb4..6c4a55ce33825 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -1211,7 +1211,7 @@ end @testset "eachindexvalue" begin A14 = [11 13; 12 14] - R = CartesianRange(axes(A14)) + R = CartesianIndices(axes(A14)) @test [a for (a,b) in pairs(IndexLinear(), A14)] == [1,2,3,4] @test [a for (a,b) in pairs(IndexCartesian(), A14)] == vec(collect(R)) @test [b for (a,b) in pairs(IndexLinear(), A14)] == [11,12,13,14] @@ -1565,7 +1565,7 @@ end @test !isless(CartesianIndex((1,2)), CartesianIndex((2,1))) a = spzeros(2,3) - @test CartesianRange(size(a)) == eachindex(a) + @test CartesianIndices(size(a)) == eachindex(a) a[CartesianIndex{2}(2,3)] = 5 @test a[2,3] == 5 b = view(a, 1:2, 2:3) @@ -1573,10 +1573,10 @@ end @test a[1,2] == 7 @test 2*CartesianIndex{3}(1,2,3) == CartesianIndex{3}(2,4,6) - R = CartesianRange(2:5, 3:5) + R = CartesianIndices(2:5, 3:5) @test eltype(R) <: CartesianIndex{2} @test eltype(typeof(R)) <: CartesianIndex{2} - @test eltype(CartesianRange{2}) <: CartesianIndex{2} + @test eltype(CartesianIndices{2}) <: CartesianIndex{2} indices = collect(R) @test indices[1] == CartesianIndex{2}(2,3) @test indices[2] == CartesianIndex{2}(3,3) @@ -1598,8 +1598,8 @@ end @test @inferred(convert(NTuple{2,UnitRange}, R)) === (2:5, 3:5) @test @inferred(convert(Tuple{Vararg{UnitRange}}, R)) === (2:5, 3:5) - @test CartesianRange((3:5,-7:7)) == CartesianRange(3:5,-7:7) - @test CartesianRange((3,-7:7)) == CartesianRange(3:3,-7:7) + @test CartesianIndices((3:5,-7:7)) == CartesianIndices(3:5,-7:7) + @test CartesianIndices((3,-7:7)) == CartesianIndices(3:3,-7:7) end # All we really care about is that we have an optimized @@ -1629,19 +1629,19 @@ end @test done(itr, state) end -R = CartesianRange((1,3)) +R = CartesianIndices((1,3)) @test done(R, start(R)) == false -R = CartesianRange((0,3)) +R = CartesianIndices((0,3)) @test done(R, start(R)) == true -R = CartesianRange((3,0)) +R = CartesianIndices((3,0)) @test done(R, start(R)) == true @testset "multi-array eachindex" begin local a = zeros(2,2) local b = view(zeros(3,2), 1:2, :) - @test @inferred(eachindex(Base.IndexCartesian(), a, b)) == CartesianRange((2,2)) + @test @inferred(eachindex(Base.IndexCartesian(), a, b)) == CartesianIndices((2,2)) @test @inferred(eachindex(Base.IndexLinear(), a, b)) == 1:4 - @test @inferred(eachindex(a, b)) == CartesianRange((2,2)) + @test @inferred(eachindex(a, b)) == CartesianIndices((2,2)) @test @inferred(eachindex(a, a)) == 1:4 @test_throws DimensionMismatch eachindex(a, rand(3,3)) @test_throws DimensionMismatch eachindex(b, rand(3,3)) diff --git a/test/copy.jl b/test/copy.jl index 96b6f9a706455..43ac928b6cf7c 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -49,15 +49,15 @@ chnlprod(x) = Channel(c->for i in x; put!(c,i); end) end end -@testset "with CartesianRange" begin +@testset "with CartesianIndices" begin let A = reshape(1:6, 3, 2), B = similar(A) - RA = CartesianRange(axes(A)) + RA = CartesianIndices(axes(A)) copy!(B, RA, A, RA) @test B == A end let A = reshape(1:6, 3, 2), B = zeros(8,8) - RA = CartesianRange(axes(A)) - copy!(B, CartesianRange((5:7,2:3)), A, RA) + RA = CartesianIndices(axes(A)) + copy!(B, CartesianIndices((5:7,2:3)), A, RA) @test B[5:7,2:3] == A B[5:7,2:3] = 0 @test all(x->x==0, B) diff --git a/test/euler.jl b/test/euler.jl index 7e81d05b635a2..84d29c6de1929 100644 --- a/test/euler.jl +++ b/test/euler.jl @@ -65,7 +65,7 @@ end #11: 70600674 function euler11(grid,n) m = typemin(eltype(grid)) - tolinear = CartesianToLinear(size(grid)) + tolinear = LinearIndices(size(grid)) for i = n:size(grid,1)-n+1, j = n:size(grid,2)-n+1, di = -1:1, dj = -1:1 diff --git a/test/offsetarray.jl b/test/offsetarray.jl index 09943ef91ae14..7aefd7a360aca 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -78,7 +78,7 @@ for i = 1:9 @test A_3_3[i] == i end @test_throws BoundsError A[CartesianIndex(1,1)] @test_throws BoundsError S[CartesianIndex(1,1)] @test eachindex(A) == 1:4 -@test eachindex(S) == CartesianRange((0:1,3:4)) +@test eachindex(S) == CartesianIndices((0:1,3:4)) # logical indexing @test A[A .> 2] == [3,4] diff --git a/test/perf/array/indexing.jl b/test/perf/array/indexing.jl index eda9b1a71541a..d77e2d15669e3 100644 --- a/test/perf/array/indexing.jl +++ b/test/perf/array/indexing.jl @@ -39,7 +39,7 @@ end function sumcartesian(A, n) s = zero(eltype(A)) + zero(eltype(A)) for k = 1:n - for I in CartesianRange(size(A)) + for I in CartesianIndices(size(A)) val = unsafe_getindex(A, I) s += val end diff --git a/test/perf/array/perf.jl b/test/perf/array/perf.jl index 001b69c078b62..e0ed745e294dc 100644 --- a/test/perf/array/perf.jl +++ b/test/perf/array/perf.jl @@ -13,7 +13,7 @@ for Ar in Alist @timeit sumelt(Ar, 10^5) string("sumeltIs ", briefname(Ar)) string("for a in A indexing, ", briefname(Ar)) sz @timeit sumeach(Ar, 10^5) string("sumeachIs ", briefname(Ar)) string("for I in eachindex(A), ", briefname(Ar)) sz @timeit sumlinear(Ar, 10^5) string("sumlinearIs ", briefname(Ar)) string("for I in 1:length(A), ", briefname(Ar)) sz - @timeit sumcartesian(Ar, 10^5) string("sumcartesianIs ", briefname(Ar)) string("for I in CartesianRange(size(A)), ", briefname(Ar)) sz + @timeit sumcartesian(Ar, 10^5) string("sumcartesianIs ", briefname(Ar)) string("for I in CartesianIndices(size(A)), ", briefname(Ar)) sz @timeit sumcolon(Ar, 10^5) string("sumcolonIs ", briefname(Ar)) string("colon indexing, ", briefname(Ar)) sz @timeit sumrange(Ar, 10^5) string("sumrangeIs ", briefname(Ar)) string("range indexing, ", briefname(Ar)) sz @timeit sumlogical(Ar, 10^5) string("sumlogicalIs ", briefname(Ar)) string("logical indexing, ", briefname(Ar)) sz @@ -25,7 +25,7 @@ for Ar in Alist @timeit sumelt(Ar, 10^5) string("sumeltFs ", briefname(Ar)) string("for a in A indexing, ", briefname(Ar)) sz @timeit sumeach(Ar, 10^5) string("sumeachFs ", briefname(Ar)) string("for I in eachindex(A), ", briefname(Ar)) sz @timeit sumlinear(Ar, 10^5) string("sumlinearFs ", briefname(Ar)) string("for I in 1:length(A), ", briefname(Ar)) sz - @timeit sumcartesian(Ar, 10^5) string("sumcartesianFs ", briefname(Ar)) string("for I in CartesianRange(size(A)), ", briefname(Ar)) sz + @timeit sumcartesian(Ar, 10^5) string("sumcartesianFs ", briefname(Ar)) string("for I in CartesianIndices(size(A)), ", briefname(Ar)) sz @timeit sumcolon(Ar, 10^5) string("sumcolonFs ", briefname(Ar)) string("colon indexing, ", briefname(Ar)) sz @timeit sumrange(Ar, 10^5) string("sumrangeFs ", briefname(Ar)) string("range indexing, ", briefname(Ar)) sz @timeit sumlogical(Ar, 10^5) string("sumlogicalFs ", briefname(Ar)) string("logical indexing, ", briefname(Ar)) sz @@ -39,7 +39,7 @@ for Ar in Alist @timeit sumelt(Ar, 100) string("sumeltIb ", briefname(Ar)) string("for a in A indexing, ", briefname(Ar)) sz @timeit sumeach(Ar, 100) string("sumeachIb ", briefname(Ar)) string("for I in eachindex(A), ", briefname(Ar)) sz @timeit sumlinear(Ar, 100) string("sumlinearIb ", briefname(Ar)) string("for I in 1:length(A), ", briefname(Ar)) sz - @timeit sumcartesian(Ar, 100) string("sumcartesianIb ", briefname(Ar)) string("for I in CartesianRange(size(A)), ", briefname(Ar)) sz + @timeit sumcartesian(Ar, 100) string("sumcartesianIb ", briefname(Ar)) string("for I in CartesianIndices(size(A)), ", briefname(Ar)) sz @timeit sumcolon(Ar, 100) string("sumcolonIb ", briefname(Ar)) string("colon indexing, ", briefname(Ar)) sz @timeit sumrange(Ar, 100) string("sumrangeIb ", briefname(Ar)) string("range indexing, ", briefname(Ar)) sz @timeit sumlogical(Ar, 100) string("sumlogicalIb ", briefname(Ar)) string("logical indexing, ", briefname(Ar)) sz @@ -51,7 +51,7 @@ for Ar in Alist @timeit sumelt(Ar, 100) string("sumeltFb ", briefname(Ar)) string("for a in A indexing, ", briefname(Ar)) sz @timeit sumeach(Ar, 100) string("sumeachFb ", briefname(Ar)) string("for I in eachindex(A), ", briefname(Ar)) sz @timeit sumlinear(Ar, 100) string("sumlinearFb ", briefname(Ar)) string("for I in 1:length(A), ", briefname(Ar)) sz - @timeit sumcartesian(Ar, 100) string("sumcartesianFb ", briefname(Ar)) string("for I in CartesianRange(size(A)), ", briefname(Ar)) sz + @timeit sumcartesian(Ar, 100) string("sumcartesianFb ", briefname(Ar)) string("for I in CartesianIndices(size(A)), ", briefname(Ar)) sz @timeit sumcolon(Ar, 100) string("sumcolonFb ", briefname(Ar)) string("colon indexing, ", briefname(Ar)) sz @timeit sumrange(Ar, 100) string("sumrangeFb ", briefname(Ar)) string("range indexing, ", briefname(Ar)) sz @timeit sumlogical(Ar, 100) string("sumlogicalFb ", briefname(Ar)) string("logical indexing, ", briefname(Ar)) sz diff --git a/test/simdloop.jl b/test/simdloop.jl index 55b6c4cf36ae1..4909101cc108d 100644 --- a/test/simdloop.jl +++ b/test/simdloop.jl @@ -115,23 +115,23 @@ function simd_cartesian_range!(indices, crng) indices end -crng = CartesianRange(2:4, 0:1, 1:1, 3:5) +crng = CartesianIndices(2:4, 0:1, 1:1, 3:5) indices = simd_cartesian_range!(Vector{eltype(crng)}(), crng) @test indices == vec(collect(crng)) -crng = CartesianRange(-1:1, 1:3) +crng = CartesianIndices(-1:1, 1:3) indices = simd_cartesian_range!(Vector{eltype(crng)}(), crng) @test indices == vec(collect(crng)) -crng = CartesianRange(-1:-1, 1:3) +crng = CartesianIndices(-1:-1, 1:3) indices = simd_cartesian_range!(Vector{eltype(crng)}(), crng) @test indices == vec(collect(crng)) -crng = CartesianRange(2:4) +crng = CartesianIndices(2:4) indices = simd_cartesian_range!(Vector{eltype(crng)}(), crng) @test indices == collect(crng) -crng = CartesianRange() +crng = CartesianIndices() indices = simd_cartesian_range!(Vector{eltype(crng)}(), crng) @test indices == vec(collect(crng)) diff --git a/test/subarray.jl b/test/subarray.jl index be85d3bacef68..f6a653537ebb7 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -132,7 +132,7 @@ function _test_mixed(@nospecialize(A), @nospecialize(B)) m = size(A, 1) n = size(A, 2) isgood = true - for J in CartesianRange(size(A)[2:end]), i in 1:m + for J in CartesianIndices(size(A)[2:end]), i in 1:m if A[i,J] != B[i,J] isgood = false break From a7e113846d70024869371baa5c52761469c9de04 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 16 Dec 2017 10:03:42 -0600 Subject: [PATCH 3/3] Update NEWS for CartesianRange changes [ci skip] --- NEWS.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/NEWS.md b/NEWS.md index 0a6feb53ced2d..8f1022333ca60 100644 --- a/NEWS.md +++ b/NEWS.md @@ -211,13 +211,6 @@ This section lists changes that do not have deprecation warnings. longer present. Use `first(R)` and `last(R)` to obtain start/stop. ([#20974]) - * `CartesianRange` inherits from AbstractArray and construction with an - `AbstractArray` argument constructs the indices for that array. Consequently, - linear indexing can be used to provide linear-to-cartesian conversion ([#24715]) - - * The type `CartesianToLinear` has been added, providing conversion from - cartesian incices to linear indices using the normal indexing operation. ([#24715]) - * The `Diagonal`, `Bidiagonal`, `Tridiagonal` and `SymTridiagonal` type definitions have changed from `Diagonal{T}`, `Bidiagonal{T}`, `Tridiagonal{T}` and `SymTridiagonal{T}` to `Diagonal{T,V<:AbstractVector{T}}`, `Bidiagonal{T,V<:AbstractVector{T}}`, @@ -453,9 +446,12 @@ Library improvements `permutedims(v::AbstractVector)` will create a row matrix ([#24839]). * `CartesianRange` changes ([#24715]): - - Inherits from `AbstractArray` - - Constructor taking an array - - `eachindex` returns the linear indices into a reshaped array, as `sub2ind` alternative + - Inherits from `AbstractArray`, and linear indexing can be used to provide + linear-to-cartesian conversion ([#24715]) + - It has a new constructor taking an array + + * The type `LinearIndices` has been added, providing conversion from + cartesian incices to linear indices using the normal indexing operation. ([#24715]) Compiler/Runtime improvements ----------------------------- @@ -804,7 +800,9 @@ Deprecated or removed and `unsafe_get`/`get` can be dropped or replaced with `coalesce`. `NullException` has been removed. - * `sub2ind` and `ind2sub` are deprecated in favor of using `CartesianRange` and `CartesianToLinear` ([#24715]). + * `CartesianRange` has been renamed `CartesianIndices` ([#24715]). + + * `sub2ind` and `ind2sub` are deprecated in favor of using `CartesianIndices` and `LinearIndices` ([#24715]). Command-line option changes ---------------------------