diff --git a/NEWS.md b/NEWS.md index f501d039b7e8b..0e3d8e0af3f92 100644 --- a/NEWS.md +++ b/NEWS.md @@ -111,6 +111,8 @@ Library improvements * Improve performance of `quantile` ([#14413]). + * `extrema` can now operate over a region ([#15550]). + * The new `Base.StackTraces` module makes stack traces easier to use programmatically. ([#14469]) Deprecated or removed diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 68649e186dd98..a89dbbda8dcd8 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -2082,13 +2082,6 @@ appended to an internal buffer of backtraces. """ :@profile -""" - extrema(itr) - -Compute both the minimum and maximum element in a single pass, and return them as a 2-tuple. -""" -extrema - """ isdigit(c::Union{Char,AbstractString}) -> Bool diff --git a/base/reduce.jl b/base/reduce.jl index 1b03964a88b55..84cbe46862dae 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -332,6 +332,11 @@ minabs(a) = mapreduce(AbsFun(), MinFun(), a) extrema(r::Range) = (minimum(r), maximum(r)) extrema(x::Real) = (x, x) +""" + extrema(itr) -> Tuple + +Compute both the minimum and maximum element in a single pass, and return them as a 2-tuple. +""" function extrema(itr) s = start(itr) done(itr, s) && throw(ArgumentError("collection must be non-empty")) @@ -353,6 +358,43 @@ function extrema(itr) return (vmin, vmax) end +""" + extrema(A,dims) -> Array{Tuple} + +Compute the minimum and maximum elements of an array over the given dimensions. +""" +function extrema(A::AbstractArray, dims) + sz = [size(A)...] + sz[[dims...]] = 1 + B = Array{Tuple{eltype(A),eltype(A)}}(sz...) + extrema!(B, A) +end + +@generated function extrema!{T,N}(B, A::Array{T,N}) + quote + sA = size(A) + sB = size(B) + @nloops $N i B begin + AI = @nref $N A i + (@nref $N B i) = (AI, AI) + end + Bmax = sB + Istart = ones(Int,ndims(A)) + Istart[([sB...].==1) & ([sA...].!=1)] = 2 + @inbounds @nloops $N i d->(Istart[d]:size(A,d)) begin + AI = @nref $N A i + @nexprs $N d->(j_d = min(Bmax[d], i_{d})) + BJ = @nref $N B j + if AI < BJ[1] + (@nref $N B j) = (AI, BJ[2]) + elseif AI > BJ[2] + (@nref $N B j) = (BJ[1], AI) + end + end + B + end +end + ## all & any any(itr) = any(IdFun(), itr) diff --git a/doc/stdlib/collections.rst b/doc/stdlib/collections.rst index 5edb9ef2bae79..034b449ac7116 100644 --- a/doc/stdlib/collections.rst +++ b/doc/stdlib/collections.rst @@ -299,12 +299,18 @@ Iterable Collections Compute the minimum value of ``A`` over the singleton dimensions of ``r``\ , and write results to ``r``\ . -.. function:: extrema(itr) +.. function:: extrema(itr) -> Tuple .. Docstring generated from Julia source Compute both the minimum and maximum element in a single pass, and return them as a 2-tuple. +.. function:: extrema(A,dims) -> Array{Tuple} + + .. Docstring generated from Julia source + + Compute the minimum and maximum elements of an array over the given dimensions. + .. function:: indmax(itr) -> Integer .. Docstring generated from Julia source diff --git a/test/reduce.jl b/test/reduce.jl index 177f76859d32e..3e4f0e3e8ec36 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -167,6 +167,10 @@ prod2(itr) = invoke(prod, Tuple{Any}, itr) @test maximum(collect(Int16(1):Int16(100))) === Int16(100) @test maximum(Int32[1,2]) === Int32(2) +@test extrema(reshape(1:24,2,3,4),1) == reshape([(1,2),(3,4),(5,6),(7,8),(9,10),(11,12),(13,14),(15,16),(17,18),(19,20),(21,22),(23,24)],1,3,4) +@test extrema(reshape(1:24,2,3,4),2) == reshape([(1,5),(2,6),(7,11),(8,12),(13,17),(14,18),(19,23),(20,24)],2,1,4) +@test extrema(reshape(1:24,2,3,4),3) == reshape([(1,19),(2,20),(3,21),(4,22),(5,23),(6,24)],2,3,1) + # any & all @test any(Bool[]) == false