Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
--------------------

Expand Down Expand Up @@ -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
-----------------------------

Expand Down
2 changes: 2 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,9 @@ export
prod,
promote_shape,
randcycle,
randcycle!,
randperm,
randperm!,
randsubseq!,
randsubseq,
range,
Expand Down
79 changes: 60 additions & 19 deletions base/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -1789,30 +1790,47 @@ 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{Int}(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).

julia> randperm(rng, 4)
# Examples
```jldoctest
julia> randperm!(MersenneTwister(1234), Vector{Int}(4))
4-element Array{Int64,1}:
2
1
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)
@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]
Expand All @@ -1822,7 +1840,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)
Expand All @@ -1832,9 +1852,29 @@ 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{Int}(n))
randcycle(n::Integer) = randcycle(GLOBAL_RNG, n)

"""
randcycle!([rng=GLOBAL_RNG,] A::Array{<:Integer})

julia> randcycle(rng, 6)
Construct in `A` a random cyclic permutation of length `length(A)`.
The optional `rng` argument specifies a random number generator, see
[Random Numbers](@ref).

# Examples
```jldoctest
julia> randcycle!(MersenneTwister(1234), Vector{Int}(6))
6-element Array{Int64,1}:
3
5
Expand All @@ -1844,20 +1884,21 @@ 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
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
i == 1+mask && (mask = 2mask + 1)
end
return a
end
randcycle(n::Integer) = randcycle(GLOBAL_RNG, n)

randcycle!(a::Array{<:Integer}) = randcycle!(GLOBAL_RNG, a)

end # module
2 changes: 2 additions & 0 deletions doc/src/stdlib/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions test/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -459,9 +459,17 @@ 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)
@test randperm!(mta, A) == randperm!(mtb, B)
@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

@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)
Expand Down