Skip to content

Commit

Permalink
re-enable the 0-arg MersenneTwister() constructor
Browse files Browse the repository at this point in the history
The arguments to `srand(rng, ...)` and `typeof(rng)(...)`
should mirror each-other, in particular
`srand(MersenneTwister(0))` and `MersenneTwister()` should
produce an equivalent object.
Also, `srand(::RandomDevice)` has been added for consistency,
which could be useful in generic code.
  • Loading branch information
rfourquet committed Sep 3, 2017
1 parent f5b96f7 commit 81b839d
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 13 deletions.
3 changes: 0 additions & 3 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1267,9 +1267,6 @@ end
end
end

# PR #16984
@deprecate MersenneTwister() MersenneTwister(0)

# #19635
for fname in (:ones, :zeros)
@eval @deprecate ($fname)(T::Type, arr) ($fname)(T, size(arr))
Expand Down
14 changes: 13 additions & 1 deletion base/random/RNGs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ end # os-test
Create a `RandomDevice` RNG object.
Two such objects will always generate different streams of random numbers.
The entropy is obtained from the operating system.
"""
RandomDevice

RandomDevice(::Void) = RandomDevice()
srand(rng::RandomDevice) = rng

### generation of floats

@inline rand(r::RandomDevice, I::FloatInterval) = rand_generic(r, I)
Expand Down Expand Up @@ -71,10 +75,17 @@ MersenneTwister(seed::Vector{UInt32}, state::DSFMT_state) =

"""
MersenneTwister(seed)
MersenneTwister()
Create a `MersenneTwister` RNG object. Different RNG objects can have
their own seeds, which may be useful for generating different streams
of random numbers.
The `seed` may be a non-negative integer or a vector of
`UInt32` integers. If no seed is provided, a randomly generated one
is created (using entropy from the system).
See the [`srand`](@ref) function for reseeding an already existing
`MersenneTwister` object.
# Examples
```jldoctest
Expand All @@ -96,7 +107,8 @@ julia> x1 == x2
true
```
"""
MersenneTwister(seed) = srand(MersenneTwister(Vector{UInt32}(), DSFMT_state()), seed)
MersenneTwister(seed=nothing) =
srand(MersenneTwister(Vector{UInt32}(), DSFMT_state()), seed)

function copy!(dst::MersenneTwister, src::MersenneTwister)
copy!(resize!(dst.seed, length(src.seed)), src.seed)
Expand Down
28 changes: 22 additions & 6 deletions base/random/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,14 @@ rand!
srand([rng=GLOBAL_RNG], seed) -> rng
srand([rng=GLOBAL_RNG]) -> rng
Reseed the random number generator. If a `seed` is provided, the RNG will give a
reproducible sequence of numbers, otherwise Julia will get entropy from the system. For
`MersenneTwister`, the `seed` may be a non-negative integer or a vector of [`UInt32`](@ref)
integers. `RandomDevice` does not support seeding.
Reseed the random number generator: `rng` will give a reproducible
sequence of numbers if and only if a `seed` is provided. Some RNGs
don't accept a seed, like `RandomDevice`.
After the call to `srand`, `rng` is equivalent to a newly created
object initialized with the same seed.
# Examples
```jldoctest
```julia-repl
julia> srand(1234);
julia> x1 = rand(2)
Expand All @@ -140,8 +141,23 @@ julia> x2 = rand(2)
julia> x1 == x2
true
julia> rng = MersenneTwister(1234); rand(rng, 2) == x1
true
julia> MersenneTwister(1) == srand(rng, 1)
true
julia> rand(srand(rng), Bool) # not reproducible
true
julia> rand(srand(rng), Bool)
false
julia> rand(MersenneTwister(), Bool) # not reproducible either
true
```
"""
srand
srand(rng::AbstractRNG, ::Void) = srand(rng)

end # module
34 changes: 31 additions & 3 deletions test/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ A = zeros(UInt128, 2, 2)
@test_throws BoundsError rand!(MersenneTwister(0), A, 5)

# rand from AbstractArray
let mt = MersenneTwister(0)
srand(mt)
let mt = MersenneTwister()
@test rand(mt, 0:3:1000) in 0:3:1000
@test issubset(rand!(mt, Array{Int}(100), 0:3:1000), 0:3:1000)
coll = Any[2, UInt128(128), big(619), "string"]
Expand Down Expand Up @@ -424,7 +423,7 @@ function hist(X, n)
end

# test uniform distribution of floats
for rng in [srand(MersenneTwister(0)), RandomDevice()],
for rng in [MersenneTwister(), RandomDevice()],
T in [Float16, Float32, Float64, BigFloat],
prec in (T == BigFloat ? [3, 53, 64, 100, 256, 1000] : [256])
setprecision(BigFloat, prec) do
Expand Down Expand Up @@ -589,3 +588,32 @@ end

# this shouldn't crash (#22403)
@test_throws MethodError rand!(Union{UInt,Int}[1, 2, 3])

@testset "$RNG() & srand(rng::$RNG) initializes randomly" for RNG in (MersenneTwister, RandomDevice)
m = RNG()
a = rand(m, Int)
m = RNG()
@test rand(m, Int) != a
# passing `nothing` is equivalent to passing nothing
m = RNG(nothing)
b = rand(m, Int)
@test b != a
srand(m)
c = rand(m, Int)
@test c (a, b)
srand(m)
@test rand(m, Int) (a, b, c)
srand(m, nothing)
d = rand(m, Int)
@test d (a, b, c)
srand(m, nothing)
@test rand(m, Int) (a, b, c, d)
end

@testset "MersenneTwister($seed_) & srand(m::MersenneTwister, $seed_) produce the same stream" for seed_ in [0:5; 10000:10005]
# "seed_" instead of "seed" because `seed` is a global variable in this file, and there is an "overwriting" warning
m = MersenneTwister(seed_)
a = [rand(m) for _=1:100]
srand(m, seed_)
@test a == [rand(m) for _=1:100]
end

0 comments on commit 81b839d

Please sign in to comment.