Generic maximum/minimum function for complex numbers

In Julia 1.7 you can use argmax

julia> a = rand(ComplexF64,4)
4-element Vector{ComplexF64}:
  0.3443509906876845 + 0.49984979589871426im
  0.1658370274750809 + 0.47815764287341156im
  0.4084798173736195 + 0.9688268736875587im
 0.47476987432458806 + 0.13651720575229853im

julia> argmax(abs2, a)
0.4084798173736195 + 0.9688268736875587im

Since it will take some time to get to 1.7, you can use the following analog

maxby(f, iter) = reduce(iter) do x, y
                   f(x) > f(y) ? x : y
                 end
julia> maxby(abs2, a)
0.4084798173736195 + 0.9688268736875587im

UPD: slightly more efficient way to find such maximum is to use something like

function maxby(f, iter; default = zero(eltype(iter)))
    isempty(iter) && return default
    res, rest = Iterators.peel(iter)
    fa = f(res)
    for x in rest
        fx = f(x)
        if fx > fa
            res = x
            fa = fx
        end
    end

    return res
end

According to octave's documentation (which presumably mimics matlab's behaviour):

 For complex arguments, the magnitude of the elements are used for
 comparison.  If the magnitudes are identical, then the results are
 ordered by phase angle in the range (-pi, pi].  Hence,

      max ([-1 i 1 -i])
          => -1

 because all entries have magnitude 1, but -1 has the largest phase
 angle with value pi.

Therefore, if you'd like to mimic matlab/octave functionality exactly, then based on this logic, I'd construct a 'max' function for complex numbers as:

function compmax( CArray )
    Absmax   = CArray[   abs.(CArray) .== maximum(  abs.(CArray)) ]
    Totalmax = Absmax[ angle.(Absmax) .== maximum(angle.(Absmax)) ]
    return Totalmax[1]
end

(adding appropriate typing as desired).

Examples:

Nums0 = [ 1, 2, 3 + 4im, 3 - 4im, 5 ];   compmax( Nums0 )
# 1-element Array{Complex{Int64},1}:
#  3 + 4im

Nums1 = [ -1, im, 1, -im ];   compmax( Nums1 )
# 1-element Array{Complex{Int64},1}:
#  -1 + 0im

If this was a code for my computations, I would have made my life much simpler by:

julia> Main.isless(u1::ComplexF64, u2::ComplexF64) = abs2(u1) < abs2(u2)

julia> maximum(rand(ComplexF64, 10))
0.9876138798492835 + 0.9267321874614858im

This adds a new implementation for an existing method in Main. Therefore for a library code it is not an elegant idea, but it will you get where you need it with the least effort.

Tags:

Julia