# This file is a part of Julia. License is MIT: https://julialang.org/license module SortingTests using Base.Order using Random using Test isdefined(Main, :OffsetArrays) || @eval Main include("testhelpers/OffsetArrays.jl") using .Main.OffsetArrays @testset "Order" begin @test Forward == ForwardOrdering() @test ReverseOrdering(Forward) == ReverseOrdering() == Reverse end @testset "midpoint" begin @test Base.Sort.midpoint(1, 3) === 2 @test Base.Sort.midpoint(2, 4) === 3 @test 2 <= Base.Sort.midpoint(1, 4) <= 3 @test Base.Sort.midpoint(-3, -1) === -2 @test Base.Sort.midpoint(-4, -2) === -3 @test -3 <= Base.Sort.midpoint(-4, -1) <= -2 @test Base.Sort.midpoint(-1, 1) === 0 @test -1 <= Base.Sort.midpoint(-2, 1) <= 0 @test 0 <= Base.Sort.midpoint(-1, 2) <= 1 @test Base.Sort.midpoint(-2, 2) === 0 @test Base.Sort.midpoint(typemax(Int)-2, typemax(Int)) === typemax(Int)-1 @test Base.Sort.midpoint(typemin(Int), typemin(Int)+2) === typemin(Int)+1 @test -1 <= Base.Sort.midpoint(typemin(Int), typemax(Int)) <= 0 end @testset "sort" begin @test sort([2,3,1]) == [1,2,3] == sort([2,3,1]; order=Forward) @test sort([2,3,1], rev=true) == [3,2,1] == sort([2,3,1], order=Reverse) @test sort(['z':-1:'a';]) == ['a':'z';] @test sort(['a':'z';], rev=true) == ['z':-1:'a';] end @testset "sortperm" begin @test sortperm([2,3,1]) == [3,1,2] @test sortperm!([1,2,3], [2,3,1]) == [3,1,2] let s = view([1,2,3,4], 1:3), r = sortperm!(s, [2,3,1]) @test r == [3,1,2] @test r === s end @test_throws ArgumentError sortperm!(view([1,2,3,4], 1:4), [2,3,1]) end @testset "misc sorting" begin @test !issorted([2,3,1]) @test issorted([1,2,3]) @test reverse([2,3,1]) == [1,3,2] @test sum(randperm(6)) == 21 end @testset "partialsort" begin @test partialsort([3,6,30,1,9],3) == 6 @test partialsort([3,6,30,1,9],3:4) == [6,9] @test partialsortperm([3,6,30,1,9], 3:4) == [2,5] @test partialsortperm!(Vector(1:5), [3,6,30,1,9], 3:4) == [2,5] let a=[1:10;] for r in Any[2:4, 1:2, 10:10, 4:2, 2:1, 4:-1:2, 2:-1:1, 10:-1:10, 4:1:3, 1:2:8, 10:-3:1, UInt(2):UInt(5)] @test partialsort(a, r) == [r;] @test partialsortperm(a, r) == [r;] @test partialsort(a, r, rev=true) == (11 .- [r;]) @test partialsortperm(a, r, rev=true) == (11 .- [r;]) end for i in (2, UInt(2), Int128(1), big(10)) @test partialsort(a, i) == i @test partialsortperm(a, i) == i @test partialsort(a, i, rev=true) == (11 - i) @test partialsortperm(a, i, rev=true) == (11 - i) end end @test_throws ArgumentError partialsortperm!([1,2], [2,3,1], 1:2) end @testset "searchsorted" begin numTypes = [ Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128, Float16, Float32, Float64, BigInt, BigFloat] @test searchsorted([1:10;], 1, by=(x -> x >= 5)) == 1:4 @test searchsorted([1:10;], 10, by=(x -> x >= 5)) == 5:10 @test searchsorted([1:5; 1:5; 1:5], 1, 6, 10, Forward) == 6:6 @test searchsorted(fill(1, 15), 1, 6, 10, Forward) == 6:10 for R in numTypes, T in numTypes @test searchsorted(R[1, 1, 2, 2, 3, 3], T(0)) == 1:0 @test searchsorted(R[1, 1, 2, 2, 3, 3], T(1)) == 1:2 @test searchsorted(R[1, 1, 2, 2, 3, 3], T(2)) == 3:4 @test searchsorted(R[1, 1, 2, 2, 3, 3], T(4)) == 7:6 @test searchsorted(R[1, 1, 2, 2, 3, 3], 2.5) == 5:4 @test searchsorted(1:3, T(0)) == 1:0 @test searchsorted(1:3, T(1)) == 1:1 @test searchsorted(1:3, T(2)) == 2:2 @test searchsorted(1:3, T(4)) == 4:3 @test searchsorted(R[1:10;], T(1), by=(x -> x >= 5)) == 1:4 @test searchsorted(R[1:10;], T(10), by=(x -> x >= 5)) == 5:10 @test searchsorted(R[1:5; 1:5; 1:5], T(1), 6, 10, Forward) == 6:6 @test searchsorted(fill(R(1), 15), T(1), 6, 10, Forward) == 6:10 end for (rg,I) in [(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)] rg_r = reverse(rg) rgv, rgv_r = [rg;], [rg_r;] for i = I @test searchsorted(rg,i) == searchsorted(rgv,i) @test searchsorted(rg_r,i,rev=true) == searchsorted(rgv_r,i,rev=true) end end rg = 0.0:0.01:1.0 for i = 2:101 @test searchsorted(rg, rg[i]) == i:i @test searchsorted(rg, prevfloat(rg[i])) == i:i-1 @test searchsorted(rg, nextfloat(rg[i])) == i+1:i end rg_r = reverse(rg) for i = 1:100 @test searchsorted(rg_r, rg_r[i], rev=true) == i:i @test searchsorted(rg_r, prevfloat(rg_r[i]), rev=true) == i+1:i @test searchsorted(rg_r, nextfloat(rg_r[i]), rev=true) == i:i-1 end @test searchsorted(1:10, 1, by=(x -> x >= 5)) == searchsorted([1:10;], 1, by=(x -> x >= 5)) @test searchsorted(1:10, 10, by=(x -> x >= 5)) == searchsorted([1:10;], 10, by=(x -> x >= 5)) @test searchsorted([], 0) == 1:0 @test searchsorted([1,2,3], 0) == 1:0 @test searchsorted([1,2,3], 4) == 4:3 @testset "issue 8866" begin @test searchsortedfirst(500:1.0:600, -1.0e20) == 1 @test searchsortedfirst(500:1.0:600, 1.0e20) == 102 @test searchsortedlast(500:1.0:600, -1.0e20) == 0 @test searchsortedlast(500:1.0:600, 1.0e20) == 101 end @testset "issue #34157" begin @test searchsorted(1:2.0, -Inf) === 1:0 @test searchsorted([1,2], -Inf) === 1:0 @test searchsorted(1:2, -Inf) === 1:0 @test searchsorted(1:2.0, Inf) === 3:2 @test searchsorted([1,2], Inf) === 3:2 @test searchsorted(1:2, Inf) === 3:2 for coll in [ Base.OneTo(10), 1:2, -4:6, 5:2:10, [1,2], 1.0:4, [10.0,20.0], ] for huge in [Inf, 1e300] @test searchsortedfirst(coll, huge) === lastindex(coll) + 1 @test searchsortedfirst(coll, -huge)=== firstindex(coll) @test searchsortedlast(coll, huge) === lastindex(coll) @test searchsortedlast(coll, -huge) === firstindex(coll) - 1 @test searchsorted(coll, huge) === lastindex(coll)+1 : lastindex(coll) @test searchsorted(coll, -huge) === firstindex(coll) : firstindex(coll) - 1 @test searchsortedfirst(reverse(coll), huge, rev=true) === firstindex(coll) @test searchsortedfirst(reverse(coll), -huge, rev=true) === lastindex(coll) + 1 @test searchsortedlast(reverse(coll), huge, rev=true) === firstindex(coll) - 1 @test searchsortedlast(reverse(coll), -huge, rev=true) === lastindex(coll) @test searchsorted(reverse(coll), huge, rev=true) === firstindex(coll):firstindex(coll) - 1 @test searchsorted(reverse(coll), -huge, rev=true) === lastindex(coll)+1:lastindex(coll) end end end end # exercise the codepath in searchsorted* methods for ranges that check for zero step range struct ConstantRange{T} <: AbstractRange{T} val::T len::Int end Base.length(r::ConstantRange) = r.len Base.getindex(r::ConstantRange, i::Int) = (1 <= i <= r.len || throw(BoundsError(r,i)); r.val) Base.step(r::ConstantRange) = 0 @testset "searchsorted method with ranges which check for zero step range" begin r = ConstantRange(1, 5) @test searchsortedfirst(r, 1.0, Forward) == 1 @test searchsortedfirst(r, 1, Forward) == 1 @test searchsortedfirst(r, UInt(1), Forward) == 1 @test searchsortedlast(r, 1.0, Forward) == 5 @test searchsortedlast(r, 1, Forward) == 5 @test searchsortedlast(r, UInt(1), Forward) == 5 a = rand(1:10000, 1000) for alg in [InsertionSort, MergeSort] b = sort(a, alg=alg) @test issorted(b) ix = sortperm(a, alg=alg) b = a[ix] @test issorted(b) @test a[ix] == b sortperm!(view(ix, 1:100), view(a, 1:100), alg=alg) b = a[ix][1:100] @test issorted(b) sortperm!(ix, a, alg=alg) b = a[ix] @test issorted(b) @test a[ix] == b b = sort(a, alg=alg, rev=true) @test issorted(b, rev=true) ix = sortperm(a, alg=alg, rev=true) b = a[ix] @test issorted(b, rev=true) @test a[ix] == b sortperm!(view(ix, 1:100), view(a, 1:100), alg=alg, rev=true) b = a[ix][1:100] @test issorted(b, rev=true) sortperm!(ix, a, alg=alg, rev=true) b = a[ix] @test issorted(b, rev=true) @test a[ix] == b b = sort(a, alg=alg, by=x->1/x) @test issorted(b, by=x->1/x) ix = sortperm(a, alg=alg, by=x->1/x) b = a[ix] @test issorted(b, by=x->1/x) @test a[ix] == b sortperm!(view(ix, 1:100), view(a, 1:100), by=x->1/x) b = a[ix][1:100] @test issorted(b, by=x->1/x) sortperm!(ix, a, alg=alg, by=x->1/x) b = a[ix] @test issorted(b, by=x->1/x) @test a[ix] == b c = copy(a) permute!(c, ix) @test c == b invpermute!(c, ix) @test c == a c = sort(a, alg=alg, lt=(>)) @test b == c c = sort(a, alg=alg, by=x->1/x) @test b == c end @testset "unstable algorithms" begin for alg in [QuickSort, PartialQuickSort(length(a))] b = sort(a, alg=alg) @test issorted(b) b = sort(a, alg=alg, rev=true) @test issorted(b, rev=true) b = sort(a, alg=alg, by=x->1/x) @test issorted(b, by=x->1/x) end end end @testset "PartialQuickSort" begin a = rand(1:10000, 1000) # test PartialQuickSort only does a partial sort let alg = PartialQuickSort(div(length(a), 10)) k = alg.k b = sort(a, alg=alg) c = sort(a, alg=alg, by=x->1/x) d = sort(a, alg=alg, rev=true) @test issorted(b[1:k]) @test issorted(c[1:k], by=x->1/x) @test issorted(d[1:k], rev=true) @test !issorted(b) @test !issorted(c, by=x->1/x) @test !issorted(d, rev=true) end @test partialsort([3,6,30,1,9], 2, rev=true) == 9 @test partialsort([3,6,30,1,9], 2, by=x->1/x) == 9 @test partialsortperm([3,6,30,1,9], 2, rev=true) == 5 @test partialsortperm([3,6,30,1,9], 2, by=x->1/x) == 5 end ## more advanced sorting tests ## randnans(n) = reinterpret(Float64,[rand(UInt64)|0x7ff8000000000000 for i=1:n]) function randn_with_nans(n,p) v = randn(n) x = findall(rand(n).