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

Faster view creation #19259

Merged
merged 4 commits into from
Jan 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,9 @@ function convert(::Type{UpperTriangular}, A::Bidiagonal)
end
end

# Deprecate three-arg SubArray since the constructor doesn't need the dims tuple
@deprecate SubArray(parent::AbstractArray, indexes::Tuple, dims::Tuple) SubArray(parent, indexes)

# Deprecate vectorized unary functions over sparse matrices in favor of compact broadcast syntax (#17265).
for f in (:sin, :sinh, :sind, :asin, :asinh, :asind,
:tan, :tanh, :tand, :atan, :atanh, :atand,
Expand Down
10 changes: 10 additions & 0 deletions base/multidimensional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,16 @@ end
end
index_ndims() = ()

# combined dimensionality of all indices
# rather than returning N, it returns an NTuple{N,Bool} so the result is inferrable
@inline index_dimsum(i1, I...) = (index_dimsum(I...)...)
@inline index_dimsum(::Colon, I...) = (true, index_dimsum(I...)...)
@inline index_dimsum(::AbstractArray{Bool}, I...) = (true, index_dimsum(I...)...)
@inline function index_dimsum{_,N}(::AbstractArray{_,N}, I...)
(ntuple(x->true, Val{N})..., index_dimsum(I...)...)
end
index_dimsum() = ()

# Recursively compute the lengths of a list of indices, without dropping scalars
# These need to be inlined for more than 3 indexes
# Trailing CartesianIndex{0}s and arrays thereof are strange when used as
Expand Down
41 changes: 26 additions & 15 deletions base/subarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,22 @@ immutable SubArray{T,N,P,I,L} <: AbstractArray{T,N}
offset1::Int # for linear indexing and pointer, only valid when L==true
stride1::Int # used only for linear indexing
function SubArray(parent, indexes, offset1, stride1)
@_inline_meta
check_parent_index_match(parent, indexes)
new(parent, indexes, offset1, stride1)
end
end
# Compute the linear indexability of the indices, and combine it with the linear indexing of the parent
function SubArray(parent::AbstractArray, indexes::Tuple, dims::Tuple)
SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, dims)
function SubArray(parent::AbstractArray, indexes::Tuple)
@_inline_meta
SubArray(linearindexing(viewindexing(indexes), linearindexing(parent)), parent, indexes, index_dimsum(indexes...))
end
function SubArray{P, I, N}(::LinearSlow, parent::P, indexes::I, dims::NTuple{N})
function SubArray{P, I, N}(::LinearSlow, parent::P, indexes::I, ::NTuple{N})
@_inline_meta
SubArray{eltype(P), N, P, I, false}(parent, indexes, 0, 0)
end
function SubArray{P, I, N}(::LinearFast, parent::P, indexes::I, dims::NTuple{N})
function SubArray{P, I, N}(::LinearFast, parent::P, indexes::I, ::NTuple{N})
@_inline_meta
# Compute the stride and offset
stride1 = compute_stride1(parent, indexes)
SubArray{eltype(P), N, P, I, true}(parent, indexes, compute_offset1(parent, stride1, indexes), stride1)
Expand Down Expand Up @@ -92,7 +96,7 @@ view(A::AbstractArray, I::Union{ViewIndex, AbstractCartesianIndex}...) = view(A,
function unsafe_view(A::AbstractArray, I::ViewIndex...)
@_inline_meta
J = to_indexes(I...)
SubArray(A, J, map(unsafe_length, index_shape(A, J...)))
SubArray(A, J)
end
# When we take the view of a view, it's often possible to "reindex" the parent
# view's indices such that we can "pop" the parent view and keep just one layer
Expand All @@ -103,15 +107,15 @@ end
unsafe_view(V::SubArray, I::ViewIndex...) = (@_inline_meta; _maybe_reindex(V, to_indexes(I...)))
_maybe_reindex(V, I) = (@_inline_meta; _maybe_reindex(V, I, I))
_maybe_reindex{C<:AbstractCartesianIndex}(V, I, ::Tuple{AbstractArray{C}, Vararg{Any}}) =
(@_inline_meta; SubArray(V, I, map(unsafe_length, index_shape(V, I...))))
(@_inline_meta; SubArray(V, I))
# But allow arrays of CartesianIndex{1}; they behave just like arrays of Ints
_maybe_reindex{C<:AbstractCartesianIndex{1}}(V, I, A::Tuple{AbstractArray{C}, Vararg{Any}}) =
(@_inline_meta; _maybe_reindex(V, I, tail(A)))
_maybe_reindex(V, I, A::Tuple{Any, Vararg{Any}}) = (@_inline_meta; _maybe_reindex(V, I, tail(A)))
function _maybe_reindex(V, I, ::Tuple{})
@_inline_meta
idxs = reindex(V, V.indexes, to_indexes(I...))
SubArray(V.parent, idxs, map(unsafe_length, (index_shape(V.parent, idxs...))))
SubArray(V.parent, idxs)
end

## Re-indexing is the heart of a view, transforming A[i, j][x, y] to A[i[x], j[y]]
Expand Down Expand Up @@ -222,7 +226,7 @@ substrides(s, parent, dim, I::Tuple{Any, Vararg{Any}}) = throw(ArgumentError("st
stride(V::SubArray, d::Integer) = d <= ndims(V) ? strides(V)[d] : strides(V)[end] * size(V)[end]

compute_stride1{N}(parent::AbstractArray, I::NTuple{N}) =
compute_stride1(1, fill_to_length(indices(parent), OneTo(1), Val{N}), I)
(@_inline_meta; compute_stride1(1, fill_to_length(indices(parent), OneTo(1), Val{N}), I))
compute_stride1(s, inds, I::Tuple{}) = s
compute_stride1(s, inds, I::Tuple{Real, Vararg{Any}}) =
(@_inline_meta; compute_stride1(s*unsafe_length(inds[1]), tail(inds), tail(I)))
Expand Down Expand Up @@ -252,11 +256,15 @@ end
# If the result is one-dimensional and it's a Colon, then linear
# indexing uses the indices along the given dimension. Otherwise
# linear indexing always starts with 1.
compute_offset1(parent, stride1::Integer, I::Tuple) = (@_inline_meta; compute_offset1(parent, stride1, find_extended_dims(I)..., I))
compute_offset1(parent, stride1::Integer, dims::Tuple{Int}, inds::Tuple{Colon}, I::Tuple) = compute_linindex(parent, I) - stride1*first(indices(parent, dims[1])) # index-preserving case
compute_offset1(parent, stride1::Integer, dims, inds, I::Tuple) = compute_linindex(parent, I) - stride1 # linear indexing starts with 1
compute_offset1(parent, stride1::Integer, I::Tuple) =
(@_inline_meta; compute_offset1(parent, stride1, find_extended_dims(I)..., I))
compute_offset1(parent, stride1::Integer, dims::Tuple{Int}, inds::Tuple{Colon}, I::Tuple) =
(@_inline_meta; compute_linindex(parent, I) - stride1*first(indices(parent, dims[1]))) # index-preserving case
compute_offset1(parent, stride1::Integer, dims, inds, I::Tuple) =
(@_inline_meta; compute_linindex(parent, I) - stride1) # linear indexing starts with 1

function compute_linindex{N}(parent, I::NTuple{N})
@_inline_meta
IP = fill_to_length(indices(parent), OneTo(1), Val{N})
compute_linindex(1, 1, IP, I)
end
Expand All @@ -278,10 +286,13 @@ end
compute_linindex(f, s, IP::Tuple, I::Tuple{}) = f

find_extended_dims(I) = (@_inline_meta; _find_extended_dims((), (), 1, I...))
_find_extended_dims(dims, inds, dim) = dims, inds
_find_extended_dims(dims, inds, dim, ::Real, I...) = _find_extended_dims(dims, inds, dim+1, I...)
_find_extended_dims(dims, inds, dim, i1::AbstractCartesianIndex, I...) = _find_extended_dims(dims, inds, dim, i1.I..., I...)
_find_extended_dims(dims, inds, dim, i1, I...) = _find_extended_dims((dims..., dim), (inds..., i1), dim+1, I...)
_find_extended_dims(dims, inds, dim) = (@_inline_meta; return (dims, inds))
_find_extended_dims(dims, inds, dim, ::Real, I...) =
(@_inline_meta; _find_extended_dims(dims, inds, dim+1, I...))
_find_extended_dims(dims, inds, dim, i1::AbstractCartesianIndex, I...) =
(@_inline_meta; _find_extended_dims(dims, inds, dim, i1.I..., I...))
_find_extended_dims(dims, inds, dim, i1, I...) =
(@_inline_meta; _find_extended_dims((dims..., dim), (inds..., i1), dim+1, I...))

unsafe_convert{T,N,P,I<:Tuple{Vararg{RangeIndex}}}(::Type{Ptr{T}}, V::SubArray{T,N,P,I}) =
unsafe_convert(Ptr{T}, V.parent) + (first_index(V)-1)*sizeof(T)
Expand Down