From 54e034aac5500d1f8264e6454163ab56e2ddfe78 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 30 Apr 2016 11:13:41 -0500 Subject: [PATCH] Make max/min synonyms for scalarmax/scalarmin in reductions Fixes #16133 --- base/reduce.jl | 10 ++++++++++ base/reducedim.jl | 28 +++++++++++++--------------- test/reducedim.jl | 4 ++++ 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index 7d8278aa73431..37478824ae839 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -28,6 +28,8 @@ r_promote(::typeof(scalarmax), x::WidenReduceResult) = x r_promote(::typeof(scalarmin), x::WidenReduceResult) = x r_promote(::typeof(scalarmax), x) = x r_promote(::typeof(scalarmin), x) = x +r_promote(::typeof(max), x) = r_promote(scalarmax, x) +r_promote(::typeof(min), x) = r_promote(scalarmin, x) ## foldl && mapfoldl @@ -126,6 +128,8 @@ mr_empty(::typeof(abs2), op::typeof(+), T) = r_promote(op, abs2(zero(T)::T)) mr_empty(::typeof(identity), op::typeof(*), T) = r_promote(op, one(T)::T) mr_empty(::typeof(abs), op::typeof(scalarmax), T) = abs(zero(T)::T) mr_empty(::typeof(abs2), op::typeof(scalarmax), T) = abs2(zero(T)::T) +mr_empty(::typeof(abs), op::typeof(max), T) = mr_empty(abs, scalarmax, T) +mr_empty(::typeof(abs2), op::typeof(max), T) = mr_empty(abs2, scalarmax, T) mr_empty(f, op::typeof(&), T) = true mr_empty(f, op::typeof(|), T) = false @@ -277,6 +281,9 @@ prod(a) = mapreduce(identity, *, a) ## maximum & minimum +function mapreduce_impl(f, op::typeof(max), A::AbstractArray, first::Int, last::Int) + mapreduce_impl(f, scalarmax, A, first, last) +end function mapreduce_impl(f, op::typeof(scalarmax), A::AbstractArray, first::Int, last::Int) # locate the first non NaN number v = f(A[first]) @@ -297,6 +304,9 @@ function mapreduce_impl(f, op::typeof(scalarmax), A::AbstractArray, first::Int, v end +function mapreduce_impl(f, op::typeof(min), A::AbstractArray, first::Int, last::Int) + mapreduce_impl(f, scalarmin, A, first, last) +end function mapreduce_impl(f, op::typeof(scalarmin), A::AbstractArray, first::Int, last::Int) # locate the first non NaN number v = f(A[first]) diff --git a/base/reducedim.jl b/base/reducedim.jl index fa2a1e6a1b832..3453da705b183 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -74,7 +74,7 @@ end ## initialization -for (Op, initfun) in ((:(typeof(+)), :zero), (:(typeof(*)), :one), (:(typeof(scalarmax)), :typemin), (:(typeof(scalarmin)), :typemax)) +for (Op, initfun) in ((:(typeof(+)), :zero), (:(typeof(*)), :one), (:(typeof(scalarmax)), :typemin), (:(typeof(scalarmin)), :typemax), (:(typeof(max)), :typemin), (:(typeof(min)), :typemax)) @eval initarray!{T}(a::AbstractArray{T}, ::$(Op), init::Bool) = (init && fill!(a, $(initfun)(T)); a) end @@ -94,32 +94,30 @@ reducedim_initarray0{T}(A::AbstractArray, region, v0::T) = reducedim_initarray0( # promote_union(T::Union) = promote_type(T.types...) promote_union(T) = T + function reducedim_init{S}(f, op::typeof(+), A::AbstractArray{S}, region) - T = promote_union(S) - if method_exists(zero, Tuple{Type{T}}) - x = f(zero(T)) - z = zero(x) + zero(x) - Tr = typeof(z) == typeof(x) && !isbits(T) ? T : typeof(z) - else - z = zero(sum(f, A)) - Tr = typeof(z) - end - return reducedim_initarray(A, region, z, Tr) + _reducedim_init(f, op, zero, sum, A, region) end - function reducedim_init{S}(f, op::typeof(*), A::AbstractArray{S}, region) - T = promote_union(S) + _reducedim_init(f, op, one, prod, A, region) +end +function _reducedim_init(f, op, fv, fop, A, region) + T = promote_union(eltype(A)) if method_exists(zero, Tuple{Type{T}}) x = f(zero(T)) - z = one(x) * one(x) + z = op(fv(x), fv(x)) Tr = typeof(z) == typeof(x) && !isbits(T) ? T : typeof(z) else - z = one(prod(f, A)) + z = fv(fop(f, A)) Tr = typeof(z) end return reducedim_initarray(A, region, z, Tr) end +reducedim_init{T}(f, op::typeof(max), A::AbstractArray{T}, region) = reducedim_init(f, scalarmax, A, region) +reducedim_init{T}(f, op::typeof(min), A::AbstractArray{T}, region) = reducedim_init(f, scalarmin, A, region) +reducedim_init{T}(f::Union{typeof(abs),typeof(abs2)}, op::typeof(max), A::AbstractArray{T}, region) = reducedim_init(f, scalarmax, A, region) + reducedim_init{T}(f, op::typeof(scalarmax), A::AbstractArray{T}, region) = reducedim_initarray0(A, region, typemin(f(zero(T)))) reducedim_init{T}(f, op::typeof(scalarmin), A::AbstractArray{T}, region) = reducedim_initarray0(A, region, typemax(f(zero(T)))) reducedim_init{T}(f::Union{typeof(abs),typeof(abs2)}, op::typeof(scalarmax), A::AbstractArray{T}, region) = diff --git a/test/reducedim.jl b/test/reducedim.jl index 6775ed1de5028..9d2b66a99bbd3 100644 --- a/test/reducedim.jl +++ b/test/reducedim.jl @@ -99,6 +99,10 @@ A = reshape(1:6, 3, 2) @test typeof(@inferred(Base.prod(abs, [1.0+1.0im], 1))) == Vector{Float64} @test typeof(@inferred(Base.prod(abs2, [1.0+1.0im], 1))) == Vector{Float64} +# min/max +@test reducedim(max, A, 1) == [3 6] +@test reducedim(min, A, 2) == reshape([1,2,3], 3, 1) + # Heterogeneously typed arrays @test sum(Union{Float32, Float64}[1.0], 1) == [1.0] @test prod(Union{Float32, Float64}[1.0], 1) == [1.0]