Skip to content

Commit

Permalink
Merge pull request JuliaLang#7359 from JuliaLang/teh/cumsumprod
Browse files Browse the repository at this point in the history
Faster cumsum & cumprod. Fixes JuliaLang#7342.
  • Loading branch information
timholy committed Jun 22, 2014
2 parents 8f12e35 + 4cecc0c commit b6ebf91
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 27 deletions.
27 changes: 0 additions & 27 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1408,33 +1408,6 @@ for (f, fp, op) = ((:cumsum, :cumsum_pairwise, :+),
return c
end

@eval function ($f)(A::StridedArray, axis::Integer)
dimsA = size(A)
ndimsA = ndims(A)
axis_size = dimsA[axis]
axis_stride = 1
for i = 1:(axis-1)
axis_stride *= size(A,i)
end

B = $(op===:+ ? (:(similar(A,_cumsum_type(A)))) :
(:(similar(A))))

if axis_size < 1
return B
end

for i = 1:length(A)
if div(i-1, axis_stride) % axis_size == 0
B[i] = A[i]
else
B[i] = ($op)(B[i-axis_stride], A[i])
end
end

return B
end

@eval ($f)(A::AbstractArray) = ($f)(A, 1)
end

Expand Down
2 changes: 2 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,9 @@ export
cummax,
cummin,
cumprod,
cumprod!,
cumsum,
cumsum!,
cumsum_kbn,
extrema,
fill!,
Expand Down
34 changes: 34 additions & 0 deletions base/multidimensional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,40 @@ end

eval(ngenerate(:N, nothing, :(setindex!{T}(s::SubArray{T,N}, v, ind::Integer)), gen_setindex!_body, 2:5, false))

cumsum(A::AbstractArray, axis::Integer) = cumsum!(similar(A, Base._cumsum_type(A)), A, axis)
cumprod(A::AbstractArray, axis::Integer) = cumprod!(similar(A), A, axis)

for (f, op) in ((:cumsum!, :+),
(:cumprod!, :*))
@eval begin
@ngenerate N typeof(B) function ($f){T,N}(B, A::AbstractArray{T,N}, axis::Integer)
if size(B, axis) < 1
return B
end
size(B) == size(A) || throw(DimensionMismatch("Size of B must match A"))
if axis == 1
# We can accumulate to a temporary variable, which allows register usage and will be slightly faster
@inbounds @nloops N i d->(d > 1 ? (1:size(A,d)) : (1:1)) begin
tmp = convert(eltype(B), @nref(N, A, i))
@nref(N, B, i) = tmp
for i_1 = 2:size(A,1)
tmp = ($op)(tmp, @nref(N, A, i))
@nref(N, B, i) = tmp
end
end
else
@nexprs N d->(isaxis_d = axis == d)
# Copy the initial element in each 1d vector along dimension `axis`
@inbounds @nloops N i d->(d == axis ? (1:1) : (1:size(A,d))) @nref(N, B, i) = @nref(N, A, i)
# Accumulate
@inbounds @nloops N i d->((1+isaxis_d):size(A, d)) d->(j_d = i_d - isaxis_d) begin
@nref(N, B, i) = ($op)(@nref(N, B, j), @nref(N, A, i))
end
end
B
end
end
end

### from abstractarray.jl

Expand Down
8 changes: 8 additions & 0 deletions doc/stdlib/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4040,10 +4040,18 @@ Array functions

Cumulative product along a dimension.

.. function:: cumprod!(B, A, [dim])

Cumulative product of ``A`` along a dimension, storing the result in ``B``.

.. function:: cumsum(A, [dim])

Cumulative sum along a dimension.

.. function:: cumsum!(B, A, [dim])

Cumulative sum of ``A`` along a dimension, storing the result in ``B``.

.. function:: cumsum_kbn(A, [dim])

Cumulative sum along a dimension, using the Kahan-Babuska-Neumaier compensated summation algorithm for additional accuracy.
Expand Down

0 comments on commit b6ebf91

Please sign in to comment.