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

Add 2-arg versions of findmax/min, argmax/min #35316

Merged
merged 29 commits into from
Dec 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a928f4a
Rename unexported isgreater in reduceddim
cmcaine Mar 30, 2020
b2f1111
Add isgreater
cmcaine Mar 30, 2020
8767109
Add 2-arg versions of findmax/min, argmax/min
cmcaine Mar 30, 2020
72c459d
Clarify description in NEWS.md
cmcaine Mar 31, 2020
1eb223b
More doctest examples for argmin/max
cmcaine Mar 31, 2020
fc0dbab
Clarify `isgreater` docstring
cmcaine Mar 31, 2020
9231741
Update `isgreater` from review
cmcaine Mar 31, 2020
4a85179
Simplify _is_reflexive and rename _is_reflexive_eq
cmcaine Nov 21, 2020
31a38a0
unexport isgreater
cmcaine Nov 21, 2020
6cc600e
Use 2-arg findmax/min for findmax/min(a)
cmcaine Nov 21, 2020
4c6923a
Fix doctest
cmcaine Nov 21, 2020
7c7cfbe
Add example showing that first value wins
cmcaine Nov 21, 2020
8356986
Fix more doctests
cmcaine Nov 21, 2020
8061ce8
omit unnecessary let
cmcaine Nov 24, 2020
96433cf
define isgreater to be compatible with min
cmcaine Dec 2, 2020
91a825f
Fix doctests
cmcaine Dec 2, 2020
51c1d07
typo
cmcaine Dec 2, 2020
f3dac8c
Use pairs() in findmax(a)
cmcaine Dec 6, 2020
9ed02b2
Make findmax(A; dims) consistent with findmax(A) again
cmcaine Dec 6, 2020
fae5eac
Update docstrings
cmcaine Dec 6, 2020
3671795
Use convert in reducedim_init
cmcaine Dec 16, 2020
202edf7
Support missing better in minimum(A; dims)
cmcaine Dec 17, 2020
7aa7fdb
rename is_poisoning -> isunordered and export
cmcaine Dec 17, 2020
c8f05bb
Add tests for isunordered
cmcaine Dec 17, 2020
abf1be4
Simplify findmin/findmax/argmin/argmax docstrings
cmcaine Dec 17, 2020
925a365
Add isunorded docstring and compat admonitions
cmcaine Dec 17, 2020
5e93247
Add NEWS entry for isunordered
cmcaine Dec 17, 2020
b2fe843
Correct compat admonition for isunordered
cmcaine Dec 17, 2020
6232810
Fix minimum(A; dims) when eltype(A) doesn't define typemin, but does …
cmcaine Dec 17, 2020
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
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Build system changes
New library functions
---------------------

* Two argument methods `findmax(f, domain)`, `argmax(f, domain)` and the corresponding `min` versions ([#27613]).
* `isunordered(x)` returns true if `x` is value that is normally unordered, such as `NaN` or `missing`.

New library features
--------------------
Expand Down
134 changes: 0 additions & 134 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2201,140 +2201,6 @@ findall(x::Bool) = x ? [1] : Vector{Int}()
findall(testf::Function, x::Number) = testf(x) ? [1] : Vector{Int}()
findall(p::Fix2{typeof(in)}, x::Number) = x in p.x ? [1] : Vector{Int}()

"""
findmax(itr) -> (x, index)

Return the maximum element of the collection `itr` and its index or key.
If there are multiple maximal elements, then the first one will be returned.
If any data element is `NaN`, this element is returned.
The result is in line with `max`.

The collection must not be empty.

# Examples
```jldoctest
julia> findmax([8,0.1,-9,pi])
(8.0, 1)

julia> findmax([1,7,7,6])
(7, 2)

julia> findmax([1,7,7,NaN])
(NaN, 4)
```
"""
findmax(a) = _findmax(a, :)

function _findmax(a, ::Colon)
p = pairs(a)
y = iterate(p)
if y === nothing
throw(ArgumentError("collection must be non-empty"))
end
(mi, m), s = y
i = mi
while true
y = iterate(p, s)
y === nothing && break
m != m && break
(i, ai), s = y
if ai != ai || isless(m, ai)
m = ai
mi = i
end
end
return (m, mi)
end

"""
findmin(itr) -> (x, index)

Return the minimum element of the collection `itr` and its index or key.
If there are multiple minimal elements, then the first one will be returned.
If any data element is `NaN`, this element is returned.
The result is in line with `min`.

The collection must not be empty.

# Examples
```jldoctest
julia> findmin([8,0.1,-9,pi])
(-9.0, 3)

julia> findmin([7,1,1,6])
(1, 2)

julia> findmin([7,1,1,NaN])
(NaN, 4)
```
"""
findmin(a) = _findmin(a, :)

function _findmin(a, ::Colon)
p = pairs(a)
y = iterate(p)
if y === nothing
throw(ArgumentError("collection must be non-empty"))
end
(mi, m), s = y
i = mi
while true
y = iterate(p, s)
y === nothing && break
m != m && break
(i, ai), s = y
if ai != ai || isless(ai, m)
m = ai
mi = i
end
end
return (m, mi)
end

"""
argmax(itr)

Return the index or key of the maximum element in a collection.
If there are multiple maximal elements, then the first one will be returned.

The collection must not be empty.

# Examples
```jldoctest
julia> argmax([8,0.1,-9,pi])
1

julia> argmax([1,7,7,6])
2

julia> argmax([1,7,7,NaN])
4
```
"""
argmax(a) = findmax(a)[2]

"""
argmin(itr)

Return the index or key of the minimum element in a collection.
If there are multiple minimal elements, then the first one will be returned.

The collection must not be empty.

# Examples
```jldoctest
julia> argmin([8,0.1,-9,pi])
3

julia> argmin([7,1,1,6])
2

julia> argmin([7,1,1,NaN])
4
```
"""
argmin(a) = findmin(a)[2]

# similar to Matlab's ismember
"""
indexin(a, b)
Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ export
isequal,
ismutable,
isless,
isunordered,
ifelse,
objectid,
sizeof,
Expand Down
59 changes: 58 additions & 1 deletion base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ is defined, it is expected to satisfy the following:
`isless(x, y) && isless(y, z)` implies `isless(x, z)`.

Values that are normally unordered, such as `NaN`,
are ordered in an arbitrary but consistent fashion.
are ordered after regular values.
[`missing`](@ref) values are ordered last.

This is the default comparison used by [`sort`](@ref).
Expand All @@ -168,6 +168,63 @@ isless(x::AbstractFloat, y::AbstractFloat) = (!isnan(x) & (isnan(y) | signless(x
isless(x::Real, y::AbstractFloat) = (!isnan(x) & (isnan(y) | signless(x, y))) | (x < y)
isless(x::AbstractFloat, y::Real ) = (!isnan(x) & (isnan(y) | signless(x, y))) | (x < y)

"""
isgreater(x, y)

Not the inverse of `isless`! Test whether `x` is greater than `y`, according to
a fixed total order compatible with `min`.

Defined with `isless`, this function is usually `isless(y, x)`, but `NaN` and
[`missing`](@ref) are ordered as smaller than any ordinary value with `missing`
smaller than `NaN`.

So `isless` defines an ascending total order with `NaN` and `missing` as the
largest values and `isgreater` defines a descending total order with `NaN` and
`missing` as the smallest values.

!!! note

Like `min`, `isgreater` orders containers (tuples, vectors, etc)
lexigraphically with `isless(y, x)` rather than recursively with itself:

```jldoctest
julia> Base.isgreater(1, NaN) # 1 is greater than NaN
true

julia> Base.isgreater((1,), (NaN,)) # But (1,) is not greater than (NaN,)
false

julia> sort([1, 2, 3, NaN]; lt=Base.isgreater)
4-element Vector{Float64}:
3.0
2.0
1.0
NaN

julia> sort(tuple.([1, 2, 3, NaN]); lt=Base.isgreater)
4-element Vector{Tuple{Float64}}:
(NaN,)
(3.0,)
(2.0,)
(1.0,)
```

# Implementation
This is unexported. Types should not usually implement this function. Instead, implement `isless`.
"""
isgreater(x, y) = isunordered(x) || isunordered(y) ? isless(x, y) : isless(y, x)

"""
isunordered(x)

Return true if `x` is a value that is not normally orderable, such as `NaN` or `missing`.

!!! compat "Julia 1.7"
This function requires Julia 1.7 or later.
"""
isunordered(x) = false
isunordered(x::AbstractFloat) = isnan(x)
isunordered(x::Missing) = true

function ==(T::Type, S::Type)
@_pure_meta
Expand Down
Loading