To conclude: I tested, hopefully correctly, the alternative partition of quick_sort, but for my specific case the original implementation I posted above seems to be faster (I renamed it partition!
, and here I apply it to a data structure which is the actual one I’m using):
julia> @benchmark partition!(s,f) setup=setup evals=1
BechmarkTools.Trial: 10000 samples with 1 evaluations.
Range (min … max): 209.000 ns … 17.891 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 382.000 ns ┊ GC (median): 0.00%
Time (mean ± σ): 412.933 ns ± 261.169 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
▁▄███▆▂
▂▂▃▅███████▇▅▄▃▃▂▂▂▂▂▂▂▂▂▂▁▂▂▂▂▁▂▁▁▂▁▁▁▁▁▁▁▁▁▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ▃
209 ns Histogram: frequency by time 1.53 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
julia> @benchmark partition_quicksort!(s,f) setup=setup evals=1
BechmarkTools.Trial: 10000 samples with 1 evaluations.
Range (min … max): 243.000 ns … 9.613 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 435.000 ns ┊ GC (median): 0.00%
Time (mean ± σ): 471.085 ns ± 226.825 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
▃▆██▇▅▂
▂▃▃▅█████████▆▅▄▃▃▃▃▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▁▁▁▁▁▁▁▁▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ▃
243 ns Histogram: frequency by time 1.56 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
Thus, I’m sticking to the original implementation. The field!
option is very interesting, and I will be using it in an alternative implementation that allows a different data structure and might be faster in specific scenarios. (if anyone is curious, these are for optimizations of this package)
code
using StaticArrays, BenchmarkTools
function partition!(v::AbstractVector, by)
iswap = 1
@inbounds for i in eachindex(v)
if by(v[i])
if iswap != i
v[iswap], v[i] = v[i], v[iswap]
end
iswap += 1
end
end
return iswap - 1
end
function partition_quicksort!(v::AbstractVector, by)
i, j = extrema(eachindex(v))
i -= 1
j += 1
@inbounds while true
i += 1; j -= 1
while i <= length(v) && by(v[i])
i += 1
end
while j > 0 && !by(v[j])
j -= 1
end
i >= j && break
v[i], v[j] = v[j], v[i]
end
return j
end
struct S
i::Int64
x::Float64
v::SVector{3,Float32}
end
function check()
for i in 1:100
s = [ S(rand(1:20), rand(), rand(SVector{3,Float64})) for i in 1:rand(1:20) ]
s1 = deepcopy(s)
s2 = deepcopy(s)
cutoff = -0.1 + 1.1*rand()
n1 = partition!(s1, el -> el.x <= cutoff)
n2 = partition_quicksort!(s2, el -> el.x <= cutoff)
if n1 != n2 || !(sum(x->x.x,s1) ≈ sum(x->x.x,s2))
error()
end
end
end
check()
setup=(s = [ S(rand(1:20), rand(), rand(SVector{3,Float64})) for i in 1:20 ]; f = el -> el.x <= -0.1 + 1.1*rand() )
@benchmark partition!(s,f) setup=setup evals=1
@benchmark partition_quicksort!(s,f) setup=setup evals=1