Skip to content

Commit 7880930

Browse files
LilithHafnerKristofferC
authored and
KristofferC
committed
Apply InitialOptimizations more consistently in sorting & fix dispatch bug (#47946)
* Apply InitialOptimizations by default in several cases when it was previously present * fixup for MissingOptimization * fix stability in the sortperm union with missing case (cherry picked from commit 12e679c)
1 parent 9a592dd commit 7880930

File tree

1 file changed

+38
-9
lines changed

1 file changed

+38
-9
lines changed

base/sort.jl

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ issorted(itr;
8686
issorted(itr, ord(lt,by,rev,order))
8787

8888
function partialsort!(v::AbstractVector, k::Union{Integer,OrdinalRange}, o::Ordering)
89-
_sort!(v, QuickerSort(k), o, (;))
89+
_sort!(v, InitialOptimizations(QuickerSort(k)), o, (;))
9090
maybeview(v, k)
9191
end
9292

@@ -566,8 +566,30 @@ function _sort!(v::AbstractVector, a::MissingOptimization, o::Ordering, kw)
566566
if nonmissingtype(eltype(v)) != eltype(v) && o isa DirectOrdering
567567
lo, hi = send_to_end!(ismissing, v, o; lo, hi)
568568
_sort!(WithoutMissingVector(v, unsafe=true), a.next, o, (;kw..., lo, hi))
569-
elseif eltype(v) <: Integer && o isa Perm{DirectOrdering} && nonmissingtype(eltype(o.data)) != eltype(o.data)
570-
lo, hi = send_to_end!(i -> ismissing(@inbounds o.data[i]), v, o)
569+
elseif eltype(v) <: Integer && o isa Perm && o.order isa DirectOrdering &&
570+
nonmissingtype(eltype(o.data)) != eltype(o.data) &&
571+
all(i === j for (i,j) in zip(v, eachindex(o.data)))
572+
# TODO make this branch known at compile time
573+
# This uses a custom function because we need to ensure stability of both sides and
574+
# we can assume v is equal to eachindex(o.data) which allows a copying partition
575+
# without allocations.
576+
lo_i, hi_i = lo, hi
577+
for (i,x) in zip(eachindex(o.data), o.data)
578+
if ismissing(x) == (o.order == Reverse) # should i go at the beginning?
579+
v[lo_i] = i
580+
lo_i += 1
581+
else
582+
v[hi_i] = i
583+
hi_i -= 1
584+
end
585+
end
586+
reverse!(v, lo_i, hi)
587+
if o.order == Reverse
588+
lo = lo_i
589+
else
590+
hi = hi_i
591+
end
592+
571593
_sort!(v, a.next, Perm(o.order, WithoutMissingVector(o.data, unsafe=true)), (;kw..., lo, hi))
572594
else
573595
_sort!(v, a.next, o, kw)
@@ -1160,7 +1182,9 @@ end
11601182
"""
11611183
InitialOptimizations(next) <: Algorithm
11621184
1163-
Attempt to apply a suite of low-cost optimizations to the input vector before sorting.
1185+
Attempt to apply a suite of low-cost optimizations to the input vector before sorting. These
1186+
optimizations may be automatically applied by the `sort!` family of functions when
1187+
`alg=InsertionSort`, `alg=MergeSort`, or `alg=QuickSort` is passed as an argument.
11641188
11651189
`InitialOptimizations` is an implementation detail and subject to change or removal in
11661190
future versions of Julia.
@@ -1347,7 +1371,7 @@ function sort!(v::AbstractVector{T};
13471371
rev::Union{Bool,Nothing}=nothing,
13481372
order::Ordering=Forward,
13491373
scratch::Union{Vector{T}, Nothing}=nothing) where T
1350-
_sort!(v, alg, ord(lt,by,rev,order), (;scratch))
1374+
_sort!(v, maybe_apply_initial_optimizations(alg), ord(lt,by,rev,order), (;scratch))
13511375
v
13521376
end
13531377

@@ -1474,7 +1498,7 @@ function partialsortperm!(ix::AbstractVector{<:Integer}, v::AbstractVector,
14741498
end
14751499

14761500
# do partial quicksort
1477-
_sort!(ix, QuickerSort(k), Perm(ord(lt, by, rev, order), v), (;))
1501+
_sort!(ix, InitialOptimizations(QuickerSort(k)), Perm(ord(lt, by, rev, order), v), (;))
14781502

14791503
maybeview(ix, k)
14801504
end
@@ -1679,11 +1703,11 @@ function sort(A::AbstractArray{T};
16791703
pdims = (dim, setdiff(1:ndims(A), dim)...) # put the selected dimension first
16801704
Ap = permutedims(A, pdims)
16811705
Av = vec(Ap)
1682-
sort_chunks!(Av, n, alg, order, scratch)
1706+
sort_chunks!(Av, n, maybe_apply_initial_optimizations(alg), order, scratch)
16831707
permutedims(Ap, invperm(pdims))
16841708
else
16851709
Av = A[:]
1686-
sort_chunks!(Av, n, alg, order, scratch)
1710+
sort_chunks!(Av, n, maybe_apply_initial_optimizations(alg), order, scratch)
16871711
reshape(Av, axes(A))
16881712
end
16891713
end
@@ -1746,7 +1770,7 @@ function sort!(A::AbstractArray{T};
17461770
rev::Union{Bool,Nothing}=nothing,
17471771
order::Ordering=Forward, # TODO stop eagerly over-allocating.
17481772
scratch::Union{Vector{T}, Nothing}=similar(A, size(A, dims))) where T
1749-
__sort!(A, Val(dims), alg, ord(lt, by, rev, order), scratch)
1773+
__sort!(A, Val(dims), maybe_apply_initial_optimizations(alg), ord(lt, by, rev, order), scratch)
17501774
end
17511775
function __sort!(A::AbstractArray{T}, ::Val{K},
17521776
alg::Algorithm,
@@ -1911,6 +1935,11 @@ Characteristics:
19111935
"""
19121936
const MergeSort = MergeSortAlg()
19131937

1938+
maybe_apply_initial_optimizations(alg::Algorithm) = alg
1939+
maybe_apply_initial_optimizations(alg::QuickSortAlg) = InitialOptimizations(alg)
1940+
maybe_apply_initial_optimizations(alg::MergeSortAlg) = InitialOptimizations(alg)
1941+
maybe_apply_initial_optimizations(alg::InsertionSortAlg) = InitialOptimizations(alg)
1942+
19141943
# selectpivot!
19151944
#
19161945
# Given 3 locations in an array (lo, mi, and hi), sort v[lo], v[mi], v[hi]) and

0 commit comments

Comments
 (0)