Skip to content

Commit d26672d

Browse files
committed
Deprecate sub2ind and ind2sub
1 parent 60dcd6f commit d26672d

File tree

17 files changed

+184
-199
lines changed

17 files changed

+184
-199
lines changed

NEWS.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,13 @@ This section lists changes that do not have deprecation warnings.
202202
longer present. Use `first(R)` and `last(R)` to obtain
203203
start/stop. ([#20974])
204204

205+
* `CartesianRange` inherits from AbstractArray and construction with an
206+
`AbstractArray` argument constructs the indices for that array. Consequently,
207+
linear indexing can be used to provide linear-to-cartesian conversion ([#24715])
208+
209+
* The type `CartesianToLinear` has been added, providing conversion from
210+
cartesian incices to linear indices using the normal indexing operation. ([#24715])
211+
205212
* The `Diagonal`, `Bidiagonal`, `Tridiagonal` and `SymTridiagonal` type definitions have
206213
changed from `Diagonal{T}`, `Bidiagonal{T}`, `Tridiagonal{T}` and `SymTridiagonal{T}`
207214
to `Diagonal{T,V<:AbstractVector{T}}`, `Bidiagonal{T,V<:AbstractVector{T}}`,
@@ -401,11 +408,6 @@ Library improvements
401408
This supersedes the old behavior of reinterpret on Arrays. As a result, reinterpreting
402409
arrays with different alignment requirements (removed in 0.6) is once again allowed ([#23750]).
403410

404-
* `CartesianRange` changes ([#24715]):
405-
- Inherits from `AbstractArray`
406-
- Constructor taking an array
407-
- `eachindex` returns the linear indices into a reshaped array, as `sub2ind` alternative
408-
409411
Compiler/Runtime improvements
410412
-----------------------------
411413

@@ -704,6 +706,8 @@ Deprecated or removed
704706
* `cumsum`, `cumprod`, `accumulate`, and their mutating versions now require a `dim`
705707
argument instead of defaulting to using the first dimension ([#24684]).
706708

709+
* `sub2ind` and `ind2sub` are deprecated in favor of using `CartesianRange` and `CartesianToLinear` ([#24715]).
710+
707711
Command-line option changes
708712
---------------------------
709713

@@ -1668,3 +1672,4 @@ Command-line option changes
16681672
[#24320]: https://github.com/JuliaLang/julia/issues/24320
16691673
[#24396]: https://github.com/JuliaLang/julia/issues/24396
16701674
[#24413]: https://github.com/JuliaLang/julia/issues/24413
1675+
[#24715]: https://github.com/JuliaLang/julia/issues/24715

base/abstractarray.jl

Lines changed: 41 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,8 @@ type:
308308
The default is `IndexCartesian()`.
309309
310310
Julia's internal indexing machinery will automatically (and invisibly)
311-
convert all indexing operations into the preferred style using
312-
[`sub2ind`](@ref) or [`ind2sub`](@ref). This allows users to access
313-
elements of your array using any indexing style, even when explicit
311+
convert all indexing operations into the preferred style. This allows users
312+
to access elements of your array using any indexing style, even when explicit
314313
methods have not been provided.
315314
316315
If you define both styles of indexing for your `AbstractArray`, this
@@ -811,17 +810,6 @@ if all inputs have fast linear indexing, a [`CartesianRange`](@ref)
811810
otherwise).
812811
If the arrays have different sizes and/or dimensionalities, `eachindex` will return an
813812
iterable that spans the largest range along each dimension.
814-
815-
For a CartesianRange, this returns a reshaped range of the linear indices into
816-
the range, e.g.:
817-
818-
```jldoctest
819-
julia> eachindex(CartesianRange((1:2,1:3)))
820-
2×3 reshape(::Base.OneTo{Int64}, 2, 3) with eltype Int64:
821-
1 3 5
822-
2 4 6
823-
```
824-
825813
"""
826814
eachindex(A::AbstractArray) = (@_inline_meta(); eachindex(IndexStyle(A), A))
827815

@@ -955,7 +943,7 @@ end
955943
_to_linear_index(A::AbstractArray, i::Int) = i
956944
_to_linear_index(A::AbstractVector, i::Int, I::Int...) = i
957945
_to_linear_index(A::AbstractArray) = 1
958-
_to_linear_index(A::AbstractArray, I::Int...) = (@_inline_meta; sub2ind(A, I...))
946+
_to_linear_index(A::AbstractArray, I::Int...) = (@_inline_meta; _sub2ind(A, I...))
959947

960948
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
961949
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
@@ -989,8 +977,8 @@ _to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, sa
989977
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
990978
_remaining_size(::Tuple{Any}, t::Tuple) = t
991979
_remaining_size(h::Tuple, t::Tuple) = (@_inline_meta; _remaining_size(tail(h), tail(t)))
992-
_unsafe_ind2sub(::Tuple{}, i) = () # ind2sub may throw(BoundsError()) in this case
993-
_unsafe_ind2sub(sz, i) = (@_inline_meta; ind2sub(sz, i))
980+
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
981+
_unsafe_ind2sub(sz, i) = (@_inline_meta; _ind2sub(sz, i))
994982

995983
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
996984
# function that allows dispatch on array storage
@@ -1573,116 +1561,67 @@ function (==)(A::AbstractArray, B::AbstractArray)
15731561
return true
15741562
end
15751563

1576-
# sub2ind and ind2sub
1564+
# _sub2ind and _ind2sub
15771565
# fallbacks
1578-
function sub2ind(A::AbstractArray, I...)
1566+
function _sub2ind(A::AbstractArray, I...)
15791567
@_inline_meta
1580-
sub2ind(indices(A), I...)
1568+
_sub2ind(indices(A), I...)
15811569
end
15821570

1583-
"""
1584-
ind2sub(a, index) -> subscripts
1585-
1586-
Return a tuple of subscripts into array `a` corresponding to the linear index `index`.
1587-
1588-
# Examples
1589-
```jldoctest
1590-
julia> A = ones(5,6,7);
1591-
1592-
julia> ind2sub(A,35)
1593-
(5, 1, 2)
1594-
1595-
julia> ind2sub(A,70)
1596-
(5, 2, 3)
1597-
```
1598-
"""
1599-
function ind2sub(A::AbstractArray, ind)
1571+
function _ind2sub(A::AbstractArray, ind)
16001572
@_inline_meta
1601-
ind2sub(indices(A), ind)
1573+
_ind2sub(indices(A), ind)
16021574
end
16031575

16041576
# 0-dimensional arrays and indexing with []
1605-
sub2ind(::Tuple{}) = 1
1606-
sub2ind(::DimsInteger) = 1
1607-
sub2ind(::Indices) = 1
1608-
sub2ind(::Tuple{}, I::Integer...) = (@_inline_meta; _sub2ind((), 1, 1, I...))
1609-
# Generic cases
1610-
1611-
"""
1612-
sub2ind(dims, i, j, k...) -> index
1613-
1614-
The inverse of [`ind2sub`](@ref), return the linear index corresponding to the provided subscripts.
1577+
_sub2ind(::Tuple{}) = 1
1578+
_sub2ind(::DimsInteger) = 1
1579+
_sub2ind(::Indices) = 1
1580+
_sub2ind(::Tuple{}, I::Integer...) = (@_inline_meta; _sub2ind_recurse((), 1, 1, I...))
16151581

1616-
# Examples
1617-
```jldoctest
1618-
julia> sub2ind((5,6,7),1,2,3)
1619-
66
1620-
1621-
julia> sub2ind((5,6,7),1,6,3)
1622-
86
1623-
```
1624-
"""
1625-
sub2ind(dims::DimsInteger, I::Integer...) = (@_inline_meta; _sub2ind(dims, 1, 1, I...))
1626-
sub2ind(inds::Indices, I::Integer...) = (@_inline_meta; _sub2ind(inds, 1, 1, I...))
1582+
# Generic cases
1583+
_sub2ind(dims::DimsInteger, I::Integer...) = (@_inline_meta; _sub2ind_recurse(dims, 1, 1, I...))
1584+
_sub2ind(inds::Indices, I::Integer...) = (@_inline_meta; _sub2ind_recurse(inds, 1, 1, I...))
16271585
# In 1d, there's a question of whether we're doing cartesian indexing
16281586
# or linear indexing. Support only the former.
1629-
sub2ind(inds::Indices{1}, I::Integer...) =
1587+
_sub2ind(inds::Indices{1}, I::Integer...) =
16301588
throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
1631-
sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@_inline_meta; _sub2ind(inds, 1, 1, I...)) # only OneTo is safe
1632-
sub2ind(inds::Tuple{OneTo}, i::Integer) = i
1589+
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@_inline_meta; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
1590+
_sub2ind(inds::Tuple{OneTo}, i::Integer) = i
16331591

1634-
_sub2ind(::Any, L, ind) = ind
1635-
function _sub2ind(::Tuple{}, L, ind, i::Integer, I::Integer...)
1592+
_sub2ind_recurse(::Any, L, ind) = ind
1593+
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
16361594
@_inline_meta
1637-
_sub2ind((), L, ind+(i-1)*L, I...)
1595+
_sub2ind_recurse((), L, ind+(i-1)*L, I...)
16381596
end
1639-
function _sub2ind(inds, L, ind, i::Integer, I::Integer...)
1597+
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
16401598
@_inline_meta
16411599
r1 = inds[1]
1642-
_sub2ind(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
1600+
_sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
16431601
end
16441602

16451603
nextL(L, l::Integer) = L*l
16461604
nextL(L, r::AbstractUnitRange) = L*unsafe_length(r)
16471605
offsetin(i, l::Integer) = i-1
16481606
offsetin(i, r::AbstractUnitRange) = i-first(r)
16491607

1650-
ind2sub(::Tuple{}, ind::Integer) = (@_inline_meta; ind == 1 ? () : throw(BoundsError()))
1651-
1652-
"""
1653-
ind2sub(dims, index) -> subscripts
1654-
1655-
Return a tuple of subscripts into an array with dimensions `dims`,
1656-
corresponding to the linear index `index`.
1657-
1658-
# Examples
1659-
```jldoctest
1660-
julia> ind2sub((3,4),2)
1661-
(2, 1)
1662-
1663-
julia> ind2sub((3,4),3)
1664-
(3, 1)
1665-
1666-
julia> ind2sub((3,4),4)
1667-
(1, 2)
1668-
```
1669-
"""
1670-
ind2sub(dims::DimsInteger, ind::Integer) = (@_inline_meta; _ind2sub(dims, ind-1))
1671-
ind2sub(inds::Indices, ind::Integer) = (@_inline_meta; _ind2sub(inds, ind-1))
1672-
ind2sub(inds::Indices{1}, ind::Integer) =
1608+
_ind2sub(::Tuple{}, ind::Integer) = (@_inline_meta; ind == 1 ? () : throw(BoundsError()))
1609+
_ind2sub(dims::DimsInteger, ind::Integer) = (@_inline_meta; _ind2sub_recurse(dims, ind-1))
1610+
_ind2sub(inds::Indices, ind::Integer) = (@_inline_meta; _ind2sub_recurse(inds, ind-1))
1611+
_ind2sub(inds::Indices{1}, ind::Integer) =
16731612
throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
1674-
ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
1613+
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
16751614

1676-
_ind2sub(::Tuple{}, ind) = (ind+1,)
1677-
function _ind2sub(indslast::NTuple{1}, ind)
1615+
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
1616+
function _ind2sub_recurse(indslast::NTuple{1}, ind)
16781617
@_inline_meta
16791618
(_lookup(ind, indslast[1]),)
16801619
end
1681-
function _ind2sub(inds, ind)
1620+
function _ind2sub_recurse(inds, ind)
16821621
@_inline_meta
16831622
r1 = inds[1]
16841623
indnext, f, l = _div(ind, r1)
1685-
(ind-l*indnext+f, _ind2sub(tail(inds), indnext)...)
1624+
(ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
16861625
end
16871626

16881627
_lookup(ind, d::Integer) = ind+1
@@ -1691,12 +1630,12 @@ _div(ind, d::Integer) = div(ind, d), 1, d
16911630
_div(ind, r::AbstractUnitRange) = (d = unsafe_length(r); (div(ind, d), first(r), d))
16921631

16931632
# Vectorized forms
1694-
function sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
1633+
function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
16951634
throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
16961635
end
1697-
sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
1636+
_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
16981637
_sub2ind_vecs(inds, I1, I...)
1699-
sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
1638+
_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
17001639
_sub2ind_vecs(inds, I1, I...)
17011640
function _sub2ind_vecs(inds, I::AbstractVector...)
17021641
I1 = I[1]
@@ -1712,39 +1651,28 @@ end
17121651
function _sub2ind!(Iout, inds, Iinds, I)
17131652
@_noinline_meta
17141653
for i in Iinds
1715-
# Iout[i] = sub2ind(inds, map(Ij -> Ij[i], I)...)
1654+
# Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
17161655
Iout[i] = sub2ind_vec(inds, i, I)
17171656
end
17181657
Iout
17191658
end
17201659

1721-
sub2ind_vec(inds, i, I) = (@_inline_meta; sub2ind(inds, _sub2ind_vec(i, I...)...))
1660+
sub2ind_vec(inds, i, I) = (@_inline_meta; _sub2ind(inds, _sub2ind_vec(i, I...)...))
17221661
_sub2ind_vec(i, I1, I...) = (@_inline_meta; (I1[i], _sub2ind_vec(i, I...)...))
17231662
_sub2ind_vec(i) = ()
17241663

1725-
function ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
1664+
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
17261665
M = length(ind)
17271666
t = ntuple(n->similar(ind),Val(N))
17281667
for (i,idx) in pairs(IndexLinear(), ind)
1729-
sub = ind2sub(inds, idx)
1668+
sub = _ind2sub(inds, idx)
17301669
for j = 1:N
17311670
t[j][i] = sub[j]
17321671
end
17331672
end
17341673
t
17351674
end
17361675

1737-
function ind2sub!(sub::Array{T}, dims::Tuple{Vararg{T}}, ind::T) where T<:Integer
1738-
ndims = length(dims)
1739-
for i=1:ndims-1
1740-
ind2 = div(ind-1,dims[i])+1
1741-
sub[i] = ind - dims[i]*(ind2-1)
1742-
ind = ind2
1743-
end
1744-
sub[ndims] = ind
1745-
return sub
1746-
end
1747-
17481676
## iteration utilities ##
17491677

17501678
"""

base/array.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ sizeof(a::Array) = Core.sizeof(a)
135135

136136
function isassigned(a::Array, i::Int...)
137137
@_inline_meta
138-
ii = (sub2ind(size(a), i...) % UInt) - 1
138+
ii = (_sub2ind(size(a), i...) % UInt) - 1
139139
@boundscheck ii < length(a) % UInt || return false
140140
ccall(:jl_array_isassigned, Cint, (Any, UInt), a, ii) == 1
141141
end

base/deprecated.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,6 +2172,27 @@ end
21722172

21732173
@deprecate merge!(repo::LibGit2.GitRepo, args...; kwargs...) LibGit2.merge!(repo, args...; kwargs...)
21742174

2175+
# sub2ind and ind2sub deprecation (PR #24715)
2176+
@deprecate ind2sub(A::AbstractArray, ind) CartesianRange(A)[ind]
2177+
@deprecate ind2sub(::Tuple{}, ind::Integer) CartesianRange()[ind]
2178+
@deprecate ind2sub(dims::Tuple{Vararg{Integer,N}} where N, ind::Integer) CartesianRange(dims)[ind]
2179+
@deprecate ind2sub(inds::Tuple{Base.OneTo}, ind::Integer) CartesianRange(inds)[ind]
2180+
@deprecate ind2sub(inds::Tuple{AbstractUnitRange}, ind::Integer) CartesianRange(inds)[ind]
2181+
@deprecate ind2sub(inds::Tuple{Vararg{AbstractUnitRange,N}} where N, ind::Integer) CartesianRange(inds)[ind]
2182+
@deprecate ind2sub(inds::Union{DimsInteger{N},Indices{N}} where N, ind::AbstractVector{<:Integer}) CartesianRange(inds)[ind]
2183+
2184+
@deprecate sub2ind(A::AbstractArray, I...) CartesianToLinear(A)[I...]
2185+
@deprecate sub2ind(dims::Tuple{}) CartesianToLinear(dims)[]
2186+
@deprecate sub2ind(dims::DimsInteger) CartesianToLinear(dims)[]
2187+
@deprecate sub2ind(dims::Indices) CartesianToLinear(dims)[]
2188+
@deprecate sub2ind(dims::Tuple{}, I::Integer...) CartesianToLinear(dims)[I...]
2189+
@deprecate sub2ind(dims::DimsInteger, I::Integer...) CartesianToLinear(dims)[I...]
2190+
@deprecate sub2ind(inds::Indices, I::Integer...) CartesianToLinear(inds)[I...]
2191+
@deprecate sub2ind(inds::Tuple{OneTo}, I::Integer...) CartesianToLinear(inds)[I...]
2192+
@deprecate sub2ind(inds::Tuple{OneTo}, i::Integer) CartesianToLinear(inds)[i]
2193+
@deprecate sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} CartesianToLinear(inds)[CartesianIndex.(I1, I...)]
2194+
@deprecate sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} CartesianToLinear(inds)[CartesianIndex.(I1, I...)]
2195+
21752196
# END 0.7 deprecations
21762197

21772198
# BEGIN 1.0 deprecations

base/exports.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export
4040
BufferStream,
4141
CartesianIndex,
4242
CartesianRange,
43+
CartesianToLinear,
4344
Channel,
4445
Cmd,
4546
Colon,
@@ -453,7 +454,6 @@ export
453454
flipdim,
454455
hcat,
455456
hvcat,
456-
ind2sub,
457457
indexin,
458458
indices,
459459
indmax,
@@ -523,7 +523,6 @@ export
523523
step,
524524
stride,
525525
strides,
526-
sub2ind,
527526
sum!,
528527
sum,
529528
sum_kbn,

0 commit comments

Comments
 (0)