Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitaaa2451

Browse files
authored
MersenneTwister: simplify seeding logic (#60204)
Since at least v0.3, `MersenneTwister` has stored the user-providedseed. More recently, this allowed `show` to print a round-trippablerepresentation of the RNG. However, storing an arbitrary deep-copieduser seed is not ideal, and the initialization logic has become morecomplicated than necessary.In particular, `MersenneTwister()` currently performs three steps:1. `seed = rand(RandomDevice(), UInt128)` # generate a seed2. `initstate = rand(SeedHasher(seed), UInt32, 8)` # expand it3. initialize dSFMT with `initstate`This commit merges the first two steps. The new initialization is:1. `initstate = rand(RandomDevice(), NTuple{2, UInt128})`2. convert `initstate` to the dSFMT format and initialize the stateWe now store only `initstate` for use in `show`, preservinground-trippability. For user-provided seeds, `initstate` is derived fromthe seed via `SeedHasher`.A small bonus is that `MersenneTwister()` is no longer restricted to"only" 2^128 distinct initializations.The cosmetic drawback is that the printed representation is less pretty:`MersenneTwister(1)` now shows as```MersenneTwister(0xc53bc12f..., 0x50a4aa15...)```
1 parent24d8ab5 commitaaa2451

File tree

2 files changed

+40
-77
lines changed

2 files changed

+40
-77
lines changed

‎stdlib/Random/src/MersenneTwister.jl‎

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const MT_CACHE_I = 501 << 4 # number of bytes in the UInt128 cache
88
@assertdsfmt_get_min_array_size()<= MT_CACHE_F
99

1010
mutable struct MersenneTwister<:AbstractRNG
11-
seed::Any
11+
seed::NTuple{2, UInt128}
1212
const state::DSFMT_state
1313
const vals::Memory{Float64}
1414
const ints::Vector{UInt128}# it's temporarily resized internally
@@ -22,7 +22,7 @@ mutable struct MersenneTwister <: AbstractRNG
2222
adv_ints::Int64# state of advance when ints is filled-up
2323

2424
global_MersenneTwister(::UndefInitializer)=
25-
new(nothing,DSFMT_state(),
25+
new((UInt128(0),UInt128(0)),DSFMT_state(),
2626
Memory{Float64}(undef, MT_CACHE_F),
2727
Vector{UInt128}(undef, MT_CACHE_I>>4),
2828
MT_CACHE_F,0,0, Base.GMP.ZERO,-1,-1)
@@ -89,33 +89,26 @@ hash(r::MersenneTwister, h::UInt) =
8989
foldr(hash, (r.seed, r.state, r.vals, r.ints, r.idxF, r.idxI); init=h)
9090

9191
functionshow(io::IO, rng::MersenneTwister)
92+
sep=","
9293
# seed
94+
print(io, MersenneTwister,"(",repr(rng.seed[1]), sep,repr(rng.seed[2]))
9395
if rng.adv_jump==0&& rng.adv==0
94-
returnprint(io,MersenneTwister,"(",repr(rng.seed),")")
96+
returnprint(io,")")
9597
end
96-
print(io, MersenneTwister,"(",repr(rng.seed),", (")
9798
# state
98-
sep=","
99-
show(io, rng.adv_jump)
100-
print(io, sep)
101-
show(io, rng.adv)
99+
print(io, sep, rng.adv_jump, sep, rng.adv)
102100
if rng.adv_vals!=-1|| rng.adv_ints!=-1
103101
# "(0, 0)" is nicer on the eyes than (-1, 1002)
104102
s= rng.adv_vals!=-1
105-
print(io, sep)
106-
show(io, s? rng.adv_vals:zero(rng.adv_vals))
107-
print(io, sep)
108-
show(io, s? rng.idxF:zero(rng.idxF))
103+
print(io, sep, s? rng.adv_vals:zero(rng.adv_vals),
104+
sep, s? rng.idxF:zero(rng.idxF))
109105
end
110106
if rng.adv_ints!=-1
111107
idxI= (length(rng.ints)*16- rng.idxI)/8# 8 represents one Int64
112108
idxI=Int(idxI)# idxI should always be an integer when using public APIs
113-
print(io, sep)
114-
show(io, rng.adv_ints)
115-
print(io, sep)
116-
show(io, idxI)
109+
print(io, sep, rng.adv_ints, sep, idxI)
117110
end
118-
print(io,"))")
111+
print(io,")")
119112
end
120113

121114
### low level API
@@ -226,27 +219,19 @@ end
226219

227220
#### seed!()
228221

229-
functioninitstate!(r::MersenneTwister, data::StridedVector, seed)
230-
# we deepcopy `seed` because the caller might mutate it, and it's useful
231-
# to keep it constant inside `MersenneTwister`; but multiple instances
232-
# can share the same seed without any problem (e.g. in `copy`)
233-
r.seed=deepcopy(seed)
234-
dsfmt_init_by_array(r.state,reinterpret(UInt32, data))
222+
functioninitstate!(r::MersenneTwister, seed)
223+
r.seed= seed# store the seed for `show`
224+
seedvec=view(r.ints,1:2)# re-use r.ints to temporarily store the seed
225+
seedvec .= seed
226+
dsfmt_init_by_array(r.state,reinterpret(UInt32, seedvec))
235227
reset_caches!(r)
236228
r.adv=0
237229
r.adv_jump= Base.GMP.ZERO
238230
return r
239231
end
240232

241-
# When a seed is not provided, we generate one via `RandomDevice()` rather
242-
# than calling directly `initstate!` with `rand(RandomDevice(), UInt32, 8)` because the
243-
# seed is printed in `show(::MersenneTwister)`, so we need one; the cost of `hash_seed` is a
244-
# small overhead compared to `initstate!`.
245-
# A random seed with 128 bits is a good compromise for almost surely getting distinct
246-
# seeds, while having them printed reasonably tersely.
247-
seed!(r::MersenneTwister, seeder::AbstractRNG)=seed!(r,rand(seeder, UInt128))
248-
seed!(r::MersenneTwister,::Nothing)=seed!(r,RandomDevice())
249-
seed!(r::MersenneTwister, seed)=initstate!(r,rand(SeedHasher(seed), UInt32,8), seed)
233+
seed!(r::MersenneTwister, seeder::AbstractRNG)=
234+
initstate!(r,rand(seeder, NTuple{2, UInt128}))
250235

251236

252237
### generation
@@ -575,14 +560,18 @@ jump!(r::MersenneTwister, steps::Integer) = copy!(r, jump(r, steps))
575560
# 3, 4: .adv_vals, .idxF (counters to reconstruct the float cache, optional if 5-6 not shown))
576561
# 5, 6: .adv_ints, .idxI (counters to reconstruct the integer cache, optional)
577562

578-
Random.MersenneTwister(seed, advance::NTuple{6,Integer})=
579-
advance!(MersenneTwister(seed), advance...)
563+
MersenneTwister(s1::Integer, s2::Integer)=initstate!(_MersenneTwister(undef), (s1, s2))
564+
565+
MersenneTwister(s1::Integer, s2::Integer, s3::Integer, s4::Integer,
566+
s5::Integer, s6::Integer, s7::Integer, s8::Integer)=
567+
advance!(MersenneTwister(s1, s2), s3, s4, s5, s6, s7, s8)
580568

581-
Random.MersenneTwister(seed, advance::NTuple{4,Integer})=
582-
MersenneTwister(seed, (advance...,0,0))
569+
MersenneTwister(s1::Integer, s2::Integer, s3::Integer, s4::Integer,
570+
s5::Integer, s6::Integer)=
571+
MersenneTwister(s1, s2, s3, s4, s5, s6,0,0)
583572

584-
Random.MersenneTwister(seed, advance::NTuple{2,Integer})=
585-
MersenneTwister(seed, (advance...,0,0,0,0))
573+
MersenneTwister(s1::Integer, s2::Integer, s3::Integer, s4::Integer)=
574+
MersenneTwister(s1, s2, s3, s4,0,0,0,0)
586575

587576
# advances raw state (per fill_array!) of r by n steps (Float64 values)
588577
function_advance_n!(r::MersenneTwister, n::Int64, work::Vector{Float64})

‎stdlib/Random/test/runtests.jl‎

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -646,18 +646,6 @@ end
646646
# MersenneTwister initialization with invalid values
647647
@test_throws DomainError DSFMT.DSFMT_state(zeros(Int32,rand(0:DSFMT.JN32-1)))
648648

649-
# seed is private to MersenneTwister
650-
let seed=rand(UInt32,10)
651-
r=MersenneTwister(seed)
652-
@test r.seed== seed&& r.seed!== seed
653-
let r2= Future.randjump(r,big(10)^20)
654-
Random.seed!(r2)
655-
@test seed== r.seed!= r2.seed
656-
end
657-
resize!(seed,4)
658-
@test r.seed!= seed
659-
end
660-
661649
@testset"Random.seed!(rng, ...) returns rng"begin
662650
# issue #21248
663651
seed=rand(UInt)
@@ -957,42 +945,28 @@ end
957945
@testset"show"begin
958946
@testset"MersenneTwister"begin
959947
m=MersenneTwister(123)
960-
@teststring(m)=="MersenneTwister(123)"
948+
@teststring(m)=="MersenneTwister(0xf80cc98e147960c1fefa8d41b8f5dca5, 0xea7a7dcb2e787c0120e2ccc17662fc1d)"
949+
@test m==MersenneTwister(0xf80cc98e147960c1fefa8d41b8f5dca5,0xea7a7dcb2e787c0120e2ccc17662fc1d)
961950
Random.jump!(m,2*big(10)^20)
962-
@teststring(m)=="MersenneTwister(123, (200000000000000000000, 0))"
963-
@test m==MersenneTwister(123, (200000000000000000000,0))
951+
@teststring(m)=="MersenneTwister(0xf80cc98e147960c1fefa8d41b8f5dca5, 0xea7a7dcb2e787c0120e2ccc17662fc1d,200000000000000000000, 0)"
952+
@test m==MersenneTwister(0xf80cc98e147960c1fefa8d41b8f5dca5,0xea7a7dcb2e787c0120e2ccc17662fc1d,200000000000000000000,0)
964953
rand(m)
965-
@teststring(m)=="MersenneTwister(123, (200000000000000000000, 1002, 0, 1))"
954+
@teststring(m)=="MersenneTwister(0xf80cc98e147960c1fefa8d41b8f5dca5, 0xea7a7dcb2e787c0120e2ccc17662fc1d,200000000000000000000, 1002, 0, 1)"
966955

967-
@test m==MersenneTwister(123, (200000000000000000000,1002,0,1))
956+
@test m==MersenneTwister(0xf80cc98e147960c1fefa8d41b8f5dca5,0xea7a7dcb2e787c0120e2ccc17662fc1d,200000000000000000000,1002,0,1)
968957
rand(m, Int64)
969-
@teststring(m)=="MersenneTwister(123, (200000000000000000000, 2256, 0, 1, 1002, 1))"
970-
@test m==MersenneTwister(123, (200000000000000000000,2256,0,1,1002,1))
958+
@teststring(m)=="MersenneTwister(0xf80cc98e147960c1fefa8d41b8f5dca5, 0xea7a7dcb2e787c0120e2ccc17662fc1d,200000000000000000000, 2256, 0, 1, 1002, 1)"
959+
@test m==MersenneTwister(0xf80cc98e147960c1fefa8d41b8f5dca5,0xea7a7dcb2e787c0120e2ccc17662fc1d,200000000000000000000,2256,0,1,1002,1)
971960

972961
m=MersenneTwister(0x0ecfd77f89dcd508caa37a17ebb7556b)
973-
@teststring(m)=="MersenneTwister(0x0ecfd77f89dcd508caa37a17ebb7556b)"
962+
@teststring(m)=="MersenneTwister(0x07a0cc280198a55c39fa6f802d242f8b, 0x8472a002c9dd8879235ae29f67bc7496)"
974963
rand(m, Int64)
975-
@teststring(m)=="MersenneTwister(0x0ecfd77f89dcd508caa37a17ebb7556b, (0, 1254, 0, 0, 0, 1))"
976-
@test m==MersenneTwister(0xecfd77f89dcd508caa37a17ebb7556b, (0,1254,0,0,0,1))
964+
@teststring(m)=="MersenneTwister(0x07a0cc280198a55c39fa6f802d242f8b, 0x8472a002c9dd8879235ae29f67bc7496,0, 1254, 0, 0, 0, 1)"
965+
@test m==MersenneTwister(0x07a0cc280198a55c39fa6f802d242f8b,0x8472a002c9dd8879235ae29f67bc7496,0,1254,0,0,0,1)
977966

978967
m=MersenneTwister(0);rand(m, Int64);rand(m)
979-
@teststring(m)=="MersenneTwister(0, (0, 2256, 1254, 1, 0, 1))"
980-
@test m==MersenneTwister(0, (0,2256,1254,1,0,1))
981-
982-
# negative seeds
983-
Random.seed!(m,-3)
984-
@teststring(m)=="MersenneTwister(-3)"
985-
Random.seed!(m,typemin(Int8))
986-
@teststring(m)=="MersenneTwister(-128)"
987-
988-
# string seeds
989-
Random.seed!(m,"seed 1")
990-
@teststring(m)=="MersenneTwister(\"seed 1\")"
991-
x=rand(m)
992-
@test x==rand(MersenneTwister("seed 1"))
993-
@teststring(m)=="""MersenneTwister("seed 1", (0, 1002, 0, 1))"""
994-
# test that MersenneTwister's fancy constructors accept string seeds
995-
@testMersenneTwister("seed 1", (0,1002,0,1))== m
968+
@teststring(m)=="MersenneTwister(0x48d73dc42d195740db2fa90498613fdf, 0x1911b814c02405e88c49bc52dc8a77ea, 0, 2256, 1254, 1, 0, 1)"
969+
@test m==MersenneTwister(0x48d73dc42d195740db2fa90498613fdf,0x1911b814c02405e88c49bc52dc8a77ea,0,2256,1254,1,0,1)
996970
end
997971

998972
@testset"RandomDevice"begin

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp