Skip to content

Commit

Permalink
Merge pull request #25278 from JuliaLang/rf/rand/fromtuples
Browse files Browse the repository at this point in the history
add rand(::Tuple)
  • Loading branch information
rfourquet authored Dec 4, 2018
2 parents d8558ee + 3ba74d6 commit 5976236
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 12 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Standard library changes
* `Base.tail` now works on named tuples ([#29595]).
* `randperm` and `randcycle` now use the type of their argument to determine the element type of
the returned array ([#29670]).
* A new method `rand(::Tuple)` implements sampling from the values of a tuple ([#25278]).

Compiler/Runtime improvements
-----------------------------
Expand Down
7 changes: 3 additions & 4 deletions stdlib/Random/src/Random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ rand(rng::AbstractRNG, ::UniformT{T}) where {T} = rand(rng, T)
#### scalars

rand(rng::AbstractRNG, X) = rand(rng, Sampler(rng, X, Val(1)))
# this is needed to disambiguate
rand(rng::AbstractRNG, X::Dims) = rand(rng, Sampler(rng, X, Val(1)))
rand(rng::AbstractRNG=GLOBAL_RNG, ::Type{X}=Float64) where {X} = rand(rng, Sampler(rng, X, Val(1)))

rand(X) = rand(GLOBAL_RNG, X)
Expand Down Expand Up @@ -249,9 +251,6 @@ rand( X, d::Integer, dims::Integer...) = rand(X, Dims((d, dims...
# rand(r, ()) would match both this method and rand(r, dims::Dims)
# moreover, a call like rand(r, NotImplementedType()) would be an infinite loop

# this is needed to disambiguate
rand(r::AbstractRNG, dims::Dims) = error("rand(rng, dims) is discontinued; try rand(rng, Float64, dims)")

rand(r::AbstractRNG, ::Type{X}, dims::Dims) where {X} = rand!(r, Array{X}(undef, dims), X)
rand( ::Type{X}, dims::Dims) where {X} = rand(GLOBAL_RNG, X, dims)

Expand Down Expand Up @@ -283,7 +282,7 @@ include("misc.jl")
Pick a random element or array of random elements from the set of values specified by `S`;
`S` can be
* an indexable collection (for example `1:n` or `['x','y','z']`),
* an indexable collection (for example `1:9` or `('x', "y", :z)`),
* an `AbstractDict` or `AbstractSet` object,
* a string (considered as a collection of characters), or
* a type: the set of values to pick from is then equivalent to `typemin(S):typemax(S)` for
Expand Down
51 changes: 51 additions & 0 deletions stdlib/Random/src/generation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -430,3 +430,54 @@ function rand(rng::AbstractRNG, sp::SamplerSimple{<:AbstractString,<:Sampler})::
isvalid_unsafe(str, pos) && return str[pos]
end
end


## random elements from tuples

### 1

Sampler(::Type{<:AbstractRNG}, t::Tuple{A}, ::Repetition) where {A} =
SamplerTrivial(t)

rand(rng::AbstractRNG, sp::SamplerTrivial{Tuple{A}}) where {A} =
@inbounds return sp[][1]

### 2

Sampler(RNG::Type{<:AbstractRNG}, t::Tuple{A,B}, n::Repetition) where {A,B} =
SamplerSimple(t, Sampler(RNG, Bool, n))

rand(rng::AbstractRNG, sp::SamplerSimple{Tuple{A,B}}) where {A,B} =
@inbounds return sp[][1 + rand(rng, sp.data)]

### 3

Sampler(RNG::Type{<:AbstractRNG}, t::Tuple{A,B,C}, n::Repetition) where {A,B,C} =
SamplerSimple(t, Sampler(RNG, UInt52(), n))

function rand(rng::AbstractRNG, sp::SamplerSimple{Tuple{A,B,C}}) where {A,B,C}
local r
while true
r = rand(rng, sp.data)
r != 0x000fffffffffffff && break # _very_ likely
end
@inbounds return sp[][1 + r ÷ 0x0005555555555555]
end

### 4

Sampler(RNG::Type{<:AbstractRNG}, t::Tuple{A,B,C,D}, n::Repetition) where {A,B,C,D} =
SamplerSimple(t, Sampler(RNG, UInt52Raw(Int), n))

function rand(rng::AbstractRNG, sp::SamplerSimple{Tuple{A,B,C,D}}) where {A,B,C,D}
r = rand(rng, sp.data) & 3
@inbounds return sp[][1 + r]
end

### n

Sampler(RNG::Type{<:AbstractRNG}, t::Tuple, n::Repetition) =
SamplerSimple(t, Sampler(RNG, Base.OneTo(length(t)), n))

rand(rng::AbstractRNG, sp::SamplerSimple{<:Tuple}) =
@inbounds return sp[][rand(rng, sp.data)]
11 changes: 11 additions & 0 deletions stdlib/Random/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -702,3 +702,14 @@ end
a = rand(Int, 1)
@test shuffle(a) == a
end

@testset "rand(::Tuple)" begin
for x in (0x1, 1)
@test rand((x,)) == 0x1
@test rand((x, 2)) 1:2
@test rand((x, 2, 3)) 1:3
@test rand((x, 2, 3, 4)) 1:4
@test rand((x, 2, 3, 4, 5)) 1:5
@test rand((x, 2, 3, 4, 6)) 1:6
end
end
11 changes: 3 additions & 8 deletions stdlib/SparseArrays/src/linalg.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

import LinearAlgebra: checksquare
using Random: rand!

## sparse matrix multiplication

Expand Down Expand Up @@ -929,12 +930,6 @@ function opnormestinv(A::SparseMatrixCSC{T}, t::Integer = min(2,maximum(size(A))

S = zeros(T <: Real ? Int : Ti, n, t)

function _rand_pm1!(v)
for i in eachindex(v)
v[i] = rand()<0.5 ? 1 : -1
end
end

function _any_abs_eq(v,n::Int)
for vv in v
if abs(vv)==n
Expand All @@ -949,7 +944,7 @@ function opnormestinv(A::SparseMatrixCSC{T}, t::Integer = min(2,maximum(size(A))
X[1:n,1] .= 1
for j = 2:t
while true
_rand_pm1!(view(X,1:n,j))
rand!(view(X,1:n,j), (-1, 1))
yaux = X[1:n,j]' * X[1:n,1:j-1]
if !_any_abs_eq(yaux,n)
break
Expand Down Expand Up @@ -1010,7 +1005,7 @@ function opnormestinv(A::SparseMatrixCSC{T}, t::Integer = min(2,maximum(size(A))
end
end
if repeated
_rand_pm1!(view(S,1:n,j))
rand!(view(S,1:n,j), (-1, 1))
else
break
end
Expand Down

0 comments on commit 5976236

Please sign in to comment.