Skip to content

Commit

Permalink
More fixes to ReshapedArrays
Browse files Browse the repository at this point in the history
  • Loading branch information
timholy committed Mar 21, 2016
1 parent d19bc22 commit 7325418
Show file tree
Hide file tree
Showing 13 changed files with 102 additions and 47 deletions.
6 changes: 5 additions & 1 deletion base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,11 @@ function copy!(dest::BitArray, doffs::Integer, src::BitArray, soffs::Integer, n:
return dest
end

function reshape{N}(B::BitArray, dims::NTuple{N,Int})
reshape(B::BitVector, dims::Tuple{Int}) = reshape_ba(B, dims)
reshape(B::BitArray, dims::Tuple{Int}) = reshape_ba(B, dims)
reshape{N}(B::BitArray, dims::NTuple{N,Int}) = reshape_ba(B, dims)

function reshape_ba{N}(B::BitArray, dims::NTuple{N,Int})
prod(dims) == length(B) ||
throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(B))"))
dims == size(B) && return B
Expand Down
4 changes: 2 additions & 2 deletions base/linalg/symmetric.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ convert{T}(::Type{AbstractMatrix{T}}, A::Symmetric) = Symmetric(convert(Abstract
convert{T,S<:AbstractMatrix}(::Type{Hermitian{T,S}},A::Hermitian{T,S}) = A
convert{T,S<:AbstractMatrix}(::Type{Hermitian{T,S}},A::Hermitian) = Hermitian{T,S}(convert(S,A.data),A.uplo)
convert{T}(::Type{AbstractMatrix{T}}, A::Hermitian) = Hermitian(convert(AbstractMatrix{T}, A.data), symbol(A.uplo))
copy{T,S}(A::Symmetric{T,S}) = Symmetric{T,S}(copy(A.data),A.uplo)
copy{T,S}(A::Hermitian{T,S}) = Hermitian{T,S}(copy(A.data),A.uplo)
copy{T,S}(A::Symmetric{T,S}) = (B = copy(A.data); Symmetric{T,typeof(B)}(B,A.uplo))
copy{T,S}(A::Hermitian{T,S}) = (B = copy(A.data); Hermitian{T,typeof(B)}(B,A.uplo))
ishermitian(A::Hermitian) = true
ishermitian{T<:Real,S}(A::Symmetric{T,S}) = true
ishermitian{T<:Complex,S}(A::Symmetric{T,S}) = all(imag(A.data) .== 0)
Expand Down
75 changes: 54 additions & 21 deletions base/reshapedarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ immutable ReshapedArray{T,N,P<:AbstractArray,MI<:Tuple{Vararg{SignedMultiplicati
end
ReshapedArray{T,N}(parent::AbstractArray{T}, dims::NTuple{N,Int}, mi) = ReshapedArray{T,N,typeof(parent),typeof(mi)}(parent, dims, mi)

# LinearFast ReshapedArray
typealias ReshapedArrayLF{T,N,P<:AbstractArray} ReshapedArray{T,N,P,Tuple{}}

# Fast iteration on ReshapedArrays: use the parent iterator
immutable ReshapedRange{I,M}
iter::I
mi::NTuple{M,SignedMultiplicativeInverse{Int}}
end
ReshapedRange(A::ReshapedArray) = reshapedrange(A.parent, A.mi)
ReshapedRange(A::ReshapedArray) = reshapedrange(parent(A), A.mi)
function reshapedrange{M}(P, mi::NTuple{M})
iter = eachindex(P)
ReshapedRange{typeof(iter),M}(iter, mi)
Expand All @@ -22,26 +25,35 @@ immutable ReshapedIndex{T}
parentindex::T
end

eachindex(A::ReshapedArray) = ReshapedRange(A)
# eachindex(A::ReshapedArray) = ReshapedRange(A) # TODO: uncomment this line
start(R::ReshapedRange) = start(R.iter)
done(R::ReshapedRange, i) = done(R.iter, i)
function next(R::ReshapedRange, i)
@_inline_meta
@inline done(R::ReshapedRange, i) = done(R.iter, i)
@inline function next(R::ReshapedRange, i)
item, inext = next(R.iter, i)
ReshapedIndex(item), inext
end
length(R::ReshapedRange) = length(R.iter)

function reshape(parent::AbstractArray, dims::Dims)
prod(dims) == length(parent) || throw(DimensionMismatch("parent has $(length(parent)) elements, which is incompatible with size $dims"))
_reshape((parent, linearindexing(parent)), dims)
end
reshape(R::ReshapedArray, dims::Dims) = reshape(R.parent, dims)
reshape(a::AbstractArray, len::Int) = reshape(a, (len,))
reshape(a::AbstractArray, dims::Int...) = reshape(a, dims)

# When reshaping Vector->Vector, don't wrap with a ReshapedArray
reshape{T}(v::ReshapedArray{T,1}, dims::Tuple{Int}) = reshape(v.parent, dims[1])
reshape(v::AbstractVector, dims::Tuple{Int}) = reshape(v, dims[1])
function reshape(v::AbstractVector, len::Int)
len == length(v) || throw(DimensionMismatch("parent has $(length(v)) elements, which is incompatible with length $len"))
v
end

function _reshape(p::Tuple{AbstractArray,LinearSlow}, dims::Dims)
parent = p[1]
strds = strides(parent)
mi = map(SignedMultiplicativeInverse, tail(strds))
strds = front(size_strides(parent))
mi = map(SignedMultiplicativeInverse, strds)
ReshapedArray(parent, dims, reverse(mi))
end

Expand All @@ -50,24 +62,45 @@ function _reshape(p::Tuple{AbstractArray,LinearFast}, dims::Dims)
ReshapedArray(parent, dims, ())
end

@inline size_strides(A::AbstractArray) = tail(size_strides((1,), size(A)...))
size_strides(out::Tuple) = out
@inline size_strides(out, s, sz...) = size_strides((out..., out[end]*s), sz...)

size(A::ReshapedArray) = A.dims
size(A::ReshapedArray, d) = d <= ndims(A) ? A.dims[d] : 1
similar(A::ReshapedArray, eltype::Type, dims...) = similar(A.parent, eltype, dims...)
linearindexing{T,N,P<:AbstractArray}(::Type{ReshapedArray{T,N,P,Tuple{}}}) = LinearFast()

ind2sub_rs(::Tuple{}, i::Int) = i
ind2sub_rs(strds, i) = (@_inline_meta; ind2sub_rs((), strds, i-1))
ind2sub_rs(out, ::Tuple{}, ind) = (@_inline_meta; (ind+1, out...))
function ind2sub_rs(out, strds, ind)
@_inline_meta
similar(A::ReshapedArray, eltype::Type) = similar(parent(A), eltype, size(A))
similar(A::ReshapedArray, eltype::Type, dims...) = similar(parent(A), eltype, dims...)
linearindexing{R<:ReshapedArrayLF}(::Type{R}) = LinearFast()
parent(A::ReshapedArray) = A.parent
parentindexes(A::ReshapedArray) = map(s->1:s, size(parent(A)))
reinterpret{T}(::Type{T}, A::ReshapedArray, dims::Dims) = reinterpret(T, parent(A), dims)

@inline ind2sub_rs(::Tuple{}, i::Int) = i
@inline ind2sub_rs(strds, i) = ind2sub_rs((), strds, i-1)
@inline ind2sub_rs(out, ::Tuple{}, ind) = (ind+1, out...)
@inline function ind2sub_rs(out, strds, ind)
d, r = divrem(ind, strds[1])
ind2sub_rs((d+1, out...), tail(strds), r)
end

getindex(A::ReshapedArray, index::Int) = A.parent[ind2sub_rs(A.mi, index)]
getindex(A::ReshapedArray, indexes::Int...) = (@_inline_meta; A.parent[ind2sub_rs(A.mi, sub2ind(size(A), indexes...))...])
getindex(A::ReshapedArray, index::ReshapedIndex) = A.parent[index.parentindex]
@inline getindex(A::ReshapedArrayLF, index::Int) = (@boundscheck checkbounds(A, index); @inbounds ret = parent(A)[index]; ret)
@inline getindex(A::ReshapedArray, indexes::Int...) = (@boundscheck checkbounds(A, indexes...); _unsafe_getindex(A, indexes...))
@inline getindex(A::ReshapedArray, index::ReshapedIndex) = (@boundscheck checkbounds(parent(A), index.parentindex); @inbounds ret = parent(A)[index.parentindex]; ret)

@inline _unsafe_getindex(A::ReshapedArray, indexes::Int...) = (@inbounds ret = parent(A)[ind2sub_rs(A.mi, sub2ind(size(A), indexes...))...]; ret)
@inline _unsafe_getindex(A::ReshapedArrayLF, indexes::Int...) = (@inbounds ret = parent(A)[sub2ind(size(A), indexes...)]; ret)

@inline setindex!(A::ReshapedArrayLF, val, index::Int) = (@boundscheck checkbounds(A, index); @inbounds parent(A)[index] = val; val)
@inline setindex!(A::ReshapedArray, val, indexes::Int...) = (@boundscheck checkbounds(A, indexes...); _unsafe_setindex!(A, val, indexes...))
@inline setindex!(A::ReshapedArray, val, index::ReshapedIndex) = (@boundscheck checkbounds(parent(A), index.parentindex); @inbounds parent(A)[index.parentindex] = val; val)

@inline _unsafe_setindex!(A::ReshapedArray, val, indexes::Int...) = (@inbounds parent(A)[ind2sub_rs(A.mi, sub2ind(size(A), indexes...))...] = val; val)
@inline _unsafe_setindex!(A::ReshapedArrayLF, val, indexes::Int...) = (@inbounds parent(A)[sub2ind(size(A), indexes...)] = val; val)

typealias ArrayT{N, T} Array{T,N}
convert{T,S,N}(::Type{Array{T,N}}, V::ReshapedArray{S,N}) = copy!(Array(T, size(V)), V)
convert{T,N}(::Type{ArrayT{N}}, V::ReshapedArray{T,N}) = copy!(Array(T, size(V)), V)

setindex!(A::ReshapedArray, val, index::Int) = (@_inline_meta; A.parent[ind2sub_rs(A.mi, index)...] = val)
setindex!(A::ReshapedArray, val, indexes::Int...) = (@_inline_meta; A.parent[ind2sub_rs(A.mi, sub2ind(size(A), indexes...))...] = val)
setindex!(A::ReshapedArray, val, index::ReshapedIndex) = A.parent[index.parentindex] = val
unsafe_convert{T}(::Type{Ptr{T}}, a::ReshapedArray{T}) = unsafe_convert(Ptr{T}, parent(a))
unsafe_convert{T,N,P<:ReshapedArray,I<:Tuple{Vararg{Union{RangeIndex, NoSlice}}}}(::Type{Ptr{T}}, V::SubArray{T,N,P,I}) =
unsafe_convert(Ptr{T}, V.parent) + (first_index(V)-1)*sizeof(T)
6 changes: 5 additions & 1 deletion base/sharedarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,11 @@ length(S::SharedArray) = prod(S.dims)
size(S::SharedArray) = S.dims
linearindexing{S<:SharedArray}(::Type{S}) = LinearFast()

function reshape{T,N}(a::SharedArray{T}, dims::NTuple{N,Int})
reshape(a::SharedVector, dims::Tuple{Int}) = reshape_sa(a, dims)
reshape(a::SharedArray, dims::Tuple{Int}) = reshape_sa(a, dims)
reshape{N}(a::SharedArray, dims::NTuple{N,Int}) = reshape_sa(a, dims)

function reshape_sa{T,N}(a::SharedArray{T}, dims::NTuple{N,Int})
(length(a) != prod(dims)) && throw(DimensionMismatch("dimensions must be consistent with array size"))
refs = Array(Future, length(a.pids))
for (i, p) in enumerate(a.pids)
Expand Down
7 changes: 4 additions & 3 deletions base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@ include("set.jl")
include("iterator.jl")

# Definition of StridedArray
typealias StridedArray{T,N,A<:DenseArray,I<:Tuple{Vararg{Union{RangeIndex, NoSlice, AbstractCartesianIndex}}},MI} Union{DenseArray{T,N}, SubArray{T,N,A,I}, ReshapedArray{T,N,A,MI}}
typealias StridedVector{T,A<:DenseArray,I<:Tuple{Vararg{Union{RangeIndex, NoSlice, AbstractCartesianIndex}}},MI} Union{DenseArray{T,1}, SubArray{T,1,A,I}, ReshapedArray{T,1,A,MI}}
typealias StridedMatrix{T,A<:DenseArray,I<:Tuple{Vararg{Union{RangeIndex, NoSlice, AbstractCartesianIndex}}},MI} Union{DenseArray{T,2}, SubArray{T,2,A,I}, ReshapedArray{T,2,A,MI}}
typealias StridedReshapedArray{T,N,A<:DenseArray} ReshapedArray{T,N,A}
typealias StridedArray{T,N,A<:Union{DenseArray,StridedReshapedArray},I<:Tuple{Vararg{Union{RangeIndex, NoSlice, AbstractCartesianIndex}}}} Union{DenseArray{T,N}, SubArray{T,N,A,I}, StridedReshapedArray{T,N}}
typealias StridedVector{T,A<:Union{DenseArray,StridedReshapedArray},I<:Tuple{Vararg{Union{RangeIndex, NoSlice, AbstractCartesianIndex}}}} Union{DenseArray{T,1}, SubArray{T,1,A,I}, StridedReshapedArray{T,1}}
typealias StridedMatrix{T,A<:Union{DenseArray,StridedReshapedArray},I<:Tuple{Vararg{Union{RangeIndex, NoSlice, AbstractCartesianIndex}}}} Union{DenseArray{T,2}, SubArray{T,2,A,I}, StridedReshapedArray{T,2}}
typealias StridedVecOrMat{T} Union{StridedVector{T}, StridedMatrix{T}}

# For OS specific stuff
Expand Down
13 changes: 13 additions & 0 deletions base/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ indexed_next(I, i, state) = done(I,state) ? throw(BoundsError()) : next(I, state
eltype(::Type{Tuple{}}) = Bottom
eltype{T,_}(::Type{NTuple{_,T}}) = T

# front (the converse of tail: it skips the last entry)

function front(t::Tuple)
@_inline_meta
_front((), t...)
end
front(::Tuple{}) = error("Cannot call front on an empty tuple")
_front(out, v) = out
function _front(out, v, t...)
@_inline_meta
_front((out..., v), t...)
end

## mapping ##

ntuple(f::Function, n::Integer) =
Expand Down
14 changes: 7 additions & 7 deletions test/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ import Base: trailingsize
const can_inline = Base.JLOptions().can_inline != 0
function test_scalar_indexing{T}(::Type{T}, shape, ::Type{TestAbstractArray})
N = prod(shape)
A = reshape(1:N, shape)
A = reshape(collect(1:N), shape)
B = T(A)
@test A == B
# Test indexing up to 5 dimensions
Expand Down Expand Up @@ -186,7 +186,7 @@ end

function test_vector_indexing{T}(::Type{T}, shape, ::Type{TestAbstractArray})
N = prod(shape)
A = reshape(1:N, shape)
A = reshape(collect(1:N), shape)
B = T(A)
idxs = rand(1:N, 3, 3, 3)
@test B[idxs] == A[idxs] == idxs
Expand All @@ -202,7 +202,7 @@ end

function test_primitives{T}(::Type{T}, shape, ::Type{TestAbstractArray})
N = prod(shape)
A = reshape(1:N, shape)
A = reshape(collect(1:N), shape)
B = T(A)

# last(a)
Expand All @@ -222,7 +222,7 @@ function test_primitives{T}(::Type{T}, shape, ::Type{TestAbstractArray})
end

# reshape(a::AbstractArray, dims::Dims)
@test_throws ArgumentError reshape(B, (0, 1))
@test_throws DimensionMismatch reshape(B, (0, 1))

# copy!(dest::AbstractArray, src::AbstractArray)
@test_throws BoundsError copy!(Array(Int, 10), [1:11...])
Expand Down Expand Up @@ -252,7 +252,7 @@ type UnimplementedArray{T, N} <: AbstractArray{T, N} end

function test_getindex_internals{T}(::Type{T}, shape, ::Type{TestAbstractArray})
N = prod(shape)
A = reshape(1:N, shape)
A = reshape(collect(1:N), shape)
B = T(A)

@test getindex(A) == 1
Expand All @@ -272,7 +272,7 @@ end

function test_setindex!_internals{T}(::Type{T}, shape, ::Type{TestAbstractArray})
N = prod(shape)
A = reshape(1:N, shape)
A = reshape(collect(1:N), shape)
B = T(A)

Base.unsafe_setindex!(B, 1)
Expand Down Expand Up @@ -362,7 +362,7 @@ function test_ind2sub(::Type{TestAbstractArray})
n = rand(2:5)
dims = tuple(rand(1:5, n)...)
len = prod(dims)
A = reshape(1:len, dims...)
A = reshape(collect(1:len), dims...)
I = ind2sub(dims, [1:len...])
for i in 1:len
idx = [ I[j][i] for j in 1:n ]
Expand Down
2 changes: 1 addition & 1 deletion test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3893,7 +3893,7 @@ end
# `TypeVar`) without crashing
let
function arrayset_unknown_dim{T}(::Type{T}, n)
Base.arrayset(reshape(Vector{T}(1), ones(Int, n)...), 2, 1)
Base.arrayset(pointer_to_array(pointer(Vector{T}(1)), (ones(Int, n)...)), 2, 1)
end
arrayset_unknown_dim(Any, 1)
arrayset_unknown_dim(Any, 2)
Expand Down
4 changes: 2 additions & 2 deletions test/fft.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ b = rand(17,14)
b[3:6,9:12] = m4
sm4 = slice(b,3:6,9:12)

m3d = map(Float32,reshape(1:5*3*2, 5, 3, 2))
m3d = map(Float32,copy(reshape(1:5*3*2, 5, 3, 2)))
true_fftd3_m3d = Array(Float32, 5, 3, 2)
true_fftd3_m3d[:,:,1] = 17:2:45
true_fftd3_m3d[:,:,2] = -15
Expand Down Expand Up @@ -277,7 +277,7 @@ end

# test inversion, scaling, and pre-allocated variants
for T in (Complex64, Complex128)
for x in (T[1:100;], reshape(T[1:200;], 20,10))
for x in (T[1:100;], copy(reshape(T[1:200;], 20,10)))
y = similar(x)
for planner in (plan_fft, plan_fft_, plan_ifft, plan_ifft_)
p = planner(x)
Expand Down
2 changes: 1 addition & 1 deletion test/linalg/arnoldi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ let
(Q,R)=qr(randn(100,50))
Q=reshape(Q,(50,2,50))
# Construct trace-preserving completely positive map from this
Phi=CPM(Q)
Phi=CPM(copy(Q))
(d,v,nconv,numiter,numop,resid) = eigs(Phi,nev=1,which=:LM)
# Properties: largest eigenvalue should be 1, largest eigenvector, when reshaped as matrix
# should be a Hermitian positive definite matrix (up to an arbitrary phase)
Expand Down
4 changes: 2 additions & 2 deletions test/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,8 @@ A = reshape(1:16,4,4)
@test replstr(Bidiagonal(A,false)) == "4x4 Bidiagonal{$Int}:\n 1 ⋅ ⋅ ⋅\n 2 6 ⋅ ⋅\n ⋅ 7 11 ⋅\n ⋅ ⋅ 12 16"
@test replstr(SymTridiagonal(A+A')) == "4x4 SymTridiagonal{$Int}:\n 2 7 ⋅ ⋅\n 7 12 17 ⋅\n ⋅ 17 22 27\n ⋅ ⋅ 27 32"
@test replstr(Tridiagonal(diag(A,-1),diag(A),diag(A,+1))) == "4x4 Tridiagonal{$Int}:\n 1 5 ⋅ ⋅\n 2 6 10 ⋅\n ⋅ 7 11 15\n ⋅ ⋅ 12 16"
@test replstr(UpperTriangular(A)) == "4x4 UpperTriangular{$Int,Array{$Int,2}}:\n 1 5 9 13\n ⋅ 6 10 14\n ⋅ ⋅ 11 15\n ⋅ ⋅ ⋅ 16"
@test replstr(LowerTriangular(A)) == "4x4 LowerTriangular{$Int,Array{$Int,2}}:\n 1 ⋅ ⋅ ⋅\n 2 6 ⋅ ⋅\n 3 7 11 ⋅\n 4 8 12 16"
@test replstr(UpperTriangular(copy(A))) == "4x4 UpperTriangular{$Int,Array{$Int,2}}:\n 1 5 9 13\n ⋅ 6 10 14\n ⋅ ⋅ 11 15\n ⋅ ⋅ ⋅ 16"
@test replstr(LowerTriangular(copy(A))) == "4x4 LowerTriangular{$Int,Array{$Int,2}}:\n 1 ⋅ ⋅ ⋅\n 2 6 ⋅ ⋅\n 3 7 11 ⋅\n 4 8 12 16"

# Issue #15525, printing of vcat
@test sprint(show, :([a;])) == ":([a;])"
Expand Down
2 changes: 1 addition & 1 deletion test/sparsedir/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ for i = 1 : 10
end

# sparse ref
a116 = reshape(1:16, 4, 4)
a116 = copy(reshape(1:16, 4, 4))
s116 = sparse(a116)
p = [4, 1, 2, 3, 2]
@test full(s116[p,:]) == a116[p,:]
Expand Down
10 changes: 5 additions & 5 deletions test/subarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ index25 = (3, 8, :, 2:11, 12:3:22, [4,1,5,9], sub(1:25,[13,22,24]))
index125 = (113, :, 85:121, 2:15:92, [99,14,103], sub(1:125,[66,18,59]))

if testfull
let A = reshape(1:5*7*11, 11, 7, 5)
let A = copy(reshape(1:5*7*11, 11, 7, 5))
runviews(A, index5, index25, index125)
end
end
Expand All @@ -296,7 +296,7 @@ end
oindex = (:, 6, 3:7, 13:-2:1, [8,4,6,12,5,7])

if testfull
let B = reshape(1:13^3, 13, 13, 13)
let B = copy(reshape(1:13^3, 13, 13, 13))
for o3 in oindex, o2 in oindex, o1 in oindex
sliceB = slice(B, o1, o2, o3)
runviews(sliceB, index5, index25, index125)
Expand All @@ -307,7 +307,7 @@ if testfull
end

if !testfull
let B = reshape(1:13^3, 13, 13, 13)
let B = copy(reshape(1:13^3, 13, 13, 13))
for oind in ((:,:,:),
(:,:,6),
(:,6,:),
Expand Down Expand Up @@ -340,7 +340,7 @@ x11289 = randn(5,5)
####### "Classical" tests #######

# sub
A = reshape(1:120, 3, 5, 8)
A = copy(reshape(1:120, 3, 5, 8))
sA = sub(A, 2, 1:5, :)
@test strides(sA) == (1, 3, 15)
@test parent(sA) == A
Expand Down Expand Up @@ -385,7 +385,7 @@ sB = sub(B, 2:3, 2:3)
@test Base.unsafe_getindex(sB, sB.>8) == [10, 11]

# slice
A = reshape(1:120, 3, 5, 8)
A = copy(reshape(1:120, 3, 5, 8))
sA = slice(A, 2, :, 1:8)
@test parent(sA) == A
@test parentindexes(sA) == (2, :, 1:8)
Expand Down

0 comments on commit 7325418

Please sign in to comment.