-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Add optimised methods for reducing(hcat/vcat on any iterators of vectors #31644
Changes from all commits
6c4cbf9
32da054
bee2ed1
62d1384
75d22ca
0a193a6
889a554
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,5 +1,10 @@ | ||||||
# This file is a part of Julia. License is MIT: https://julialang.org/license | ||||||
|
||||||
## Helpers | ||||||
eltype_or_default_eltype(itr::T) where T = eltype_or_default_eltype(itr, IteratorEltype(T)) | ||||||
eltype_or_default_eltype(itr::T, ::HasEltype) where T = eltype(T) | ||||||
eltype_or_default_eltype(itr, ::EltypeUnknown) = @default_eltype(itr) | ||||||
|
||||||
## reductions ## | ||||||
|
||||||
###### Generic (map)reduce functions ###### | ||||||
|
@@ -354,10 +359,102 @@ julia> reduce(*, [2; 3; 4]; init=-1) | |||||
-24 | ||||||
``` | ||||||
""" | ||||||
reduce(op, itr; kw...) = mapreduce(identity, op, itr; kw...) | ||||||
function reduce(op, itr::T; kw...) where T | ||||||
# Redispatch, adding traits | ||||||
reduce(op, itr, eltype_or_default_eltype(itr), IteratorSize(T); kw...) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a private There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, unless it should be a private There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess |
||||||
end | ||||||
|
||||||
function reduce(op, itr, et, isize; kw...) | ||||||
# Fallback: if nothing interesting is being done with the traits | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Think this comment can likely be removed. |
||||||
# or the operation | ||||||
return mapreduce(identity, op, itr; kw...) | ||||||
end | ||||||
|
||||||
reduce(op, a::Number) = a # Do we want this? | ||||||
|
||||||
##### Operation specific reduce optimisations | ||||||
|
||||||
## vcat | ||||||
|
||||||
function reduce(::typeof(vcat), xs, T::Type{<:AbstractVector{V}}, isize) where V | ||||||
x_state = iterate(xs) | ||||||
x_state === nothing && return reduce_empty(vcat, T) | ||||||
x1, state = x_state | ||||||
|
||||||
ret = Vector(x1) | ||||||
|
||||||
hinted_size = 0 | ||||||
if !(isize isa SizeUnknown) | ||||||
# Assume first element has representitive size, unless that would make this too large | ||||||
SIZEHINT_CAP = 10^5 | ||||||
hinted_size = min(SIZEHINT_CAP, length(xs)*length(x1)) | ||||||
sizehint!(ret, hinted_size) | ||||||
end | ||||||
|
||||||
x_state = iterate(xs, state) | ||||||
while(x_state !== nothing) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
x, state = x_state | ||||||
append!(ret, x) | ||||||
x_state = iterate(xs, state) | ||||||
end | ||||||
|
||||||
if length(ret) < hinted_size/2 # it is only allowable to be at most 2x too much memory | ||||||
sizehint!(ret, length(ret)) | ||||||
end | ||||||
|
||||||
return ret | ||||||
end | ||||||
|
||||||
## hcat | ||||||
|
||||||
function reduce(::typeof(hcat), xs, T::Type{<:AbstractVector{V}}, isize::SizeUnknown) where V | ||||||
x_state = iterate(xs) | ||||||
x_state === nothing && return reduce_empty(hcat, T) | ||||||
x1, state = x_state | ||||||
|
||||||
dim1_size = length(x1) | ||||||
dim2_size = 1 | ||||||
ret_vec = Vector(x1) | ||||||
|
||||||
x_state = iterate(xs, state) | ||||||
|
||||||
while(x_state !== nothing) | ||||||
x, state = x_state | ||||||
append!(ret_vec, x) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do we know this will fit into
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct we don't, see https://github.com/JuliaLang/julia/pull/31644/files#r274153197 |
||||||
dim2_size += 1 | ||||||
x_state = iterate(xs, state) | ||||||
end | ||||||
|
||||||
# Reshape will throw errors if anything was the wrong size | ||||||
nalimilan marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
return reshape(ret_vec, (dim1_size, dim2_size)) | ||||||
end | ||||||
|
||||||
function reduce(::typeof(hcat), xs, T::Type{<:AbstractVector{V}}, isize) where V | ||||||
# Size is known | ||||||
x_state = iterate(xs) | ||||||
x_state === nothing && return reduce_empty(hcat, T) | ||||||
x1, state = x_state | ||||||
|
||||||
dim1_size = size(x1,1) | ||||||
dim2_size = length(xs) | ||||||
|
||||||
ret = similar(x1, eltype(x1), (dim1_size, dim2_size)) | ||||||
copyto!(ret, 1, x1, 1) | ||||||
|
||||||
x_state = iterate(xs, state) | ||||||
offset = length(x1)+1 | ||||||
while(x_state !== nothing) | ||||||
x, state = x_state | ||||||
length(x)==dim1_size || throw(DimensionMismatch("hcat")) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should include dimensions in error message |
||||||
copyto!(ret, offset, x, 1) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do we know this will fit into
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we don't this function needs to be tightenned to
And things that fell back though And then a nother (marginally slower, but benchmarking will tell) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't understand, this PR breaks the use cases I linked so how can it be in another PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry I was unclear.
does not have to be handled, in this PR (I think it should, if it doesn't add undue complexity). Thus working out how to actually efficently handle hetrogeneous types could be in a PR; |
||||||
offset += length(x) | ||||||
x_state = iterate(xs, state) | ||||||
end | ||||||
|
||||||
return ret | ||||||
end | ||||||
|
||||||
|
||||||
###### Specific reduction functions ###### | ||||||
|
||||||
## sum | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can remove this comment, it is literally what the code below it does.