Mercury-only library for the Mersenne Twister random number generator. This uses a unique random number random.urandom
type class and a shared random type random.random
type class. For each approach, seed(uint32)
function is provided that returns a generator that is seeded as per R’s set.seed()
function.
Many of the random number generators in programming languages are based on a 32-bit Mersenne Twister generator. However, Mercury’s random
type classes default to using a 64-bit random number generators. We have provided a runif(float::out, mt::in, mt::out)
predicate that generates uniform random numbers between 0 and 1 using a 32-bit random number generator to provide the same random numbers as per R’s runif()
function.
Question for Mercury users: is it better to do this as a ground generator or as a unique generator?
:- module test_mt. :- interface. :- import_module io. :- pred main(io::di, io::uo) is det. :- implementation. :- import_module mt, float, list, int, uint32, string, random. :- pred runif(int::in, list(float)::out, random::in, random::out). runif(N, List, !Rng) :- map_foldl((pred(_I::in,U::out,R0::in,R::out) is det :- runif(U, R0, R)), 1..N, List, !Rng). main(!IO) :- print_line("Expected: {0.72090390, 0.07196114}", !IO), seed(12345u32, S0), test(S0, S1, !IO), test(S1, _, !IO), test(S0, _, !IO). :- pred test(random::in, random::out, io::di, io::uo) is det. test(R0, R, !IO) :- N = 624, runif(2*N,Us,R0,R), list.det_index1(Us,1,U1), list.det_index1(Us,2*N,U2), format("Observed: {%10.8f, %10.8f}\n", [f(U1), f(U2)], !IO).
mmc --make test_mt && ./test_mt Expected: {0.72090390, 0.07196114} Observed: {0.72090390, 0.07196114} Observed: {0.76355383, 0.70150276} Observed: {0.72090390, 0.07196114}
set.seed(12345)
runif(624*2)[c(1,624*2)]
runif(624*2)[c(1,624*2)]
set.seed(12345)
runif(624*2)[c(1,624*2)]
[1] 0.72090390 0.07196114 [1] 0.7635538 0.7015028 [1] 0.72090390 0.07196114
:- module mt. :- interface. :- import_module random, uint8, uint16, uint32, uint64. %% Types :- type params. :- type ustate. :- type random == shared_random(params, ustate). :- instance urandom(params, ustate). :- instance urandom_dup(ustate). %% Constructs an instance based on R's set.seed algorithm :- pred seed(uint32::in, params::out, ustate::uo) is det. :- pred seed(uint32::in, random::out) is det. % Generate a uniformly distributed pseudo-random unsigned integer % of 8, 16, 32 or 64 bits, respectively. % :- pred generate_uint8(params::in, uint8::out, ustate::di, ustate::uo) is det. :- pred generate_uint16(params::in, uint16::out, ustate::di, ustate::uo) is det. :- pred generate_uint32(params::in, uint32::out, ustate::di, ustate::uo) is det. :- pred generate_uint64(params::in, uint64::out, ustate::di, ustate::uo) is det. % Duplicate a 32-bit SFC state. % :- pred urandom_dup(ustate::di, ustate::uo, ustate::uo) is det. % Generate a uniformly distributed pseudo-random unsigned integer % of 8, 16, 32 or 64 bits, respectively. % % As above, but does not require the params argument (which is a dummy % type only needed to satisfy the typeclass interface). % :- pred generate_uint8(uint8::out, ustate::di, ustate::uo) is det. :- pred generate_uint16(uint16::out, ustate::di, ustate::uo) is det. :- pred generate_uint32(uint32::out, ustate::di, ustate::uo) is det. :- pred generate_uint64(uint64::out, ustate::di, ustate::uo) is det. :- pred runif(params::in, float::out, ustate::di, ustate::uo) is det. :- pred runif(float::out, random::in, random::out) is det.