Skip to content

Commit dab5c8d

Browse files
authored
Merge pull request #16260 from JuliaLang/teh/inds
Support for 0-indexed and arbitrary-indexed arrays
2 parents 4c1af23 + a7b88cf commit dab5c8d

40 files changed

+1838
-946
lines changed

NEWS.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ New language features
2727
* Function return type syntax `function f()::T` has been added ([#1090]). Values returned
2828
from a function with such a declaration will be converted to the specified type `T`.
2929

30+
* Experimental support for arrays with indexing starting at values
31+
different from 1. The array types are expected to be defined in
32+
packages, but now Julia provides an API for writing generic
33+
algorithms for arbitrary indexing schemes ([#16260]).
34+
3035
Language changes
3136
----------------
3237

@@ -130,7 +135,7 @@ Library improvements
130135

131136
* `cov` and `cor` don't use keyword arguments anymore and are therefore now type stable ([#13465]).
132137

133-
* Linear algebra:
138+
* Arrays and linear algebra:
134139

135140
* All dimensions indexed by scalars are now dropped, whereas previously only
136141
trailing scalar dimensions would be omitted from the result ([#13612]).
@@ -268,3 +273,4 @@ Deprecated or removed
268273
[#16403]: https://github.com/JuliaLang/julia/issues/16403
269274
[#16481]: https://github.com/JuliaLang/julia/issues/16481
270275
[#16731]: https://github.com/JuliaLang/julia/issues/16731
276+
[#16280]: https://github.com/JuliaLang/julia/issues/16260

base/abstractarray.jl

Lines changed: 501 additions & 172 deletions
Large diffs are not rendered by default.

base/abstractarraymath.jl

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ imag{T<:Real}(x::AbstractArray{T}) = zero(x)
6161
# index A[:,:,...,i,:,:,...] where "i" is in dimension "d"
6262
# TODO: more optimized special cases
6363
slicedim(A::AbstractArray, d::Integer, i) =
64-
A[[ n==d ? i : (1:size(A,n)) for n in 1:ndims(A) ]...]
64+
A[[ n==d ? i : (indices(A,n)) for n in 1:ndims(A) ]...]
6565

6666
function flipdim(A::AbstractVector, d::Integer)
6767
d > 0 || throw(ArgumentError("dimension to flip must be positive"))
@@ -71,25 +71,26 @@ end
7171

7272
function flipdim(A::AbstractArray, d::Integer)
7373
nd = ndims(A)
74-
sd = d > nd ? 1 : size(A, d)
75-
if sd == 1 || isempty(A)
74+
if d > nd || isempty(A)
7675
return copy(A)
7776
end
7877
B = similar(A)
7978
nnd = 0
8079
for i = 1:nd
8180
nnd += Int(size(A,i)==1 || i==d)
8281
end
82+
inds = indices(A, d)
83+
sd = first(inds)+last(inds)
8384
if nnd==nd
8485
# flip along the only non-singleton dimension
85-
for i = 1:sd
86-
B[i] = A[sd+1-i]
86+
for i in inds
87+
B[i] = A[sd-i]
8788
end
8889
return B
8990
end
90-
alli = [ 1:size(B,n) for n in 1:nd ]
91-
for i = 1:sd
92-
B[[ n==d ? sd+1-i : alli[n] for n in 1:nd ]...] = slicedim(A, d, i)
91+
alli = [ indices(B,n) for n in 1:nd ]
92+
for i in inds
93+
B[[ n==d ? sd-i : alli[n] for n in 1:nd ]...] = slicedim(A, d, i)
9394
end
9495
return B
9596
end
@@ -107,13 +108,14 @@ end
107108

108109
# Uses K-B-N summation
109110
function cumsum_kbn{T<:AbstractFloat}(v::AbstractVector{T})
110-
n = length(v)
111-
r = similar(v, n)
112-
if n == 0; return r; end
111+
r = similar(v)
112+
if isempty(v); return r; end
113113

114-
s = r[1] = v[1]
114+
inds = indices(v, 1)
115+
i1 = first(inds)
116+
s = r[i1] = v[i1]
115117
c = zero(T)
116-
for i=2:n #Fixme iter
118+
for i=i1+1:last(inds)
117119
vi = v[i]
118120
t = s + vi
119121
if abs(s) >= abs(vi)

base/array.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ end
5656

5757
function copy!{T}(dest::Array{T}, doffs::Integer, src::Array{T}, soffs::Integer, n::Integer)
5858
n == 0 && return dest
59-
if n < 0 || soffs < 1 || doffs < 1 || soffs+n-1 > length(src) || doffs+n-1 > length(dest)
59+
n > 0 || throw(ArgumentError(string("tried to copy n=", n, " elements, but n should be nonnegative")))
60+
if soffs < 1 || doffs < 1 || soffs+n-1 > length(src) || doffs+n-1 > length(dest)
6061
throw(BoundsError())
6162
end
6263
unsafe_copy!(dest, doffs, src, soffs, n)
@@ -299,8 +300,8 @@ end
299300

300301
## Iteration ##
301302
start(A::Array) = 1
302-
next(a::Array,i) = (a[i],i+1)
303-
done(a::Array,i) = i == length(a)+1
303+
next(a::Array,i) = (@_propagate_inbounds_meta; (a[i],i+1))
304+
done(a::Array,i) = (@_inline_meta; i == length(a)+1)
304305

305306
## Indexing: getindex ##
306307

@@ -917,6 +918,7 @@ function findin(a, b)
917918
end
918919

919920
# Copying subregions
921+
# TODO: DEPRECATE FOR #14770
920922
function indcopy(sz::Dims, I::Vector)
921923
n = length(I)
922924
s = sz[n]

base/arraymath.jl

Lines changed: 52 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,21 @@ for f in (:+, :-, :div, :mod, :&, :|, :$)
5959
return F
6060
end
6161
function ($f){S,T}(A::AbstractArray{S}, B::Range{T})
62-
F = similar(A, promote_op($f,S,T), promote_shape(size(A),size(B)))
62+
F = similar(A, promote_op($f,S,T), promote_shape(A,B))
6363
for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
6464
@inbounds F[iF] = ($f)(A[iA], B[iB])
6565
end
6666
return F
6767
end
6868
function ($f){S,T}(A::Range{S}, B::AbstractArray{T})
69-
F = similar(B, promote_op($f,S,T), promote_shape(size(A),size(B)))
69+
F = similar(B, promote_op($f,S,T), promote_shape(A,B))
7070
for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
7171
@inbounds F[iF] = ($f)(A[iA], B[iB])
7272
end
7373
return F
7474
end
7575
function ($f){S,T}(A::AbstractArray{S}, B::AbstractArray{T})
76-
F = similar(A, promote_op($f,S,T), promote_shape(size(A),size(B)))
76+
F = similar(A, promote_op($f,S,T), promote_shape(A,B))
7777
for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
7878
@inbounds F[iF] = ($f)(A[iA], B[iB])
7979
end
@@ -211,26 +211,29 @@ function flipdim{T}(A::Array{T}, d::Integer)
211211
end
212212

213213
function rotl90(A::AbstractMatrix)
214-
m,n = size(A)
215-
B = similar(A,(n,m))
216-
for i=1:m, j=1:n #Fixme iter
217-
B[n-j+1,i] = A[i,j]
214+
B = similar_transpose(A)
215+
ind2 = indices(A,2)
216+
n = first(ind2)+last(ind2)
217+
for i=indices(A,1), j=ind2
218+
B[n-j,i] = A[i,j]
218219
end
219220
return B
220221
end
221222
function rotr90(A::AbstractMatrix)
222-
m,n = size(A)
223-
B = similar(A,(n,m))
224-
for i=1:m, j=1:n #Fixme iter
225-
B[j,m-i+1] = A[i,j]
223+
B = similar_transpose(A)
224+
ind1 = indices(A,1)
225+
m = first(ind1)+last(ind1)
226+
for i=ind1, j=indices(A,2)
227+
B[j,m-i] = A[i,j]
226228
end
227229
return B
228230
end
229231
function rot180(A::AbstractMatrix)
230-
m,n = size(A)
231232
B = similar(A)
232-
for i=1:m, j=1:n #Fixme iter
233-
B[m-i+1,n-j+1] = A[i,j]
233+
ind1, ind2 = indices(A,1), indices(A,2)
234+
m, n = first(ind1)+last(ind1), first(ind2)+last(ind2)
235+
for j=ind2, i=ind1
236+
B[m-i,n-j] = A[i,j]
234237
end
235238
return B
236239
end
@@ -243,96 +246,65 @@ end
243246
rotr90(A::AbstractMatrix, k::Integer) = rotl90(A,-k)
244247
rot180(A::AbstractMatrix, k::Integer) = mod(k, 2) == 1 ? rot180(A) : copy(A)
245248

249+
similar_transpose(A::AbstractMatrix) = similar_transpose(indicesbehavior(A), A)
250+
similar_transpose(::IndicesStartAt1, A::AbstractMatrix) = similar(A, (size(A,2), size(A,1)))
251+
similar_transpose(::IndicesBehavior, A::AbstractMatrix) = similar(A, (indices(A,2), indices(A,1)))
246252

247253
## Transpose ##
248-
const transposebaselength=64
249-
function transpose!(B::AbstractMatrix,A::AbstractMatrix)
250-
m, n = size(A)
251-
size(B,1) == n && size(B,2) == m || throw(DimensionMismatch("transpose"))
252-
253-
if m*n<=4*transposebaselength
254-
@inbounds begin
255-
for j = 1:n #Fixme iter
256-
for i = 1:m #Fixme iter
257-
B[j,i] = transpose(A[i,j])
258-
end
259-
end
260-
end
261-
else
262-
transposeblock!(B,A,m,n,0,0)
263-
end
264-
return B
265-
end
254+
transpose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(transpose, B, A)
255+
ctranspose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(ctranspose, B, A)
266256
function transpose!(B::AbstractVector, A::AbstractMatrix)
267-
length(B) == length(A) && size(A,1) == 1 || throw(DimensionMismatch("transpose"))
257+
indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose"))
268258
copy!(B, A)
269259
end
270260
function transpose!(B::AbstractMatrix, A::AbstractVector)
271-
length(B) == length(A) && size(B,1) == 1 || throw(DimensionMismatch("transpose"))
261+
indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose"))
272262
copy!(B, A)
273263
end
274-
function transposeblock!(B::AbstractMatrix,A::AbstractMatrix,m::Int,n::Int,offseti::Int,offsetj::Int)
275-
if m*n<=transposebaselength
276-
@inbounds begin
277-
for j = offsetj+(1:n) #Fixme iter
278-
for i = offseti+(1:m) #Fixme iter
279-
B[j,i] = transpose(A[i,j])
280-
end
281-
end
282-
end
283-
elseif m>n
284-
newm=m>>1
285-
transposeblock!(B,A,newm,n,offseti,offsetj)
286-
transposeblock!(B,A,m-newm,n,offseti+newm,offsetj)
287-
else
288-
newn=n>>1
289-
transposeblock!(B,A,m,newn,offseti,offsetj)
290-
transposeblock!(B,A,m,n-newn,offseti,offsetj+newn)
291-
end
292-
return B
264+
function ctranspose!(B::AbstractVector, A::AbstractMatrix)
265+
indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose"))
266+
ccopy!(B, A)
293267
end
294-
function ctranspose!(B::AbstractMatrix,A::AbstractMatrix)
295-
m, n = size(A)
296-
size(B,1) == n && size(B,2) == m || throw(DimensionMismatch("transpose"))
268+
function ctranspose!(B::AbstractMatrix, A::AbstractVector)
269+
indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose"))
270+
ccopy!(B, A)
271+
end
272+
273+
const transposebaselength=64
274+
function transpose_f!(f,B::AbstractMatrix,A::AbstractMatrix)
275+
indices(B,1) == indices(A,2) && indices(B,2) == indices(A,1) || throw(DimensionMismatch(string(f)))
297276

277+
m, n = size(A)
298278
if m*n<=4*transposebaselength
299279
@inbounds begin
300-
for j = 1:n #Fixme iter
301-
for i = 1:m #Fixme iter
302-
B[j,i] = ctranspose(A[i,j])
280+
for j = indices(A,2)
281+
for i = indices(A,1)
282+
B[j,i] = f(A[i,j])
303283
end
304284
end
305285
end
306286
else
307-
ctransposeblock!(B,A,m,n,0,0)
287+
transposeblock!(f,B,A,m,n,first(indices(A,1))-1,first(indices(A,2))-1)
308288
end
309289
return B
310290
end
311-
function ctranspose!(B::AbstractVector, A::AbstractMatrix)
312-
length(B) == length(A) && size(A,1) == 1 || throw(DimensionMismatch("transpose"))
313-
ccopy!(B, A)
314-
end
315-
function ctranspose!(B::AbstractMatrix, A::AbstractVector)
316-
length(B) == length(A) && size(B,1) == 1 || throw(DimensionMismatch("transpose"))
317-
ccopy!(B, A)
318-
end
319-
function ctransposeblock!(B::AbstractMatrix,A::AbstractMatrix,m::Int,n::Int,offseti::Int,offsetj::Int)
291+
function transposeblock!(f,B::AbstractMatrix,A::AbstractMatrix,m::Int,n::Int,offseti::Int,offsetj::Int)
320292
if m*n<=transposebaselength
321293
@inbounds begin
322-
for j = offsetj+(1:n) #Fixme iter
323-
for i = offseti+(1:m) #Fixme iter
324-
B[j,i] = ctranspose(A[i,j])
294+
for j = offsetj+(1:n)
295+
for i = offseti+(1:m)
296+
B[j,i] = f(A[i,j])
325297
end
326298
end
327299
end
328300
elseif m>n
329301
newm=m>>1
330-
ctransposeblock!(B,A,newm,n,offseti,offsetj)
331-
ctransposeblock!(B,A,m-newm,n,offseti+newm,offsetj)
302+
transposeblock!(f,B,A,newm,n,offseti,offsetj)
303+
transposeblock!(f,B,A,m-newm,n,offseti+newm,offsetj)
332304
else
333305
newn=n>>1
334-
ctransposeblock!(B,A,m,newn,offseti,offsetj)
335-
ctransposeblock!(B,A,m,n-newn,offseti,offsetj+newn)
306+
transposeblock!(f,B,A,m,newn,offseti,offsetj)
307+
transposeblock!(f,B,A,m,n-newn,offseti,offsetj+newn)
336308
end
337309
return B
338310
end
@@ -343,11 +315,11 @@ function ccopy!(B, A)
343315
end
344316

345317
function transpose(A::AbstractMatrix)
346-
B = similar(A, size(A, 2), size(A, 1))
318+
B = similar_transpose(A)
347319
transpose!(B, A)
348320
end
349321
function ctranspose(A::AbstractMatrix)
350-
B = similar(A, size(A, 2), size(A, 1))
322+
B = similar_transpose(A)
351323
ctranspose!(B, A)
352324
end
353325
ctranspose{T<:Real}(A::AbstractVecOrMat{T}) = transpose(A)
@@ -366,7 +338,7 @@ for (f, f!, fp, op) = ((:cumsum, :cumsum!, :cumsum_pairwise!, :+),
366338
if n < 128
367339
@inbounds s_ = v[i1]
368340
@inbounds c[i1] = ($op)(s, s_)
369-
for i = i1+1:i1+n-1 #Fixme iter
341+
for i = i1+1:i1+n-1
370342
@inbounds s_ = $(op)(s_, v[i])
371343
@inbounds c[i] = $(op)(s, s_)
372344
end
@@ -381,7 +353,7 @@ for (f, f!, fp, op) = ((:cumsum, :cumsum!, :cumsum_pairwise!, :+),
381353
@eval function ($f!)(result::AbstractVector, v::AbstractVector)
382354
n = length(v)
383355
if n == 0; return result; end
384-
($fp)(v, result, $(op==:+ ? :(zero(v[1])) : :(one(v[1]))), 1, n)
356+
($fp)(v, result, $(op==:+ ? :(zero(first(v))) : :(one(first(v)))), first(indices(v,1)), n)
385357
return result
386358
end
387359

0 commit comments

Comments
 (0)