Skip to content

Commit 28330a2

Browse files
authored
Remove specialized PartialQuickSort{<:Integer} method (#36896)
This specialized method is actually considerably slower than the one that also works for `PartialQuickSort{<:OrdinalRange}`. It had been removed before in 9e8fcd3 due to an inference issue, and reintroduced by c41d5a3 (#31632) once that issue got fixed, but apparently without benchmarks. It turns out that saving one comparison per iteration isn't worth it. The gain is especially large when looking for a value among the largest in the array, as the specialized method always sorted all values lower than the requested one.
1 parent 06ba657 commit 28330a2

File tree

2 files changed

+49
-38
lines changed

2 files changed

+49
-38
lines changed

base/sort.jl

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -650,40 +650,20 @@ function sort!(v::AbstractVector, lo::Integer, hi::Integer, a::MergeSortAlg, o::
650650
return v
651651
end
652652

653-
function sort!(v::AbstractVector, lo::Integer, hi::Integer, a::PartialQuickSort{<:Integer},
653+
function sort!(v::AbstractVector, lo::Integer, hi::Integer, a::PartialQuickSort,
654654
o::Ordering)
655655
@inbounds while lo < hi
656656
hi-lo <= SMALL_THRESHOLD && return sort!(v, lo, hi, SMALL_ALGORITHM, o)
657657
j = partition!(v, lo, hi, o)
658-
if j >= a.k
659-
# we don't need to sort anything bigger than j
660-
hi = j-1
661-
elseif j-lo < hi-j
662-
# recurse on the smaller chunk
663-
# this is necessary to preserve O(log(n))
664-
# stack space in the worst case (rather than O(n))
665-
lo < (j-1) && sort!(v, lo, j-1, a, o)
666-
lo = j+1
667-
else
668-
(j+1) < hi && sort!(v, j+1, hi, a, o)
669-
hi = j-1
670-
end
671-
end
672-
return v
673-
end
674-
675-
676-
function sort!(v::AbstractVector, lo::Integer, hi::Integer, a::PartialQuickSort{T},
677-
o::Ordering) where T<:OrdinalRange
678-
@inbounds while lo < hi
679-
hi-lo <= SMALL_THRESHOLD && return sort!(v, lo, hi, SMALL_ALGORITHM, o)
680-
j = partition!(v, lo, hi, o)
681658

682659
if j <= first(a.k)
683660
lo = j+1
684661
elseif j >= last(a.k)
685662
hi = j-1
686663
else
664+
# recurse on the smaller chunk
665+
# this is necessary to preserve O(log(n))
666+
# stack space in the worst case (rather than O(n))
687667
if j-lo < hi-j
688668
lo < (j-1) && sort!(v, lo, j-1, a, o)
689669
lo = j+1

test/sorting.jl

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,15 @@ Base.step(r::ConstantRange) = 0
294294
end
295295

296296
@testset "unstable algorithms" begin
297-
for alg in [QuickSort, PartialQuickSort(length(a))]
298-
b = sort(a, alg=alg)
299-
@test issorted(b)
300-
b = sort(a, alg=alg, rev=true)
301-
@test issorted(b, rev=true)
302-
b = sort(a, alg=alg, by=x->1/x)
303-
@test issorted(b, by=x->1/x)
304-
end
297+
b = sort(a, alg=QuickSort)
298+
@test issorted(b)
299+
@test last(b) == last(sort(a, alg=PartialQuickSort(length(a))))
300+
b = sort(a, alg=QuickSort, rev=true)
301+
@test issorted(b, rev=true)
302+
@test last(b) == last(sort(a, alg=PartialQuickSort(length(a)), rev=true))
303+
b = sort(a, alg=QuickSort, by=x->1/x)
304+
@test issorted(b, by=x->1/x)
305+
@test last(b) == last(sort(a, alg=PartialQuickSort(length(a)), by=x->1/x))
305306
end
306307
end
307308
@testset "insorted" begin
@@ -362,14 +363,26 @@ end
362363
@testset "PartialQuickSort" begin
363364
a = rand(1:10000, 1000)
364365
# test PartialQuickSort only does a partial sort
366+
let alg = PartialQuickSort(1:div(length(a), 10))
367+
k = alg.k
368+
b = sort(a, alg=alg)
369+
c = sort(a, alg=alg, by=x->1/x)
370+
d = sort(a, alg=alg, rev=true)
371+
@test issorted(b[k])
372+
@test issorted(c[k], by=x->1/x)
373+
@test issorted(d[k], rev=true)
374+
@test !issorted(b)
375+
@test !issorted(c, by=x->1/x)
376+
@test !issorted(d, rev=true)
377+
end
365378
let alg = PartialQuickSort(div(length(a), 10))
366379
k = alg.k
367380
b = sort(a, alg=alg)
368381
c = sort(a, alg=alg, by=x->1/x)
369382
d = sort(a, alg=alg, rev=true)
370-
@test issorted(b[1:k])
371-
@test issorted(c[1:k], by=x->1/x)
372-
@test issorted(d[1:k], rev=true)
383+
@test b[k] == sort(a)[k]
384+
@test c[k] == sort(a, by=x->1/x)[k]
385+
@test d[k] == sort(a, rev=true)[k]
373386
@test !issorted(b)
374387
@test !issorted(c, by=x->1/x)
375388
@test !issorted(d, rev=true)
@@ -417,7 +430,8 @@ end
417430
# stable algorithms
418431
for alg in [MergeSort]
419432
p = sortperm(v, alg=alg, rev=rev)
420-
@test p == sortperm(float(v), alg=alg, rev=rev)
433+
p2 = sortperm(float(v), alg=alg, rev=rev)
434+
@test p == p2
421435
@test p == pi
422436
s = copy(v)
423437
permute!(s, p)
@@ -427,9 +441,10 @@ end
427441
end
428442

429443
# unstable algorithms
430-
for alg in [QuickSort, PartialQuickSort(n)]
444+
for alg in [QuickSort, PartialQuickSort(1:n)]
431445
p = sortperm(v, alg=alg, rev=rev)
432-
@test p == sortperm(float(v), alg=alg, rev=rev)
446+
p2 = sortperm(float(v), alg=alg, rev=rev)
447+
@test p == p2
433448
@test isperm(p)
434449
@test v[p] == si
435450
s = copy(v)
@@ -438,6 +453,22 @@ end
438453
invpermute!(s, p)
439454
@test s == v
440455
end
456+
for alg in [PartialQuickSort(n)]
457+
p = sortperm(v, alg=alg, rev=rev)
458+
p2 = sortperm(float(v), alg=alg, rev=rev)
459+
if n == 0
460+
@test isempty(p) && isempty(p2)
461+
else
462+
@test p[n] == p2[n]
463+
@test v[p][n] == si[n]
464+
@test isperm(p)
465+
s = copy(v)
466+
permute!(s, p)
467+
@test s[n] == si[n]
468+
invpermute!(s, p)
469+
@test s == v
470+
end
471+
end
441472
end
442473

443474
v = randn_with_nans(n,0.1)

0 commit comments

Comments
 (0)