Skip to content

Commit

Permalink
specialize argmin/argmax on ranges (#34315)
Browse files Browse the repository at this point in the history
Also: document and add test_broken on argmin of degenerate ranges
  • Loading branch information
jw3126 authored Sep 29, 2020
1 parent be54a6c commit 24c468d
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
34 changes: 34 additions & 0 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,40 @@ maximum(r::AbstractUnitRange) = isempty(r) ? throw(ArgumentError("range must be
minimum(r::AbstractRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : min(first(r), last(r))
maximum(r::AbstractRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : max(first(r), last(r))

"""
argmin(r::AbstractRange)
Ranges can have multiple minimal elements. In that case
`argmin` will return a minimal index, but not necessarily the
first one.
"""
function argmin(r::AbstractRange)
if isempty(r)
throw(ArgumentError("range must be non-empty"))
elseif step(r) > 0
firstindex(r)
else
first(searchsorted(r, last(r)))
end
end

"""
argmax(r::AbstractRange)
Ranges can have multiple maximal elements. In that case
`argmax` will return a maximal index, but not necessarily the
first one.
"""
function argmax(r::AbstractRange)
if isempty(r)
throw(ArgumentError("range must be non-empty"))
elseif step(r) > 0
first(searchsorted(r, last(r)))
else
firstindex(r)
end
end

extrema(r::AbstractRange) = (minimum(r), maximum(r))

# Ranges are immutable
Expand Down
27 changes: 27 additions & 0 deletions test/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,31 @@ end
@test convert(Array{Float64,1}, r) == a
end

@testset "extrema" begin
@test_throws ArgumentError minimum(1:2:-1)
@test_throws ArgumentError argmin(Base.OneTo(-1))
@test_throws ArgumentError maximum(Base.OneTo(-1))
@test_throws ArgumentError argmax(1:-1)

for (r, imin, imax) in [
(Base.OneTo(5), 1, 5),
(1:10, 1, 10),
(10:-1:0, 11, 1),
(range(10, stop=20, length=5), 1, 5),
(range(10.3, step=-2, length=7), 7, 1),
]
@test minimum(r) === r[imin]
@test maximum(r) === r[imax]
@test imin === argmin(r)
@test imax === argmax(r)
@test extrema(r) === (r[imin], r[imax])
end

r = 1f8-10:1f8
@test_broken argmin(f) == argmin(collect(r))
@test_broken argmax(f) == argmax(collect(r))
end

@testset "OneTo" begin
let r = Base.OneTo(-5)
@test isempty(r)
Expand All @@ -1227,6 +1252,8 @@ end
@test last(r) == 3
@test minimum(r) == 1
@test maximum(r) == 3
@test argmin(r) == 1
@test argmax(r) == 3
@test r[2] == 2
@test r[2:3] === 2:3
@test_throws BoundsError r[4]
Expand Down
5 changes: 5 additions & 0 deletions test/sorting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ end
@test searchsorted(reverse(coll), -huge, rev=true) === lastindex(coll)+1:lastindex(coll)
end
end
@testset "issue ##34408" begin
r = 1f8-10:1f8
# collect(r) = Float32[9.999999e7, 9.999999e7, 9.999999e7, 9.999999e7, 1.0e8, 1.0e8, 1.0e8, 1.0e8, 1.0e8]
@test_broken searchsorted(collect(r)) == searchsorted(r)
end
end
@testset "issue #35272" begin
for v0 = (3:-1:1, 3.0:-1.0:1.0), v = (v0, collect(v0))
Expand Down

0 comments on commit 24c468d

Please sign in to comment.