-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make Compiler use separate sorting algorithm. (#47066)
* add Compiler sorting algorithm. Co-authored-by: Valentin Churavy <[email protected]> Co-authored-by: Lilith Hafner <[email protected]> Co-authored-by: Hendrik Ranocha <[email protected]>
- Loading branch information
1 parent
2590712
commit 17afb66
Showing
7 changed files
with
180 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
||
# reference on sorted binary search: | ||
# https://www.tbray.org/ongoing/When/200x/2003/03/22/Binary | ||
|
||
# index of the first value of vector a that is greater than or equal to x; | ||
# returns lastindex(v)+1 if x is greater than all values in v. | ||
function searchsortedfirst(v::AbstractVector, x, lo::T, hi::T, o::Ordering)::keytype(v) where T<:Integer | ||
hi = hi + T(1) | ||
len = hi - lo | ||
@inbounds while len != 0 | ||
half_len = len >>> 0x01 | ||
m = lo + half_len | ||
if lt(o, v[m], x) | ||
lo = m + 1 | ||
len -= half_len + 1 | ||
else | ||
hi = m | ||
len = half_len | ||
end | ||
end | ||
return lo | ||
end | ||
|
||
# index of the last value of vector a that is less than or equal to x; | ||
# returns firstindex(v)-1 if x is less than all values of v. | ||
function searchsortedlast(v::AbstractVector, x, lo::T, hi::T, o::Ordering)::keytype(v) where T<:Integer | ||
u = T(1) | ||
lo = lo - u | ||
hi = hi + u | ||
@inbounds while lo < hi - u | ||
m = midpoint(lo, hi) | ||
if lt(o, x, v[m]) | ||
hi = m | ||
else | ||
lo = m | ||
end | ||
end | ||
return lo | ||
end | ||
|
||
# returns the range of indices of v equal to x | ||
# if v does not contain x, returns a 0-length range | ||
# indicating the insertion point of x | ||
function searchsorted(v::AbstractVector, x, ilo::T, ihi::T, o::Ordering)::UnitRange{keytype(v)} where T<:Integer | ||
u = T(1) | ||
lo = ilo - u | ||
hi = ihi + u | ||
@inbounds while lo < hi - u | ||
m = midpoint(lo, hi) | ||
if lt(o, v[m], x) | ||
lo = m | ||
elseif lt(o, x, v[m]) | ||
hi = m | ||
else | ||
a = searchsortedfirst(v, x, max(lo,ilo), m, o) | ||
b = searchsortedlast(v, x, m, min(hi,ihi), o) | ||
return a : b | ||
end | ||
end | ||
return (lo + 1) : (hi - 1) | ||
end | ||
|
||
for s in [:searchsortedfirst, :searchsortedlast, :searchsorted] | ||
@eval begin | ||
$s(v::AbstractVector, x, o::Ordering) = $s(v,x,firstindex(v),lastindex(v),o) | ||
$s(v::AbstractVector, x; | ||
lt=isless, by=identity, rev::Union{Bool,Nothing}=nothing, order::Ordering=Forward) = | ||
$s(v,x,ord(lt,by,rev,order)) | ||
end | ||
end | ||
|
||
# An unstable sorting algorithm for internal use | ||
function sort!(v::Vector; by::Function=identity, (<)::Function=<) | ||
isempty(v) && return v # This branch is hit 95% of the time | ||
|
||
# Of the remaining 5%, this branch is hit less than 1% of the time | ||
if length(v) > 200 # Heap sort prevents quadratic runtime | ||
o = ord(<, by, true) | ||
heapify!(v, o) | ||
for i in lastindex(v):-1:2 | ||
y = v[i] | ||
v[i] = v[1] | ||
percolate_down!(v, 1, y, o, i-1) | ||
end | ||
return v | ||
end | ||
|
||
@inbounds for i in 2:length(v) # Insertion sort | ||
x = v[i] | ||
y = by(x) | ||
while i > 1 && y < by(v[i-1]) | ||
v[i] = v[i-1] | ||
i -= 1 | ||
end | ||
v[i] = x | ||
end | ||
|
||
v | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
@testset "searchsorted" begin | ||
@test Core.Compiler.searchsorted([1, 1, 2, 2, 3, 3], 0) === Core.Compiler.UnitRange(1, 0) | ||
@test Core.Compiler.searchsorted([1, 1, 2, 2, 3, 3], 1) === Core.Compiler.UnitRange(1, 2) | ||
@test Core.Compiler.searchsorted([1, 1, 2, 2, 3, 3], 2) === Core.Compiler.UnitRange(3, 4) | ||
@test Core.Compiler.searchsorted([1, 1, 2, 2, 3, 3], 4) === Core.Compiler.UnitRange(7, 6) | ||
@test Core.Compiler.searchsorted([1, 1, 2, 2, 3, 3], 2.5; lt=<) === Core.Compiler.UnitRange(5, 4) | ||
|
||
@test Core.Compiler.searchsorted(Core.Compiler.UnitRange(1, 3), 0) === Core.Compiler.UnitRange(1, 0) | ||
@test Core.Compiler.searchsorted(Core.Compiler.UnitRange(1, 3), 1) === Core.Compiler.UnitRange(1, 1) | ||
@test Core.Compiler.searchsorted(Core.Compiler.UnitRange(1, 3), 2) === Core.Compiler.UnitRange(2, 2) | ||
@test Core.Compiler.searchsorted(Core.Compiler.UnitRange(1, 3), 4) === Core.Compiler.UnitRange(4, 3) | ||
|
||
@test Core.Compiler.searchsorted([1:10;], 1, by=(x -> x >= 5)) === Core.Compiler.UnitRange(1, 4) | ||
@test Core.Compiler.searchsorted([1:10;], 10, by=(x -> x >= 5)) === Core.Compiler.UnitRange(5, 10) | ||
@test Core.Compiler.searchsorted([1:5; 1:5; 1:5], 1, 6, 10, Core.Compiler.Forward) === Core.Compiler.UnitRange(6, 6) | ||
@test Core.Compiler.searchsorted(fill(1, 15), 1, 6, 10, Core.Compiler.Forward) === Core.Compiler.UnitRange(6, 10) | ||
|
||
for (rg,I) in Any[(Core.Compiler.UnitRange(49, 57), 47:59), | ||
(Core.Compiler.StepRange(1, 2, 17), -1:19)] | ||
rg_r = Core.Compiler.reverse(rg) | ||
rgv, rgv_r = Core.Compiler.collect(rg), Core.Compiler.collect(rg_r) | ||
for i = I | ||
@test Core.Compiler.searchsorted(rg,i) === Core.Compiler.searchsorted(rgv,i) | ||
@test Core.Compiler.searchsorted(rg_r,i,rev=true) === Core.Compiler.searchsorted(rgv_r,i,rev=true) | ||
end | ||
end | ||
end | ||
|
||
@testset "basic sort" begin | ||
v = [3,1,2] | ||
@test v == [3,1,2] | ||
@test Core.Compiler.sort!(v) === v == [1,2,3] | ||
@test Core.Compiler.sort!(v, by = x -> -x) === v == [3,2,1] | ||
@test Core.Compiler.sort!(v, by = x -> -x, < = >) === v == [1,2,3] | ||
end | ||
|
||
@testset "randomized sorting tests" begin | ||
for n in [0, 1, 3, 10, 30, 100, 300], k in [0, 30, 2n] | ||
v = rand(-1:k, n) | ||
for by in [identity, x -> -x, x -> x^2 + .1x], lt in [<, >] | ||
@test sort(v; by, lt) == Core.Compiler.sort!(copy(v); by, < = lt) | ||
end | ||
end | ||
end |
17afb66
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Executing the daily package evaluation, I will reply here when finished:
@nanosoldier
runtests(ALL, isdaily = true, configuration=(rr=true,))