Some corehydro verbs call a function you write and hand it the seeded random number generator
the run is using: the proposal function of a Gibbs sampler, the resample function of a
bootstrap. rng_uniform() and rng_integers() are how that generator is drawn from.
Arguments
- rng
the handle your callback was given. It cannot be created any other way.
- n
how many values to draw; a single positive whole number. A fractional
nis an error, not a silent truncation, and the identical call in Python is refused the same way.- min, max
the bounds for
rng_integers().minis included andmaxis EXCLUDED, matching the ported NumericsNext(minInclusive, maxExclusive)a C# proposal is written against, sorng_integers(rng, 1, 0, 10)draws one of0:9. Both must be whole numbers, and the range between them can be at most 2147483647 wide (the ported generator draws an integer span, and C# throws for a wider one).
Value
rng_uniform() a numeric vector of length n with values in [0, 1);
rng_integers() an integer vector of length n.
Details
Use them for every random number your callback needs. Reaching for R's own generator
(stats::runif(), base::sample()) instead is not an error and will not be caught, but it
silently breaks two guarantees corehydro otherwise makes: the run stops being reproducible from
its seed, and it stops agreeing with the identical run in Python. The handle draws from the same
Mersenne Twister the core seeded, so both hold.
Lifetime
The handle borrows the generator for the duration of the one call it was given to. It is not an object to keep. Storing it and drawing from it after your callback has returned raises an error ("this random number generator handle is no longer valid"), which is deliberate: the generator it pointed at no longer exists, and reading it would crash the session rather than merely misbehave.
See also
mcmc_posterior(), whose proposal argument is the verb that hands you a handle, and
stats::runif() for ordinary R random numbers, which is what to use anywhere OUTSIDE a
corehydro callback.
Examples
# The Gibbs proposal is the surface that hands you a handle. This model's full conditional
# really is uniform: with x_i ~ Uniform(mu - 1, mu + 1) and a flat prior, mu given the data is
# Uniform(max(x) - 1, min(x) + 1), so one uniform draw IS the Gibbs step.
x <- c(4.9, 5.1, 5.0, 5.2, 4.8)
ll <- function(p) if (all(abs(x - p[1]) <= 1)) 0 else -Inf
proposal <- function(parameters, rng) {
lo <- max(x) - 1
hi <- min(x) + 1
lo + rng_uniform(rng, 1) * (hi - lo)
}
fit <- mcmc_posterior(ll, distribution("Uniform", c(0, 10)),
sampler = "Gibbs", proposal = proposal,
iterations = 200, seed = 12345, initialize = "Randomize")
fit$posterior_mean
#> [1] 5.003371
# rng_integers() draws whole numbers on [min, max) off the same stream -- a resampling
# proposal, say, picking one of the observations by index.
pick_one <- function(parameters, rng) x[rng_integers(rng, 1, 1, length(x) + 1)]
mcmc_posterior(ll, distribution("Uniform", c(0, 10)),
sampler = "Gibbs", proposal = pick_one,
iterations = 200, seed = 12345, initialize = "Randomize")$posterior_mean
#> [1] 4.9992