diff --git a/base/abstractarray.jl b/base/abstractarray.jl index e9e58c6beab8b..5cc00a3a6bdcf 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -96,12 +96,13 @@ linearindexing(::LinearIndexing, ::LinearIndexing) = LinearSlow() Expr(:block, Expr(:meta, :inline), ex) end +# check along a single dimension checkbounds(::Type{Bool}, sz::Integer, i) = throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))")) checkbounds(::Type{Bool}, sz::Integer, i::Real) = 1 <= i <= sz checkbounds(::Type{Bool}, sz::Integer, ::Colon) = true function checkbounds(::Type{Bool}, sz::Integer, r::Range) @_propagate_inbounds_meta - isempty(r) || (checkbounds(Bool, sz, minimum(r)) && checkbounds(Bool, sz, maximum(r))) + isempty(r) | (checkbounds(Bool, sz, first(r)) & checkbounds(Bool, sz, last(r))) end checkbounds(::Type{Bool}, sz::Integer, I::AbstractArray{Bool}) = length(I) == sz function checkbounds(::Type{Bool}, sz::Integer, I::AbstractArray) @@ -112,6 +113,21 @@ function checkbounds(::Type{Bool}, sz::Integer, I::AbstractArray) end b end + +# check all dimensions +function checkbounds{N,T}(::Type{Bool}, sz::NTuple{N,Integer}, I1::T, I...) + @_inline_meta + checkbounds(Bool, sz[1], I1) & checkbounds(Bool, tail(sz), I...) +end +checkbounds{T<:Integer}(::Type{Bool}, sz::Tuple{T}, I1) = (@_inline_meta; checkbounds(Bool, sz[1], I1)) +checkbounds{N}(::Type{Bool}, sz::NTuple{N,Integer}, I1) = (@_inline_meta; checkbounds(Bool, prod(sz), I1)) +checkbounds{N}(::Type{Bool}, sz::NTuple{N,Integer}) = (@_inline_meta; checkbounds(Bool, sz, 1)) # for a[] + +checkbounds(::Type{Bool}, sz::Tuple{}, i) = (@_inline_meta; checkbounds(Bool, 1, i)) +function checkbounds(::Type{Bool}, sz::Tuple{}, i, I...) + @_inline_meta + checkbounds(Bool, 1, i) & checkbounds(Bool, (), I...) +end # Prevent allocation of a GC frame by hiding the BoundsError in a noinline function throw_boundserror(A, I) = (@_noinline_meta; throw(BoundsError(A, I))) @@ -119,41 +135,16 @@ throw_boundserror(A, I) = (@_noinline_meta; throw(BoundsError(A, I))) checkbounds(A::AbstractArray, I...) = (@_inline_meta; _internal_checkbounds(A, I...)) # The internal function is named _internal_checkbounds since there had been a # _checkbounds previously that meant something different. +_internal_checkbounds(A::AbstractArray) = true _internal_checkbounds(A::AbstractArray, I::AbstractArray{Bool}) = size(A) == size(I) || throw_boundserror(A, I) _internal_checkbounds(A::AbstractArray, I::AbstractVector{Bool}) = length(A) == length(I) || throw_boundserror(A, I) -_internal_checkbounds(A::AbstractArray, I) = (@_inline_meta; checkbounds(Bool, length(A), I) || throw_boundserror(A, I)) -function _internal_checkbounds(A::AbstractMatrix, I, J) - @_inline_meta - (checkbounds(Bool, size(A,1), I) && checkbounds(Bool, size(A,2), J)) || - throw_boundserror(A, (I, J)) -end -function _internal_checkbounds(A::AbstractArray, I, J) +function _internal_checkbounds(A::AbstractArray, I1, I...) + # having I1 seems important for good codegen @_inline_meta - (checkbounds(Bool, size(A,1), I) && checkbounds(Bool, trailingsize(A,Val{2}), J)) || - throw_boundserror(A, (I, J)) -end -@generated function _internal_checkbounds(A::AbstractArray, I...) - meta = Expr(:meta, :inline) - N = length(I) - Isplat = [:(I[$d]) for d=1:N] - error = :(throw_boundserror(A, tuple($(Isplat...)))) - args = Expr[:(checkbounds(Bool, size(A,$dim), I[$dim]) || $error) for dim in 1:N-1] - push!(args, :(checkbounds(Bool, trailingsize(A,Val{$N}), I[$N]) || $error)) - Expr(:block, meta, args...) + checkbounds(Bool, size(A), I1, I...) || throw_boundserror(A, (I1, I...)) end -## Bounds-checking without errors ## -function checkbounds(::Type{Bool}, sz::Dims, I...) - n = length(I) - for dim = 1:(n-1) - checkbounds(Bool, sz[dim], I[dim]) || return false - end - s = sz[n] - for i = n+1:length(sz) - s *= sz[i] - end - checkbounds(Bool, s, I[n]) -end +# See also specializations in multidimensional ## Constructors ## @@ -167,14 +158,6 @@ similar( a::AbstractArray, T::Type, dims::Integer...) = similar(a, T, dims) similar( a::AbstractArray, T::Type, dims::DimsInteger) = Array(T, dims...) similar( a::AbstractArray, T::Type, dims::Dims) = Array(T, dims) -function reshape(a::AbstractArray, dims::Dims) - if prod(dims) != length(a) - throw(ArgumentError("dimensions must be consistent with array size (expected $(length(a)), got $(prod(dims)))")) - end - copy!(similar(a, dims), a) -end -reshape(a::AbstractArray, dims::Int...) = reshape(a, dims) - ## from general iterable to any array function copy!(dest::AbstractArray, src) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 58109ef463954..818a67a344c7b 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -201,7 +201,7 @@ function repmat(a::AbstractVector, m::Int) end # Generalized repmat -function repeat{T}(A::Array{T}; +function repeat{T}(A::AbstractArray{T}; inner::Array{Int} = ones(Int, ndims(A)), outer::Array{Int} = ones(Int, ndims(A))) ndims_in = ndims(A) diff --git a/base/array.jl b/base/array.jl index 5da33987fdcc6..727b0bb0152db 100644 --- a/base/array.jl +++ b/base/array.jl @@ -96,8 +96,11 @@ function reinterpret{T,S,N}(::Type{T}, a::Array{S}, dims::NTuple{N,Int}) ccall(:jl_reshape_array, Array{T,N}, (Any, Any, Any), Array{T,N}, a, dims) end +reshape(a::Vector, dims::Tuple{Int}) = reshape_a(a, dims) +reshape{N}(a::Array, dims::NTuple{N,Int}) = reshape_a(a, dims) + # reshaping to same # of dimensions -function reshape{T,N}(a::Array{T,N}, dims::NTuple{N,Int}) +function reshape_a{T,N}(a::Array{T,N}, dims::NTuple{N,Int}) if prod(dims) != length(a) throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(a))")) end @@ -108,7 +111,7 @@ function reshape{T,N}(a::Array{T,N}, dims::NTuple{N,Int}) end # reshaping to different # of dimensions -function reshape{T,N}(a::Array{T}, dims::NTuple{N,Int}) +function reshape_a{T,N}(a::Array{T}, dims::NTuple{N,Int}) if prod(dims) != length(a) throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(a))")) end diff --git a/base/bitarray.jl b/base/bitarray.jl index a1bcfb64f7701..ed1bdc973a240 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -463,8 +463,11 @@ function copy!(dest::BitArray, src::Array) return unsafe_copy!(dest, 1, src, 1, length(src)) end +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{N}(B::BitArray, dims::NTuple{N,Int}) +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 diff --git a/base/complex.jl b/base/complex.jl index afa246b6a04a2..b0d781a804cd3 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -792,7 +792,7 @@ big{T<:AbstractFloat,N}(A::AbstractArray{Complex{T},N}) = convert(AbstractArray{ promote_array_type{S<:Union{Complex, Real}, AT<:AbstractFloat}(F, ::Type{S}, ::Type{Complex{AT}}) = Complex{AT} -function complex{S<:Real,T<:Real}(A::Array{S}, B::Array{T}) +function complex{S<:Real,T<:Real}(A::AbstractArray{S}, B::AbstractArray{T}) if size(A) != size(B); throw(DimensionMismatch()); end F = similar(A, typeof(complex(zero(S),zero(T)))) for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B)) @@ -801,7 +801,7 @@ function complex{S<:Real,T<:Real}(A::Array{S}, B::Array{T}) return F end -function complex{T<:Real}(A::Real, B::Array{T}) +function complex{T<:Real}(A::Real, B::AbstractArray{T}) F = similar(B, typeof(complex(A,zero(T)))) for (iF, iB) in zip(eachindex(F), eachindex(B)) @inbounds F[iF] = complex(A, B[iB]) @@ -809,7 +809,7 @@ function complex{T<:Real}(A::Real, B::Array{T}) return F end -function complex{T<:Real}(A::Array{T}, B::Real) +function complex{T<:Real}(A::AbstractArray{T}, B::Real) F = similar(A, typeof(complex(zero(T),B))) for (iF, iA) in zip(eachindex(F), eachindex(A)) @inbounds F[iF] = complex(A[iA], B) diff --git a/base/linalg/dense.jl b/base/linalg/dense.jl index a7236b2c6dbb0..e6e7c3be05b19 100644 --- a/base/linalg/dense.jl +++ b/base/linalg/dense.jl @@ -150,7 +150,7 @@ function trace{T}(A::Matrix{T}) t end -function kron{T,S}(a::Matrix{T}, b::Matrix{S}) +function kron{T,S}(a::AbstractMatrix{T}, b::AbstractMatrix{S}) R = Array(promote_type(T,S), size(a,1)*size(b,1), size(a,2)*size(b,2)) m = 1 for j = 1:size(a,2), l = 1:size(b,2), i = 1:size(a,1) @@ -163,11 +163,11 @@ function kron{T,S}(a::Matrix{T}, b::Matrix{S}) R end -kron(a::Number, b::Union{Number, Vector, Matrix}) = a * b -kron(a::Union{Vector, Matrix}, b::Number) = a * b -kron(a::Vector, b::Vector)=vec(kron(reshape(a,length(a),1),reshape(b,length(b),1))) -kron(a::Matrix, b::Vector)=kron(a,reshape(b,length(b),1)) -kron(a::Vector, b::Matrix)=kron(reshape(a,length(a),1),b) +kron(a::Number, b::Union{Number, AbstractVecOrMat}) = a * b +kron(a::AbstractVecOrMat, b::Number) = a * b +kron(a::AbstractVector, b::AbstractVector)=vec(kron(reshape(a,length(a),1),reshape(b,length(b),1))) +kron(a::AbstractMatrix, b::AbstractVector)=kron(a,reshape(b,length(b),1)) +kron(a::AbstractVector, b::AbstractMatrix)=kron(reshape(a,length(a),1),b) ^(A::Matrix, p::Integer) = p < 0 ? inv(A^-p) : Base.power_by_squaring(A,p) diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index d7227b70932bb..9ba9673e9da63 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -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) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 2fa75eda9456c..74ed2b7c1e07b 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -178,6 +178,40 @@ end # IteratorsMD using .IteratorsMD +# Bounds-checking specialization +# Specializing for a fixed number of arguments provides a ~25% +# improvement over the general definitions in abstractarray.jl +for N = 1:5 + args = [:($(symbol(:I, d))) for d = 1:N] + targs = [:($(symbol(:I, d))::Union{Colon,Number,AbstractVector}) for d = 1:N] # prevent co-opting the CartesianIndex version + exs = [:(checkbounds(Bool, size(A, $d), $(args[d]))) for d = 1:N] + cbexpr = exs[1] + for d = 2:N + cbexpr = :($(exs[d]) & $cbexpr) + end + @eval begin + function checkbounds(A::AbstractArray, $(args...)) + @_inline_meta + _internal_checkbounds(A, $(args...)) + end + function _internal_checkbounds{T}(A::AbstractArray{T,$N}, $(targs...)) + @_inline_meta + ($cbexpr) || throw_boundserror(A, ($(args...),)) + end + end +end + +# Bounds-checking with CartesianIndex +@inline function checkbounds(::Type{Bool}, ::Tuple{}, I1::CartesianIndex) + checkbounds(Bool, (), I1.I...) +end +@inline function checkbounds(::Type{Bool}, sz::Tuple{}, I1::CartesianIndex, I...) + checkbounds(Bool, (), I1.I..., I...) +end +@inline function checkbounds(::Type{Bool}, sz::Dims, I1::CartesianIndex, I...) + checkbounds(Bool, sz, I1.I..., I...) +end + # Recursively compute the lengths of a list of indices, without dropping scalars # These need to be inlined for more than 3 indexes index_lengths(A::AbstractArray, I::Colon) = (length(A),) diff --git a/base/pointer.jl b/base/pointer.jl index d8e2a82c03a7a..6a6c6f9f29244 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -26,7 +26,7 @@ cconvert(::Type{Ptr{UInt8}}, s::AbstractString) = bytestring(s) cconvert(::Type{Ptr{Int8}}, s::AbstractString) = bytestring(s) unsafe_convert{T}(::Type{Ptr{T}}, a::Array{T}) = ccall(:jl_array_ptr, Ptr{T}, (Any,), a) -unsafe_convert(::Type{Ptr{Void}}, a::Array) = ccall(:jl_array_ptr, Ptr{Void}, (Any,), a) +unsafe_convert{S,T}(::Type{Ptr{S}}, a::AbstractArray{T}) = convert(Ptr{S}, unsafe_convert(Ptr{T}, a)) # unsafe pointer to array conversions function pointer_to_array{T}(p::Ptr{T}, d::Integer, own::Bool=false) diff --git a/base/reduce.jl b/base/reduce.jl index b9ab425ac13fa..8e5238b7624ce 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -370,7 +370,7 @@ function extrema(A::AbstractArray, dims) extrema!(B, A) end -@generated function extrema!{T,N}(B, A::Array{T,N}) +@generated function extrema!{T,N}(B, A::AbstractArray{T,N}) quote sA = size(A) sB = size(B) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl new file mode 100644 index 0000000000000..52a8fe755e0ae --- /dev/null +++ b/base/reshapedarray.jl @@ -0,0 +1,107 @@ +using Base.MultiplicativeInverses: SignedMultiplicativeInverse + +immutable ReshapedArray{T,N,P<:AbstractArray,MI<:Tuple{Vararg{SignedMultiplicativeInverse{Int}}}} <: AbstractArray{T,N} + parent::P + dims::NTuple{N,Int} + mi::MI +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(parent(A), A.mi) +function reshapedrange{M}(P, mi::NTuple{M}) + iter = eachindex(P) + ReshapedRange{typeof(iter),M}(iter, mi) +end + +immutable ReshapedIndex{T} + parentindex::T +end + +# eachindex(A::ReshapedArray) = ReshapedRange(A) # TODO: uncomment this line +start(R::ReshapedRange) = start(R.iter) +@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 = front(size_strides(parent)) + strds1 = map(s->max(1,s), strds) # for resizing empty arrays + mi = map(SignedMultiplicativeInverse, strds1) + ReshapedArray(parent, dims, reverse(mi)) +end + +function _reshape(p::Tuple{AbstractArray,LinearFast}, dims::Dims) + parent = p[1] + 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) = 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 + +@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) + +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) diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 61a3f6b8e3ed0..3ac95c4d7c6b5 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -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) diff --git a/base/sparse.jl b/base/sparse.jl index 963abc1a946f3..6a4d684d1b943 100644 --- a/base/sparse.jl +++ b/base/sparse.jl @@ -3,6 +3,7 @@ module SparseArrays using Base: Func, AddFun, OrFun, ConjFun, IdFun +using Base: ReshapedArray using Base.Sort: Forward using Base.LinAlg: AbstractTriangular, PosDefException diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index e5afd28f0d2ad..5418e2ca33e4b 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -956,23 +956,30 @@ end function convert{T}(::Type{Matrix{T}}, D::Dense{T}) s = unsafe_load(D.p) a = Array(T, s.nrow, s.ncol) - if s.d == s.nrow - unsafe_copy!(pointer(a), s.x, s.d*s.ncol) + copy!(a, D) +end +function Base.copy!(dest::AbstractArray, D::Dense) + s = unsafe_load(D.p) + n = s.nrow*s.ncol + n <= length(dest) || throw(BoundsError(dest, n)) + if s.d == s.nrow && isa(dest, Array) + unsafe_copy!(pointer(dest), s.x, s.d*s.ncol) else + k = 0 for j = 1:s.ncol for i = 1:s.nrow - a[i,j] = unsafe_load(s.x, i + (j - 1)*s.d) + dest[k+=1] = unsafe_load(s.x, i + (j - 1)*s.d) end end end - a + dest end convert{T}(::Type{Matrix}, D::Dense{T}) = convert(Matrix{T}, D) function convert{T}(::Type{Vector{T}}, D::Dense{T}) if size(D, 2) > 1 throw(DimensionMismatch("input must be a vector but had $(size(D, 2)) columns")) end - reshape(convert(Matrix, D), size(D, 1)) + copy!(Array(T, size(D, 1)), D) end convert{T}(::Type{Vector}, D::Dense{T}) = convert(Vector{T}, D) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index dad4ea51eeae4..b04abd2264cd8 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -172,14 +172,12 @@ function reinterpret{T,Tv,Ti,N}(::Type{T}, a::SparseMatrixCSC{Tv,Ti}, dims::NTup return SparseMatrixCSC(mS, nS, colptr, rowval, nzval) end -function reshape{Tv,Ti}(a::SparseMatrixCSC{Tv,Ti}, dims::NTuple{2,Int}) - if prod(dims) != length(a) - throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(a))")) - end - mS,nS = dims +function copy{T,P<:SparseMatrixCSC}(ra::ReshapedArray{T,2,P}) + mS,nS = size(ra) + a = parent(ra) mA,nA = size(a) numnz = nnz(a) - colptr = Array(Ti, nS+1) + colptr = similar(a.colptr, nS+1) rowval = similar(a.rowval) nzval = copy(a.nzval) diff --git a/base/subarray.jl b/base/subarray.jl index 5077d8faec5de..402c838b4e1d0 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -2,6 +2,7 @@ typealias NonSliceIndex Union{Colon, AbstractVector} typealias ViewIndex Union{Real, NonSliceIndex} +abstract AbstractCartesianIndex{N} # This is a hacky forward declaration for CartesianIndex # L is true if the view itself supports fast linear indexing immutable SubArray{T,N,P,I,L} <: AbstractArray{T,N} @@ -47,8 +48,6 @@ function getindex(N::NoSlice, r::Range{Int}) N end -abstract AbstractCartesianIndex{N} # This is a hacky forward declaration for CartesianIndex - # This computes the linear indexing compatability for a given tuple of indices viewindexing() = LinearFast() # Leading scalar indexes simply increase the stride @@ -264,10 +263,7 @@ compute_first_index(f, s, parent, dim, I::Tuple{}) = f unsafe_convert{T,N,P<:Array,I<:Tuple{Vararg{Union{RangeIndex, NoSlice}}}}(::Type{Ptr{T}}, V::SubArray{T,N,P,I}) = - pointer(V.parent) + (first_index(V)-1)*sizeof(T) - -unsafe_convert{T,N,P<:Array,I<:Tuple{Vararg{Union{RangeIndex, NoSlice}}}}(::Type{Ptr{Void}}, V::SubArray{T,N,P,I}) = - convert(Ptr{Void}, unsafe_convert(Ptr{T}, V)) + unsafe_convert(Ptr{T}, V.parent) + (first_index(V)-1)*sizeof(T) pointer(V::FastSubArray, i::Int) = pointer(V.parent, V.first_index + V.stride1*(i-1)) pointer(V::FastContiguousSubArray, i::Int) = pointer(V.parent, V.first_index + i-1) diff --git a/base/sysimg.jl b/base/sysimg.jl index 012ebae67f88a..cf7e55471ae0b 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -96,16 +96,18 @@ importall .SimdLoop include("reduce.jl") ## core structures +include("reshapedarray.jl") include("bitarray.jl") include("intset.jl") include("dict.jl") include("set.jl") include("iterator.jl") -# StridedArrays -typealias StridedArray{T,N,A<:DenseArray,I<:Tuple{Vararg{Union{RangeIndex, NoSlice, AbstractCartesianIndex}}}} Union{DenseArray{T,N}, SubArray{T,N,A,I}} -typealias StridedVector{T,A<:DenseArray,I<:Tuple{Vararg{Union{RangeIndex, NoSlice, AbstractCartesianIndex}}}} Union{DenseArray{T,1}, SubArray{T,1,A,I}} -typealias StridedMatrix{T,A<:DenseArray,I<:Tuple{Vararg{Union{RangeIndex, NoSlice, AbstractCartesianIndex}}}} Union{DenseArray{T,2}, SubArray{T,2,A,I}} +# Definition of StridedArray +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 diff --git a/base/tuple.jl b/base/tuple.jl index ba1659c21c571..030e8ead2a04d 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -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) = diff --git a/base/unicode/checkstring.jl b/base/unicode/checkstring.jl index 8b9f344831f95..50bece61b683d 100644 --- a/base/unicode/checkstring.jl +++ b/base/unicode/checkstring.jl @@ -37,7 +37,7 @@ Input Arguments: Optional Input Arguments: -* `pos` start position (defaults to `start(dat)`) +* `pos` start position (defaults to 1) * `endpos` end position (defaults to `endof(dat)`) Keyword Arguments: @@ -56,8 +56,8 @@ Throws: """ function unsafe_checkstring end -function unsafe_checkstring(dat::Vector{UInt8}, - pos = start(dat), +function unsafe_checkstring(dat::AbstractVector{UInt8}, + pos = 1, endpos = endof(dat) ; accept_long_null = true, @@ -152,9 +152,11 @@ function unsafe_checkstring(dat::Vector{UInt8}, return totalchar, flags, num4byte, num3byte, num2byte end -function unsafe_checkstring{T <: Union{Vector{UInt16}, Vector{UInt32}, AbstractString}}( - dat::T, - pos = start(dat), +typealias AbstractString1632{Tel<:Union{UInt16,UInt32}} Union{AbstractVector{Tel}, AbstractString} + +function unsafe_checkstring( + dat::AbstractString1632, + pos = 1, endpos = endof(dat) ; accept_long_null = true, @@ -184,7 +186,7 @@ function unsafe_checkstring{T <: Union{Vector{UInt16}, Vector{UInt32}, AbstractS ch, pos = next(dat, pos) !is_surrogate_trail(ch) && throw(UnicodeError(UTF_ERR_NOT_TRAIL, pos, ch)) num4byte += 1 - if T != Vector{UInt16} + if !(typeof(dat) <: AbstractVector{UInt16}) !accept_surrogates && throw(UnicodeError(UTF_ERR_SURROGATE, pos, ch)) flags |= UTF_SURROGATE end @@ -210,7 +212,7 @@ Input Arguments: Optional Input Arguments: -* `startpos` start position (defaults to `start(dat)`) +* `startpos` start position (defaults to 1) * `endpos` end position (defaults to `endof(dat)`) Keyword Arguments: @@ -230,7 +232,7 @@ Throws: function checkstring end # No need to check bounds if using defaults -checkstring(dat; kwargs...) = unsafe_checkstring(dat, start(dat), endof(dat); kwargs...) +checkstring(dat; kwargs...) = unsafe_checkstring(dat, 1, endof(dat); kwargs...) # Make sure that beginning and end positions are bounds checked function checkstring(dat, startpos, endpos = endof(dat); kwargs...) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index c75c144690fa8..0c1726c40c37e 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -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 @@ -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 @@ -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) @@ -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...]) @@ -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 @@ -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) @@ -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 ] diff --git a/test/arrayops.jl b/test/arrayops.jl index c9ee2caf1373a..9867e062af864 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -87,6 +87,14 @@ a = reshape(b, (2, 2, 2, 2, 2)) @test a[2,1,2,2,1] == b[14] @test a[2,2,2,2,2] == b[end] +# reshaping linearslow arrays +a = zeros(1, 5) +s = sub(a, :, [2,3,5]) +@test length(reshape(s, length(s))) == 3 +a = zeros(0, 5) # an empty linearslow array +s = sub(a, :, [2,3,5]) +@test length(reshape(s, length(s))) == 0 + a = rand(1, 1, 8, 8, 1) @test @inferred(squeeze(a, 1)) == @inferred(squeeze(a, (1,))) == reshape(a, (1, 8, 8, 1)) @test @inferred(squeeze(a, (1, 5))) == squeeze(a, (5, 1)) == reshape(a, (1, 8, 8)) @@ -1090,7 +1098,7 @@ a = ones(5,0) b = sub(a, :, :) @test mdsum(b) == 0 -a = reshape(1:60, 3, 4, 5) +a = copy(reshape(1:60, 3, 4, 5)) @test a[CartesianIndex{3}(2,3,4)] == 44 a[CartesianIndex{3}(2,3,3)] = -1 @test a[CartesianIndex{3}(2,3,3)] == -1 diff --git a/test/fft.jl b/test/fft.jl index 354964ec88324..ef32747382c0d 100644 --- a/test/fft.jl +++ b/test/fft.jl @@ -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 @@ -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) diff --git a/test/linalg/arnoldi.jl b/test/linalg/arnoldi.jl index 4ce632206cc47..98588016588b5 100644 --- a/test/linalg/arnoldi.jl +++ b/test/linalg/arnoldi.jl @@ -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) diff --git a/test/show.jl b/test/show.jl index 3094ac11f2aa3..56d29e132b98c 100644 --- a/test/show.jl +++ b/test/show.jl @@ -390,8 +390,8 @@ A = reshape(1:16,4,4) @test replstr(Bidiagonal(A,false)) == "4×4 Bidiagonal{$Int}:\n 1 ⋅ ⋅ ⋅\n 2 6 ⋅ ⋅\n ⋅ 7 11 ⋅\n ⋅ ⋅ 12 16" @test replstr(SymTridiagonal(A+A')) == "4×4 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))) == "4×4 Tridiagonal{$Int}:\n 1 5 ⋅ ⋅\n 2 6 10 ⋅\n ⋅ 7 11 15\n ⋅ ⋅ 12 16" -@test replstr(UpperTriangular(A)) == "4×4 UpperTriangular{$Int,Array{$Int,2}}:\n 1 5 9 13\n ⋅ 6 10 14\n ⋅ ⋅ 11 15\n ⋅ ⋅ ⋅ 16" -@test replstr(LowerTriangular(A)) == "4×4 LowerTriangular{$Int,Array{$Int,2}}:\n 1 ⋅ ⋅ ⋅\n 2 6 ⋅ ⋅\n 3 7 11 ⋅\n 4 8 12 16" +@test replstr(UpperTriangular(copy(A))) == "4×4 UpperTriangular{$Int,Array{$Int,2}}:\n 1 5 9 13\n ⋅ 6 10 14\n ⋅ ⋅ 11 15\n ⋅ ⋅ ⋅ 16" +@test replstr(LowerTriangular(copy(A))) == "4×4 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;])" diff --git a/test/sparsedir/sparse.jl b/test/sparsedir/sparse.jl index 93bbf69d769af..74cd45195cb7a 100644 --- a/test/sparsedir/sparse.jl +++ b/test/sparsedir/sparse.jl @@ -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,:] @@ -650,7 +650,7 @@ let A = sprand(5,5,0.5,(n)->rand(Float64,n)), ACPY = copy(A) @test A == ACPY C = reinterpret(Int64, A, (25, 1)) @test A == ACPY - D = reinterpret(Int64, B) + D = reinterpret(Int64, copy(B)) @test C == D end diff --git a/test/subarray.jl b/test/subarray.jl index 8aed951ccc382..877e69633539b 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -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 @@ -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) @@ -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,:), @@ -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 @@ -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)