Skip to content

Commit

Permalink
introduce a Pair API (alternative to make)
Browse files Browse the repository at this point in the history
  • Loading branch information
rfourquet committed Sep 9, 2020
1 parent 544d965 commit 38beaf5
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ is omitted). For example, `rand(make(Array, 2, 3), 3)` creates an array of matri
Of course, `make` is not necessary, in that the same can be achieved with an ad hoc `struct`,
which in some cases is clearer (e.g. `Normal(m, s)` rather than something like `make(Float64, Val(:Normal), m, s)`).

As an experimental feature, the following alternative API is available:
- `rand(T => x)` is equivalent to `rand(make(T, x))`
- `rand(T => (x, y, ...))` is equivalent to `rand(make(T, x, y, ...))`

This is for convenience only (it may be more readable), but may be less efficient due to the
fact that the type of a pair containing a type doesn't know this exact type (e.g. `Pair => Int`
has type `Pair{UnionAll,DataType}`), so `rand` can't infer the type of the generated value.
Thanks to inlining, the inferred types can however be sufficiently tight in some cases
(e.g. `rand(Complex => Int, 3)` is of type `Vector{Complex{Int64}}` instead of `Vector{Any}`).

Point 3) allows something like `rand(1:30, Set, 10)` to produce a `Set` of length `10` with values
from `1:30`. The idea is that `rand([rng], [S], Cont, etc...)` should always be equivalent to
`rand([rng], make(Cont, [S], etc...))`. This design goes somewhat against the trend in `Base` to create
Expand Down Expand Up @@ -204,6 +214,12 @@ julia> collect(Iterators.take(Uniform(1:10), 3)) # distributions can be iterated
7
10
5

julia> rand(Complex => Int) # equivalent to rand(make(Complex, Int)) (experimental)
4610038282330316390 + 4899086469899572461im

julia> rand(Pair => (String, Int8)) # equivalent to rand(make(Pair, String, Int8)) (experimental)
"ODNXIePK" => 4
```

In some cases, the `Rand` iterator can provide efficiency gains compared to
Expand Down
23 changes: 22 additions & 1 deletion src/sampling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,14 @@ Sampler(RNG::Type{<:AbstractRNG}, c::Categorical, n::Repetition) =

## random elements from pairs

#= disabled in favor of a special meaning for pairs
Sampler(RNG::Type{<:AbstractRNG}, t::Pair, n::Repetition) =
SamplerSimple(t, Sampler(RNG, Bool, n))
rand(rng::AbstractRNG, sp::SamplerSimple{<:Pair}) =
@inbounds return sp[][1 + rand(rng, sp.data)]

=#

## composite types

Expand Down Expand Up @@ -559,3 +561,22 @@ let b = UInt8['0':'9';'A':'Z';'a':'z'],

rand(rng::AbstractRNG, sp::SamplerTag{Cont{String}}) = String(rand(rng, sp.data.first, sp.data.second))
end


## X => a / X => (a, as...) syntax as an alternative to make(X, a) / make(X, a, as...)

# this is experimental

@inline Sampler(RNG::Type{<:AbstractRNG}, (a, b)::Pair{<:Union{DataType,UnionAll}},
r::Repetition) =
b isa Tuple ?
Sampler(RNG, make(a, b...), r) :
Sampler(RNG, make(a, b), r)

# nothing can be inferred when only the pair type is available
@inline gentype(::Type{<:Pair{<:Union{DataType,UnionAll}}}) = Any

@inline gentype((a, b)::Pair{<:Union{DataType,UnionAll}}) =
b isa Tuple ?
gentype(make(a, b...)) :
gentype(make(a, b))
10 changes: 10 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,16 @@ end
@test rand(make(Float64)) isa Float64
end

@testset "rand(T => x) & rand(T => (x, y, ...))" begin
@test rand(Complex => Int) isa Complex{Int}
@test rand(Pair => (String, Int8)) isa Pair{String,Int8}
@test_throws ArgumentError rand(1=>2) # should not call rand(make(1, 2))

@test rand(Complex => Int, 3) isa Vector{Complex{Int}}
@test rand(Pair => (String, Int8), Set, 3) isa Set{Pair{String,Int8}}
end


## @rand

struct Die
Expand Down

0 comments on commit 38beaf5

Please sign in to comment.