Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

specialize argmin/argmax on ranges #34315

Merged
merged 4 commits into from
Sep 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
jw3126 marked this conversation as resolved.
Show resolved Hide resolved
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