From 57fedc9c8ee0c882b0f563a3202b493de3608c49 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Sun, 9 Jul 2017 20:17:12 +0200 Subject: [PATCH 1/4] add mutating versions of randperm & randcycle --- base/exports.jl | 2 ++ base/random.jl | 77 ++++++++++++++++++++++++++++++++++++++----------- test/random.jl | 6 ++++ 3 files changed, 68 insertions(+), 17 deletions(-) diff --git a/base/exports.jl b/base/exports.jl index 335a5c4bba385..7f84a282e37cf 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -508,7 +508,9 @@ export prod, promote_shape, randcycle, + randcycle!, randperm, + randperm!, randsubseq!, randsubseq, range, diff --git a/base/random.jl b/base/random.jl index 50c7cab06cafd..74a7739380861 100644 --- a/base/random.jl +++ b/base/random.jl @@ -12,9 +12,10 @@ export srand, randexp, randexp!, bitrand, randstring, - randsubseq,randsubseq!, - shuffle,shuffle!, - randperm, randcycle, + randsubseq, randsubseq!, + shuffle, shuffle!, + randperm, randperm!, + randcycle, randcycle!, AbstractRNG, MersenneTwister, RandomDevice, GLOBAL_RNG, randjump @@ -1789,14 +1790,34 @@ shuffle(a::AbstractArray) = shuffle(GLOBAL_RNG, a) Construct a random permutation of length `n`. The optional `rng` argument specifies a random number generator (see [Random Numbers](@ref)). -To randomly permute a arbitrary vector, see [`shuffle`](@ref) +To randomly permute an arbitrary vector, see [`shuffle`](@ref) or [`shuffle!`](@ref). # Examples ```jldoctest -julia> rng = MersenneTwister(1234); +julia> randperm(MersenneTwister(1234), 4) +4-element Array{Int64,1}: + 2 + 1 + 4 + 3 +``` +""" +randperm(r::AbstractRNG, n::Integer) = randperm!(r, Vector{typeof(n)}(n)) +randperm(n::Integer) = randperm(GLOBAL_RNG, n) + +""" + randperm!([rng=GLOBAL_RNG,] A::Array{<:Integer}) + +Construct in `A` a random permutation of length `length(A)`. The +optional `rng` argument specifies a random number generator (see +[Random Numbers](@ref)). To randomly permute an arbitrary vector, see +[`shuffle`](@ref) or [`shuffle!`](@ref). + +# Example -julia> randperm(rng, 4) +```jldoctest +julia> randperm!(MersenneTwister(1234), Vector{Int}(4)) 4-element Array{Int64,1}: 2 1 @@ -1804,12 +1825,10 @@ julia> randperm(rng, 4) 3 ``` """ -function randperm(r::AbstractRNG, n::Integer) - a = Vector{typeof(n)}(n) +function randperm!(r::AbstractRNG, a::Array{<:Integer}) + n = length(a) @assert n <= Int64(2)^52 - if n == 0 - return a - end + n == 0 && return a a[1] = 1 mask = 3 @inbounds for i = 2:Int(n) @@ -1822,7 +1841,9 @@ function randperm(r::AbstractRNG, n::Integer) end return a end -randperm(n::Integer) = randperm(GLOBAL_RNG, n) + +randperm!(a::Array{<:Integer}) = randperm!(GLOBAL_RNG, a) + """ randcycle([rng=GLOBAL_RNG,] n::Integer) @@ -1832,9 +1853,30 @@ argument specifies a random number generator, see [Random Numbers](@ref). # Examples ```jldoctest -julia> rng = MersenneTwister(1234); +julia> randcycle(MersenneTwister(1234), 6) +6-element Array{Int64,1}: + 3 + 5 + 4 + 6 + 1 + 2 +``` +""" +randcycle(r::AbstractRNG, n::Integer) = randcycle!(r, Vector{typeof(n)}(n)) +randcycle(n::Integer) = randcycle(GLOBAL_RNG, n) + +""" + randcycle!([rng=GLOBAL_RNG,] A::Array{<:Integer}) + +Construct in `A` a random cyclic permutation of length `length(A)`. +The optional `rng` argument specifies a random number generator, see +[Random Numbers](@ref). + +# Example -julia> randcycle(rng, 6) +```jldoctest +julia> randcycle!(MersenneTwister(1234), Vector{Int}(6)) 6-element Array{Int64,1}: 3 5 @@ -1844,8 +1886,8 @@ julia> randcycle(rng, 6) 2 ``` """ -function randcycle(r::AbstractRNG, n::Integer) - a = Vector{typeof(n)}(n) +function randcycle!(r::AbstractRNG, a::Array{<:Integer}) + n = length(a) n == 0 && return a @assert n <= Int64(2)^52 a[1] = 1 @@ -1858,6 +1900,7 @@ function randcycle(r::AbstractRNG, n::Integer) end return a end -randcycle(n::Integer) = randcycle(GLOBAL_RNG, n) + +randcycle!(a::Array{<:Integer}) = randcycle!(GLOBAL_RNG, a) end # module diff --git a/test/random.jl b/test/random.jl index cb2b9bf635f64..1c33e98184237 100644 --- a/test/random.jl +++ b/test/random.jl @@ -461,7 +461,13 @@ let mta = MersenneTwister(42), mtb = MersenneTwister(42) @test randperm(0) == [] @test_throws ErrorException randperm(-1) + A, B = Vector{Int}(10), Vector{Int}(10) + @test randperm!(mta, A) == randperm!(mtb, B) + @test randperm!(A) === A + @test randcycle(mta,10) == randcycle(mtb,10) + @test randcycle!(mta, A) == randcycle!(mtb, B) + @test randcycle!(A) === A @test sprand(mta,1,1,0.9) == sprand(mtb,1,1,0.9) @test sprand(mta,10,10,0.3) == sprand(mtb,10,10,0.3) From f54e450fac5ad16ab0957438312151578d195a49 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Sun, 9 Jul 2017 20:34:47 +0200 Subject: [PATCH 2/4] randperm(n) always return Array{Int} --- NEWS.md | 7 +++++++ base/random.jl | 8 ++++---- test/random.jl | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index d35daff87fedb..b25a894047526 100644 --- a/NEWS.md +++ b/NEWS.md @@ -75,6 +75,10 @@ This section lists changes that do not have deprecation warnings. `@everywhere include_string(Main, $(read("filename", String)), "filename")`. Improving upon this API is left as an opportunity for packages. + * `randperm(n)` and `randcycle(n)` now always return a `Vector{Int}` (independent of + the type of `n`). Use the corresponding mutating functions `randperm!` and `randcycle!` + to control the array type ([#22723]). + Library improvements -------------------- @@ -128,6 +132,9 @@ Library improvements * `Diagonal` is now parameterized on the type of the wrapped vector. This allows for `Diagonal` matrices with arbitrary `AbstractVector`s ([#22718]). + * Mutating versions of `randperm` and `randcycle` have been added: + `randperm!` and `randcycle!` ([#22723]). + Compiler/Runtime improvements ----------------------------- diff --git a/base/random.jl b/base/random.jl index 74a7739380861..4a4171325cf97 100644 --- a/base/random.jl +++ b/base/random.jl @@ -1803,7 +1803,7 @@ julia> randperm(MersenneTwister(1234), 4) 3 ``` """ -randperm(r::AbstractRNG, n::Integer) = randperm!(r, Vector{typeof(n)}(n)) +randperm(r::AbstractRNG, n::Integer) = randperm!(r, Vector{Int}(n)) randperm(n::Integer) = randperm(GLOBAL_RNG, n) """ @@ -1831,7 +1831,7 @@ function randperm!(r::AbstractRNG, a::Array{<:Integer}) n == 0 && return a a[1] = 1 mask = 3 - @inbounds for i = 2:Int(n) + @inbounds for i = 2:n j = 1 + rand_lt(r, i, mask) if i != j # a[i] is uninitialized (and could be #undef) a[i] = a[j] @@ -1863,7 +1863,7 @@ julia> randcycle(MersenneTwister(1234), 6) 2 ``` """ -randcycle(r::AbstractRNG, n::Integer) = randcycle!(r, Vector{typeof(n)}(n)) +randcycle(r::AbstractRNG, n::Integer) = randcycle!(r, Vector{Int}(n)) randcycle(n::Integer) = randcycle(GLOBAL_RNG, n) """ @@ -1892,7 +1892,7 @@ function randcycle!(r::AbstractRNG, a::Array{<:Integer}) @assert n <= Int64(2)^52 a[1] = 1 mask = 3 - @inbounds for i = 2:Int(n) + @inbounds for i = 2:n j = 1 + rand_lt(r, i-1, mask) a[i] = a[j] a[j] = i diff --git a/test/random.jl b/test/random.jl index 1c33e98184237..46b2c6fce7474 100644 --- a/test/random.jl +++ b/test/random.jl @@ -459,6 +459,7 @@ let mta = MersenneTwister(42), mtb = MersenneTwister(42) @test sort!(randperm(10)) == sort!(shuffle(1:10)) == collect(1:10) @test randperm(mta,big(10)) == randperm(mtb,big(10)) # cf. #16376 @test randperm(0) == [] + @test eltype(randperm(UInt(1))) === Int @test_throws ErrorException randperm(-1) A, B = Vector{Int}(10), Vector{Int}(10) @@ -466,6 +467,7 @@ let mta = MersenneTwister(42), mtb = MersenneTwister(42) @test randperm!(A) === A @test randcycle(mta,10) == randcycle(mtb,10) + @test eltype(randcycle(UInt(1))) === Int @test randcycle!(mta, A) == randcycle!(mtb, B) @test randcycle!(A) === A From e285857b4096b432265c0ea5c88f63fe31b0ec60 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Mon, 10 Jul 2017 09:16:40 +0200 Subject: [PATCH 3/4] remove newline before "Examples", made pluralized (tkelman) [ci skip] --- base/random.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/base/random.jl b/base/random.jl index 4a4171325cf97..d1a544d18ba02 100644 --- a/base/random.jl +++ b/base/random.jl @@ -1814,8 +1814,7 @@ optional `rng` argument specifies a random number generator (see [Random Numbers](@ref)). To randomly permute an arbitrary vector, see [`shuffle`](@ref) or [`shuffle!`](@ref). -# Example - +# Examples ```jldoctest julia> randperm!(MersenneTwister(1234), Vector{Int}(4)) 4-element Array{Int64,1}: @@ -1873,8 +1872,7 @@ Construct in `A` a random cyclic permutation of length `length(A)`. The optional `rng` argument specifies a random number generator, see [Random Numbers](@ref). -# Example - +# Examples ```jldoctest julia> randcycle!(MersenneTwister(1234), Vector{Int}(6)) 6-element Array{Int64,1}: From 16d11fe96fa16b2506bd5dd21826dfae57d9848c Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Mon, 10 Jul 2017 15:11:18 +0200 Subject: [PATCH 4/4] add new functions to docs' stdlib --- doc/src/stdlib/arrays.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index b9cdb5dff672f..aedb79e7f6a64 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -157,11 +157,13 @@ Base.sum_kbn ```@docs Base.Random.randperm +Base.Random.randperm! Base.invperm Base.isperm Base.permute!(::Any, ::AbstractVector) Base.ipermute! Base.Random.randcycle +Base.Random.randcycle! Base.Random.shuffle Base.Random.shuffle! Base.reverse