star-sp

Random number generators and distributions
git clone git://git.meso-star.fr/star-sp.git
Log | Files | Refs | README | LICENSE

commit 2a2c2572b07857b108d983feab45c27ab2470f41
parent 8b1aa179a7ed924669914eebdbb7a238500b0645
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Tue, 25 Aug 2015 14:35:46 +0200

Add the new discard() API call

And use it when building state of proxy generators

Diffstat:
Msrc/ssp.h | 7+++++++
Msrc/ssp_rng.c | 40++++++++++++++++++++++++++++++++++++++++
Msrc/ssp_rng_proxy.c | 17+++++++++++++++--
Msrc/test_ssp_rng.c | 12++++++++++++
Msrc/test_ssp_rng_proxy.c | 16++++++++++++++++
5 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/src/ssp.h b/src/ssp.h @@ -68,6 +68,7 @@ struct ssp_rng_type { res_T (*set)(void* state, const uint64_t seed); uint64_t (*get)(void* state); + res_T(*discard)(void* state, uint64_t n); uint64_t (*uniform_uint64)(void* state, const uint64_t min, const uint64_t max); double (*uniform_double)(void* state, const double min, const double max); double (*canonical)(void* state); @@ -130,6 +131,12 @@ SSP_API uint64_t ssp_rng_get (struct ssp_rng* rng); +/* Advances the internal state by n times. + Equivalent to calling ssp_rng_get() n times and discarding the result */ +SSP_API res_T +ssp_rng_discard + (struct ssp_rng* rng, uint64_t n); + /* Uniform random integer distribution in [lower, upper) */ SSP_API uint64_t ssp_rng_uniform_uint64 diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -178,12 +178,22 @@ rng_kiss_entropy(const void* data) return 0.; } +static res_T +rng_kiss_discard(void* data, uint64_t n) +{ + while (n-- > 0) { + rng_kiss_get(data); + } + return RES_OK; +} + /* Exported type */ const struct ssp_rng_type ssp_rng_kiss = { rng_kiss_init, rng_kiss_release, rng_kiss_set, rng_kiss_get, + rng_kiss_discard, rng_kiss_uniform_uint64, rng_kiss_uniform_double, rng_kiss_canonical, @@ -329,6 +339,24 @@ rng_cxx_entropy(const void* data) return 0; } +template<typename RNG> +res_T +rng_cxx_discard(void* data, uint64_t n) +{ + RNG* rng = (RNG*) data; + ASSERT(rng); + rng->discard(n); + return RES_OK; +} + +template<> +res_T +rng_cxx_discard<RAN_NAMESPACE::random_device>(void* data, uint64_t n) +{ + (void) data; (void) n; + return RES_BAD_OP; +} + template<> double rng_cxx_entropy<RAN_NAMESPACE::random_device>(const void* data) @@ -345,6 +373,7 @@ const struct ssp_rng_type ssp_rng_mt19937_64 = { rng_cxx_release<RAN_NAMESPACE::mt19937_64>, rng_cxx_set<RAN_NAMESPACE::mt19937_64>, rng_cxx_get<RAN_NAMESPACE::mt19937_64>, + rng_cxx_discard<RAN_NAMESPACE::mt19937_64>, rng_cxx_uniform_uint64<RAN_NAMESPACE::mt19937_64>, rng_cxx_uniform_double<RAN_NAMESPACE::mt19937_64>, rng_cxx_canonical<RAN_NAMESPACE::mt19937_64>, @@ -362,6 +391,7 @@ const struct ssp_rng_type ssp_rng_ranlux48 = { rng_cxx_release<RAN_NAMESPACE::ranlux48>, rng_cxx_set<RAN_NAMESPACE::ranlux48>, rng_cxx_get<RAN_NAMESPACE::ranlux48>, + rng_cxx_discard<RAN_NAMESPACE::ranlux48>, rng_cxx_uniform_uint64<RAN_NAMESPACE::ranlux48>, rng_cxx_uniform_double<RAN_NAMESPACE::ranlux48>, rng_cxx_canonical<RAN_NAMESPACE::ranlux48>, @@ -379,6 +409,7 @@ const struct ssp_rng_type ssp_rng_random_device = { rng_cxx_release<RAN_NAMESPACE::random_device>, rng_cxx_set<RAN_NAMESPACE::random_device>, rng_cxx_get<RAN_NAMESPACE::random_device>, + rng_cxx_discard<RAN_NAMESPACE::random_device>, rng_cxx_uniform_uint64<RAN_NAMESPACE::random_device>, rng_cxx_uniform_double<RAN_NAMESPACE::random_device>, rng_cxx_canonical<RAN_NAMESPACE::random_device>, @@ -419,6 +450,7 @@ const struct ssp_rng_type ssp_rng_threefry = { rng_cxx_release<threefry_T>, rng_cxx_set<threefry_T>, rng_cxx_get<threefry_T>, + rng_cxx_discard<threefry_T>, rng_cxx_uniform_uint64<threefry_T>, rng_cxx_uniform_double<threefry_T>, rng_cxx_canonical<threefry_T>, @@ -437,6 +469,7 @@ const struct ssp_rng_type ssp_rng_aes = { rng_cxx_release<aes_T>, rng_cxx_set<aes_T>, rng_cxx_get<aes_T>, + rng_cxx_discard<aes_T>, rng_cxx_uniform_uint64<aes_T>, rng_cxx_uniform_double<aes_T>, rng_cxx_canonical<aes_T>, @@ -622,6 +655,13 @@ ssp_rng_entropy(const struct ssp_rng* rng) return rng->type.entropy(rng->state); } +res_T +ssp_rng_discard(struct ssp_rng* rng, uint64_t n) +{ + if (!rng) FATAL("The Random Number Generator is NULL\n"); + return rng->type.discard(rng->state, n); +} + /******************************************************************************* * Exported distributions ******************************************************************************/ diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c @@ -262,11 +262,25 @@ rng_bucket_entropy(const void* data) return 0; } +static res_T +rng_bucket_discard(void* data, uint64_t n) +{ + struct rng_bucket* rng = (struct rng_bucket*)data; + ASSERT(data); + while (rng->count <= n) { + n -= rng->count; + rng_bucket_next_ran_pool(rng); + } + rng->count -= n; + return ssp_rng_discard(rng->pool, n); +} + static const struct ssp_rng_type RNG_BUCKET_NULL = { rng_bucket_init, rng_bucket_release, rng_bucket_set, rng_bucket_get, + rng_bucket_discard, rng_bucket_uniform_uint64, rng_bucket_uniform_double, rng_bucket_canonical, @@ -295,10 +309,9 @@ rng_proxy_next_ran_pool size_t ibucket; /* Register a new state for *all* buckets */ FOR_EACH(ibucket, 0, sa_size(proxy->states)) { - size_t irand; res = rng_state_cache_write(proxy->states + ibucket, proxy->rng); if(res != RES_OK) FATAL("RNG proxy: cannot write to state cache\n"); - FOR_EACH(irand, 0, BUCKET_SIZE) ssp_rng_get(proxy->rng); /* Discard */ + ssp_rng_discard(proxy->rng, BUCKET_SIZE); } } diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c @@ -42,6 +42,7 @@ test_rng(const struct ssp_rng_type* type) { FILE* stream; struct ssp_rng* rng; + struct ssp_rng* rng1, * rng2; struct mem_allocator allocator; struct time t0, t1; uint64_t datai0[NRAND]; @@ -53,6 +54,7 @@ test_rng(const struct ssp_rng_type* type) const char can_set = (type != &ssp_rng_random_device); const char can_rw = (type != &ssp_rng_random_device); const char can_have_entropy = (type == &ssp_rng_random_device); + const char can_discard = (type != &ssp_rng_random_device); mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -82,6 +84,14 @@ test_rng(const struct ssp_rng_type* type) CHECK(ssp_rng_set(NULL, 0), RES_BAD_ARG); CHECK(ssp_rng_set(rng, 0), can_set ? RES_OK : RES_BAD_OP); + ssp_rng_create(NULL, type, &rng1); + ssp_rng_create(NULL, type, &rng2); + CHECK(ssp_rng_discard(rng1, 10), can_discard ? RES_OK : RES_BAD_OP); + if (type != &ssp_rng_random_device) { + for (i = 0; i < 10; i++) ssp_rng_get(rng2); + CHECK(ssp_rng_get(rng1), ssp_rng_get(rng2)); + } + FOR_EACH(i, 0, NRAND) { datai0[i] = ssp_rng_get(rng); CHECK(datai0[i] >= ssp_rng_min(rng), 1); @@ -171,6 +181,8 @@ test_rng(const struct ssp_rng_type* type) fclose(stream); CHECK(ssp_rng_ref_put(rng), RES_OK); + ssp_rng_ref_put(rng1); + ssp_rng_ref_put(rng2); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); } diff --git a/src/test_ssp_rng_proxy.c b/src/test_ssp_rng_proxy.c @@ -35,7 +35,9 @@ int main(int argc, char** argv) { struct ssp_rng_proxy* proxy; + struct ssp_rng_proxy* proxy1, *proxy2; struct ssp_rng* rng[4]; + struct ssp_rng* rng1[4], * rng2[4]; struct mem_allocator allocator; size_t i = 0; (void)argc, (void)argv; @@ -84,7 +86,21 @@ main(int argc, char** argv) } } + CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 4, &proxy1), RES_OK); + CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 4, &proxy2), RES_OK); + FOR_EACH(i, 0, 4) { + CHECK(ssp_rng_proxy_create_rng(proxy1, i, &rng1[i]), RES_OK); + CHECK(ssp_rng_proxy_create_rng(proxy2, i, &rng2[i]), RES_OK); + } + CHECK(ssp_rng_proxy_ref_put(proxy1), RES_OK); + CHECK(ssp_rng_proxy_ref_put(proxy2), RES_OK); + ssp_rng_discard(rng1[0], 1000307); + for (i = 0; i < 1000307; i++) ssp_rng_get(rng2[0]); + CHECK(ssp_rng_get(rng1[0]), ssp_rng_get(rng2[0])); + FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng[i]), RES_OK); + FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng1[i]), RES_OK); + FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng2[i]), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator);