JuliaMath / JuliaMath/MeasureBase.jl

Use `Sampler` interface?

Open
#73 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
Julia
Stars
32
Forks
4
PR merge metrics
No merged PRs in 30d

Description

In a recent Zulip discussion (https://julialang.zulipchat.com/#narrow/stream/137791-general/topic/Static.20code.20blocks/near/289768224), @Seelengrab reminded me of the `Random.Sampler` interface, with this example:
```julia
struct BoundedFloat64
min::Float64
max::Float64
end
Base.eltype(::Type{BoundedFloat64}) = Float64
Base.rand(_::AbstractRNG, b::Random.SamplerTrivial{BoundedFloat64}) = b[].min + (b[].max - b[].min) * rand(Float64)
Random.Sampler(_::Type{<:AbstractRNG}, bf64::BoundedFloat64, r::Random.Repetition) = Random.SamplerTrivial(bf64)
```

This makes it so you can call e.g.
```julia
julia> rand(BoundedFloat64(0.5, 10.0), 3)
3-element Vector{Float64}:
0.8715965799597065
4.250901702717998
0.9709465785383822
```

Our current implementation ignore this interface, instead working entirely in terms of dispatching to `rand`. Our `rand` takes three arguments, with these defaults:
```julia
Base.rand(d::AbstractMeasure) = rand(Random.GLOBAL_RNG, Float64, d)
Base.rand(T::Type, μ::AbstractMeasure) = rand(Random.GLOBAL_RNG, T, μ)
Base.rand(rng::AbstractRNG, d::AbstractMeasure) = rand(rng, Float64, d)

```
Here the type argument in the second position is passed to the "inner" `rand` call. For example,
```julia
julia> using MeasureBase

julia> rand(Float64, StdExponential())
1.8034180730760465

julia> rand(Float32, StdExponential())
2.1787617f0

julia> rand(Float16, StdExponential())
Float16(0.1595)
```

I think it's very useful to keep this kind of flexibility, but it could help to also have thing set up in a way to take advantage of the Sampler interface. It's very new to me and doesn't seem to be well-documented. But maybe we can go from examples or ask for help if we get stuck.

One thing to consider is that we can easily build measures over spaces more complex than a simple scalar or array. To minimize allocations in cases like this, I've previously explored having every `rand` have two steps: an allocation, followed by a call to `rand!` to fill in the values. It's not clear to me if this is the "right" way to do things. As usual in this ecosystem, we need to think a lot about composability and its impact on performance.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.