Skip to content

Commit c874559

Browse files
committed
Merge pull request #10337 from Jutho/jh/stagedsub2ind
improved ind2sub/sub2ind
2 parents 861f027 + 8c718f1 commit c874559

File tree

2 files changed

+71
-92
lines changed

2 files changed

+71
-92
lines changed

base/abstractarray.jl

+68-92
Original file line numberDiff line numberDiff line change
@@ -1009,97 +1009,81 @@ function repmat(a::AbstractVector, m::Int)
10091009
return b
10101010
end
10111011

1012-
sub2ind(dims) = 1
1013-
sub2ind(dims, i::Integer) = Int(i)
1014-
sub2ind(dims, i::Integer, j::Integer) = sub2ind(dims, Int(i), Int(j))
1015-
sub2ind(dims, i::Int, j::Int) = (j-1)*dims[1] + i
1016-
sub2ind(dims, i0::Integer, i1::Integer, i2::Integer) = sub2ind(dims, Int(i0),Int(i1),Int(i2))
1017-
sub2ind(dims, i0::Int, i1::Int, i2::Int) =
1018-
i0 + dims[1]*((i1-1) + dims[2]*(i2-1))
1019-
sub2ind(dims, i0::Integer, i1::Integer, i2::Integer, i3::Integer) =
1020-
sub2ind(dims, Int(i0),Int(i1),Int(i2),Int(i3))
1021-
sub2ind(dims, i0::Int, i1::Int, i2::Int, i3::Int) =
1022-
i0 + dims[1]*((i1-1) + dims[2]*((i2-1) + dims[3]*(i3-1)))
1023-
1024-
function sub2ind(dims, I::Integer...)
1025-
ndims = length(dims)
1026-
index = Int(I[1])
1027-
stride = 1
1028-
for k=2:ndims
1029-
stride = stride * dims[k-1]
1030-
index += (Int(I[k])-1) * stride
1012+
sub2ind(dims::Tuple{Vararg{Integer}}) = 1
1013+
sub2ind(dims::Tuple{Vararg{Integer}}, I::Integer...) = _sub2ind(dims,I)
1014+
@generated function _sub2ind{N,M}(dims::NTuple{N,Integer}, I::NTuple{M,Integer})
1015+
meta = Expr(:meta,:inline)
1016+
ex = :(I[$M] - 1)
1017+
for i = M-1:-1:1
1018+
if i > N
1019+
ex = :(I[$i] - 1 + $ex)
1020+
else
1021+
ex = :(I[$i] - 1 + dims[$i]*$ex)
1022+
end
10311023
end
1032-
return index
1024+
Expr(:block, meta,:($ex + 1))
10331025
end
10341026

1035-
function sub2ind{T<:Integer}(dims::Array{T}, sub::Array{T})
1036-
ndims = length(dims)
1037-
ind = sub[1]
1038-
stride = 1
1039-
for k in 2:ndims
1040-
stride = stride * dims[k - 1]
1041-
ind += (sub[k] - 1) * stride
1027+
@generated function ind2sub{N}(dims::NTuple{N,Integer}, ind::Integer)
1028+
meta = Expr(:meta,:inline)
1029+
N==0 && return :($meta; ind==1 ? () : throw(BoundsError()))
1030+
exprs = Expr[:(ind = ind-1)]
1031+
for i = 1:N-1
1032+
push!(exprs,:(ind2 = div(ind,dims[$i])))
1033+
push!(exprs,Expr(:(=),symbol(:s,i),:(ind-dims[$i]*ind2+1)))
1034+
push!(exprs,:(ind=ind2))
10421035
end
1043-
return ind
1036+
push!(exprs,Expr(:(=),symbol(:s,N),:(ind+1)))
1037+
Expr(:block,meta,exprs...,Expr(:tuple,[symbol(:s,i) for i=1:N]...))
10441038
end
10451039

1046-
sub2ind{T<:Integer}(dims, I::AbstractVector{T}...) =
1047-
[ sub2ind(dims, map(X->X[i], I)...)::Int for i=1:length(I[1]) ]
1040+
# TODO in v0.5: either deprecate line 1 or add line 2
1041+
ind2sub(a::AbstractArray, ind::Integer) = ind2sub(size(a), ind)
1042+
# sub2ind(a::AbstractArray, I::Integer...) = sub2ind(size(a), I...)
10481043

1049-
function ind2sub(dims::Tuple{Integer,Vararg{Integer}}, ind::Int)
1050-
ndims = length(dims)
1051-
stride = dims[1]
1052-
for i=2:ndims-1
1053-
stride *= dims[i]
1054-
end
1055-
1056-
sub = ()
1057-
for i=(ndims-1):-1:1
1058-
rest = rem(ind-1, stride) + 1
1059-
sub = tuple(div(ind - rest, stride) + 1, sub...)
1060-
ind = rest
1061-
stride = div(stride, dims[i])
1062-
end
1063-
return tuple(ind, sub...)
1064-
end
1065-
1066-
ind2sub(dims::Tuple{Vararg{Integer}}, ind::Integer) = ind2sub(dims, Int(ind))
1067-
ind2sub(dims::Tuple{}, ind::Integer) = ind==1 ? () : throw(BoundsError())
1068-
ind2sub(dims::Tuple{Integer,}, ind::Int) = (ind,)
1069-
ind2sub(dims::Tuple{Integer,Integer}, ind::Int) =
1070-
(rem(ind-1,dims[1])+1, div(ind-1,dims[1])+1)
1071-
ind2sub(dims::Tuple{Integer,Integer,Integer}, ind::Int) =
1072-
(rem(ind-1,dims[1])+1, div(rem(ind-1,dims[1]*dims[2]), dims[1])+1,
1073-
div(rem(ind-1,dims[1]*dims[2]*dims[3]), dims[1]*dims[2])+1)
1074-
ind2sub(a::AbstractArray, ind::Integer) = ind2sub(size(a), Int(ind))
1075-
1076-
function ind2sub{T<:Integer}(dims::Tuple{Integer,Vararg{Integer}}, ind::AbstractVector{T})
1077-
n = length(dims)
1078-
l = length(ind)
1079-
t = ntuple(n, x->Array(Int, l))
1080-
for i = 1:l
1081-
s = ind2sub(dims, ind[i])
1082-
for j = 1:n
1083-
t[j][i] = s[j]
1044+
function sub2ind{T<:Integer}(dims::Tuple{Vararg{Integer}}, I::AbstractVector{T}...)
1045+
N = length(dims)
1046+
M = length(I[1])
1047+
indices = Array{T}(length(I[1]))
1048+
copy!(indices,I[1])
1049+
1050+
s = dims[1]
1051+
for j=2:length(I)
1052+
Ij = I[j]
1053+
for i=1:M
1054+
indices[i] += s*(Ij[i]-1)
1055+
end
1056+
s*= (j <= N ? dims[j] : 1)
1057+
end
1058+
return indices
1059+
end
1060+
1061+
function ind2sub{N,T<:Integer}(dims::NTuple{N,Integer}, ind::AbstractVector{T})
1062+
M = length(ind)
1063+
t = NTuple{N,Vector{T}}(ntuple(N,n->Array{T}(M)))
1064+
copy!(t[1],ind)
1065+
for j = 1:N-1
1066+
d = dims[j]
1067+
tj = t[j]
1068+
tj2 = t[j+1]
1069+
for i = 1:M
1070+
ind2 = div(tj[i]-1, d)
1071+
tj[i] -= d*ind2
1072+
tj2[i] = ind2+1
10841073
end
10851074
end
10861075
return t
10871076
end
10881077

1089-
function ind2sub!{T<:Integer}(sub::Array{T}, dims::Array{T}, ind::T)
1078+
function ind2sub!{T<:Integer}(sub::Array{T}, dims::Tuple{Vararg{T}}, ind::T)
10901079
ndims = length(dims)
1091-
stride = dims[1]
1092-
for i in 2:(ndims - 1)
1093-
stride *= dims[i]
1094-
end
1095-
for i in (ndims - 1):-1:1
1096-
rest = rem1(ind, stride)
1097-
sub[i + 1] = div(ind - rest, stride) + 1
1098-
ind = rest
1099-
stride = div(stride, dims[i])
1080+
for i=1:ndims-1
1081+
ind2 = div(ind-1,dims[i])+1
1082+
sub[i] = ind - dims[i]*(ind2-1)
1083+
ind = ind2
11001084
end
1101-
sub[1] = ind
1102-
return
1085+
sub[ndims] = ind
1086+
return sub
11031087
end
11041088

11051089
# Generalized repmat
@@ -1115,26 +1099,18 @@ function repeat{T}(A::Array{T};
11151099
throw(ArgumentError("inner/outer repetitions must be set for all input dimensions"))
11161100
end
11171101

1118-
size_in = Array(Int, ndims_in)
1119-
size_out = Array(Int, ndims_out)
1120-
inner_size_out = Array(Int, ndims_out)
1102+
inner = vcat(inner, ones(Int,ndims_out-length_inner))
1103+
outer = vcat(outer, ones(Int,ndims_out-length_outer))
11211104

1122-
for i in 1:ndims_in
1123-
size_in[i] = size(A, i)
1124-
end
1125-
for i in 1:ndims_out
1126-
t1 = ndims_in < i ? 1 : size_in[i]
1127-
t2 = length_inner < i ? 1 : inner[i]
1128-
t3 = length_outer < i ? 1 : outer[i]
1129-
size_out[i] = t1 * t2 * t3
1130-
inner_size_out[i] = t1 * t2
1131-
end
1105+
size_in = size(A)
1106+
size_out = ntuple(i->inner[i]*size(A,i)*outer[i],ndims_out)::Dims
1107+
inner_size_out = ntuple(i->inner[i]*size(A,i),ndims_out)::Dims
11321108

11331109
indices_in = Array(Int, ndims_in)
11341110
indices_out = Array(Int, ndims_out)
11351111

11361112
length_out = prod(size_out)
1137-
R = Array(T, size_out...)
1113+
R = Array(T, size_out)
11381114

11391115
for index_out in 1:length_out
11401116
ind2sub!(indices_out, size_out, index_out)
@@ -1146,7 +1122,7 @@ function repeat{T}(A::Array{T};
11461122
indices_in[t] = fld1(indices_in[t], inner[t])
11471123
end
11481124
end
1149-
index_in = sub2ind(size_in, indices_in)
1125+
index_in = sub2ind(size_in, indices_in...)
11501126
R[index_out] = A[index_in]
11511127
end
11521128

base/deprecated.jl

+3
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,9 @@ end
321321
@deprecate flipud(A::AbstractArray) flipdim(A, 1)
322322
@deprecate fliplr(A::AbstractArray) flipdim(A, 2)
323323

324+
@deprecate sub2ind{T<:Integer}(dims::Array{T}, sub::Array{T}) sub2ind(tuple(dims...), sub...)
325+
@deprecate ind2sub!{T<:Integer}(sub::Array{T}, dims::Array{T}, ind::T) ind2sub!(sub, tuple(dims...), ind)
326+
324327
@deprecate strftime Libc.strftime
325328
@deprecate strptime Libc.strptime
326329
@deprecate flush_cstdio Libc.flush_cstdio

0 commit comments

Comments
 (0)