# Generate next random value based on a given statistical distribution in julia?

``````mutable struct DistrRng{T<:Sampleable}
d::T
rng::MersenneTwister

function DistrRng(d::T, rng::MersenneTwister) where T <: Sampleable
return new{T}(d, deepcopy(rng))
end
function DistrRng(d::T; seed::Int = nullIndex) where T <: Sampleable
rng = (seed >= 0 ? MersenneTwister(seed) : MersenneTwister(rand(UInt32)))
return new{T}(d, rng)
end
end

global GlobalRngBackup = MersenneTwister(0);

function copyRng!(dest::MersenneTwister, src::MersenneTwister)

dest.seed = src.seed
dest.state = src.state
dest.vals = src.vals
dest.ints = src.ints
dest.idxF = src.idxF
dest.idxI = src.idxI

end

function Base.rand(distrRng::DistrRng, n::Int)
rng = distrRng.rng # shorthand
copyRng!(GlobalRngBackup, GLOBAL_RNG)
copyRng!(GLOBAL_RNG, rng)
value = rand(distrRng.d, n)
copyRng!(rng, GLOBAL_RNG)
copyRng!(GLOBAL_RNG, GlobalRngBackup)
return value
end
function Base.rand(distrRng::DistrRng)
return rand(distrRng, 1)[1]
end
``````

The above is a very interesting piece of code to randomly generate a number following a given probability distribution sampler and random number generator, with the help of rewriting the default `Base.rand` functions. I only have a few confusing points as the following.
1: In the first inner constructor inside of the `mutable struct DistrRng`, `deepcopy` is used. Then, in the function `copyRng!`, apparently, a simple reassignment is used. I was wondering, why is this?
2: Is there a better way to accomplish this, besides rewriting this `Base.rand()` function?

You should probably ask the author of the algorithm.

But this code looks weird, with all that copying back and forth. It is unclear why that is needed, or what it is supposed to accomplish. It is generally best to just provide `rng`s to functions that use randomness explicitly, with the understanding that they may be mutated in an unpredictable manner, and not rely on the specifics.

1 Like

@Tamas_Papp, thanks for replying. Here is my understanding. The key function, based on my understanding, is the `Base.rand(distrRng::DistrRng, n::Int)` function. The intended goal is to generate next random value using the `d` attribute (which is for the statistical distribution) of the defined DistrRng type, and the random number generator, which is `rng` attribute of the defined DistrRng type. The author is trying to use the provided `rand` function in the `Base` module/library. Since `Base.rand(::AbstractRNG, ::Distribution)` does not exist for all distributions, the author uses the provided `Base.rand(::Distribution)`, indeed, itâ€™s `rand(distrRng.d,n)` inside of the `Base.rand(distrRng::DistrRng, n::Int)` to generate the next random number with distribution in distrRng, and with RNG in â€śGLOBAL_RNGâ€ť. Thatâ€™s why the copying back and forth, before and after calling the `rand(distrRng.d,n)` function.

FWIW, I am still not getting what is going on here, but as I said, you should probably talk to the author.

Also, it may be better to just formulate a question about what you want to do, instead of trying to figure out what someoneâ€™s code does. Doing that without context is particularly difficult.

If you are trying to implement another RNG, there is some documentation, even though the API is not finalized yet. In particular, an RNG should define a few particular `rand` methods for bits types, the rest is optimization.

1 Like