Open tkf opened 2 years ago
Two variants are discussed in https://julialang.zulipchat.com/#narrow/stream/301865-juliafolds/topic/Poll.3A.20.20new.20reduction.20syntax.60FLoops.2E.40combine.60/near/269893356
(1) @init sub_acc = ...
and @combine acc .+= sub_acc
(i.e., syntax as in the OP)
@floop begin
@init subsum = 0.0
@init buf = zeros(Int, 10)
for x in xs
bin = max(1, min(10, floor(Int, x)))
buf[bin] += 1
subsum += sin(x)
end
@combine s = s + subsum # equivalent to: @combine s += subsum
@combine h .+= buf
end
s :: Float64 # computed sum (assuming `subsum::Float64`)
h :: Vector{Int} # computed histogram
!@isdefined(buf) # `buf` not defined here
!@isdefined(subsum) # `subsum` not defined here
(2) @init acc = ...
and @combine acc .+= _
@floop begin
@init s = 0.0
@init h = zeros(Int, 10)
for x in xs
bin = max(1, min(10, floor(Int, x)))
h[bin] += 1
s += sin(x)
end
@combine s = s + _ # equivalent to: @combine s += _
@combine h .+= _
end
s :: Float64 # computed sum (assuming `s::Float64` in the for loop)
h :: Vector{Int} # computed histogram
i.e., @combine acc .+= _
uses _
as an implicit argument for "another acc
" from a different task
Some syntax ideas from brainstorming in JuliaLab meeting:
Example 1: maybe useful to "flip" the arguments?
julia> @floop begin
@init odds = Int[]
@init evens = Int[]
for x in 1:5
if isodd(x)
# push!(odds, x)
pushfirst!(odds, x)
else
push!(evens, x)
end
end
# @combine odds = append!(_, _)
@combine odds = append!(_2, _1)
@combine evens = append!(_, _)
end
(odds, evens)
([5, 3, 1], [2, 4])
Example 2:
@floop begin
@init buf = zero(MVector{10,Int32})
for char in pidigits
n = char - '0'
buf[n+1] += 1
end
hist = SVector(buf)
@combine hist .+= _
end
maybe @combine
on rhs?
hist = @combine _ .+= _
hist = @combine _1 .+= _2
use _
as the accumulator?
lhist = SVector(buf)
hist = @combine _ .+= lhist
It is sometimes useful to separately define reduction inside of basecase and reduction across basecases. A typical example is histogram computation. Currently, implementing this requires coming up with a gadget like
OneHotVector
:But, if we don't have
OneHotVector
, it's tricky for users to define this. It may be a good idea to support more verbose but controllable syntax.New syntax
The idea is to add a new syntax, for example:
The new macro
@combine
takes the same expressions as@reduce
does. However, it is not executed inside of the loop body like@reduce
.This is lowered to something equivalent to
(with a extra care so that the compiler can eliminate the branch in
op!
and the base case is compiled down to a straight loop)The name
@combine
reflects the Transducers APITransducers.combine
.Comparison
Example:
collatz_histogram
https://juliafolds.github.io/data-parallelism/tutorials/quick-introduction/#practical_example_histogram_of_stopping_time_of_collatz_function is an example of using FLoops.jl to compute histogram when you don't know the upper bound:
This can be written as
Compared to
@reduce
version,@combine
version has more repetition (forresize!
). However, it can be written without coming up with the abstraction likemaxkey
and also without knowingSingletonDict
.Example: using
mul!
https://juliafolds.github.io/data-parallelism/tutorials/mutations/#advanced_fusing_multiplication_and_addition_in_base_cases shows how to use 5-arg
mul!
This can be written as
This is much cleaner to use
@combine
than@reduce
.Discussion/feedbacks