# 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 Any[(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 10966" begin for R in numTypes, T in numTypes @test searchsortedfirst(R(2):R(2), T(0)) == 1 @test searchsortedfirst(R(2):R(2), T(2)) == 1 @test searchsortedfirst(R(2):R(2), T(3)) == 2 @test searchsortedfirst(R(1):1//2:R(5), T(0)) == 1 @test searchsortedfirst(R(1):1//2:R(5), T(2)) == 3 @test searchsortedfirst(R(1):1//2:R(5), T(6)) == 10 @test searchsortedlast(R(2):R(2), T(0)) == 0 @test searchsortedlast(R(2):R(2), T(2)) == 1 @test searchsortedlast(R(2):R(2), T(3)) == 1 @test searchsortedlast(R(1):1//2:R(5), T(0)) == 0 @test searchsortedlast(R(1):1//2:R(5), T(2)) == 3 @test searchsortedlast(R(1):1//2:R(5), T(6)) == 9 @test searchsorted(R(2):R(2), T(0)) === 1:0 @test searchsorted(R(2):R(2), T(2)) == 1:1 @test searchsorted(R(2):R(2), T(3)) === 2:1 end end @testset "issue 32568" begin for R in numTypes, T in numTypes for arr in Any[R[1:5;], R(1):R(5), R(1):2:R(5)] @test eltype(searchsorted(arr, T(2))) == keytype(arr) @test eltype(searchsorted(arr, T(2), big(1), big(4), Forward)) == keytype(arr) @test searchsortedfirst(arr, T(2)) isa keytype(arr) @test searchsortedfirst(arr, T(2), big(1), big(4), Forward) isa keytype(arr) @test searchsortedlast(arr, T(2)) isa keytype(arr) @test searchsortedlast(arr, T(2), big(1), big(4), Forward) isa keytype(arr) end end 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 Any[ Base.OneTo(10), 1:2, 0x01:0x02, -4:6, 5:2:10, [1,2], 1.0:4, [10.0,20.0], ] for huge in Any[Inf, 1e300, typemax(Int64), typemax(UInt64)] @test searchsortedfirst(coll, huge) === lastindex(coll) + 1 @test searchsortedlast(coll, huge) === lastindex(coll) @test searchsorted(coll, huge) === lastindex(coll)+1 : lastindex(coll) if !(eltype(coll) <: Unsigned) @test searchsortedfirst(reverse(coll), huge, rev=true) === firstindex(coll) @test searchsortedlast(reverse(coll), huge, rev=true) === firstindex(coll) - 1 @test searchsorted(reverse(coll), huge, rev=true) === firstindex(coll):firstindex(coll) - 1 end if !(huge isa Unsigned) @test searchsortedfirst(coll, -huge)=== firstindex(coll) @test searchsortedlast(coll, -huge) === firstindex(coll) - 1 @test searchsorted(coll, -huge) === firstindex(coll) : firstindex(coll) - 1 if !(eltype(coll) <: Unsigned) @test searchsortedfirst(reverse(coll), -huge, rev=true) === lastindex(coll) + 1 @test searchsortedlast(reverse(coll), -huge, rev=true) === lastindex(coll) @test searchsorted(reverse(coll), -huge, rev=true) === lastindex(coll)+1:lastindex(coll) end end end end @test_broken length(reverse(0x1:0x2)) == 2 @testset "issue #34408" begin r = 1f8-10:1f8 # collect(r) = Float32[9.999999e7, 9.999999e7, 9.999999e7, 9.999999e7, 1.0e8, 1.0e8, 1.0e8, 1.0e8, 1.0e8] for i in r @test_broken searchsorted(collect(r), i) == searchsorted(r, i) end end end @testset "issue #35272" begin for v0 = (3:-1:1, 3.0:-1.0:1.0), v = (v0, collect(v0)) @test searchsorted(v, 3, rev=true) == 1:1 @test searchsorted(v, 3.0, rev=true) == 1:1 @test searchsorted(v, 2.5, rev=true) === 2:1 @test searchsorted(v, 2, rev=true) == 2:2 @test searchsorted(v, 1.2, rev=true) === 3:2 @test searchsorted(v, 1, rev=true) == 3:3 @test searchsorted(v, 0.1, rev=true) === 4:3 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 b = sort(a, alg=QuickSort) @test issorted(b) @test last(b) == last(sort(a, alg=PartialQuickSort(length(a)))) b = sort(a, alg=QuickSort, rev=true) @test issorted(b, rev=true) @test last(b) == last(sort(a, alg=PartialQuickSort(length(a)), rev=true)) b = sort(a, alg=QuickSort, by=x->1/x) @test issorted(b, by=x->1/x) @test last(b) == last(sort(a, alg=PartialQuickSort(length(a)), by=x->1/x)) end end @testset "insorted" begin numTypes = [Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128, Float16, Float32, Float64, BigInt, BigFloat] @test insorted(1, collect(1:10), by=(>=(5))) @test insorted(10, collect(1:10), by=(>=(5))) for R in numTypes, T in numTypes @test !insorted(T(0), R[1, 1, 2, 2, 3, 3]) @test insorted(T(1), R[1, 1, 2, 2, 3, 3]) @test insorted(T(2), R[1, 1, 2, 2, 3, 3]) @test !insorted(T(4), R[1, 1, 2, 2, 3, 3]) @test !insorted(2.5, R[1, 1, 2, 2, 3, 3]) @test !insorted(T(0), 1:3) @test insorted(T(1), 1:3) @test insorted(T(2), 1:3) @test !insorted(T(4), 1:3) @test insorted(T(1), R.(collect(1:10)), by=(>=(5))) @test insorted(T(10), R.(collect(1:10)), by=(>=(5))) end for (rg,I) in Any[(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)] rg_r = reverse(rg) rgv, rgv_r = collect(rg), collect(rg_r) for i = I @test insorted(i,rg) === insorted(i,rgv) @test insorted(i,rg_r) === insorted(i,rgv_r,rev=true) end end rg = 0.0:0.01:1.0 for i = 2:101 @test insorted(rg[i], rg) @test !insorted(prevfloat(rg[i]), rg) @test !insorted(nextfloat(rg[i]), rg) end rg_r = reverse(rg) for i = 1:100 @test insorted(rg_r[i], rg_r) @test !insorted(prevfloat(rg_r[i]), rg_r) @test !insorted(nextfloat(rg_r[i]), rg_r) end @test insorted(1, 1:10) == insorted(1, collect(1:10), by=(>=(5))) @test insorted(10, 1:10) == insorted(10, collect(1:10), by=(>=(5))) @test !insorted(0, []) @test !insorted(0, [1,2,3]) @test !insorted(4, [1,2,3]) @test insorted(3, [10,8,6,9,4,7,2,5,3,1], by=(x -> iseven(x) ? x+5 : x), rev=true) end @testset "PartialQuickSort" begin a = rand(1:10000, 1000) # test PartialQuickSort only does a partial sort let alg = PartialQuickSort(1: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[k]) @test issorted(c[k], by=x->1/x) @test issorted(d[k], rev=true) @test !issorted(b) @test !issorted(c, by=x->1/x) @test !issorted(d, rev=true) end 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 b[k] == sort(a)[k] @test c[k] == sort(a, by=x->1/x)[k] @test d[k] == sort(a, rev=true)[k] @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).