From aa7b3f95cf885331555a218dfbfe7b23304a0aa6 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Tue, 20 Mar 2018 10:48:37 -0500 Subject: [PATCH] Fix #26488: don't map over values not provided (#26521) This is a symptom of the good old how-to-allocate-a-result-array-of-an-arbitrary-transform-of-its-elements problem. Eventually it'd be nice to solve this with `collect` of a lazy implementation, but for now this papers over the egregious problem. --- base/reducedim.jl | 12 ++++++++---- test/reducedim.jl | 12 ++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/base/reducedim.jl b/base/reducedim.jl index df3e249cee54a..89b01379f2f09 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -140,10 +140,14 @@ let [AbstractArray{t} for t in uniontypes(BitIntFloat)]..., [AbstractArray{Complex{t}} for t in uniontypes(BitIntFloat)]...} - global reducedim_init(f, op::Union{typeof(+),typeof(add_sum)}, A::T, region) = - reducedim_initarray(A, region, mapreduce_first(f, op, zero(eltype(A)))) - global reducedim_init(f, op::Union{typeof(*),typeof(mul_prod)}, A::T, region) = - reducedim_initarray(A, region, mapreduce_first(f, op, one(eltype(A)))) + global function reducedim_init(f, op::Union{typeof(+),typeof(add_sum)}, A::T, region) + z = zero(f(zero(eltype(A)))) + reducedim_initarray(A, region, op(z, z)) + end + global function reducedim_init(f, op::Union{typeof(*),typeof(mul_prod)}, A::T, region) + u = one(f(one(eltype(A)))) + reducedim_initarray(A, region, op(u, u)) + end end ## generic (map)reduction diff --git a/test/reducedim.jl b/test/reducedim.jl index 4beace3579254..2d5e5ae4e5160 100644 --- a/test/reducedim.jl +++ b/test/reducedim.jl @@ -338,6 +338,18 @@ for region in Any[-1, 0, (-1, 2), [0, 1], (1,-2,3), [0 1; @test_throws ArgumentError minimum(abs, Areduc, dims=region) end +# issue #26488 +@testset "don't map over initial values not provided" begin + @test sum(x->x+1, [1], dims=1)[1] === sum(x->x+1, [1]) === 2 + @test prod(x->x+1, [1], dims=1)[1] === prod(x->x+1, [1]) === 2 + @test mapreduce(x->x+1, +, [1], dims=1)[1] === mapreduce(x->x+1, +, [1]) === 2 + @test mapreduce(x->x+1, *, [1], dims=1)[1] === mapreduce(x->x+1, *, [1]) === 2 + @test mapreduce(!, &, [false], dims=1)[1] === mapreduce(!, &, [false]) === true + @test mapreduce(!, |, [true], dims=1)[1] === mapreduce(!, |, [true]) === false + @test mapreduce(x->1/x, max, [1], dims=1)[1] === mapreduce(x->1/x, max, [1]) === 1.0 + @test mapreduce(x->-1/x, min, [1], dims=1)[1] === mapreduce(x->-1/x, min, [1]) === -1.0 +end + # check type of result @testset "type of sum(::Array{$T}" for T in [UInt8, Int8, Int32, Int64, BigInt] result = sum(T[1 2 3; 4 5 6; 7 8 9], dims=2)