diff --git a/NEWS.md b/NEWS.md index c17d36b1f7021..a98044a7ec505 100644 --- a/NEWS.md +++ b/NEWS.md @@ -65,6 +65,7 @@ New library features * `isapprox` (or `≈`) now has a one-argument "curried" method `isapprox(x)` which returns a function, like `isequal` (or `==`)` ([#32305]). * `Ref{NTuple{N,T}}` can be passed to `Ptr{T}`/`Ref{T}` `ccall` signatures ([#34199]) +* `accumulate`, `cumsum`, and `cumprod` now support `Tuple` ([#34654]). Standard library changes diff --git a/base/accumulate.jl b/base/accumulate.jl index c5c4e83b3b0e3..8e959df71b28a 100644 --- a/base/accumulate.jl +++ b/base/accumulate.jl @@ -92,12 +92,15 @@ function cumsum(A::AbstractArray{T}; dims::Integer) where T end """ - cumsum(x::AbstractVector) + cumsum(itr::Union{AbstractVector,Tuple}) -Cumulative sum a vector. See also [`cumsum!`](@ref) +Cumulative sum an iterator. See also [`cumsum!`](@ref) to use a preallocated output array, both for performance and to control the precision of the output (e.g. to avoid overflow). +!!! compat "Julia 1.5" + `cumsum` on a tuple requires at least Julia 1.5. + # Examples ```jldoctest julia> cumsum([1, 1, 1]) @@ -111,9 +114,13 @@ julia> cumsum([fill(1, 2) for i in 1:3]) [1, 1] [2, 2] [3, 3] + +julia> cumsum((1, 1, 1)) +(1, 2, 3) ``` """ cumsum(x::AbstractVector) = cumsum(x, dims=1) +cumsum(itr) = accumulate(add_sum, itr) """ @@ -163,12 +170,15 @@ function cumprod(A::AbstractArray; dims::Integer) end """ - cumprod(x::AbstractVector) + cumprod(itr::Union{AbstractVector,Tuple}) -Cumulative product of a vector. See also +Cumulative product of an iterator. See also [`cumprod!`](@ref) to use a preallocated output array, both for performance and to control the precision of the output (e.g. to avoid overflow). +!!! compat "Julia 1.5" + `cumprod` on a tuple requires at least Julia 1.5. + # Examples ```jldoctest julia> cumprod(fill(1//2, 3)) @@ -182,9 +192,13 @@ julia> cumprod([fill(1//3, 2, 2) for i in 1:3]) [1//3 1//3; 1//3 1//3] [2//9 2//9; 2//9 2//9] [4//27 4//27; 4//27 4//27] + +julia> cumprod((1, 2, 1)) +(1, 2, 2) ``` """ cumprod(x::AbstractVector) = cumprod(x, dims=1) +cumprod(itr) = accumulate(mul_prod, itr) """ @@ -247,6 +261,15 @@ function accumulate(op, A; dims::Union{Nothing,Integer}=nothing, kw...) accumulate!(op, out, A; dims=dims, kw...) end +function accumulate(op, xs::Tuple; init = _InitialValue()) + rf = BottomRF(op) + ys, = afoldl(((), init), xs...) do (ys, acc), x + acc = rf(acc, x) + (ys..., acc), acc + end + return ys +end + """ accumulate!(op, B, A; [dims], [init]) diff --git a/test/tuple.jl b/test/tuple.jl index c33598ee65a3c..d0985537addff 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -368,6 +368,17 @@ end end end +@testset "accumulate" begin + @test @inferred(cumsum(())) == () + @test @inferred(cumsum((1, 2, 3))) == (1, 3, 6) + @test @inferred(cumprod((1, 2, 3))) == (1, 2, 6) + @test @inferred(accumulate(+, (1, 2, 3); init=10)) == (11, 13, 16) + op(::Nothing, ::Any) = missing + op(::Missing, ::Any) = nothing + @test @inferred(accumulate(op, (1, 2, 3, 4); init = nothing)) === + (missing, nothing, missing, nothing) +end + @testset "ntuple" begin nttest1(x::NTuple{n, Int}) where {n} = n @test nttest1(()) == 0