Skip to content

Commit f9fb4da

Browse files
authored
Merge pull request #17816 from JuliaLang/teh/indices_iters
More indices generalizations
2 parents 2d24eda + 37e9c5c commit f9fb4da

File tree

6 files changed

+65
-15
lines changed

6 files changed

+65
-15
lines changed

base/abstractarray.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,13 @@ convert{T,S,N}(::Type{AbstractArray{T }}, A::AbstractArray{S,N}) = convert(Abst
625625

626626
convert{T,N}(::Type{Array}, A::AbstractArray{T,N}) = convert(Array{T,N}, A)
627627

628+
"""
629+
of_indices(x, y)
630+
631+
Represents the array `y` as an array having the same indices type as `x`.
632+
"""
633+
of_indices(x, y) = similar(dims->y, oftype(indices(x), indices(y)))
634+
628635
full(x::AbstractArray) = x
629636

630637
map(::Type{Integer}, a::Array) = map!(Integer, similar(a,typeof(Integer(one(eltype(a))))), a)

base/array.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ The result has the same shape and number of dimensions as `collection`.
211211
collect{T}(::Type{T}, itr) = _collect(T, itr, iteratorsize(itr))
212212

213213
_collect{T}(::Type{T}, itr, isz::HasLength) = copy!(Array{T,1}(Int(length(itr)::Integer)), itr)
214-
_collect{T}(::Type{T}, itr, isz::HasShape) = copy!(Array{T}(convert(Dims,size(itr))), itr)
214+
_collect{T}(::Type{T}, itr, isz::HasShape) = copy!(similar(Array{T}, indices(itr)), itr)
215215
function _collect{T}(::Type{T}, itr, isz::SizeUnknown)
216216
a = Array{T,1}(0)
217217
for x in itr
@@ -259,7 +259,7 @@ end
259259
_default_eltype{I,T}(::Type{Generator{I,Type{T}}}) = T
260260

261261
_array_for(T, itr, ::HasLength) = Array{T,1}(Int(length(itr)::Integer))
262-
_array_for(T, itr, ::HasShape) = Array{T}(convert(Dims,size(itr)))
262+
_array_for(T, itr, ::HasShape) = similar(Array{T}, indices(itr))
263263

264264
function collect(itr::Generator)
265265
isz = iteratorsize(itr.iter)
@@ -795,7 +795,7 @@ function findn(A::AbstractMatrix)
795795
I = similar(A, Int, nnzA)
796796
J = similar(A, Int, nnzA)
797797
count = 1
798-
for j=1:size(A,2), i=1:size(A,1)
798+
for j=indices(A,2), i=indices(A,1)
799799
if A[i,j] != 0
800800
I[count] = i
801801
J[count] = j
@@ -812,7 +812,7 @@ function findnz{T}(A::AbstractMatrix{T})
812812
NZs = Array{T,1}(nnzA)
813813
count = 1
814814
if nnzA > 0
815-
for j=1:size(A,2), i=1:size(A,1)
815+
for j=indices(A,2), i=indices(A,1)
816816
Aij = A[i,j]
817817
if Aij != 0
818818
I[count] = i

base/arraymath.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,8 @@ function ctranspose(A::AbstractMatrix)
413413
end
414414
ctranspose{T<:Real}(A::AbstractVecOrMat{T}) = transpose(A)
415415

416-
transpose(x::AbstractVector) = [ transpose(v) for i=1:1, v in x ]
417-
ctranspose{T}(x::AbstractVector{T}) = T[ ctranspose(v) for i=1:1, v in x ]
416+
transpose(x::AbstractVector) = [ transpose(v) for i=of_indices(x, OneTo(1)), v in x ]
417+
ctranspose{T}(x::AbstractVector{T}) = T[ ctranspose(v) for i=of_indices(x, OneTo(1)), v in x ]
418418

419419
_cumsum_type{T<:Number}(v::AbstractArray{T}) = typeof(+zero(T))
420420
_cumsum_type(v) = typeof(v[1]+v[1])

base/iterator.jl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ end
6969
zip(a) = Zip1(a)
7070
length(z::Zip1) = length(z.a)
7171
size(z::Zip1) = size(z.a)
72+
indices(z::Zip1) = indices(z.a)
7273
eltype{I}(::Type{Zip1{I}}) = Tuple{eltype(I)}
7374
@inline start(z::Zip1) = start(z.a)
7475
@inline function next(z::Zip1, st)
@@ -87,6 +88,7 @@ end
8788
zip(a, b) = Zip2(a, b)
8889
length(z::Zip2) = _min_length(z.a, z.b, iteratorsize(z.a), iteratorsize(z.b))
8990
size(z::Zip2) = promote_shape(size(z.a), size(z.b))
91+
indices(z::Zip2) = promote_shape(indices(z.a), indices(z.b))
9092
eltype{I1,I2}(::Type{Zip2{I1,I2}}) = Tuple{eltype(I1), eltype(I2)}
9193
@inline start(z::Zip2) = (start(z.a), start(z.b))
9294
@inline function next(z::Zip2, st)
@@ -137,6 +139,7 @@ julia> first(c)
137139
zip(a, b, c...) = Zip(a, zip(b, c...))
138140
length(z::Zip) = _min_length(z.a, z.z, iteratorsize(z.a), iteratorsize(z.z))
139141
size(z::Zip) = promote_shape(size(z.a), size(z.z))
142+
indices(z::Zip) = promote_shape(indices(z.a), indices(z.z))
140143
tuple_type_cons{S}(::Type{S}, ::Type{Union{}}) = Union{}
141144
function tuple_type_cons{S,T<:Tuple}(::Type{S}, ::Type{T})
142145
@_pure_meta
@@ -430,8 +433,10 @@ iteratoreltype{O}(::Type{Repeated{O}}) = HasEltype()
430433
abstract AbstractProdIterator
431434

432435
length(p::AbstractProdIterator) = prod(size(p))
436+
_length(p::AbstractProdIterator) = prod(map(unsafe_length, indices(p)))
433437
size(p::AbstractProdIterator) = _prod_size(p.a, p.b, iteratorsize(p.a), iteratorsize(p.b))
434-
ndims(p::AbstractProdIterator) = length(size(p))
438+
indices(p::AbstractProdIterator) = _prod_indices(p.a, p.b, iteratorsize(p.a), iteratorsize(p.b))
439+
ndims(p::AbstractProdIterator) = length(indices(p))
435440

436441
# generic methods to handle size of Prod* types
437442
_prod_size(a, ::HasShape) = size(a)
@@ -445,6 +450,17 @@ _prod_size(a, b, ::HasShape, ::HasShape) = (size(a)..., size(b)...)
445450
_prod_size(a, b, A, B) =
446451
throw(ArgumentError("Cannot construct size for objects of types $(typeof(a)) and $(typeof(b))"))
447452

453+
_prod_indices(a, ::HasShape) = indices(a)
454+
_prod_indices(a, ::HasLength) = (OneTo(length(a)), )
455+
_prod_indices(a, A) =
456+
throw(ArgumentError("Cannot compute indices for object of type $(typeof(a))"))
457+
_prod_indices(a, b, ::HasLength, ::HasLength) = (OneTo(length(a)), OneTo(length(b)))
458+
_prod_indices(a, b, ::HasLength, ::HasShape) = (OneTo(length(a)), indices(b)...)
459+
_prod_indices(a, b, ::HasShape, ::HasLength) = (indices(a)..., OneTo(length(b)))
460+
_prod_indices(a, b, ::HasShape, ::HasShape) = (indices(a)..., indices(b)...)
461+
_prod_indices(a, b, A, B) =
462+
throw(ArgumentError("Cannot construct indices for objects of types $(typeof(a)) and $(typeof(b))"))
463+
448464
# one iterator
449465
immutable Prod1{I} <: AbstractProdIterator
450466
a::I
@@ -453,6 +469,7 @@ product(a) = Prod1(a)
453469

454470
eltype{I}(::Type{Prod1{I}}) = Tuple{eltype(I)}
455471
size(p::Prod1) = _prod_size(p.a, iteratorsize(p.a))
472+
indices(p::Prod1) = _prod_indices(p.a, iteratorsize(p.a))
456473

457474
@inline start(p::Prod1) = start(p.a)
458475
@inline function next(p::Prod1, st)

base/test.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -827,10 +827,11 @@ approx_full(x) = full(x)
827827
function test_approx_eq(va, vb, Eps, astr, bstr)
828828
va = approx_full(va)
829829
vb = approx_full(vb)
830-
if length(va) != length(vb)
830+
la, lb = length(linearindices(va)), length(linearindices(vb))
831+
if la != lb
831832
error("lengths of ", astr, " and ", bstr, " do not match: ",
832-
"\n ", astr, " (length $(length(va))) = ", va,
833-
"\n ", bstr, " (length $(length(vb))) = ", vb)
833+
"\n ", astr, " (length $la) = ", va,
834+
"\n ", bstr, " (length $lb) = ", vb)
834835
end
835836
diff = real(zero(eltype(va)))
836837
for (xa, xb) = zip(va, vb)
@@ -856,7 +857,7 @@ array_eps{T}(a::AbstractArray{Complex{T}}) = eps(float(maximum(x->(isfinite(x) ?
856857
array_eps(a) = eps(float(maximum(x->(isfinite(x) ? abs(x) : oftype(x,NaN)), a)))
857858

858859
test_approx_eq(va, vb, astr, bstr) =
859-
test_approx_eq(va, vb, 1E4*length(va)*max(array_eps(va), array_eps(vb)), astr, bstr)
860+
test_approx_eq(va, vb, 1E4*length(linearindices(va))*max(array_eps(va), array_eps(vb)), astr, bstr)
860861

861862
"""
862863
@test_approx_eq_eps(a, b, tol)
@@ -966,10 +967,10 @@ end
966967
# nothing.
967968
function test_approx_eq_modphase{S<:Real,T<:Real}(
968969
a::StridedVecOrMat{S}, b::StridedVecOrMat{T}, err=nothing)
969-
m, n = size(a)
970-
@test n==size(b, 2) && m==size(b, 1)
970+
@test indices(a,1) == indices(b,1) && indices(a,2) == indices(b,2)
971+
m = length(indices(a,1))
971972
err === nothing && (err=m^3*(eps(S)+eps(T)))
972-
for i=1:n
973+
for i in indices(a,2)
973974
v1, v2 = a[:, i], b[:, i]
974975
@test_approx_eq_eps min(abs(norm(v1-v2)), abs(norm(v1+v2))) 0.0 err
975976
end

test/offsetarray.jl

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ using OAs
101101

102102
let
103103
# Basics
104+
v0 = rand(4)
105+
v = OffsetArray(v0, (-3,))
106+
@test indices(v) == (-2:1,)
107+
@test_throws ErrorException size(v)
108+
@test_throws ErrorException size(v, 1)
109+
104110
A0 = [1 3; 2 4]
105111
A = OffsetArray(A0, (-1,2)) # LinearFast
106112
S = OffsetArray(view(A0, 1:2, 1:2), (-1,2)) # LinearSlow
@@ -179,6 +185,10 @@ end
179185

180186
# show
181187
io = IOBuffer()
188+
show(io, v)
189+
str = takebuf_string(io)
190+
show(io, v0)
191+
@test str == takebuf_string(io)
182192
show(io, A)
183193
str = takebuf_string(io)
184194
@test str == "[1 3; 2 4]"
@@ -261,7 +271,7 @@ v = view(A0, 1:1, i1)
261271
# logical indexing
262272
@test A[A .> 2] == [3,4]
263273

264-
# copy!
274+
# copy! and fill!
265275
a = OffsetArray{Int}((-3:-1,))
266276
fill!(a, -1)
267277
copy!(a, (1,2)) # non-array iterables
@@ -316,6 +326,7 @@ copy!(am, b)
316326
@test am[1,8] == 2
317327
@test am[1,9] == -1
318328

329+
# map
319330
dest = similar(am)
320331
map!(+, dest, am, am)
321332
@test dest[1,7] == 2
@@ -326,7 +337,13 @@ am = map(identity, a)
326337
@test isa(am, OffsetArray)
327338
@test am == a
328339

340+
# other functions
341+
v = OffsetArray(v0, (-3,))
342+
@test_approx_eq v v
343+
@test parent(v') == v0'
344+
@test indices(v') === (1:1,-2:1)
329345
A = OffsetArray(rand(4,4), (-3,5))
346+
@test_approx_eq A A
330347
@test maximum(A) == maximum(parent(A))
331348
@test minimum(A) == minimum(parent(A))
332349
@test extrema(A) == extrema(parent(A))
@@ -352,6 +369,14 @@ pmax, ipmax = findmax(parent(A))
352369
@test amax == pmax
353370
@test A[iamax] == amax
354371
@test amax == parent(A)[ipmax]
372+
z = OffsetArray([0 0; 2 0; 0 0; 0 0], (-3,-1))
373+
I,J = findn(z)
374+
@test I == [-1]
375+
@test J == [0]
376+
I,J,N = findnz(z)
377+
@test I == [-1]
378+
@test J == [0]
379+
@test N == [2]
355380

356381
v = OffsetArray([1,1e100,1,-1e100], (-3,))*1000
357382
v2 = OffsetArray([1,-1e100,1,1e100], (5,))*1000

0 commit comments

Comments
 (0)