diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 734d8140676f8..a8032d297e088 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1079,6 +1079,34 @@ indices(I::(Indices...)) = map(indices, I) ## iteration utilities ## +# TODO: something sensible should happen when each_col et. al. are used with a +# pure function argument +function each_col!(f::Function, a::AbstractMatrix) + m = size(a,1) + for i = 1:m:numel(a) + f(sub(a, i:(i+m-1))) + end + return a +end + +function each_row!(f::Function, a::AbstractMatrix) + m = size(a,1) + for i = 1:m + f(sub(a, i:m:numel(a))) + end + return a +end + +function each_vec!(f::Function, a::AbstractMatrix, dim::Integer) + if dim == 1; return each_col!(f,a); end + if dim == 2; return each_row!(f,a); end + error("invalid matrix dimensions: ", dim) +end + +each_col(f::Function, a::AbstractMatrix) = each_col!(f,copy(a)) +each_row(f::Function, a::AbstractMatrix) = each_row!(f,copy(a)) +each_vec(f::Function, a::AbstractMatrix, d::Integer) = each_vec!(f,copy(a),d) + # slow, but useful function cartesian_map(body, t::(Int...), it...) idx = length(t)-length(it) diff --git a/base/combinatorics.jl b/base/combinatorics.jl index 26ff247dd3af2..2d6e24cd19198 100644 --- a/base/combinatorics.jl +++ b/base/combinatorics.jl @@ -1,3 +1,5 @@ +import Sort.@in_place_matrix_op + function factorial(n::Integer) if n < 0 return zero(n) diff --git a/base/export.jl b/base/export.jl index dcddf722a47e6..9b32e78b3e4f7 100644 --- a/base/export.jl +++ b/base/export.jl @@ -590,6 +590,8 @@ export ipermute, isperm, issorted, + issorted_r, + issorted_by, last, linspace, logspace, @@ -618,10 +620,20 @@ export rotl90, rotr90, search_sorted, + search_sorted_r, + search_sorted_by, search_sorted_first, + search_sorted_first_r, + search_sorted_first_by, search_sorted_last, + search_sorted_last_r, + search_sorted_last_by, select, + select_r, + select_by, select!, + select_r!, + select_by!, shuffle, shuffle!, size, @@ -632,6 +644,7 @@ export sort_by, sort_by!, sortperm, + sortperm!, sortr, sortr!, squeeze, @@ -652,6 +665,16 @@ export make_loop_nest, check_bounds, +# sort routines + insertionsort, + insertionsort!, + quicksort, + quicksort!, + mergesort, + mergesort!, + timsort, + timsort!, + # linear algebra axpy, chol, diff --git a/base/sort.jl b/base/sort.jl index c5f1331e56adb..1a84326f27d33 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -1,5 +1,87 @@ ## standard sort comparisons ## +module Sort + +export + @in_place_matrix_op, + issorted, + issorted_r, + issorted_by, + order, + search_sorted, + search_sorted_r, + search_sorted_by, + search_sorted_first, + search_sorted_first_r, + search_sorted_first_by, + search_sorted_last, + search_sorted_last_r, + search_sorted_last_by, + select, + select!, + select_r, + select_r!, + select_by, + select_by!, + sort, + sort!, + sort_by, + sort_by!, + sortr, + sortr!, + sortperm, + sortperm!, + sortperm_r, + sortperm_r!, + sortperm_by, + sortperm_by!, + + insertionsort, + insertionsort!, + insertionsort_r, + insertionsort_r!, + insertionsort_by, + insertionsort_by!, + insertionsort_perm, + insertionsort_perm!, + insertionsort_perm_r, + insertionsort_perm_r!, + insertionsort_perm_by, + insertionsort_perm_by!, + mergesort, + mergesort!, + mergesort_r, + mergesort_r!, + mergesort_by, + mergesort_by!, + mergesort_perm, + mergesort_perm!, + mergesort_perm_r, + mergesort_perm_r!, + mergesort_perm_by, + mergesort_perm_by!, + quicksort, + quicksort!, + quicksort_r, + quicksort_r!, + quicksort_by, + quicksort_by!, + timsort, + timsort!, + timsort_r, + timsort_r!, + timsort_by, + timsort_by!, + timsort_perm, + timsort_perm!, + timsort_perm_r, + timsort_perm_r!, + timsort_perm_by, + timsort_perm_by! + +import Base.sort, Base.issorted, Base.sort, Base.sort!, Base.sortperm, Base.slt_int, + Base.unbox, Base.sle_int, Base.length + _jl_fp_pos_lt(x::Float32, y::Float32) = slt_int(unbox(Float32,x),unbox(Float32,y)) _jl_fp_pos_lt(x::Float64, y::Float64) = slt_int(unbox(Float64,x),unbox(Float64,y)) _jl_fp_pos_le(x::Float32, y::Float32) = sle_int(unbox(Float32,x),unbox(Float32,y)) @@ -11,17 +93,38 @@ _jl_fp_neg_le(x::Float32, y::Float32) = sle_int(unbox(Float32,y),unbox(Float32,x _jl_fp_neg_le(x::Float64, y::Float64) = sle_int(unbox(Float64,y),unbox(Float64,x)) ## internal sorting functionality ## + +include("$JULIA_HOME/../share/julia/base/timsort.jl") + for (suffix, lt, args) in (("", (a,b)->:(isless($a,$b)), ()), ("_r", (a,b)->:(isless($b,$a)), ()), - ("_lt", (a,b)->:(lt($a,$b)), (:(lt::Function),)), + ("", (a,b)->:(lt($a,$b)), (:(lt::Function),)), ("_by", (a,b)->:(isless(by($a),by($b))), (:(by::Function),)), ## special sorting for floating-point arrays ## ("_fp_pos", (a,b)->:(_jl_fp_pos_lt($a,$b)), ()), ("_fp_neg", (a,b)->:(_jl_fp_neg_lt($a,$b)), ())) - insertionsort = symbol("_jl_insertionsort$suffix") - quicksort = symbol("_jl_quicksort$suffix") - mergesort = symbol("_jl_mergesort$suffix") - pivot_middle = symbol("_jl_pivot_middle$suffix") + insertionsort = symbol("insertionsort$(suffix)") + insertionsort! = symbol("insertionsort$(suffix)!") + insertionsort_perm = symbol("insertionsort_perm$(suffix)") + insertionsort_perm! = symbol("insertionsort_perm$(suffix)!") + quicksort = symbol("quicksort$(suffix)") + quicksort! = symbol("quicksort$(suffix)!") + quicksort_perm = symbol("quicksort_perm$(suffix)") + quicksort_perm! = symbol("quicksort_perm$(suffix)!") + mergesort = symbol("mergesort$(suffix)") + mergesort! = symbol("mergesort$(suffix)!") + mergesort_perm = symbol("mergesort_perm$(suffix)") + mergesort_perm! = symbol("mergesort_perm$(suffix)!") + pivot_middle = symbol("_jl_pivot_middle$(suffix)") + issorted = symbol("issorted$(suffix)") + _jl_quickselect = symbol("_jl_quickselect$(suffix)") + select = symbol("select$(suffix)") + select! = symbol("select$(suffix)!") + search_sorted = symbol("search_sorted$(suffix)") + search_sorted_first = symbol("search_sorted_first$(suffix)") + search_sorted_last = symbol("search_sorted_last$(suffix)") + sortperm = symbol("sortperm$(suffix)") + sortperm! = symbol("sortperm$(suffix)!") @eval begin # sorting should be stable @@ -30,7 +133,7 @@ for (suffix, lt, args) in (("", (a,b)->:(isless($a,$b)), ()), # If only numbers are being sorted, a faster quicksort can be used. # fast sort for small arrays -function ($insertionsort)($(args...), a::AbstractVector, lo::Int, hi::Int) +function ($insertionsort!)($(args...), a::AbstractVector, lo::Int, hi::Int) for i = lo+1:hi j = i x = a[i] @@ -47,8 +150,11 @@ function ($insertionsort)($(args...), a::AbstractVector, lo::Int, hi::Int) return a end +($insertionsort!)($(args...), a::AbstractVector) = ($insertionsort!)($(args...), a, 1, length(a)) +($insertionsort)($(args...), a::AbstractVector, args2...) = ($insertionsort!)($(args...), copy(a), args2...) + # permutes an auxilliary array mirroring the sort -function ($insertionsort)($(args...), a::AbstractVector, p::AbstractVector{Int}, lo::Int, hi::Int) +function ($insertionsort_perm!)($(args...), a::AbstractVector, p::AbstractVector{Int}, lo::Int, hi::Int) for i = lo+1:hi j = i x = a[i] @@ -68,20 +174,28 @@ function ($insertionsort)($(args...), a::AbstractVector, p::AbstractVector{Int}, return a, p end -($pivot_middle)(a,b,c) = $(lt(:a,:b)) ? ($(lt(:b,:c)) ? b : c) : ($(lt(:a,:c)) ? a : c) +($insertionsort_perm!){T}($(args...), a::AbstractVector{T}, p::AbstractVector{Int}) = + ($insertionsort_perm!)($(args...), a, p, 1, length(a)) +($insertionsort_perm!){T}($(args...), a::AbstractVector{T}) = + ($insertionsort_perm!)($(args...), a, [1:length(a)]) +($insertionsort_perm){T}($(args...), a::AbstractVector{T}, args2...) = + ($insertionsort_perm!)($(args...), copy(a), [1:length(a)], args2...) + + +($pivot_middle)($(args...),a,b,c) = $(lt(:a,:b)) ? ($(lt(:b,:c)) ? b : c) : ($(lt(:a,:c)) ? a : c) # very fast but unstable -function ($quicksort)($(args...), a::AbstractVector, lo::Int, hi::Int) +function ($quicksort!)($(args...), a::AbstractVector, lo::Int, hi::Int) while hi > lo if hi-lo <= 20 - return $(expr(:call, insertionsort, args..., :a, :lo, :hi)) + return $(expr(:call, insertionsort!, args..., :a, :lo, :hi)) end i, j = lo, hi - # pivot = (a[lo]+a[hi])/2 # 1.14x - pivot = a[(lo+hi)>>>1] # 1.15x - # pivot = (a[lo]+a[hi]+a[(lo+hi)>>>1])/3 # 1.16x - # pivot = _jl_pivot_middle(a[lo], a[hi], a[(lo+hi)>>>1]) # 1.23x - # pivot = a[randival(lo,hi)] # 1.28x + # pivot = (a[lo]+a[hi])/2 # 1.14x + pivot = a[(lo+hi)>>>1] # 1.15x + # pivot = (a[lo]+a[hi]+a[(lo+hi)>>>1])/3 # 1.16x + # pivot = _jl_pivot_middle($(args...), a[lo], a[hi], a[(lo+hi)>>>1]) # 1.23x + # pivot = a[randival(lo,hi)] # 1.28x while i <= j while $(lt(:(a[i]), :pivot)); i += 1; end while $(lt(:pivot, :(a[j]))); j -= 1; end @@ -92,23 +206,26 @@ function ($quicksort)($(args...), a::AbstractVector, lo::Int, hi::Int) end end if lo < j - $(expr(:call, quicksort, args..., :a, :lo, :j)) + $(expr(:call, quicksort!, args..., :a, :lo, :j)) end lo = i end return a end +($quicksort!)($(args...), a::AbstractVector) = ($quicksort!)($(args...), a, 1, length(a)) +($quicksort)($(args...), a::AbstractVector) = ($quicksort!)($(args...), copy(a), 1, length(a)) + # less fast & not in-place, but stable -function ($mergesort)($(args...), a::AbstractVector, lo::Int, hi::Int, b::AbstractVector) +function ($mergesort!)($(args...), a::AbstractVector, lo::Int, hi::Int, b::AbstractVector) if lo < hi if hi-lo <= 20 - return ($insertionsort)($(args...), a, lo, hi) + return ($insertionsort!)($(args...), a, lo, hi) end m = (lo+hi)>>>1 - ($mergesort)($(args...), a, lo, m, b) - ($mergesort)($(args...), a, m+1, hi, b) + ($mergesort!)($(args...), a, lo, m, b) + ($mergesort!)($(args...), a, m+1, hi, b) # merge(lo,m,hi) i = 1 @@ -140,18 +257,22 @@ function ($mergesort)($(args...), a::AbstractVector, lo::Int, hi::Int, b::Abstra return a end +($mergesort!){T}($(args...), a::AbstractVector{T}) = ($mergesort!)($(args...), a, 1, length(a), Array(T,length(a))) +($mergesort){T}($(args...), a::AbstractVector{T}) = + ($mergesort!)($(args...), copy(a), 1, length(a), Array(T,length(a))) + # permutes auxilliary arrays mirroring the sort -function ($mergesort)($(args...), - a::AbstractVector, p::AbstractVector{Int}, lo::Int, hi::Int, - b::AbstractVector, pb::AbstractVector{Int}) +function ($mergesort_perm!)($(args...), + a::AbstractVector, p::AbstractVector{Int}, lo::Int, hi::Int, + b::AbstractVector, pb::AbstractVector{Int}) if lo < hi if hi-lo <= 20 - return ($insertionsort)($(args...), a, p, lo, hi) + return ($insertionsort_perm!)($(args...), a, p, lo, hi) end m = (lo+hi)>>>1 - ($mergesort)($(args...), a, p, lo, m, b, pb) - ($mergesort)($(args...), a, p, m+1, hi, b, pb) + ($mergesort_perm!)($(args...), a, p, lo, m, b, pb) + ($mergesort_perm!)($(args...), a, p, m+1, hi, b, pb) # merge(lo,m,hi) i = 1 @@ -187,19 +308,119 @@ function ($mergesort)($(args...), return a, p end +($mergesort_perm!){T}($(args...), a::AbstractVector{T}, p::AbstractVector{Int}) = + ($mergesort_perm!)($(args...), a, p, 1, length(a), Array(T,length(a)), Array(Int,length(a))) +($mergesort_perm!){T}($(args...), a::AbstractVector{T}) = + ($mergesort_perm!)($(args...), a, [1:length(a)]) +($mergesort_perm){T}($(args...), a::AbstractVector{T}, args2...) = + ($mergesort_perm!)($(args...), copy(a), [1:length(a)], args2...) + + +function ($issorted)($(args...), v::AbstractVector) + for i = 1:length(v)-1 + if $(lt(:(v[i+1]), :(v[i]))) + return false + end + end + return true +end + +function ($_jl_quickselect)($(args...), a::AbstractArray, k::Int, lo::Int, hi::Int) + if k < lo || k > hi; error("k is out of bounds"); end + + while true + + if lo == hi; return a[lo]; end + + i, j = lo, hi + pivot = ($pivot_middle)($(args...), a[lo], a[hi], a[(lo+hi)>>>1]) + while i < j + while $(lt(:(a[i]), :(pivot))); i += 1; end + while $(lt(:(pivot), :(a[j]))); j -= 1; end + #if isequal(a[i], a[j]) + if !$(lt(:(a[i]), :(a[j]))) && !$(lt(:(a[j]), :(a[i]))) + i += 1 + elseif i < j + a[i], a[j] = a[j], a[i] + end + end + pivot_ind = j + + len = pivot_ind - lo + 1 + if k == len + return a[pivot_ind] + elseif k < len + hi = pivot_ind - 1 + else + lo = pivot_ind + 1 + k = k - len + end + + end # while true... + +end + +($select!)($(args...), a::AbstractArray, k::Int) = ($_jl_quickselect)($(args...), a, k, 1, length(a)) +($select)($(args...), a::AbstractArray, k::Int) = ($_jl_quickselect)($(args...), copy(a), k, 1, length(a)) + +($search_sorted)($(args...), a::Vector, x) = ($search_sorted_first)($(args...), a, x, 1, length(a)) + +($search_sorted_last)($(args...), a::Vector, x) = ($search_sorted_last)($(args...), a, x, 1, length(a)) + +function ($search_sorted_last)($(args...), a::Vector, x, lo::Int, hi::Int) + ## Index of the last value of vector a that is less than or equal to x. + ## Returns 0 if x is less than all values of a. + ## + ## Good reference: http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary + lo = lo-1 + hi = hi+1 + while lo < hi-1 + i = (lo+hi)>>>1 + if isless(x,a[i]) + hi = i + else + lo = i + end + end + lo +end + +($search_sorted_first)($(args...), a::Vector, x) = ($search_sorted_first)($(args...), a, x, 1, length(a)) + +function ($search_sorted_first)($(args...), a::Vector, x, lo::Int, hi::Int) + ## Index of the first value of vector a that is greater than or equal to x. + ## Returns length(a) + 1 if x is greater than all values in a. + ## + ## Good reference: http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary + lo = lo-1 + hi = hi+1 + while lo < hi-1 + i = (lo+hi)>>>1 + if isless(a[i],x) + lo = i + else + hi = i + end + end + hi +end + +($sortperm){T}($(args...), a::AbstractVector{T}, args2...) = ($mergesort_perm)($(args...), a, args2...) +($sortperm!){T}($(args...), a::AbstractVector{T}, args2...) = ($mergesort_perm!)($(args...), a, args2...) + end; end # @eval / for ## external sorting functions ## -sort!{T<:Real}(a::AbstractVector{T}) = _jl_quicksort(a, 1, length(a)) -sortr!{T<:Real}(a::AbstractVector{T}) = _jl_quicksort_r(a, 1, length(a)) -sort!{T}(a::AbstractVector{T}) = _jl_mergesort(a, 1, length(a), Array(T,length(a))) -sortr!{T}(a::AbstractVector{T}) = _jl_mergesort_r(a, 1, length(a), Array(T,length(a))) +sort!{T<:Real}(a::AbstractVector{T}) = quicksort!(a, 1, length(a)) +sortr!{T<:Real}(a::AbstractVector{T}) = quicksort_r!(a, 1, length(a)) +sort!{T}(a::AbstractVector{T}) = mergesort!(a, 1, length(a), Array(T,length(a))) +sortr!{T}(a::AbstractVector{T}) = mergesort_r!(a, 1, length(a), Array(T,length(a))) sort!{T}(lt::Function, a::AbstractVector{T}) = - _jl_mergesort_lt(lt, a, 1, length(a), Array(T,length(a))) + mergesort!(lt, a, 1, length(a), Array(T,length(a))) sort_by!{T}(by::Function, a::AbstractVector{T}) = - _jl_mergesort_by(by, a, 1, length(a), Array(T,length(a))) + mergesort_by!(by, a, 1, length(a), Array(T,length(a))) # push NaNs to the end of a, returning # of non-NaNs function _jl_nans_to_end{T<:FloatingPoint}(a::AbstractVector{T}) @@ -243,38 +464,11 @@ function sort!{T<:FloatingPoint}(a::AbstractVector{T}) break end end - _jl_quicksort_fp_neg(a, 1, j) - _jl_quicksort_fp_pos(a, i, n) - return a -end - -# TODO: something sensible should happen when each_col et. al. are used with a -# pure function argument -function each_col!(f::Function, a::AbstractMatrix) - m = size(a,1) - for i = 1:m:numel(a) - f(sub(a, i:(i+m-1))) - end - return a -end - -function each_row!(f::Function, a::AbstractMatrix) - m = size(a,1) - for i = 1:m - f(sub(a, i:m:numel(a))) - end + quicksort_fp_neg!(a, 1, j) + quicksort_fp_pos!(a, i, n) return a end -function each_vec!(f::Function, a::AbstractMatrix, dim::Integer) - if dim == 1; return each_col!(f,a); end - if dim == 2; return each_row!(f,a); end - error("invalid matrix dimensions: $dim") -end - -each_col(f::Function, a::AbstractMatrix) = each_col!(f,copy(a)) -each_row(f::Function, a::AbstractMatrix) = each_row!(f,copy(a)) -each_vec(f::Function, a::AbstractMatrix, d::Integer) = each_vec!(f,copy(a),d) ## other sorting functions defined in terms of sort! ## @@ -309,6 +503,26 @@ end @in_place_matrix_op sortr @in_place_matrix_op sort_by by::Function +@in_place_matrix_op insertionsort +@in_place_matrix_op insertionsort lt::Function +@in_place_matrix_op insertionsort_r +@in_place_matrix_op insertionsort_by by::Function + +@in_place_matrix_op quicksort +@in_place_matrix_op quicksort lt::Function +@in_place_matrix_op quicksort_r +@in_place_matrix_op quicksort_by by::Function + +@in_place_matrix_op mergesort +@in_place_matrix_op mergesort lt::Function +@in_place_matrix_op mergesortr +@in_place_matrix_op mergesort_by by::Function + +@in_place_matrix_op timsort +@in_place_matrix_op timsort lt::Function +@in_place_matrix_op timsortr +@in_place_matrix_op timsort_by by::Function + # TODO: implement generalized in-place, ditch this function sort(a::AbstractArray, dim::Int) X = similar(a) @@ -326,107 +540,6 @@ function sort(a::AbstractArray, dim::Int) return X end -sortperm{T}(a::AbstractVector{T}) = - _jl_mergesort(copy(a), [1:length(a)], 1, length(a), - Array(T, length(a)), Array(Int, length(a))) - -function issorted(v::AbstractVector) - for i = 1:length(v)-1 - if isless(v[i+1], v[i]) - return false - end - end - return true -end - -function _jl_quickselect(a::AbstractArray, k::Int, lo::Int, hi::Int) - if k < lo || k > hi; error("k is out of bounds"); end - - while true - - if lo == hi; return a[lo]; end - - i, j = lo, hi - pivot = _jl_pivot_middle(a[lo], a[hi], a[(lo+hi)>>>1]) - while i < j - while isless(a[i], pivot); i += 1; end - while isless(pivot, a[j]); j -= 1; end - if isequal(a[i], a[j]) - i += 1 - elseif i < j - a[i], a[j] = a[j], a[i] - end - end - pivot_ind = j - - length = pivot_ind - lo + 1 - if k == length - return a[pivot_ind] - elseif k < length - hi = pivot_ind - 1 - else - lo = pivot_ind + 1 - k = k - length - end - - end # while true... - -end - -select(a::AbstractArray, k::Int) = _jl_quickselect(copy(a), k, 1, length(a)) -select!(a::AbstractArray, k::Int) = _jl_quickselect(a, k, 1, length(a)) - -search_sorted(a::Vector, x) = search_sorted(a, x, 1, length(a)) - -function search_sorted(a::Vector, x, lo::Int, hi::Int) - if isless(a[hi], x) - return hi+1 - end - while lo < hi-1 - i = (lo+hi)>>>1 - if isless(x,a[i]) - hi = i - else - lo = i - end - end - return isless(a[lo],x) ? hi : lo -end - -search_sorted_last(a::Vector, x) = search_sorted_last(a, x, 0, length(a)+1) - -function search_sorted_last(a::Vector, x, lo::Int, hi::Int) - ## Index of the last value of vector a that is less than or equal to x. - ## Returns 0 if x is less than all values of a. - ## - ## Good reference: http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary - while lo < hi-1 - i = (lo+hi)>>>1 - if isless(x,a[i]) - hi = i - else - lo = i - end - end - lo -end - -search_sorted_first(a::Vector, x) = search_sorted_first(a, x, 0, length(a)+1) - -function search_sorted_first(a::Vector, x, lo::Int, hi::Int) - ## Index of the first value of vector a that is greater than or equal to x. - ## Returns length(a) + 1 if x is greater than all values in a. - ## - ## Good reference: http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary - while lo < hi-1 - i = (lo+hi)>>>1 - if isless(a[i],x) - lo = i - else - hi = i - end - end - hi -end - order(a::AbstractVector) = sortperm(a)[2] + +end # module Sort diff --git a/base/sysimg.jl b/base/sysimg.jl index 9e05c77857ed7..8f3bf3b658809 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -121,6 +121,7 @@ using RNG # Combinatorics include("sort.jl") +using Sort include("combinatorics.jl") # distributed arrays and memory-mapped arrays diff --git a/base/timsort.jl b/base/timsort.jl new file mode 100644 index 0000000000000..9bf590b6831b5 --- /dev/null +++ b/base/timsort.jl @@ -0,0 +1,798 @@ +# timsort for julia +# +# This is an implementation of timsort based on the algorithm description at +# +# http://svn.python.org/projects/python/trunk/Objects/listsort.txt +# http://en.wikipedia.org/wiki/Timsort +# +# @kmsquire + + +typealias Run Range1{Int} + +const MIN_GALLOP = 7 + +type MergeState + runs::Array{Run} + min_gallop::Int +end +MergeState() = MergeState(Run[], MIN_GALLOP) + +# Determine a good minimum run size for efficient merging +# For details, see "Computing minrun" in +# http://svn.python.org/projects/python/trunk/Objects/listsort.txt +function merge_compute_minrun(N::Int, bits::Int) + r = 0 + max_val = 2^bits + while N >= max_val + r |= (N & 1) + N >>= 1 + end + N + r +end + +merge_compute_minrun(N::Int) = merge_compute_minrun(N, 6) + +# Macro to create different versions of the sort function, +# cribbed from sort.jl +for (suffix, lt, args) in (("", (a,b)->:(isless($a,$b)), ()), + ("_r", (a,b)->:(isless($b,$a)), ()), + ("", (a,b)->:(lt($a,$b)), (:(lt::Function),)), + ("_by", (a,b)->:(isless(by($a),by($b))), (:(by::Function),))) + insertionsort! = symbol("insertionsort$(suffix)!") + insertionsort_perm! = symbol("insertionsort_perm$(suffix)!") + timsort = symbol("timsort$(suffix)") + timsort! = symbol("timsort$(suffix)!") + timsort_perm = symbol("timsort_perm$(suffix)") + timsort_perm! = symbol("timsort_perm$(suffix)!") + next_run = symbol("_jl_next_run$suffix") + merge_collapse = symbol("_jl_merge_collapse$suffix") + merge = symbol("_jl_merge$suffix") + merge_lo = symbol("_jl_merge_lo$suffix") + merge_hi = symbol("_jl_merge_hi$suffix") + + gallop_last = symbol("_jl_gallop_last$suffix") + gallop_first = symbol("_jl_gallop_first$suffix") + rgallop_last = symbol("_jl_rgallop_last$suffix") + rgallop_first = symbol("_jl_rgallop_first$suffix") +@eval begin + +# Galloping binary search starting at left +function ($gallop_last)($(args...), a::AbstractVector, x, lo::Int, hi::Int) + i = lo + inc = 1 + lo = lo-1 + hi = hi+1 + while i < hi && !($(lt(:x, :(a[i])))) + lo = i + i += inc + inc <<= 1 + end + hi = min(i+1, hi) + # Binary search + while lo < hi-1 + i = (lo+hi)>>>1 + if !($(lt(:x, :(a[i])))) + lo = i + else + hi = i + end + end + hi +end + + +# Galloping binary search starting at right +function ($rgallop_last)($(args...), a::AbstractVector, x, lo::Int, hi::Int) + i = hi + dec = 1 + lo = lo-1 + hi = hi+1 + while i > lo && $(lt(:x, :(a[i]))) + hi = i + i -= dec + dec <<= 1 + end + lo = max(lo, i-1) + # Binary search + while lo < hi-1 + i = (lo+hi)>>>1 + if !($(lt(:x, :(a[i])))) + lo = i + else + hi = i + end + end + hi +end + + +# Galloping binary search starting at left +function ($gallop_first)($(args...), a::AbstractVector, x, lo::Int, hi::Int) + i = lo + inc = 1 + lo = lo-1 + hi = hi+1 + while i < hi && $(lt(:(a[i]),:x)) + lo = i + i += inc + inc <<= 1 + end + hi = min(i+1, hi) + # Binary search + while lo < hi-1 + i = (lo+hi)>>>1 + if $(lt(:(a[i]), :x)) + lo = i + else + hi = i + end + end + hi +end + + +# Galloping binary search starting at right +function ($rgallop_first)($(args...), a::AbstractVector, x, lo::Int, hi::Int) + i = hi + dec = 1 + lo = lo-1 + hi = hi+1 + while i > lo && !($(lt(:(a[i]),:x))) + hi = i + i -= dec + dec <<= 1 + end + lo = max(lo, i-1) + # Binary search + while lo < hi-1 + i = (lo+hi)>>>1 + if $(lt(:(a[i]), :x)) + lo = i + else + hi = i + end + end + hi +end + + +# Get the next run +# Returns the a range a:b, or b:-1:a for a reversed sequence +function ($next_run)($(args...), v::AbstractVector, lo::Int, hi::Int) + if lo == hi + return lo:lo + end + + if !($(lt(:(v[lo+1]), :(v[lo])))) + for i = lo+2:hi + if $(lt(:(v[i]), :(v[i-1]))) + return lo:i-1 + end + end + return lo:hi + else + for i = lo+2:hi + if !($(lt(:(v[i]), :(v[i-1])))) + return i-1:-1:lo + end + end + return hi:-1:lo + end +end + + +# Merge consecutive runs +# For A,B,C = last three lengths, merge_collapse!() +# maintains 2 invariants: +# +# A > B + C +# B > C +# +# If any of these are violated, a merge occurs to +# correct it +function ($merge_collapse)($(args...), v::AbstractVector, state::MergeState, force::Bool) + + while length(state.runs) > 2 + (a,b,c) = state.runs[end-2:end] + + if length(a) > length(b)+length(c) && length(b) > length(c) && !force + break # invariants are satisfied, leave loop + end + + if length(a) < length(c) + ($merge)($(args...), v,a,b,state) + pop(state.runs) + pop(state.runs) + pop(state.runs) + push(state.runs, first(a):last(b)) + push(state.runs, c) + else + ($merge)($(args...), v,b,c,state) + pop(state.runs) + pop(state.runs) + push(state.runs, first(b):last(c)) + end + end + + if length(state.runs) == 2 + (a,b) = state.runs[end-1:end] + + if length(a) <= length(b) || force + ($merge)($(args...), v,a,b,state) + pop(state.runs) + pop(state.runs) + push(state.runs, first(a):last(b)) + end + end + + return # v ## Used to return v, but should be unnecessary, as the only user of this function + ## is timsort(), and the return value is ignored there... +end + + +# Version which permutes an auxilliary array mirroring the sort +function ($merge_collapse)($(args...), v::AbstractVector, p::AbstractVector{Int}, state::MergeState, force::Bool) + + while length(state.runs) > 2 + (a,b,c) = state.runs[end-2:end] + + if length(a) > length(b)+length(c) && length(b) > length(c) && !force + break # invariants are satisfied, leave loop + end + + if length(a) < length(c) + ($merge)($(args...), v,p,a,b,state) + pop(state.runs) + pop(state.runs) + pop(state.runs) + push(state.runs, first(a):last(b)) + push(state.runs, c) + else + ($merge)($(args...), v,p,b,c,state) + pop(state.runs) + pop(state.runs) + push(state.runs, first(b):last(c)) + end + end + + if length(state.runs) == 2 + (a,b) = state.runs[end-1:end] + + if length(a) <= length(b) || force + ($merge)($(args...), v,p,a,b,state) + pop(state.runs) + pop(state.runs) + push(state.runs, first(a):last(b)) + end + end + + return # v ## Used to return v, but should be unnecessary, as the only user of this function + ## is timsort(), and the return value is ignored there... +end + + +# Merge runs a and b in vector v +function ($merge)($(args...), v::AbstractVector, a::Run, b::Run, state::MergeState) + + # First elements in a <= b[1] are already in place + a = ($gallop_last)($(args...), v, v[first(b)], first(a), last(a)) : last(a) + + if length(a) == 0 return end + + # Last elements in b >= a[end] are already in place + b = first(b) : ($rgallop_first)($(args...), v, v[last(a)], first(b), last(b))-1 + + # Choose merge_lo or merge_hi based on the amount + # of temporary memory needed (smaller of a and b) + if length(a) < length(b) + ($merge_lo)($(args...), v, a, b, state) + else + ($merge_hi)($(args...), v, a, b, state) + end +end + + +# Merge runs a and b in vector v (version which permutes an auxilliary array mirroring the sort) +function ($merge)($(args...), v::AbstractVector, p::AbstractVector{Int}, a::Run, b::Run, state::MergeState) + + # First elements in a <= b[1] are already in place + a = ($gallop_last)($(args...), v, v[first(b)], first(a), last(a)) : last(a) + + if length(a) == 0 return end + + # Last elements in b >= a[end] are already in place + b = first(b) : ($rgallop_first)($(args...), v, v[last(a)], first(b), last(b))-1 + + # Choose merge_lo or merge_hi based on the amount + # of temporary memory needed (smaller of a and b) + if length(a) < length(b) + ($merge_lo)($(args...), v, p, a, b, state) + else + ($merge_hi)($(args...), v, p, a, b, state) + end +end + +# Merge runs a and b in vector v (a is smaller) +function ($merge_lo)($(args...), v::AbstractVector, a::Run, b::Run, state::MergeState) + + # Copy a + v_a = v[a] + + # Pointer into (sub)arrays + i = first(a) + from_a = 1 + from_b = first(b) + + mode = :normal + while true + if mode == :normal + # Compare and copy element by element + count_a = count_b = 0 + while from_a <= length(a) && from_b <= last(b) + if $(lt(:(v[from_b]), :(v_a[from_a]))) + v[i] = v[from_b] + from_b += 1 + count_a = 0 + count_b += 1 + else + v[i] = v_a[from_a] + from_a += 1 + count_a += 1 + count_b = 0 + end + i += 1 + + # Switch to galloping mode if a string of elements + # has come from the same set + if count_b >= state.min_gallop || count_a >= state.min_gallop + mode = :galloping + break + end + end + # Finalize if we've exited the loop normally + if mode == :normal + mode = :finalize + end + end + + if mode == :galloping + # Use binary search to find range to copy + while from_a <= length(a) && from_b <= last(b) + # Copy the next run from b + b_run = from_b : ($gallop_first)($(args...), v, v_a[from_a], from_b, last(b)) - 1 + i_end = i + length(b_run) - 1 + v[i:i_end] = v[b_run] + i = i_end + 1 + from_b = last(b_run) + 1 + + # ... then copy the first element from a + v[i] = v_a[from_a] + i += 1 + from_a += 1 + + if from_a > length(a) || from_b > last(b) break end + + # Copy the next run from a + a_run = from_a : ($gallop_last)($(args...), v_a, v[from_b], from_a, length(a)) - 1 + i_end = i + length(a_run) - 1 + v[i:i_end] = v_a[a_run] + i = i_end + 1 + from_a = last(a_run) + 1 + + # ... then copy the first element from b + v[i] = v[from_b] + i += 1 + from_b += 1 + + # Return to normal mode if we haven't galloped... + if length(a_run) < MIN_GALLOP && length(b_run) < MIN_GALLOP + mode = :normal + break + end + # Reduce min_gallop if this gallop was successful + state.min_gallop -= 1 + end + if mode == :galloping + mode = :finalize + end + state.min_gallop = max(state.min_gallop,0) + 2 # penalty for leaving gallop mode + end + + if mode == :finalize + # copy end of a + i_end = i + (length(a) - from_a) + v[i:i_end] = v_a[from_a:end] + break + end + end +end + +# Merge runs a and b in vector v (a is smaller) +function ($merge_lo)($(args...), v::AbstractVector, p::AbstractVector{Int}, a::Run, b::Run, state::MergeState) + + # Copy a + v_a = v[a] + p_a = p[a] + + # Pointer into (sub)arrays + i = first(a) + from_a = 1 + from_b = first(b) + + mode = :normal + while true + if mode == :normal + # Compare and copy element by element + count_a = count_b = 0 + while from_a <= length(a) && from_b <= last(b) + if $(lt(:(v[from_b]), :(v_a[from_a]))) + v[i] = v[from_b] + p[i] = p[from_b] + from_b += 1 + count_a = 0 + count_b += 1 + else + v[i] = v_a[from_a] + p[i] = p_a[from_a] + from_a += 1 + count_a += 1 + count_b = 0 + end + i += 1 + + # Switch to galloping mode if a string of elements + # has come from the same set + if count_b >= state.min_gallop || count_a >= state.min_gallop + mode = :galloping + break + end + end + # Finalize if we've exited the loop normally + if mode == :normal + mode = :finalize + end + end + + if mode == :galloping + # Use binary search to find range to copy + while from_a <= length(a) && from_b <= last(b) + # Copy the next run from b + b_run = from_b : ($gallop_first)($(args...), v, v_a[from_a], from_b, last(b)) - 1 + i_end = i + length(b_run) - 1 + v[i:i_end] = v[b_run] + p[i:i_end] = p[b_run] + i = i_end + 1 + from_b = last(b_run) + 1 + + # ... then copy the first element from a + v[i] = v_a[from_a] + p[i] = p_a[from_a] + i += 1 + from_a += 1 + + if from_a > length(a) || from_b > last(b) break end + + # Copy the next run from a + a_run = from_a : ($gallop_last)($(args...), v_a, v[from_b], from_a, length(a)) - 1 + i_end = i + length(a_run) - 1 + v[i:i_end] = v_a[a_run] + p[i:i_end] = p_a[a_run] + i = i_end + 1 + from_a = last(a_run) + 1 + + # ... then copy the first element from b + v[i] = v[from_b] + p[i] = p[from_b] + i += 1 + from_b += 1 + + # Return to normal mode if we haven't galloped... + if length(a_run) < MIN_GALLOP && length(b_run) < MIN_GALLOP + mode = :normal + break + end + # Reduce min_gallop if this gallop was successful + state.min_gallop -= 1 + end + if mode == :galloping + mode = :finalize + end + state.min_gallop = max(state.min_gallop,0) + 2 # penalty for leaving gallop mode + end + + if mode == :finalize + # copy end of a + i_end = i + (length(a) - from_a) + v[i:i_end] = v_a[from_a:end] + p[i:i_end] = p_a[from_a:end] + break + end + end +end + + +# Merge runs a and b in vector v (b is smaller) +function ($merge_hi)($(args...), v::AbstractVector, a::Run, b::Run, state::MergeState) + + # Copy b + v_b = v[b] + + # Pointer into (sub)arrays + i = last(b) + from_a = last(a) + from_b = length(b) + + mode = :normal + while true + if mode == :normal + # Compare and copy element by element + count_a = count_b = 0 + while from_a >= first(a) && from_b >= 1 + if $(lt(:(v[from_a]), :(v_b[from_b]))) + v[i] = v_b[from_b] + from_b -= 1 + count_a = 0 + count_b += 1 + else + v[i] = v[from_a] + from_a -= 1 + count_a += 1 + count_b = 0 + end + i -= 1 + + # Switch to galloping mode if a string of elements + # has come from the same set + if count_b >= state.min_gallop || count_a >= state.min_gallop + mode = :galloping + break + end + end + # Finalize if we've exited the loop normally + if mode == :normal + mode = :finalize + end + end + + if mode == :galloping + # Use binary search to find range to copy + while from_a >= first(a) && from_b >= 1 + # Copy the next run from b + b_run = ($rgallop_first)($(args...), v_b, v[from_a], 1, from_b) : from_b + i_start = i - length(b_run) + 1 + v[i_start:i] = v_b[b_run] + i = i_start - 1 + from_b = first(b_run) - 1 + + # ... then copy the first element from a + v[i] = v[from_a] + i -= 1 + from_a -= 1 + + if from_a < first(a) || from_b < 1 break end + + # Copy the next run from a + a_run = ($rgallop_last)($(args...), v, v_b[from_b], first(a), from_a) : from_a + i_start = i - length(a_run) + 1 + v[i_start:i] = v[a_run] + i = i_start - 1 + from_a = first(a_run) - 1 + + # ... then copy the first element from b + v[i] = v_b[from_b] + i -= 1 + from_b -= 1 + + # Return to normal mode if we haven't galloped... + if length(a_run) < MIN_GALLOP && length(b_run) < MIN_GALLOP + mode = :normal + break + end + # Reduce min_gallop if this gallop was successful + state.min_gallop -= 1 + end + if mode == :galloping + mode = :finalize + end + state.min_gallop = max(state.min_gallop, 0) + 2 # penalty for leaving gallop mode + end + + if mode == :finalize + # copy start of b + i_start = i - from_b + 1 + v[i_start:i] = v_b[1:from_b] + break + end + end +end + +# Merge runs a and b in vector v (b is smaller) +function ($merge_hi)($(args...), v::AbstractVector, p::AbstractVector{Int}, a::Run, b::Run, state::MergeState) + + # Copy b + v_b = v[b] + p_b = p[b] + + # Pointer into (sub)arrays + i = last(b) + from_a = last(a) + from_b = length(b) + + mode = :normal + while true + if mode == :normal + # Compare and copy element by element + count_a = count_b = 0 + while from_a >= first(a) && from_b >= 1 + if $(lt(:(v[from_a]), :(v_b[from_b]))) + v[i] = v_b[from_b] + p[i] = p_b[from_b] + from_b -= 1 + count_a = 0 + count_b += 1 + else + v[i] = v[from_a] + p[i] = p[from_a] + from_a -= 1 + count_a += 1 + count_b = 0 + end + i -= 1 + + # Switch to galloping mode if a string of elements + # has come from the same set + if count_b >= state.min_gallop || count_a >= state.min_gallop + mode = :galloping + break + end + end + # Finalize if we've exited the loop normally + if mode == :normal + mode = :finalize + end + end + + if mode == :galloping + # Use binary search to find range to copy + while from_a >= first(a) && from_b >= 1 + # Copy the next run from b + b_run = ($rgallop_first)($(args...), v_b, v[from_a], 1, from_b) : from_b + i_start = i - length(b_run) + 1 + v[i_start:i] = v_b[b_run] + p[i_start:i] = p_b[b_run] + i = i_start - 1 + from_b = first(b_run) - 1 + + # ... then copy the first element from a + v[i] = v[from_a] + p[i] = p[from_a] + i -= 1 + from_a -= 1 + + if from_a < first(a) || from_b < 1 break end + + # Copy the next run from a + a_run = ($rgallop_last)($(args...), v, v_b[from_b], first(a), from_a) : from_a + i_start = i - length(a_run) + 1 + v[i_start:i] = v[a_run] + p[i_start:i] = p[a_run] + i = i_start - 1 + from_a = first(a_run) - 1 + + # ... then copy the first element from b + v[i] = v_b[from_b] + p[i] = p_b[from_b] + i -= 1 + from_b -= 1 + + # Return to normal mode if we haven't galloped... + if length(a_run) < MIN_GALLOP && length(b_run) < MIN_GALLOP + mode = :normal + break + end + # Reduce min_gallop if this gallop was successful + state.min_gallop -= 1 + end + if mode == :galloping + mode = :finalize + end + state.min_gallop = max(state.min_gallop, 0) + 2 # penalty for leaving gallop mode + end + + if mode == :finalize + # copy start of b + i_start = i - from_b + 1 + v[i_start:i] = v_b[1:from_b] + p[i_start:i] = p_b[1:from_b] + break + end + end +end + + +# Timsort function +function ($timsort!)($(args...), v::AbstractVector, lo::Int, hi::Int) + # Initialization + minrun = merge_compute_minrun(hi-lo+1) + state = MergeState() + + i = lo + while i <= hi + run_range = $(next_run)($(args...), v, i, hi) + count = length(run_range) + if count < minrun + # Make a run of length minrun + count = min(minrun, hi-i+1) + run_range = i:i+count-1 + ($insertionsort!)($(args...), v, i, i+count-1) + else + if !issorted(run_range) + run_range = last(run_range):first(run_range) + reverse!(sub(v, run_range)) + end + end + + # Push this run onto the queue and merge if needed + push(state.runs, run_range) + i = i+count + ($merge_collapse)($(args...), v, state, false) + end + + # Force merge at the end + if length(state.runs) > 1 + ($merge_collapse)($(args...), v, state, true) + end + + v +end + +($timsort!)($(args...), v::AbstractVector) = ($timsort!)($(args...), v, 1, length(v)) +($timsort)($(args...), v::AbstractVector, args2...) = ($timsort!)($(args...), copy(v), args2...) + + +# Timsort function which permutes an auxilliary array mirroring the sort +function ($timsort_perm!)($(args...), v::AbstractVector, p::AbstractVector{Int}, lo::Int, hi::Int) + # Initialization + minrun = merge_compute_minrun(hi-lo+1) + state = MergeState() + + i = lo + while i <= hi + run_range = $(next_run)($(args...), v, i, hi) + count = length(run_range) + if count < minrun + # Make a run of length minrun + count = min(minrun, hi-i+1) + run_range = i:i+count-1 + ($insertionsort_perm!)($(args...), v, p, i, i+count-1) + else + if !issorted(run_range) + run_range = last(run_range):first(run_range) + reverse!(sub(v, run_range)) + reverse!(sub(p, run_range)) + end + end + + # Push this run onto the queue and merge if needed + push(state.runs, run_range) + i = i+count + ($merge_collapse)($(args...), v, p, state, false) + end + + # Force merge at the end + if length(state.runs) > 1 + ($merge_collapse)($(args...), v, p, state, true) + end + + v, p +end + +($timsort_perm!)($(args...), v::AbstractVector, p::AbstractVector{Int}) = + ($timsort_perm!)($(args...), v, p, 1, length(v)) +($timsort_perm!)($(args...), v::AbstractVector) = + ($timsort_perm!)($(args...), v, [1:length(v)]) +($timsort_perm)($(args...), v::AbstractVector, args2...) = + ($timsort_perm!)($(args...), copy(v), args2...) + +end; end # quote; macro diff --git a/doc/helpdb.jl b/doc/helpdb.jl index 712106bc8b989..c1f8d1fcdf9be 100644 --- a/doc/helpdb.jl +++ b/doc/helpdb.jl @@ -223,7 +223,7 @@ "), -(E"Getting Around",E"Base",E"whos",E"whos([Module][, pattern::Regex]) +(E"Getting Around",E"Base",E"whos",E"whos([Module,] [pattern::Regex]) Print information about global variables in a module, optionally restricted to those matching \"pattern\". @@ -917,14 +917,17 @@ collection[key...] = value "), -(E"Strings",E"Base",E"split",E"split(string, chars[, limit][, include_empty]) +(E"Strings",E"Base",E"split",E"split(string, [chars, [limit,] [include_empty]]) Return an array of strings by splitting the given string on occurrences of the given character delimiters, which may be specified in any of the formats allowed by \"search\"'s second - argument. The last two arguments are optional; they are are a - maximum size for the result and a flag determining whether empty - fields should be included in the result. + argument (i.e. a single character, collection of characters, + string, or regular expression). If \"chars\" is omitted, it + defaults to the set of all space characters, and \"include_empty\" + is taken to be false. The last two arguments are also optional: + they are are a maximum size for the result and a flag determining + whether empty fields should be included in the result. "), @@ -1431,7 +1434,7 @@ collection[key...] = value "), -(E"Mathematical Functions",E"Base",E"atan2",E"atan2(x, y) +(E"Mathematical Functions",E"Base",E"atan2",E"atan2(y, x) Compute the inverse tangent of \"y/x\", using the signs of both \"x\" and \"y\" to determine the quadrant of the return value. @@ -2607,6 +2610,88 @@ airyaiprime(x) "), +(E"Sparse Matrices",E"Base",E"sparse",E"sparse(I, J, V[, m, n, combine]) + + Create a sparse matrix \"S\" of dimensions \"m x n\" such that + \"S[I[k], J[k]] = V[k]\". The \"combine\" function is used to + combine duplicates. If \"m\" and \"n\" are not specified, they are + set to \"max(I)\" and \"max(J)\" respectively. If the \"combine\" + function is not supplied, duplicates are added by default. + +"), + +(E"Sparse Matrices",E"Base",E"issparse",E"issparse(S) + + Returns \"true\" if \"S\" is sparse, and \"false\" otherwise. + +"), + +(E"Sparse Matrices",E"Base",E"nnz",E"nnz(S) + + Return the number of nonzeros in \"S\". + +"), + +(E"Sparse Matrices",E"Base",E"sparse",E"sparse(A) + + Convert a dense matrix \"A\" into a sparse matrix. + +"), + +(E"Sparse Matrices",E"Base",E"dense",E"dense(S) + + Convert a sparse matrix \"S\" into a dense matrix. + +"), + +(E"Sparse Matrices",E"Base",E"full",E"full(S) + + Convert a sparse matrix \"S\" into a dense matrix. + +"), + +(E"Sparse Matrices",E"Base",E"spzeros",E"spzeros(m, n) + + Create an empty sparse matrix of size \"m x n\". + +"), + +(E"Sparse Matrices",E"Base",E"speye",E"speye(type, m[, n]) + + Create a sparse identity matrix of specified type of size \"m x + m\". In case \"n\" is supplied, create a sparse identity matrix of + size \"m x n\". + +"), + +(E"Sparse Matrices",E"Base",E"spones",E"spones(S) + + Create a sparse matrix with the same structure as that of \"S\", + but with every nonzero element having the value \"1.0\". + +"), + +(E"Sparse Matrices",E"Base",E"sprand",E"sprand(m, n, density[, rng]) + + Create a random sparse matrix with the specified density. Nonzeros + are sampled from the distribution specified by \"rng\". The uniform + distribution is used in case \"rng\" is not specified. + +"), + +(E"Sparse Matrices",E"Base",E"sprandn",E"sprandn(m, n, density) + + Create a random sparse matrix of specified density with nonzeros + sampled from the normal distribution. + +"), + +(E"Sparse Matrices",E"Base",E"sprandbool",E"sprandbool(m, n, density) + + Create a random sparse boolean matrix with the specified density. + +"), + (E"Linear Algebra",E"Base",E"*",E"*() Matrix multiplication @@ -2815,31 +2900,45 @@ airyaiprime(x) (E"Combinatorics",E"Base",E"sort!",E"sort!(v) - In-place sort + In-place sort. "), (E"Combinatorics",E"Base",E"sortr",E"sortr(v) - Sort a vector in descending order + Sort a vector in descending order. "), (E"Combinatorics",E"Base",E"sortr!",E"sortr!(v) - In-place descending-order sort + In-place sort in descending-order. + +"), + +(E"Combinatorics",E"Base",E"sort_by",E"sort_by(by, v) + + Sort a vector by the result of applying function \"by\" to every + element. + +"), + +(E"Combinatorics",E"Base",E"sort_by!",E"sort_by!(by, v) + + Sort a vector in place by the result of applying function \"by\" to + every element. "), (E"Combinatorics",E"Base",E"sort",E"sort(a, dim) - Sort an array along the given dimension + Sort an array along the given dimension. "), (E"Combinatorics",E"Base",E"sort",E"sort(lessthan, a[, dim]) - Sort with a custom comparison function + Sort with a custom comparison function. "), @@ -2850,12 +2949,62 @@ airyaiprime(x) "), +(E"Combinatorics",E"Base",E"sortperm!",E"sortperm!(v) -> s,p + + Sort a vector in ascending order in-place, also constructing the + permutation that sorts the vector + +"), + +(E"Combinatorics",E"Base",E"sortperm_r",E"sortperm_r(v) -> s,p + + Sort a vector in descending order, also constructing the + permutation that sorts the vector + +"), + +(E"Combinatorics",E"Base",E"sortperm_r!",E"sortperm_r!(v) -> s,p + + Sort a vector in descending order in-place, also constructing the + permutation that sorts the vector + +"), + +(E"Combinatorics",E"Base",E"sortperm_by",E"sortperm_by(by, v) -> s,p + + Sort a vector according to the result of function \"by\" applied to + all values, also constructing the permutation that sorts the + vector. + +"), + +(E"Combinatorics",E"Base",E"sortperm_by!",E"sortperm_by!(by, v) -> s,p + + Sort a vector in-place according to the result of function \"by\" + applied to all values of \"v\", also constructing the permutation + that sorts the vector + +"), + (E"Combinatorics",E"Base",E"issorted",E"issorted(v) Test whether a vector is in ascending sorted order "), +(E"Combinatorics",E"Base",E"issorted_r",E"issorted_r(v) + + Test whether a vector is in descending sorted order + +"), + +(E"Combinatorics",E"Base",E"issorted_by",E"issorted_by(by, v) + + Test whether a vector is sorted by the result of function \"by\" + applied to all values of \"v\" + +"), + (E"Combinatorics",E"Base",E"nthperm",E"nthperm(v, k) Compute the kth lexicographic permutation of a vector @@ -2999,11 +3148,12 @@ airyaiprime(x) "), -(E"Signal Processing",E"Base",E"rfft",E"rfft(A[, dim=1]) +(E"Signal Processing",E"Base",E"rfft",E"rfft(A[, dim]) One-dimensional FFT of real array A along dimension dim. If A has size \"(..., n_dim, ...)\", the result has size \"(..., - floor(n_dim/2)+1, ...)\". + floor(n_dim/2)+1, ...)\". The \"dim\" argument is optional and + defaults to 1. "), @@ -5234,6 +5384,378 @@ eval_tab_col(glp_prob, k) "), +(E"Base.Sort",E"Base.Sort",E"insertionsort",E"insertionsort(v[, dim]) + + Sort a vector in ascending order with insertion sort, according to + \"isless\". + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort",E"insertionsort(lessthan, v[, dim]) + + Sort a vector in ascending order with insertion sort, using a + custom comparison function. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort!",E"insertionsort!(v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort!",E"insertionsort!(v[, lo, hi]) + + In-place insertion sort, accoring to \"isless\". + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort!",E"insertionsort!(lessthan, v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort!",E"insertionsort!(lessthan, v[, lo, hi]) + + In-place insertion sort with a custom comparison function. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_r",E"insertionsort_r(v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_r",E"insertionsort_r(v[, lo, hi]) + + Sort a vector in descending order using insertion sort. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_r!",E"insertionsort_r!(v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_r!",E"insertionsort_r!(v[, lo, hi]) + + In-place insertion sort in descending order. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_by",E"insertionsort_by(by, v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_by",E"insertionsort_by(by, v[, lo, hi]) + + Sort a vector with insertion sort according to the result of + function \"by\" applied to all values. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_by!",E"insertionsort_by!(by, v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_by!",E"insertionsort_by!(by, v[, lo, hi]) + + Sort a vector with insertion sort in place according to the result + of function \"by\" applied to all values. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_perm",E"insertionsort_perm(v[, p[, lo, hi]]) -> s,p + + Sort a vector in ascending order, also constructing the permutation + that sorts the vector + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_perm",E"insertionsort_perm(lessthan, v[, p[, lo, hi]]) -> s,p + + Sort a vector, using a custom comparison function, also + constructing the permutation that sorts the vector . + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_perm!",E"insertionsort_perm!(v[, p[, lo, hi]]) + + Sort a vector in ascending order in-place, also constructing the + permutation that sorts the vector + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_perm!",E"insertionsort_perm!(lessthan, v[, p[, lo, hi]]) + + Sort a vector in place, using a custom comparison function, also + constructing the permutation that sorts the vector . + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_perm_r",E"insertionsort_perm_r(v[, p[, lo, hi]]) + + Sort a vector in descending order, also constructing the + permutation that sorts the vector + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_perm_r!",E"insertionsort_perm_r!(v[, p[, lo, hi]]) + + Sort a vector in descending order in place, also constructing the + permutation that sorts the vector + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_perm_by",E"insertionsort_perm_by(by, v[, p[, lo, hi]]) + + Sort a vector with insertion sort according to the result of + function \"by\" applied to all values. + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"insertionsort_perm_by!",E"insertionsort_perm_by!(by, v[, p[, lo, hi]]) + + Sort a vector with insertion sort in place according to the result + of function \"by\" applied to all values. + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort",E"mergesort(v[, dim]) + + Sort a vector in ascending order with mergesort, according to + \"isless\". + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort",E"mergesort(lessthan, v[, dim]) + + Sort a vector in ascending order with mergesort, using a custom + comparison function. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort!",E"mergesort!(v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort!",E"mergesort!(v[, lo, hi]) + + In-place mergesort, accoring to \"isless\". + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort!",E"mergesort!(lessthan, v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort!",E"mergesort!(lessthan, v[, lo, hi]) + + In-place mergesort with a custom comparison function. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_r",E"mergesort_r(v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_r",E"mergesort_r(v[, lo, hi]) + + Sort a vector in descending order using mergesort. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_r!",E"mergesort_r!(v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_r!",E"mergesort_r!(v[, lo, hi]) + + In-place mergesort in descending order. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_by",E"mergesort_by(by, v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_by",E"mergesort_by(by, v[, lo, hi]) + + Sort a vector with mergesort according to the result of function + \"by\" applied to all values. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_by!",E"mergesort_by!(by, v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_by!",E"mergesort_by!(by, v[, lo, hi]) + + Sort a vector with mergesort in place according to the result of + function \"by\" applied to all values. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_perm",E"mergesort_perm(v[, p[, lo, hi]]) -> s,p + + Sort a vector in ascending order, also constructing the permutation + that sorts the vector + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_perm",E"mergesort_perm(lessthan, v[, p[, lo, hi]]) -> s,p + + Sort a vector, using a custom comparison function, also + constructing the permutation that sorts the vector . + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_perm!",E"mergesort_perm!(v[, p[, lo, hi]]) + + Sort a vector in ascending order in-place, also constructing the + permutation that sorts the vector + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_perm!",E"mergesort_perm!(lessthan, v[, p[, lo, hi]]) + + Sort a vector in place, using a custom comparison function, also + constructing the permutation that sorts the vector . + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_perm_r",E"mergesort_perm_r(v[, p[, lo, hi]]) + + Sort a vector in descending order, also constructing the + permutation that sorts the vector + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_perm_r!",E"mergesort_perm_r!(v[, p[, lo, hi]]) + + Sort a vector in descending order in place, also constructing the + permutation that sorts the vector + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_perm_by",E"mergesort_perm_by(by, v[, p[, lo, hi]]) + + Sort a vector with mergesort according to the result of function + \"by\" applied to all values. + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"mergesort_perm_by!",E"mergesort_perm_by!(by, v[, p[, lo, hi]]) + + Sort a vector with mergesort in place according to the result of + function \"by\" applied to all values. + + If provided, \"p\" is an initial permutation. + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort",E"quicksort(v[, dim]) + + Sort a vector in ascending order with quicksort, according to + \"isless\". + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort",E"quicksort(lessthan, v[, dim]) + + Sort a vector in ascending order with quicksort, using a custom + comparison function. + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort!",E"quicksort!(v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort!",E"quicksort!(v[, lo, hi]) + + In-place quicksort, accoring to \"isless\". + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort!",E"quicksort!(lessthan, v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort!",E"quicksort!(lessthan, v[, lo, hi]) + + In-place quicksort with a custom comparison function. + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort_r",E"quicksort_r(v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort_r",E"quicksort_r(v[, lo, hi]) + + Sort a vector in descending order using quicksort. + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort_r!",E"quicksort_r!(v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort_r!",E"quicksort_r!(v[, lo, hi]) + + In-place quicksort in descending order. + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort_by",E"quicksort_by(by, v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort_by",E"quicksort_by(by, v[, lo, hi]) + + Sort a vector with quicksort according to the result of function + \"by\" applied to all values. + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort_by!",E"quicksort_by!(by, v[, dim]) + +"), + +(E"Base.Sort",E"Base.Sort",E"quicksort_by!",E"quicksort_by!(by, v[, lo, hi]) + + Sort a vector with quicksort in place according to the result of + function \"by\" applied to all values. + +"), + (E"Sound",E"Sound",E"wavread",E"wavread(io[, options]) Reads and returns the samples from a RIFF/WAVE file. The samples @@ -5342,7 +5864,6 @@ eval_tab_col(glp_prob, k) "), - (E"strpack.jl",E"",E"pack",E"pack(io, composite[, strategy]) Create a packed buffer representation of \"composite\" in stream diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index d8b5eb9b80772..dababbdf22014 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -1772,32 +1772,74 @@ Combinatorics .. function:: sort!(v) - In-place sort + In-place sort. .. function:: sortr(v) - Sort a vector in descending order + Sort a vector in descending order. .. function:: sortr!(v) - In-place descending-order sort + In-place sort in descending-order. + +.. function:: sort_by(by, v) + + Sort a vector by the result of applying function ``by`` + to every element. + +.. function:: sort_by!(by, v) + + Sort a vector in place by the result of applying function ``by`` + to every element. .. function:: sort(a, dim) - Sort an array along the given dimension + Sort an array along the given dimension. .. function:: sort(lessthan, a, [dim]) - Sort with a custom comparison function + Sort with a custom comparison function. .. function:: sortperm(v) -> s,p Sort a vector in ascending order, also constructing the permutation that sorts the vector +.. function:: sortperm!(v) -> s,p + + Sort a vector in ascending order in-place, also constructing the permutation that sorts the vector + +.. function:: sortperm_r(v) -> s,p + + Sort a vector in descending order, also constructing the permutation that sorts the vector + +.. function:: sortperm_r!(v) -> s,p + + Sort a vector in descending order in-place, also constructing the permutation that sorts the vector + +.. function:: sortperm_by(by,v) -> s,p + + Sort a vector according to the result of function ``by`` applied to + all values, also constructing the permutation that sorts the vector. + +.. function:: sortperm_by!(by,v) -> s,p + + Sort a vector in-place according to the result of function ``by`` + applied to all values of ``v``, also constructing the permutation + that sorts the vector + .. function:: issorted(v) Test whether a vector is in ascending sorted order +.. function:: issorted_r(v) + + Test whether a vector is in descending sorted order + +.. function:: issorted_by(by,v) + + Test whether a vector is sorted by the result of function ``by`` + applied to all values of ``v`` + .. function:: nthperm(v, k) Compute the kth lexicographic permutation of a vector diff --git a/doc/stdlib/index.rst b/doc/stdlib/index.rst index 9ae98fcc94c48..9915ddfbeb51d 100644 --- a/doc/stdlib/index.rst +++ b/doc/stdlib/index.rst @@ -16,6 +16,7 @@ Built-ins :maxdepth: 1 base + sort ****** Extras @@ -24,15 +25,15 @@ Extras .. toctree:: :maxdepth: 1 - profile - options + argparse cpp + options + gzip + profile + sound + strpack textwrap zlib - strpack - sound - argparse - gzip **************** Math & Numerical diff --git a/doc/stdlib/sort.rst b/doc/stdlib/sort.rst new file mode 100644 index 0000000000000..7a27f98a1f2ab --- /dev/null +++ b/doc/stdlib/sort.rst @@ -0,0 +1,361 @@ +:mod:`Base.Sort` --- Routines related to sorting +================================================================= + +.. module:: Base.Sort + :synopsis: Sort and related routines + +This module contains algorithms and other functions related to +sorting. Standard versions of all functions are exported in base. +Specific versions of unexported routines can be used by importing +`Base.Sort`, or for finer grain control, importing the fully qualified +function name, e.g.,:: + + # Julia code + import Base.Sort.timsort_perm! + +will allow use of the in-place version of timsort which provides a +permutation, which is not exported by default. All of the sorting +routines can be made available directly with:: + + # Julia code + using Base.Sort + + +Overview +-------- + +There are currently four main sorting algorithms available in Julia:: + + insertionsort + quicksort + mergesort + timsort + +Insertion sort is an ``O(n^2)`` stable sorting algorithm. It is +efficient only for very small ``n``. It is used internally by +``quicksort!`` and ``timsort!``. + +Quicksort is an ``O(n log n)`` sorting algorithm. For efficiency, it +is not stable. It is among the fastest sorting algorithms. + +Mergesort is an ``O(n log n)`` stable sorting algorithm. + +Timsort is an ``O(n log n)`` stable adaptive sorting algorithm. It +takes advantage of sorted runs which exist in many real world +datasets. + +The `sort`, `sortr`, `sort_by`, and `sortperm` functions select a reasonable +default algorithm, depending on the type of the target array. + +Mutating and non-mutating versions of the sort functions and of each +of the algorithm functions are exported and available for use by +default. + ++-------------------+--------------------+---------+-------------------+ +| Non-mutating | Mutating | Stable | Time Complexity | ++===================+====================+=========+===================+ +| ``sort`` | ``sort!`` | (\*) | O(n log n) | ++-------------------+--------------------+---------+-------------------+ +| ``sortr`` | ``sortr!`` | (\*) | O(n log n) | ++-------------------+--------------------+---------+-------------------+ +| ``sort_by`` | ``sort_by!`` | (\*) | O(n log n) | ++-------------------+--------------------+---------+-------------------+ +| ``sortperm`` | ``sortperm!`` | (\*) | O(n log n) | ++-------------------+--------------------+---------+-------------------+ +| ``insertionsort`` | ``insertionsort!`` | yes | O(n^2) | ++-------------------+--------------------+---------+-------------------+ +| ``quicksort`` | ``quicksort!`` | no | O(n log n) | ++-------------------+--------------------+---------+-------------------+ +| ``mergesort`` | ``mergesort!`` | yes | O(n log n) | ++-------------------+--------------------+---------+-------------------+ +| ``timsort`` | ``timsort!`` | yes | <= O(n log n) | ++-------------------+--------------------+---------+-------------------+ + +(\*) Stability depends on the algorithm for the target array data type. + +In addition to the exported functions shown in the table, each of the +algorithms also has an additional set of unexported functions for +reverse sorting, sorting by a function of the data, and for the stable +sorts, function varieties which return a permutation in addition to +the sorted array. These are shown in the table below. + ++----------------------+---------------------------+----------------------------+--------------------------+ +| Sort | Non-mutating Variation | Mutating Variation | Function | ++======================+===========================+============================+==========================+ +| ``insertionsort`` | ``insertionsort_r`` | ``insertionsort_r!`` | Reverse sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``insertionsort_by`` | ``insertionsort_by!`` | Sort by function | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``insertionsort_perm`` | ``insertionsort_perm!`` | Permutation sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``insertionsort_perm_r`` | ``insertionsort_perm_r!`` | Reverse permutation sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``insertionsort_perm_by`` | ``insertionsort_perm_by!`` | Permutation sort by func | ++----------------------+---------------------------+----------------------------+--------------------------+ +| ``mergesort`` | ``mergesort_r`` | ``mergesort_r!`` | Reverse sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``mergesort_by`` | ``mergesort_by!`` | Sort by function | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``mergesort_perm`` | ``mergesort_perm!`` | Permutation sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``mergesort_perm_r`` | ``mergesort_perm_r!`` | Reverse permutation sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``mergesort_perm_by`` | ``mergesort_perm_by!`` | Permutation sort by func | ++----------------------+---------------------------+----------------------------+--------------------------+ +| ``timsort`` | ``timsort_r`` | ``timsort_r!`` | Reverse sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``timsort_by`` | ``timsort_by!`` | Sort by function | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``timsort_perm`` | ``timsort_perm!`` | Permutation sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``timsort_perm_r`` | ``timsort_perm_r!`` | Reverse permutation sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``timsort_perm_by`` | ``timsort_perm_by!`` | Permutation sort by func | ++----------------------+---------------------------+----------------------------+--------------------------+ +| ``quicksort`` | ``quicksort_r`` | ``quicksort_r!`` | Reverse sort | ++----------------------+---------------------------+----------------------------+--------------------------+ +| | ``quicksort_by`` | ``quicksort_by!`` | Sort by function | ++----------------------+---------------------------+----------------------------+--------------------------+ + + +----------------- +Sorting Functions +----------------- + +.. function:: insertionsort(v[,dim]) + + Sort a vector in ascending order with insertion sort, according to ``isless``. + +.. function:: insertionsort(lessthan,v[,dim]) + + Sort a vector in ascending order with insertion sort, using a + custom comparison function. + +.. function:: insertionsort!(v[,dim]) +.. function:: insertionsort!(v[,lo,hi]) + + In-place insertion sort, accoring to ``isless``. + +.. function:: insertionsort!(lessthan,v[,dim]) +.. function:: insertionsort!(lessthan,v[,lo,hi]) + + In-place insertion sort with a custom comparison function. + +.. function:: insertionsort_r(v[,dim]) +.. function:: insertionsort_r(v[,lo,hi]) + + Sort a vector in descending order using insertion sort. + +.. function:: insertionsort_r!(v[,dim]) +.. function:: insertionsort_r!(v[,lo,hi]) + + In-place insertion sort in descending order. + +.. function:: insertionsort_by(by,v[,dim]) +.. function:: insertionsort_by(by,v[,lo,hi]) + + Sort a vector with insertion sort according to the result of + function ``by`` applied to all values. + +.. function:: insertionsort_by!(by,v[,dim]) +.. function:: insertionsort_by!(by,v[,lo,hi]) + + Sort a vector with insertion sort in place according to the result + of function ``by`` applied to all values. + +.. function:: insertionsort_perm(v[,p[,lo,hi]]) -> s,p + + Sort a vector in ascending order, also constructing the + permutation that sorts the vector + + If provided, ``p`` is an initial permutation. + +.. function:: insertionsort_perm(lessthan,v[,p[,lo,hi]]) -> s,p + + Sort a vector, using a custom comparison function, also + constructing the permutation that sorts the vector . + + If provided, ``p`` is an initial permutation. + +.. function:: insertionsort_perm!(v[,p[,lo,hi]]) + + Sort a vector in ascending order in-place, also constructing the + permutation that sorts the vector + + If provided, ``p`` is an initial permutation. + +.. function:: insertionsort_perm!(lessthan,v[,p[,lo,hi]]) + + Sort a vector in place, using a custom comparison function, also + constructing the permutation that sorts the vector . + + If provided, ``p`` is an initial permutation. + +.. function:: insertionsort_perm_r(v[,p,[,lo,hi]]) + + Sort a vector in descending order, also constructing the + permutation that sorts the vector + + If provided, ``p`` is an initial permutation. + +.. function:: insertionsort_perm_r!(v[,p,[,lo,hi]]) + + Sort a vector in descending order in place, also constructing the + permutation that sorts the vector + + If provided, ``p`` is an initial permutation. + +.. function:: insertionsort_perm_by(by,v[,p[,lo,hi]]) + + Sort a vector with insertion sort according to the result + of function ``by`` applied to all values. + + If provided, ``p`` is an initial permutation. + +.. function:: insertionsort_perm_by!(by,v[,p[,lo,hi]]) + + Sort a vector with insertion sort in place according to the result + of function ``by`` applied to all values. + + If provided, ``p`` is an initial permutation. + + +.. function:: mergesort(v[,dim]) + + Sort a vector in ascending order with mergesort, according to ``isless``. + +.. function:: mergesort(lessthan,v[,dim]) + + Sort a vector in ascending order with mergesort, using a + custom comparison function. + +.. function:: mergesort!(v[,dim]) +.. function:: mergesort!(v[,lo,hi]) + + In-place mergesort, accoring to ``isless``. + +.. function:: mergesort!(lessthan,v[,dim]) +.. function:: mergesort!(lessthan,v[,lo,hi]) + + In-place mergesort with a custom comparison function. + +.. function:: mergesort_r(v[,dim]) +.. function:: mergesort_r(v[,lo,hi]) + + Sort a vector in descending order using mergesort. + +.. function:: mergesort_r!(v[,dim]) +.. function:: mergesort_r!(v[,lo,hi]) + + In-place mergesort in descending order. + +.. function:: mergesort_by(by,v[,dim]) +.. function:: mergesort_by(by,v[,lo,hi]) + + Sort a vector with mergesort according to the result of + function ``by`` applied to all values. + +.. function:: mergesort_by!(by,v[,dim]) +.. function:: mergesort_by!(by,v[,lo,hi]) + + Sort a vector with mergesort in place according to the result + of function ``by`` applied to all values. + +.. function:: mergesort_perm(v[,p[,lo,hi]]) -> s,p + + Sort a vector in ascending order, also constructing the + permutation that sorts the vector + + If provided, ``p`` is an initial permutation. + +.. function:: mergesort_perm(lessthan,v[,p[,lo,hi]]) -> s,p + + Sort a vector, using a custom comparison function, also + constructing the permutation that sorts the vector . + + If provided, ``p`` is an initial permutation. + +.. function:: mergesort_perm!(v[,p[,lo,hi]]) + + Sort a vector in ascending order in-place, also constructing the + permutation that sorts the vector + + If provided, ``p`` is an initial permutation. + +.. function:: mergesort_perm!(lessthan,v[,p[,lo,hi]]) + + Sort a vector in place, using a custom comparison function, also + constructing the permutation that sorts the vector . + + If provided, ``p`` is an initial permutation. + +.. function:: mergesort_perm_r(v[,p,[,lo,hi]]) + + Sort a vector in descending order, also constructing the + permutation that sorts the vector + + If provided, ``p`` is an initial permutation. + +.. function:: mergesort_perm_r!(v[,p,[,lo,hi]]) + + Sort a vector in descending order in place, also constructing the + permutation that sorts the vector + + If provided, ``p`` is an initial permutation. + +.. function:: mergesort_perm_by(by,v[,p[,lo,hi]]) + + Sort a vector with mergesort according to the result + of function ``by`` applied to all values. + + If provided, ``p`` is an initial permutation. + +.. function:: mergesort_perm_by!(by,v[,p[,lo,hi]]) + + Sort a vector with mergesort in place according to the result + of function ``by`` applied to all values. + + If provided, ``p`` is an initial permutation. + + +.. function:: quicksort(v[,dim]) + + Sort a vector in ascending order with quicksort, according to ``isless``. + +.. function:: quicksort(lessthan,v[,dim]) + + Sort a vector in ascending order with quicksort, using a + custom comparison function. + +.. function:: quicksort!(v[,dim]) +.. function:: quicksort!(v[,lo,hi]) + + In-place quicksort, accoring to ``isless``. + +.. function:: quicksort!(lessthan,v[,dim]) +.. function:: quicksort!(lessthan,v[,lo,hi]) + + In-place quicksort with a custom comparison function. + +.. function:: quicksort_r(v[,dim]) +.. function:: quicksort_r(v[,lo,hi]) + + Sort a vector in descending order using quicksort. + +.. function:: quicksort_r!(v[,dim]) +.. function:: quicksort_r!(v[,lo,hi]) + + In-place quicksort in descending order. + +.. function:: quicksort_by(by,v[,dim]) +.. function:: quicksort_by(by,v[,lo,hi]) + + Sort a vector with quicksort according to the result of + function ``by`` applied to all values. + +.. function:: quicksort_by!(by,v[,dim]) +.. function:: quicksort_by!(by,v[,lo,hi]) + + Sort a vector with quicksort in place according to the result + of function ``by`` applied to all values. + diff --git a/test/combinatorics.jl b/test/combinatorics.jl index 57ad7da8a501d..d155c60244b58 100644 --- a/test/combinatorics.jl +++ b/test/combinatorics.jl @@ -18,3 +18,42 @@ @test search_sorted_last([1, 1, 2, 2, 3, 3], 2) == 4 @test search_sorted_last([1, 1, 2, 2, 3, 3], 4) == 6 @test search_sorted_last([1.0, 1, 2, 2, 3, 3], 2.5) == 4 + +a = randi(10000, 1000) + +# insertion_sort +for _sort in [insertionsort, mergesort, timsort] + _sort_r = symbol("$(_sort)_r") + _sort_by = symbol("$(_sort)_by") + _sort_perm = symbol("$(_sort)_perm") + _sort_perm_r = symbol("$(_sort)_perm_r") + _sort_perm_by = symbol("$(_sort)_perm_by") + + b = _sort(a) + @test issorted(b) + (b, ix) = Base.(_sort_perm)(a) + @test issorted(b) + @test a[ix] == b + + b = Base.(_sort_r)(a) + @test issorted_r(b) + (b, ix) = Base.(_sort_perm_r)(a) + @test issorted_r(b) + @test a[ix] == b + + b = Base.(_sort_by)((x -> -10x), a) + @test issorted_by((x -> -10x), b) + (b, ix) = Base.(_sort_perm_by)((x -> -10x), a) + @test issorted_by((x -> -10x), b) + @test a[ix] == b +end + +b = quicksort(a) +@test issorted(b) +b = Base.quicksort_r(a) +@test issorted_r(b) +b = Base.quicksort_by((x -> -10x), a) +@test issorted_by((x -> -10x), b) + +@test select_r([3,6,30,1,9],2) == 9 +@test select_by((x -> -x),[3,6,30,1,9],2) == 9