diff --git a/base/reducedim.jl b/base/reducedim.jl index c1c58ccdfefed..aa3408b036587 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -528,6 +528,9 @@ Sum elements of `A` over the singleton dimensions of `r`, and write results to ` Note that since the sum! function is intended to operate without making any allocations, the target should not alias with the source. +!!! warning + Incorrect result may occur when `r` is alias or `view` of `A`. + # Examples ```jldoctest julia> A = [1 2; 3 4] @@ -601,6 +604,9 @@ prod(f, A::AbstractArray; dims) Multiply elements of `A` over the singleton dimensions of `r`, and write results to `r`. +!!! warning + Incorrect result may occur when `r` is alias or `view` of `A`. + # Examples ```jldoctest julia> A = [1 2; 3 4] @@ -895,6 +901,9 @@ all(::Function, ::AbstractArray; dims) Test whether all values in `A` along the singleton dimensions of `r` are `true`, and write results to `r`. +!!! warning + Incorrect result may occur when `r` is alias or `view` of `A`. + # Examples ```jldoctest julia> A = [true false; true false] @@ -968,6 +977,9 @@ any(::Function, ::AbstractArray; dims) Test whether any values in `A` along the singleton dimensions of `r` are `true`, and write results to `r`. +!!! warning + Incorrect result may occur when `r` is alias or `view` of `A`. + # Examples ```jldoctest julia> A = [true false; true false] @@ -1019,7 +1031,13 @@ for (fname, op) in [(:sum, :add_sum), (:prod, :mul_prod), @eval begin $(fname!)(f::Function, r::AbstractArray, A::AbstractArray; init::Bool=true) = mapreducedim!($mapf, $(op), initarray!(r, $mapf, $(op), init, A), A) - $(fname!)(r::AbstractArray, A::AbstractArray; init::Bool=true) = $(fname!)(identity, r, A; init=init) + @inline function $(fname!)(r::AbstractArray, A::AbstractArray; init::Bool=true) + if size(r) == size(A) && init + copyto!(r, A) + return r + end + $(fname!)(identity, r, A; init=init) + end $(_fname)(A, dims; kw...) = $(_fname)(identity, A, dims; kw...) $(_fname)(f, A, dims; kw...) = mapreduce($mapf, $(op), A; dims=dims, kw...) diff --git a/test/reducedim.jl b/test/reducedim.jl index daa0a3fbe1f92..0db60db9543b2 100644 --- a/test/reducedim.jl +++ b/test/reducedim.jl @@ -97,6 +97,18 @@ safe_minabs(A::Array{T}, region) where {T} = safe_mapslices(minimum, abs.(A), re ) end +@testset "test in-place reductions with alias" begin + a = rand(3) + b = copy(a) + @test sum!(a, a) == b + @test prod!(a, a) == b + + c = rand(Bool, 5) + d = copy(c) + @test all!(c, c) == d + @test any!(c, c) == d +end + # Combining dims and init A = Array{Int}(undef, 0, 3) @test_throws "reducing over an empty collection is not allowed" maximum(A; dims=1)