Skip to content
Draft
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
7 changes: 7 additions & 0 deletions src/vector_of_array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,13 @@ function Base.append!(
end

function Base.stack(VA::AbstractVectorOfArray; dims = :)
# `stack.(VA.u)` exists to collapse any nested `AbstractVectorOfArray`
# (or other non-numeric-array) elements of `VA.u` into plain arrays before
# the outer `stack`. When the elements are already plain numeric arrays,
# that inner `stack.()` call is a redundant elementwise copy.
if eltype(VA.u) <: AbstractArray{<:Number}
return stack(VA.u; dims)
end
return stack(stack.(VA.u); dims)
end

Expand Down
8 changes: 8 additions & 0 deletions test/Core/interface_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ testva = VA[VA[ones(2, 2), 2ones(2, 2)], 3ones(2, 2, 2)]
@test stack(testva) ==
[1.0 1.0; 1.0 1.0;;; 2.0 2.0; 2.0 2.0;;;; 3.0 3.0; 3.0 3.0;;; 3.0 3.0; 3.0 3.0]

# stack on plain-numeric inner arrays skips `stack.(VA.u)` (an elementwise
# copy of every inner array before the outer stack): only the final output
# array is allocated, instead of also allocating one copy per inner array.
numeric_stack = VectorOfArray([rand(2) for _ in 1:1000])
stack(numeric_stack) # compile away type instability before measuring
@test (@allocated stack(numeric_stack)) < 20_000 # final 2x1000 Float64 array alone is 16000 bytes
@test stack(numeric_stack) == reduce(hcat, numeric_stack.u)

# convert array from VectorOfArray/DiffEqArray
t = 1:8
recs = [rand(10, 7) for i in 1:8]
Expand Down
Loading