Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for 0-indexed and arbitrary-indexed arrays #16260

Merged
merged 44 commits into from
Jun 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
252f0ff
Add `indices` to support indexing with arbitrary offsets
timholy May 25, 2016
25b5ee5
Fix compiling bug in generated trailingsize
timholy May 25, 2016
9ee6112
Rework bounds-checking so it uses `indices`
timholy May 25, 2016
7cf1163
Speed up `in` for UnitRange
timholy May 25, 2016
7925233
Use indices rather than size in equality checks
timholy May 25, 2016
4a9affa
Add parameter to Dims and DimsInteger, and more typealiases
timholy May 25, 2016
43c8d84
sub2ind and ind2sub that support indices
timholy May 25, 2016
7a30542
Use array, rather than its size, in calls to ind2sub/sub2ind
timholy May 25, 2016
4b385f0
Support indices in similar
timholy May 25, 2016
9ef029b
Make get index-friendly
timholy May 25, 2016
b7eec60
Add a deprecation comment in array.jl
timholy May 25, 2016
d3667ef
Update NEWS.md
timholy May 25, 2016
53ef3ae
Introduce `decolon` to simplify indexing
timholy May 27, 2016
3469fa9
Tweaks to 0-d indexing
timholy Jun 12, 2016
95a9a6f
Split out OffsetArray tests and add more methods/tests
timholy May 30, 2016
266890c
Fix and test indexing with OffsetArrays
timholy May 30, 2016
cdf325b
Rework copy! for arbitrary indices
timholy Jun 4, 2016
071dbfe
Add IndicesBehavior trait and use it for similar/indexing
timholy Jun 6, 2016
0735ad0
Index-generalize transpose/rotation functions and rework implementation
timholy Jun 6, 2016
79f649f
Fix the majority of # fixme iter labels
timholy Jun 7, 2016
0d688dd
Fix show for OffsetArrays
timholy Jun 7, 2016
eb51aa2
Fix subarrays for OffsetArrays
timholy Jun 8, 2016
1520c63
Support indices in PermutedDimsArrays, rework overall design
timholy Jun 8, 2016
c2e0b2c
Fixes to sort and unique
timholy Jun 8, 2016
1b59063
Fixes to binary operations with arrays
timholy Jun 8, 2016
a57e872
Avoid calling sub2ind for AbstractVector in indexing
timholy Jun 8, 2016
9e66642
Get mapslices working with indices
timholy Jun 8, 2016
a547b9f
Fix slicedim/flipdim
timholy Jun 8, 2016
54658a8
Changes to broadcast to support .<, .==, etc for indices
timholy Jun 9, 2016
522547b
Rewrite broadcast for the jb/functions era
timholy Jun 10, 2016
b66d06c
Support OffsetArrays in broadcast
timholy Jun 10, 2016
d5750d1
boundscheck annotations for copy and perfimprovement for SubArray ind…
timholy Jun 10, 2016
336cfe6
Redesign allocate_for so it always gets passed a reference array
timholy Jun 11, 2016
9d97d4a
Make Colon index-preserving
timholy Jun 12, 2016
877ae39
shapeinfo->shape, linindices->linearindices, and add core API to exports
timholy Jun 12, 2016
b81b729
Docs and NEWS
timholy Jun 12, 2016
ea2e2d7
More show fixes and tests
timholy Jun 12, 2016
d6e65e4
Use atsign-inbounds in next for AbstractArrays
timholy Jun 12, 2016
02f111b
Optimize specializations of indices
timholy Jun 12, 2016
9da5ffc
Fixes to index_shape
timholy Jun 13, 2016
9a5c4e9
Stop using @inbounds in array iteration
timholy Jun 13, 2016
a5c16e4
Use type-stable newindexer in broadcast
timholy Jun 13, 2016
5924290
Improve performance of bounds-checking for SubArrays
timholy Jun 13, 2016
a7b88cf
Move a few atsign-inbounds to improve loop performance
timholy Jun 13, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ New language features
* Function return type syntax `function f()::T` has been added ([#1090]). Values returned
from a function with such a declaration will be converted to the specified type `T`.

* Experimental support for arrays with indexing starting at values
different from 1. The array types are expected to be defined in
packages, but now Julia provides an API for writing generic
algorithms for arbitrary indexing schemes ([#16260]).

Language changes
----------------

Expand Down Expand Up @@ -130,7 +135,7 @@ Library improvements

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

* Linear algebra:
* Arrays and linear algebra:

* All dimensions indexed by scalars are now dropped, whereas previously only
trailing scalar dimensions would be omitted from the result ([#13612]).
Expand Down Expand Up @@ -268,3 +273,4 @@ Deprecated or removed
[#16403]: https://github.com/JuliaLang/julia/issues/16403
[#16481]: https://github.com/JuliaLang/julia/issues/16481
[#16731]: https://github.com/JuliaLang/julia/issues/16731
[#16280]: https://github.com/JuliaLang/julia/issues/16260
673 changes: 501 additions & 172 deletions base/abstractarray.jl

Large diffs are not rendered by default.

28 changes: 15 additions & 13 deletions base/abstractarraymath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ imag{T<:Real}(x::AbstractArray{T}) = zero(x)
# index A[:,:,...,i,:,:,...] where "i" is in dimension "d"
# TODO: more optimized special cases
slicedim(A::AbstractArray, d::Integer, i) =
A[[ n==d ? i : (1:size(A,n)) for n in 1:ndims(A) ]...]
A[[ n==d ? i : (indices(A,n)) for n in 1:ndims(A) ]...]

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

function flipdim(A::AbstractArray, d::Integer)
nd = ndims(A)
sd = d > nd ? 1 : size(A, d)
if sd == 1 || isempty(A)
if d > nd || isempty(A)
return copy(A)
end
B = similar(A)
nnd = 0
for i = 1:nd
nnd += Int(size(A,i)==1 || i==d)
end
inds = indices(A, d)
sd = first(inds)+last(inds)
if nnd==nd
# flip along the only non-singleton dimension
for i = 1:sd
B[i] = A[sd+1-i]
for i in inds
B[i] = A[sd-i]
end
return B
end
alli = [ 1:size(B,n) for n in 1:nd ]
for i = 1:sd
B[[ n==d ? sd+1-i : alli[n] for n in 1:nd ]...] = slicedim(A, d, i)
alli = [ indices(B,n) for n in 1:nd ]
for i in inds
B[[ n==d ? sd-i : alli[n] for n in 1:nd ]...] = slicedim(A, d, i)
end
return B
end
Expand All @@ -107,13 +108,14 @@ end

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

s = r[1] = v[1]
inds = indices(v, 1)
i1 = first(inds)
s = r[i1] = v[i1]
c = zero(T)
for i=2:n #Fixme iter
for i=i1+1:last(inds)
vi = v[i]
t = s + vi
if abs(s) >= abs(vi)
Expand Down
8 changes: 5 additions & 3 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ end

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

## Iteration ##
start(A::Array) = 1
next(a::Array,i) = (a[i],i+1)
done(a::Array,i) = i == length(a)+1
next(a::Array,i) = (@_propagate_inbounds_meta; (a[i],i+1))
done(a::Array,i) = (@_inline_meta; i == length(a)+1)

## Indexing: getindex ##

Expand Down Expand Up @@ -917,6 +918,7 @@ function findin(a, b)
end

# Copying subregions
# TODO: DEPRECATE FOR #14770
function indcopy(sz::Dims, I::Vector)
n = length(I)
s = sz[n]
Expand Down
132 changes: 52 additions & 80 deletions base/arraymath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,21 @@ for f in (:+, :-, :div, :mod, :&, :|, :$)
return F
end
function ($f){S,T}(A::AbstractArray{S}, B::Range{T})
F = similar(A, promote_op($f,S,T), promote_shape(size(A),size(B)))
F = similar(A, promote_op($f,S,T), promote_shape(A,B))
for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
@inbounds F[iF] = ($f)(A[iA], B[iB])
end
return F
end
function ($f){S,T}(A::Range{S}, B::AbstractArray{T})
F = similar(B, promote_op($f,S,T), promote_shape(size(A),size(B)))
F = similar(B, promote_op($f,S,T), promote_shape(A,B))
for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
@inbounds F[iF] = ($f)(A[iA], B[iB])
end
return F
end
function ($f){S,T}(A::AbstractArray{S}, B::AbstractArray{T})
F = similar(A, promote_op($f,S,T), promote_shape(size(A),size(B)))
F = similar(A, promote_op($f,S,T), promote_shape(A,B))
for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
@inbounds F[iF] = ($f)(A[iA], B[iB])
end
Expand Down Expand Up @@ -211,26 +211,29 @@ function flipdim{T}(A::Array{T}, d::Integer)
end

function rotl90(A::AbstractMatrix)
m,n = size(A)
B = similar(A,(n,m))
for i=1:m, j=1:n #Fixme iter
B[n-j+1,i] = A[i,j]
B = similar_transpose(A)
ind2 = indices(A,2)
n = first(ind2)+last(ind2)
for i=indices(A,1), j=ind2
B[n-j,i] = A[i,j]
end
return B
end
function rotr90(A::AbstractMatrix)
m,n = size(A)
B = similar(A,(n,m))
for i=1:m, j=1:n #Fixme iter
B[j,m-i+1] = A[i,j]
B = similar_transpose(A)
ind1 = indices(A,1)
m = first(ind1)+last(ind1)
for i=ind1, j=indices(A,2)
B[j,m-i] = A[i,j]
end
return B
end
function rot180(A::AbstractMatrix)
m,n = size(A)
B = similar(A)
for i=1:m, j=1:n #Fixme iter
B[m-i+1,n-j+1] = A[i,j]
ind1, ind2 = indices(A,1), indices(A,2)
m, n = first(ind1)+last(ind1), first(ind2)+last(ind2)
for j=ind2, i=ind1
B[m-i,n-j] = A[i,j]
end
return B
end
Expand All @@ -243,96 +246,65 @@ end
rotr90(A::AbstractMatrix, k::Integer) = rotl90(A,-k)
rot180(A::AbstractMatrix, k::Integer) = mod(k, 2) == 1 ? rot180(A) : copy(A)

similar_transpose(A::AbstractMatrix) = similar_transpose(indicesbehavior(A), A)
similar_transpose(::IndicesStartAt1, A::AbstractMatrix) = similar(A, (size(A,2), size(A,1)))
similar_transpose(::IndicesBehavior, A::AbstractMatrix) = similar(A, (indices(A,2), indices(A,1)))

## Transpose ##
const transposebaselength=64
function transpose!(B::AbstractMatrix,A::AbstractMatrix)
m, n = size(A)
size(B,1) == n && size(B,2) == m || throw(DimensionMismatch("transpose"))

if m*n<=4*transposebaselength
@inbounds begin
for j = 1:n #Fixme iter
for i = 1:m #Fixme iter
B[j,i] = transpose(A[i,j])
end
end
end
else
transposeblock!(B,A,m,n,0,0)
end
return B
end
transpose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(transpose, B, A)
ctranspose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(ctranspose, B, A)
function transpose!(B::AbstractVector, A::AbstractMatrix)
length(B) == length(A) && size(A,1) == 1 || throw(DimensionMismatch("transpose"))
indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose"))
copy!(B, A)
end
function transpose!(B::AbstractMatrix, A::AbstractVector)
length(B) == length(A) && size(B,1) == 1 || throw(DimensionMismatch("transpose"))
indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose"))
copy!(B, A)
end
function transposeblock!(B::AbstractMatrix,A::AbstractMatrix,m::Int,n::Int,offseti::Int,offsetj::Int)
if m*n<=transposebaselength
@inbounds begin
for j = offsetj+(1:n) #Fixme iter
for i = offseti+(1:m) #Fixme iter
B[j,i] = transpose(A[i,j])
end
end
end
elseif m>n
newm=m>>1
transposeblock!(B,A,newm,n,offseti,offsetj)
transposeblock!(B,A,m-newm,n,offseti+newm,offsetj)
else
newn=n>>1
transposeblock!(B,A,m,newn,offseti,offsetj)
transposeblock!(B,A,m,n-newn,offseti,offsetj+newn)
end
return B
function ctranspose!(B::AbstractVector, A::AbstractMatrix)
indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose"))
ccopy!(B, A)
end
function ctranspose!(B::AbstractMatrix,A::AbstractMatrix)
m, n = size(A)
size(B,1) == n && size(B,2) == m || throw(DimensionMismatch("transpose"))
function ctranspose!(B::AbstractMatrix, A::AbstractVector)
indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose"))
ccopy!(B, A)
end

const transposebaselength=64
function transpose_f!(f,B::AbstractMatrix,A::AbstractMatrix)
indices(B,1) == indices(A,2) && indices(B,2) == indices(A,1) || throw(DimensionMismatch(string(f)))

m, n = size(A)
if m*n<=4*transposebaselength
@inbounds begin
for j = 1:n #Fixme iter
for i = 1:m #Fixme iter
B[j,i] = ctranspose(A[i,j])
for j = indices(A,2)
for i = indices(A,1)
B[j,i] = f(A[i,j])
end
end
end
else
ctransposeblock!(B,A,m,n,0,0)
transposeblock!(f,B,A,m,n,first(indices(A,1))-1,first(indices(A,2))-1)
end
return B
end
function ctranspose!(B::AbstractVector, A::AbstractMatrix)
length(B) == length(A) && size(A,1) == 1 || throw(DimensionMismatch("transpose"))
ccopy!(B, A)
end
function ctranspose!(B::AbstractMatrix, A::AbstractVector)
length(B) == length(A) && size(B,1) == 1 || throw(DimensionMismatch("transpose"))
ccopy!(B, A)
end
function ctransposeblock!(B::AbstractMatrix,A::AbstractMatrix,m::Int,n::Int,offseti::Int,offsetj::Int)
function transposeblock!(f,B::AbstractMatrix,A::AbstractMatrix,m::Int,n::Int,offseti::Int,offsetj::Int)
if m*n<=transposebaselength
@inbounds begin
for j = offsetj+(1:n) #Fixme iter
for i = offseti+(1:m) #Fixme iter
B[j,i] = ctranspose(A[i,j])
for j = offsetj+(1:n)
for i = offseti+(1:m)
B[j,i] = f(A[i,j])
end
end
end
elseif m>n
newm=m>>1
ctransposeblock!(B,A,newm,n,offseti,offsetj)
ctransposeblock!(B,A,m-newm,n,offseti+newm,offsetj)
transposeblock!(f,B,A,newm,n,offseti,offsetj)
transposeblock!(f,B,A,m-newm,n,offseti+newm,offsetj)
else
newn=n>>1
ctransposeblock!(B,A,m,newn,offseti,offsetj)
ctransposeblock!(B,A,m,n-newn,offseti,offsetj+newn)
transposeblock!(f,B,A,m,newn,offseti,offsetj)
transposeblock!(f,B,A,m,n-newn,offseti,offsetj+newn)
end
return B
end
Expand All @@ -343,11 +315,11 @@ function ccopy!(B, A)
end

function transpose(A::AbstractMatrix)
B = similar(A, size(A, 2), size(A, 1))
B = similar_transpose(A)
transpose!(B, A)
end
function ctranspose(A::AbstractMatrix)
B = similar(A, size(A, 2), size(A, 1))
B = similar_transpose(A)
ctranspose!(B, A)
end
ctranspose{T<:Real}(A::AbstractVecOrMat{T}) = transpose(A)
Expand All @@ -366,7 +338,7 @@ for (f, f!, fp, op) = ((:cumsum, :cumsum!, :cumsum_pairwise!, :+),
if n < 128
@inbounds s_ = v[i1]
@inbounds c[i1] = ($op)(s, s_)
for i = i1+1:i1+n-1 #Fixme iter
for i = i1+1:i1+n-1
@inbounds s_ = $(op)(s_, v[i])
@inbounds c[i] = $(op)(s, s_)
end
Expand All @@ -381,7 +353,7 @@ for (f, f!, fp, op) = ((:cumsum, :cumsum!, :cumsum_pairwise!, :+),
@eval function ($f!)(result::AbstractVector, v::AbstractVector)
n = length(v)
if n == 0; return result; end
($fp)(v, result, $(op==:+ ? :(zero(v[1])) : :(one(v[1]))), 1, n)
($fp)(v, result, $(op==:+ ? :(zero(first(v))) : :(one(first(v)))), first(indices(v,1)), n)
return result
end

Expand Down
Loading