diff --git a/doc/src/devdocs/subarrays.md b/doc/src/devdocs/subarrays.md index 02e75fa00ec48..cec7a64a65245 100644 --- a/doc/src/devdocs/subarrays.md +++ b/doc/src/devdocs/subarrays.md @@ -19,14 +19,14 @@ julia> A = rand(2,3,4); julia> S1 = view(A, :, 1, 2:3) 2×2 view(::Array{Float64, 3}, :, 1, 2:3) with eltype Float64: - 0.342284 0.831961 - 0.237287 0.435938 + 0.839622 0.711389 + 0.967143 0.103929 julia> S2 = view(A, 1, :, 2:3) 3×2 view(::Array{Float64, 3}, 1, :, 2:3) with eltype Float64: - 0.342284 0.831961 - 0.988944 0.927795 - 0.178426 0.404876 + 0.839622 0.711389 + 0.789764 0.806704 + 0.566704 0.962715 ``` ```@meta DocTestSetup = nothing diff --git a/doc/src/manual/performance-tips.md b/doc/src/manual/performance-tips.md index 542166bb248cf..13990769259da 100644 --- a/doc/src/manual/performance-tips.md +++ b/doc/src/manual/performance-tips.md @@ -77,12 +77,12 @@ julia> function sum_global() end; julia> @time sum_global() - 0.010414 seconds (9.07 k allocations: 373.448 KiB, 98.40% compilation time) -493.6199223951192 + 0.011539 seconds (9.08 k allocations: 373.386 KiB, 98.69% compilation time) +523.0007221951678 julia> @time sum_global() - 0.000108 seconds (3.49 k allocations: 70.156 KiB) -493.6199223951192 + 0.000091 seconds (3.49 k allocations: 70.156 KiB) +523.0007221951678 ``` 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) end; julia> @time sum_arg(x) - 0.007971 seconds (3.96 k allocations: 200.171 KiB, 99.83% compilation time) -493.6199223951192 + 0.007551 seconds (3.98 k allocations: 200.548 KiB, 99.77% compilation time) +523.0007221951678 julia> @time sum_arg(x) - 0.000003 seconds (1 allocation: 16 bytes) -493.6199223951192 + 0.000006 seconds (1 allocation: 16 bytes) +523.0007221951678 ``` 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: julia> time_sum(x) = @time sum_arg(x); julia> time_sum(x) - 0.000001 seconds -493.6199223951192 + 0.000002 seconds +523.0007221951678 ``` In some situations, your function may need to allocate memory as part of its operation, and this diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index d6d882fabc65b..2f61c8af403e3 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -22,10 +22,10 @@ Random.seed!(1234323) @testset "for $elty" for elty in (Float32, Float64, ComplexF32, ComplexF64) ainit = convert(Matrix{elty}, ainit) for a in (copy(ainit), view(ainit, 1:n, 1:n)) - @test cond(a,1) ≈ 122.15725126320953 atol=0.5 - @test cond(a,2) ≈ 78.44837047684149 atol=0.5 - @test cond(a,Inf) ≈ 174.10761543202744 atol=0.4 - @test cond(a[:,1:5]) ≈ 6.7492840150789135 atol=0.01 + @test cond(a,1) ≈ 198.3324294531168 atol=0.5 + @test cond(a,2) ≈ 85.93920079319506 atol=0.5 + @test cond(a,Inf) ≈ 149.7523084803039 atol=0.4 + @test cond(a[:,1:5]) ≈ 8.319279144493297 atol=0.01 @test_throws ArgumentError cond(a,3) end end diff --git a/stdlib/LinearAlgebra/test/eigen.jl b/stdlib/LinearAlgebra/test/eigen.jl index c1bba4de4f0ee..4ee1845ecc385 100644 --- a/stdlib/LinearAlgebra/test/eigen.jl +++ b/stdlib/LinearAlgebra/test/eigen.jl @@ -163,7 +163,7 @@ end end @testset "eigen of an Adjoint" begin - Random.seed!(1) + Random.seed!(4) A = randn(3,3) @test eigvals(A') == eigvals(copy(A')) @test eigen(A') == eigen(copy(A')) diff --git a/stdlib/Random/Project.toml b/stdlib/Random/Project.toml index 6958e618d3ea8..199dcab940c86 100644 --- a/stdlib/Random/Project.toml +++ b/stdlib/Random/Project.toml @@ -3,6 +3,7 @@ uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [deps] Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/Random/docs/src/index.md b/stdlib/Random/docs/src/index.md index a78b08ea89295..6750dd35b40f7 100644 --- a/stdlib/Random/docs/src/index.md +++ b/stdlib/Random/docs/src/index.md @@ -151,22 +151,22 @@ Scalar and array methods for `Die` now work as expected: ```jldoctest Die; setup = :(Random.seed!(1)) julia> rand(Die) -Die(7) +Die(5) julia> rand(MersenneTwister(0), Die) Die(11) julia> rand(Die, 3) 3-element Vector{Die}: - Die(13) - Die(8) - Die(20) + Die(9) + Die(15) + Die(14) julia> a = Vector{Die}(undef, 3); rand!(a) 3-element Vector{Die}: - Die(4) - Die(14) - Die(10) + Die(19) + Die(7) + Die(17) ``` #### A simple sampler without pre-computed data @@ -183,9 +183,9 @@ julia> rand(Die(4)) julia> rand(Die(4), 3) 3-element Vector{Any}: - 3 2 - 4 + 3 + 3 ``` 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`. diff --git a/stdlib/Random/src/RNGs.jl b/stdlib/Random/src/RNGs.jl index c483296fe3af1..141ec14f4ed31 100644 --- a/stdlib/Random/src/RNGs.jl +++ b/stdlib/Random/src/RNGs.jl @@ -384,7 +384,7 @@ end seed!(rng::_GLOBAL_RNG, ::Nothing) = seed!(rng) # to resolve ambiguity -seed!(seed::Union{Nothing,Integer,Vector{UInt32},Vector{UInt64},NTuple{4,UInt64}}=nothing) = +seed!(seed::Union{Nothing,Integer,Vector{UInt32},Vector{UInt64}}=nothing) = seed!(GLOBAL_RNG, seed) rng_native_52(::_GLOBAL_RNG) = rng_native_52(default_rng()) diff --git a/stdlib/Random/src/Random.jl b/stdlib/Random/src/Random.jl index 45aa6442eed7e..05fe872eb6ebc 100644 --- a/stdlib/Random/src/Random.jl +++ b/stdlib/Random/src/Random.jl @@ -13,6 +13,7 @@ include("DSFMT.jl") using .DSFMT using Base.GMP.MPZ using Base.GMP: Limb +import SHA using Base: BitInteger, BitInteger_types, BitUnsigned, require_one_based_indexing diff --git a/stdlib/Random/src/Xoshiro.jl b/stdlib/Random/src/Xoshiro.jl index d39a41276a7e1..af1a5668507db 100644 --- a/stdlib/Random/src/Xoshiro.jl +++ b/stdlib/Random/src/Xoshiro.jl @@ -117,65 +117,21 @@ end # Shared implementation between Xoshiro and TaskLocalRNG -- seeding -function seed!(x::Union{TaskLocalRNG,Xoshiro}) +function seed!(rng::Union{TaskLocalRNG,Xoshiro}) # as we get good randomness from RandomDevice, we can skip hashing - parent = RandomDevice() - # Constants have nothing up their sleeve, see task.c - # 0x02011ce34bce797f == hash(UInt(1))|0x01 - # 0x5a94851fb48a6e05 == hash(UInt(2))|0x01 - # 0x3688cf5d48899fa7 == hash(UInt(3))|0x01 - # 0x867b4bb4c42e5661 == hash(UInt(4))|0x01 - setstate!(x, - 0x02011ce34bce797f * rand(parent, UInt64), - 0x5a94851fb48a6e05 * rand(parent, UInt64), - 0x3688cf5d48899fa7 * rand(parent, UInt64), - 0x867b4bb4c42e5661 * rand(parent, UInt64)) + rd = RandomDevice() + setstate!(rng, rand(rd, UInt64), rand(rd, UInt64), rand(rd, UInt64), rand(rd, UInt64)) end -function seed!(rng::Union{TaskLocalRNG,Xoshiro}, seed::NTuple{4,UInt64}) - # TODO: Consider a less ad-hoc construction - # We can afford burning a handful of cycles here, and we don't want any - # surprises with respect to bad seeds / bad interactions. - - s0 = s = Base.hash_64_64(seed[1]) - s1 = s += Base.hash_64_64(seed[2]) - s2 = s += Base.hash_64_64(seed[3]) - s3 = s += Base.hash_64_64(seed[4]) - +function seed!(rng::Union{TaskLocalRNG,Xoshiro}, seed::Union{Vector{UInt32}, Vector{UInt64}}) + c = SHA.SHA2_256_CTX() + SHA.update!(c, reinterpret(UInt8, seed)) + s0, s1, s2, s3 = reinterpret(UInt64, SHA.digest!(c)) setstate!(rng, s0, s1, s2, s3) - - rand(rng, UInt64) - rand(rng, UInt64) - rand(rng, UInt64) - rand(rng, UInt64) - rng end -function seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::UInt128) - seed0 = seed % UInt64 - seed1 = (seed>>>64) % UInt64 - seed!(rng, (seed0, seed1, zero(UInt64), zero(UInt64))) -end -seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::Integer) = seed!(rng, UInt128(seed)) - -function seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::AbstractVector{UInt64}) - if length(seed) > 4 - throw(ArgumentError("seed should have no more than 256 bits")) - end - seed0 = length(seed)>0 ? seed[1] : UInt64(0) - seed1 = length(seed)>1 ? seed[2] : UInt64(0) - seed2 = length(seed)>2 ? seed[3] : UInt64(0) - seed3 = length(seed)>3 ? seed[4] : UInt64(0) - seed!(rng, (seed0, seed1, seed2, seed3)) -end +seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::Integer) = seed!(rng, make_seed(seed)) -function seed!(rng::Union{TaskLocalRNG, Xoshiro}, seed::AbstractVector{UInt32}) - if iseven(length(seed)) - seed!(rng, reinterpret(UInt64, seed)) - else - seed!(rng, UInt64[reinterpret(UInt64, @view(seed[begin:end-1])); seed[end] % UInt64]) - end -end @inline function rand(rng::Union{TaskLocalRNG, Xoshiro}, ::SamplerType{UInt128}) first = rand(rng, UInt64) diff --git a/stdlib/Random/src/misc.jl b/stdlib/Random/src/misc.jl index 2dff5a51eff9a..0d6e06c444a09 100644 --- a/stdlib/Random/src/misc.jl +++ b/stdlib/Random/src/misc.jl @@ -53,13 +53,13 @@ number generator, see [Random Numbers](@ref). # Examples ```jldoctest julia> Random.seed!(3); randstring() -"h8BzxSoS" +"Lxz5hUwn" julia> randstring(MersenneTwister(3), 'a':'z', 6) "ocucay" julia> randstring("ACGT") -"CTTACTGC" +"TGCTCCTC" ``` !!! note diff --git a/stdlib/Random/test/runtests.jl b/stdlib/Random/test/runtests.jl index 1995a9efbc471..8ba7c5fc26663 100644 --- a/stdlib/Random/test/runtests.jl +++ b/stdlib/Random/test/runtests.jl @@ -688,7 +688,7 @@ end @testset "$RNG(seed) & Random.seed!(m::$RNG, seed) produce the same stream" for RNG=(MersenneTwister,Xoshiro) seeds = Any[0, 1, 2, 10000, 10001, rand(UInt32, 8), rand(UInt128, 3)...] if RNG == Xoshiro - push!(seeds, rand(UInt64, rand(1:4)), Tuple(rand(UInt64, 4))) + push!(seeds, rand(UInt64, rand(1:4))) end for seed=seeds m = RNG(seed) @@ -699,7 +699,7 @@ end end @testset "Random.seed!(seed) sets Random.GLOBAL_SEED" begin - seeds = Any[0, rand(UInt128), rand(UInt64, 4), Tuple(rand(UInt64, 4))] + seeds = Any[0, rand(UInt128), rand(UInt64, 4)] for seed=seeds Random.seed!(seed) diff --git a/stdlib/SparseArrays/src/sparsematrix.jl b/stdlib/SparseArrays/src/sparsematrix.jl index 5287da8d959a0..ea8a8f0b442e2 100644 --- a/stdlib/SparseArrays/src/sparsematrix.jl +++ b/stdlib/SparseArrays/src/sparsematrix.jl @@ -1642,12 +1642,13 @@ argument specifies a random number generator, see [Random Numbers](@ref). ```jldoctest; setup = :(using Random; Random.seed!(1234)) julia> sprand(Bool, 2, 2, 0.5) 2×2 SparseMatrixCSC{Bool, Int64} with 2 stored entries: - 1 ⋅ - ⋅ 1 + 1 1 + ⋅ ⋅ julia> sprand(Float64, 3, 0.75) -3-element SparseVector{Float64, Int64} with 1 stored entry: - [3] = 0.787459 +3-element SparseVector{Float64, Int64} with 2 stored entries: + [1] = 0.795547 + [2] = 0.49425 ``` """ function sprand(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat, rfn::Function, ::Type{T}=eltype(rfn(r, 1))) where T @@ -1688,9 +1689,9 @@ argument specifies a random number generator, see [Random Numbers](@ref). # Examples ```jldoctest; setup = :(using Random; Random.seed!(0)) julia> sprandn(2, 2, 0.75) -2×2 SparseMatrixCSC{Float64, Int64} with 1 stored entry: - ⋅ ⋅ - ⋅ 1.32078 +2×2 SparseMatrixCSC{Float64, Int64} with 3 stored entries: + -1.20577 ⋅ + 0.311817 -0.234641 ``` """ sprandn(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat) = diff --git a/stdlib/SparseArrays/test/sparse.jl b/stdlib/SparseArrays/test/sparse.jl index bc8e3f15a0ec7..128bb4735f063 100644 --- a/stdlib/SparseArrays/test/sparse.jl +++ b/stdlib/SparseArrays/test/sparse.jl @@ -1750,7 +1750,7 @@ end A = guardseed(1234321) do triu(sprand(10, 10, 0.2)) end - @test getcolptr(SparseArrays.droptol!(A, 0.01)) == [1, 1, 3, 4, 5, 6, 7, 11, 13, 15, 18] + @test getcolptr(SparseArrays.droptol!(A, 0.01)) == [1, 1, 1, 1, 2, 2, 2, 4, 4, 5, 5] @test isequal(SparseArrays.droptol!(sparse([1], [1], [1]), 1), SparseMatrixCSC(1, 1, Int[1, 1], Int[], Int[])) end