Skip to content

Commit 3b2c143

Browse files
rfourquetKristofferC
authored andcommitted
Xoshiro: allow any non-negative integer as a seed, via SHA2_256 (#41558)
(cherry picked from commit 2174ee1)
1 parent 0904a12 commit 3b2c143

File tree

13 files changed

+53
-94
lines changed

13 files changed

+53
-94
lines changed

doc/src/devdocs/subarrays.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ julia> A = rand(2,3,4);
1919
2020
julia> S1 = view(A, :, 1, 2:3)
2121
2×2 view(::Array{Float64, 3}, :, 1, 2:3) with eltype Float64:
22-
0.342284 0.831961
23-
0.237287 0.435938
22+
0.839622 0.711389
23+
0.967143 0.103929
2424
2525
julia> S2 = view(A, 1, :, 2:3)
2626
3×2 view(::Array{Float64, 3}, 1, :, 2:3) with eltype Float64:
27-
0.342284 0.831961
28-
0.988944 0.927795
29-
0.178426 0.404876
27+
0.839622 0.711389
28+
0.789764 0.806704
29+
0.566704 0.962715
3030
```
3131
```@meta
3232
DocTestSetup = nothing

doc/src/manual/performance-tips.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ julia> function sum_global()
7777
end;
7878
7979
julia> @time sum_global()
80-
0.010414 seconds (9.07 k allocations: 373.448 KiB, 98.40% compilation time)
81-
493.6199223951192
80+
0.011539 seconds (9.08 k allocations: 373.386 KiB, 98.69% compilation time)
81+
523.0007221951678
8282
8383
julia> @time sum_global()
84-
0.000108 seconds (3.49 k allocations: 70.156 KiB)
85-
493.6199223951192
84+
0.000091 seconds (3.49 k allocations: 70.156 KiB)
85+
523.0007221951678
8686
```
8787

8888
On the first call (`@time sum_global()`) the function gets compiled. (If you've not yet used [`@time`](@ref)
@@ -113,12 +113,12 @@ julia> function sum_arg(x)
113113
end;
114114
115115
julia> @time sum_arg(x)
116-
0.007971 seconds (3.96 k allocations: 200.171 KiB, 99.83% compilation time)
117-
493.6199223951192
116+
0.007551 seconds (3.98 k allocations: 200.548 KiB, 99.77% compilation time)
117+
523.0007221951678
118118
119119
julia> @time sum_arg(x)
120-
0.000003 seconds (1 allocation: 16 bytes)
121-
493.6199223951192
120+
0.000006 seconds (1 allocation: 16 bytes)
121+
523.0007221951678
122122
```
123123

124124
The 1 allocation seen is from running the `@time` macro itself in global scope. If we instead run
@@ -128,8 +128,8 @@ the timing in a function, we can see that indeed no allocations are performed:
128128
julia> time_sum(x) = @time sum_arg(x);
129129
130130
julia> time_sum(x)
131-
0.000001 seconds
132-
493.6199223951192
131+
0.000002 seconds
132+
523.0007221951678
133133
```
134134

135135
In some situations, your function may need to allocate memory as part of its operation, and this

stdlib/LinearAlgebra/test/dense.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ Random.seed!(1234323)
2222
@testset "for $elty" for elty in (Float32, Float64, ComplexF32, ComplexF64)
2323
ainit = convert(Matrix{elty}, ainit)
2424
for a in (copy(ainit), view(ainit, 1:n, 1:n))
25-
@test cond(a,1) 122.15725126320953 atol=0.5
26-
@test cond(a,2) 78.44837047684149 atol=0.5
27-
@test cond(a,Inf) 174.10761543202744 atol=0.4
28-
@test cond(a[:,1:5]) 6.7492840150789135 atol=0.01
25+
@test cond(a,1) 198.3324294531168 atol=0.5
26+
@test cond(a,2) 85.93920079319506 atol=0.5
27+
@test cond(a,Inf) 149.7523084803039 atol=0.4
28+
@test cond(a[:,1:5]) 8.319279144493297 atol=0.01
2929
@test_throws ArgumentError cond(a,3)
3030
end
3131
end

stdlib/LinearAlgebra/test/eigen.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ end
163163
end
164164

165165
@testset "eigen of an Adjoint" begin
166-
Random.seed!(1)
166+
Random.seed!(4)
167167
A = randn(3,3)
168168
@test eigvals(A') == eigvals(copy(A'))
169169
@test eigen(A') == eigen(copy(A'))

stdlib/Random/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
33

44
[deps]
55
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
6+
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
67

78
[extras]
89
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

stdlib/Random/docs/src/index.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -151,22 +151,22 @@ Scalar and array methods for `Die` now work as expected:
151151

152152
```jldoctest Die; setup = :(Random.seed!(1))
153153
julia> rand(Die)
154-
Die(7)
154+
Die(5)
155155
156156
julia> rand(MersenneTwister(0), Die)
157157
Die(11)
158158
159159
julia> rand(Die, 3)
160160
3-element Vector{Die}:
161-
Die(13)
162-
Die(8)
163-
Die(20)
161+
Die(9)
162+
Die(15)
163+
Die(14)
164164
165165
julia> a = Vector{Die}(undef, 3); rand!(a)
166166
3-element Vector{Die}:
167-
Die(4)
168-
Die(14)
169-
Die(10)
167+
Die(19)
168+
Die(7)
169+
Die(17)
170170
```
171171

172172
#### A simple sampler without pre-computed data
@@ -183,9 +183,9 @@ julia> rand(Die(4))
183183
184184
julia> rand(Die(4), 3)
185185
3-element Vector{Any}:
186-
3
187186
2
188-
4
187+
3
188+
3
189189
```
190190

191191
Given a collection type `S`, it's currently assumed that if `rand(::S)` is defined, an object of type `eltype(S)` will be produced. In the last example, a `Vector{Any}` is produced; the reason is that `eltype(Die) == Any`. The remedy is to define `Base.eltype(::Type{Die}) = Int`.

stdlib/Random/src/RNGs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ end
384384

385385
seed!(rng::_GLOBAL_RNG, ::Nothing) = seed!(rng) # to resolve ambiguity
386386

387-
seed!(seed::Union{Nothing,Integer,Vector{UInt32},Vector{UInt64},NTuple{4,UInt64}}=nothing) =
387+
seed!(seed::Union{Nothing,Integer,Vector{UInt32},Vector{UInt64}}=nothing) =
388388
seed!(GLOBAL_RNG, seed)
389389

390390
rng_native_52(::_GLOBAL_RNG) = rng_native_52(default_rng())

stdlib/Random/src/Random.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ include("DSFMT.jl")
1313
using .DSFMT
1414
using Base.GMP.MPZ
1515
using Base.GMP: Limb
16+
import SHA
1617

1718
using Base: BitInteger, BitInteger_types, BitUnsigned, require_one_based_indexing
1819

stdlib/Random/src/Xoshiro.jl

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -115,65 +115,21 @@ end
115115

116116
# Shared implementation between Xoshiro and TaskLocalRNG -- seeding
117117

118-
function seed!(x::Union{TaskLocalRNG,Xoshiro})
118+
function seed!(rng::Union{TaskLocalRNG,Xoshiro})
119119
# as we get good randomness from RandomDevice, we can skip hashing
120-
parent = RandomDevice()
121-
# Constants have nothing up their sleeve, see task.c
122-
# 0x02011ce34bce797f == hash(UInt(1))|0x01
123-
# 0x5a94851fb48a6e05 == hash(UInt(2))|0x01
124-
# 0x3688cf5d48899fa7 == hash(UInt(3))|0x01
125-
# 0x867b4bb4c42e5661 == hash(UInt(4))|0x01
126-
setstate!(x,
127-
0x02011ce34bce797f * rand(parent, UInt64),
128-
0x5a94851fb48a6e05 * rand(parent, UInt64),
129-
0x3688cf5d48899fa7 * rand(parent, UInt64),
130-
0x867b4bb4c42e5661 * rand(parent, UInt64))
120+
rd = RandomDevice()
121+
setstate!(rng, rand(rd, UInt64), rand(rd, UInt64), rand(rd, UInt64), rand(rd, UInt64))
131122
end
132123

133-
function seed!(rng::Union{TaskLocalRNG,Xoshiro}, seed::NTuple{4,UInt64})
134-
# TODO: Consider a less ad-hoc construction
135-
# We can afford burning a handful of cycles here, and we don't want any
136-
# surprises with respect to bad seeds / bad interactions.
137-
138-
s0 = s = Base.hash_64_64(seed[1])
139-
s1 = s += Base.hash_64_64(seed[2])
140-
s2 = s += Base.hash_64_64(seed[3])
141-
s3 = s += Base.hash_64_64(seed[4])
142-
124+
function seed!(rng::Union{TaskLocalRNG,Xoshiro}, seed::Union{Vector{UInt32}, Vector{UInt64}})
125+
c = SHA.SHA2_256_CTX()
126+
SHA.update!(c, reinterpret(UInt8, seed))
127+
s0, s1, s2, s3 = reinterpret(UInt64, SHA.digest!(c))
143128
setstate!(rng, s0, s1, s2, s3)
144-
145-
rand(rng, UInt64)
146-
rand(rng, UInt64)
147-
rand(rng, UInt64)
148-
rand(rng, UInt64)
149-
rng
150129
end
151130

152-
function seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::UInt128)
153-
seed0 = seed % UInt64
154-
seed1 = (seed>>>64) % UInt64
155-
seed!(rng, (seed0, seed1, zero(UInt64), zero(UInt64)))
156-
end
157-
seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::Integer) = seed!(rng, UInt128(seed))
158-
159-
function seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::AbstractVector{UInt64})
160-
if length(seed) > 4
161-
throw(ArgumentError("seed should have no more than 256 bits"))
162-
end
163-
seed0 = length(seed)>0 ? seed[1] : UInt64(0)
164-
seed1 = length(seed)>1 ? seed[2] : UInt64(0)
165-
seed2 = length(seed)>2 ? seed[3] : UInt64(0)
166-
seed3 = length(seed)>3 ? seed[4] : UInt64(0)
167-
seed!(rng, (seed0, seed1, seed2, seed3))
168-
end
131+
seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::Integer) = seed!(rng, make_seed(seed))
169132

170-
function seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::AbstractVector{UInt32})
171-
if iseven(length(seed))
172-
seed!(rng, reinterpret(UInt64, seed))
173-
else
174-
seed!(rng, UInt64[reinterpret(UInt64, @view(seed[begin:end-1])); seed[end] % UInt64])
175-
end
176-
end
177133

178134
@inline function rand(rng::Union{TaskLocalRNG, Xoshiro}, ::SamplerType{UInt128})
179135
first = rand(rng, UInt64)

stdlib/Random/src/misc.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ number generator, see [Random Numbers](@ref).
5353
# Examples
5454
```jldoctest
5555
julia> Random.seed!(3); randstring()
56-
"h8BzxSoS"
56+
"Lxz5hUwn"
5757
5858
julia> randstring(MersenneTwister(3), 'a':'z', 6)
5959
"ocucay"
6060
6161
julia> randstring("ACGT")
62-
"CTTACTGC"
62+
"TGCTCCTC"
6363
```
6464
6565
!!! note

0 commit comments

Comments
 (0)