In julia, one can find (supposedly) efficient implementations of the min
/minimum
and max
/maximum
over collections of real numbers.
As these concepts are not uniquely defined for complex numbers, I was wondering if a parametrized version of these functions was already implemented somewhere.
I am currently sorting elements of the array of interest, then taking the last value, which is as far as I know, much more costly than finding the value with the maximum absolute value (or something else).
This is mostly to reproduce the Matlab behavior of the max
function over complex arrays.
Here is my current code
a = rand(ComplexF64,4)
b = sort(a,by = (x) -> abs(x))
c = b[end]
The probable function call would look like
c = maximum/minimum(a,by=real/imag/abs/phase)
EDIT Some performance tests in Julia 1.5.3 with the provided solutions
function maxby0(f,iter)
b = sort(iter,by = (x) -> f(x))
c = b[end]
end
function maxby1(f, iter)
reduce(iter) do x, y
f(x) > f(y) ? x : y
end
end
function maxby2(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
compmax(CArray) = CArray[ (abs.(CArray) .== maximum(abs.(CArray))) .& (angle.(CArray) .== maximum( angle.(CArray))) ][1]
Main.isless(u1::ComplexF64, u2::ComplexF64) = abs2(u1) < abs2(u2)
function maxby5(arr)
arr_max = arr[argmax(map(abs, arr))]
end
a = rand(ComplexF64,10)
using BenchmarkTools
@btime maxby0(abs,$a)
@btime maxby1(abs,$a)
@btime maxby2(abs,$a)
@btime compmax($a)
@btime maximum($a)
@btime maxby5($a)
Output for a vector of length 10:
>841.653 ns (1 allocation: 240 bytes)
>214.797 ns (0 allocations: 0 bytes)
>118.961 ns (0 allocations: 0 bytes)
>Execution fails
>20.340 ns (0 allocations: 0 bytes)
>144.444 ns (1 allocation: 160 bytes)
Output for a vector of length 1000:
>315.100 μs (1 allocation: 15.75 KiB)
>25.299 μs (0 allocations: 0 bytes)
>12.899 μs (0 allocations: 0 bytes)
>Execution fails
>1.520 μs (0 allocations: 0 bytes)
>14.199 μs (1 allocation: 7.94 KiB)
Output for a vector of length 1000 (with all comparisons made with abs2
):
>35.399 μs (1 allocation: 15.75 KiB)
>3.075 μs (0 allocations: 0 bytes)
>1.460 μs (0 allocations: 0 bytes)
>Execution fails
>1.520 μs (0 allocations: 0 bytes)
>2.211 μs (1 allocation: 7.94 KiB)
Some remarks :
abs2
saves a lot of performance (expected as well)To conclude :
Main.isless
method, though it is all things considered the most performing one, to not modify the core of my juliamaxby1
and maxby2
allocate nothingmaxby1
feels more readablethe winner is therefore Andrej Oskin!
EDIT n°2 a new benchmark using the corrected compmax
implementation
julia> @btime maxby0(abs2,$a)
36.799 μs (1 allocation: 15.75 KiB)
julia> @btime maxby1(abs2,$a)
3.062 μs (0 allocations: 0 bytes)
julia> @btime maxby2(abs2,$a)
1.160 μs (0 allocations: 0 bytes)
julia> @btime compmax($a)
26.899 μs (9 allocations: 12.77 KiB)
julia> @btime maximum($a)
1.520 μs (0 allocations: 0 bytes)
julia> @btime maxby5(abs2,$a)
2.500 μs (4 allocations: 8.00 KiB)
Originally Answered: If z is a complex number, then what is the minimum value of |z|+|z-1|? Geometrically, it is the sum of the distances from z to 0 and to 1. The minimum clearly occurs when z lies on the segment [0, 1] and its value is 1. attained whenever 0<z<1.”
If we want to find where the minimum or maximum is located, i.e. the index instead of the actual value, then we can use which. min() and which. max() functions. Note that these functions will return the index of the first minimum or maximum in case multiple of them exists.
max() in R The max() is a built-in R function that finds the maximum value of the vector or data frame. It takes the R object as an input and returns the maximum value out of it. To find the maximum value of vector elements, data frame, and columns, use the max() function.
As per the documentation, < (and co.) only compare the real part of a number, whereas min returns the complex number with the smallest magnitude. If x1=1.1+2*i and x2=1+2.1*i What is the smallest number ? You can't compare two complex numbers, you can compare their modulus
It can be proven that complex numbers cannot be ordered (under the definition of an ordered field). That means that you cannot compare complex numbers. As per the documentation, < (and co.) only compare the real part of a number, whereas min returns the complex number with the smallest magnitude.
Because Generic Programming means: A single algorithm (Generic) can cover many implementations (for many types) maintaining efficiency of hand-written versions. Take an example. The handwritten version for integers would be: public static int Max ( int x, int y) { return (x.CompareTo (y) > 0) ? x : y; }
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With