star-sp

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

commit 6c7fa93fd5e0a6de489c8c27b391f70e5fe69892
parent e8468cc4e3751edb40218fbdeaae2fac3ba1d3c9
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon,  1 Jun 2015 17:54:25 +0200

Pave the way to new generators that can fail in init or set.
This is a new incompatible API version: 0.1.0.
Also rename the uniform_int API call into uniform_uint64 to better reflect what it really does
and add a new API call entropy in the spirit of the C++11 one.

Diffstat:
Mcmake/CMakeLists.txt | 2+-
Msrc/ssp.h | 15++++++++++-----
Msrc/ssp_rng.c | 58+++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/ssp_rng_proxy.c | 25+++++++++++++++++--------
Msrc/test_ssp_rng.c | 2+-
5 files changed, 72 insertions(+), 30 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -60,7 +60,7 @@ rcmake_append_runtime_dirs(_runtime_dirs RSys) # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 0) +set(VERSION_MINOR 1) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) diff --git a/src/ssp.h b/src/ssp.h @@ -63,17 +63,18 @@ struct mem_allocator; /* Generic Random Number Generator type descriptor */ struct ssp_rng_type { - void (*init)(struct mem_allocator* allocator, void* state); + res_T (*init)(struct mem_allocator* allocator, void* state); void (*release)(void* state); - void (*set)(void* state, const uint64_t seed); + res_T (*set)(void* state, const uint64_t seed); uint64_t (*get)(void* state); - uint64_t (*uniform_int)(void* state, const uint64_t min, const uint64_t max); + 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); res_T (*read)(void* state, FILE* file); res_T (*write)(const void* state, FILE* file); - + double (*entropy)(const void* state); + uint64_t min; uint64_t max; size_t sizeof_state; @@ -118,7 +119,7 @@ ssp_rng_get /* Uniform random integer distribution in [lower, upper] */ SSP_API uint64_t -ssp_rng_uniform_int +ssp_rng_uniform_uint64 (struct ssp_rng* rng, const uint64_t lower, const uint64_t upper); @@ -153,6 +154,10 @@ ssp_rng_read (struct ssp_rng* rng, FILE* stream); +SSP_API double +ssp_rng_entropy +(const struct ssp_rng* rng); + /******************************************************************************* * Proxy of Random Number Generators - It manages a list of `nbuckets' RNGs * whose each have independant `infinite' random sequences diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -48,13 +48,12 @@ #include <sstream> - /******************************************************************************* * KISS PRNG ******************************************************************************/ struct rng_kiss { uint32_t x, y, z, c; }; -static void +static res_T rng_kiss_set(void* data, const size_t seed) { struct rng_kiss* kiss = (struct rng_kiss*)data; @@ -67,6 +66,7 @@ rng_kiss_set(void* data, const size_t seed) kiss->z = (uint32_t)rng_mt(); /* Offset c by 1 to avoid z=c=0; should be less than 698769069 */ kiss->c = (uint32_t)rng_mt() % 698769068 + 1; + return RES_OK; } static uint64_t @@ -87,7 +87,7 @@ rng_kiss_get(void* data) } static uint64_t -rng_kiss_uniform_int(void* data, const uint64_t lower, const uint64_t upper) +rng_kiss_uniform_uint64(void* data, const uint64_t lower, const uint64_t upper) { ASSERT(lower <= upper); return (uint32_t) @@ -130,11 +130,12 @@ rng_kiss_write(const void* data, FILE* file) return res < 0 ? RES_IO_ERR : RES_OK; } -static void +static res_T rng_kiss_init(struct mem_allocator* allocator, void* data) { (void)allocator; rng_kiss_set(data, 0); + return RES_OK; } static void @@ -143,17 +144,25 @@ rng_kiss_release(void* data) (void)data; } +static double +rng_kiss_entropy(const void* data) +{ + (void)data; + return 0.; +} + /* Exported type */ const struct ssp_rng_type ssp_rng_kiss = { rng_kiss_init, rng_kiss_release, rng_kiss_set, rng_kiss_get, - rng_kiss_uniform_int, + rng_kiss_uniform_uint64, rng_kiss_uniform_double, rng_kiss_canonical, rng_kiss_read, rng_kiss_write, + rng_kiss_entropy, 0, UINT32_MAX, sizeof(struct rng_kiss) @@ -163,12 +172,13 @@ const struct ssp_rng_type ssp_rng_kiss = { * C++11 PRNG ******************************************************************************/ template<typename RNG> -static void +static res_T rng_cxx_set(void* data, const uint64_t seed) { RNG* rng = (RNG*)data; ASSERT(rng); rng->seed((unsigned long)seed); + return RES_OK; } template<typename RNG> @@ -182,7 +192,7 @@ rng_cxx_get(void* data) template<typename RNG> static uint64_t -rng_cxx_uniform_int +rng_cxx_uniform_uint64 (void* data, const uint64_t lower, const uint64_t upper) { RNG* rng = (RNG*)data; @@ -241,12 +251,13 @@ rng_cxx_read(void* data, FILE* file) } template<typename RNG> -static void +static res_T rng_cxx_init(struct mem_allocator* allocator, void* data) { (void)allocator; ASSERT(data); new (data) RNG; + return RES_OK; } template<typename RNG> @@ -259,17 +270,26 @@ rng_cxx_release(void* data) rng->~RNG(); } +template<typename RNG> +static double +rng_cxx_entropy(const void* data) +{ + (void)data; + return 0; +} + /* 64-bits Mersenne Twister PRNG */ const struct ssp_rng_type ssp_rng_mt19937_64 = { rng_cxx_init<RAN_NAMESPACE::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_uniform_int<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>, rng_cxx_read<RAN_NAMESPACE::mt19937_64>, rng_cxx_write<RAN_NAMESPACE::mt19937_64>, + rng_cxx_entropy<RAN_NAMESPACE::mt19937_64>, RAN_NAMESPACE::mt19937_64::min(), RAN_NAMESPACE::mt19937_64::max(), sizeof(RAN_NAMESPACE::mt19937_64) @@ -281,11 +301,12 @@ 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_uniform_int<RAN_NAMESPACE::ranlux48>, + rng_cxx_uniform_uint64<RAN_NAMESPACE::ranlux48>, rng_cxx_uniform_double<RAN_NAMESPACE::ranlux48>, rng_cxx_canonical<RAN_NAMESPACE::ranlux48>, rng_cxx_read<RAN_NAMESPACE::ranlux48>, rng_cxx_write<RAN_NAMESPACE::ranlux48>, + rng_cxx_entropy<RAN_NAMESPACE::ranlux48>, RAN_NAMESPACE::ranlux48::min(), RAN_NAMESPACE::ranlux48::max(), sizeof(RAN_NAMESPACE::ranlux48) @@ -302,11 +323,12 @@ check_type(const struct ssp_rng_type* type) && NULL != type->release && NULL != type->set && NULL != type->get - && NULL != type->uniform_int + && NULL != type->uniform_uint64 && NULL != type->uniform_double && NULL != type->canonical && NULL != type->read && NULL != type->write + && NULL != type->entropy && type->min <= type->max; } @@ -393,11 +415,11 @@ ssp_rng_get(struct ssp_rng* rng) } uint64_t -ssp_rng_uniform_int +ssp_rng_uniform_uint64 (struct ssp_rng* rng, const uint64_t lower, const uint64_t upper) { if(!rng) FATAL("The Random Number Generator is NULL\n"); - return rng->type.uniform_int(rng->state, lower, upper); + return rng->type.uniform_uint64(rng->state, lower, upper); } double @@ -433,8 +455,7 @@ res_T ssp_rng_set(struct ssp_rng* rng, const uint64_t seed) { if(!rng) return RES_BAD_ARG; - rng->type.set(rng->state, seed); - return RES_OK; + return rng->type.set(rng->state, seed); } res_T @@ -451,6 +472,13 @@ ssp_rng_write(const struct ssp_rng* rng, FILE* stream) return rng->type.write(rng->state, stream); } +double +ssp_rng_entropy(const struct ssp_rng* rng) +{ + if (!rng) FATAL("The Random Number Generator is NULL\n"); + return rng->type.entropy(rng->state); +} + #ifdef COMPILER_CL #pragma warning(pop) #endif diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c @@ -171,11 +171,11 @@ rng_bucket_next_ran_pool(struct rng_bucket* rng) rng->count = BUCKET_SIZE; } -static void +static res_T rng_bucket_set(void* data, const uint64_t seed) { (void)data, (void)seed; - FATAL("The seed can't be set explicitly on bucket RNGs\n"); + return RES_BAD_OP; } static uint64_t @@ -189,14 +189,14 @@ rng_bucket_get(void* data) } static uint64_t -rng_bucket_uniform_int +rng_bucket_uniform_uint64 (void* data, const uint64_t lower, const uint64_t upper) { struct rng_bucket* rng = (struct rng_bucket*)data; ASSERT(data); if(!rng->count) rng_bucket_next_ran_pool(rng); --rng->count; - return ssp_rng_uniform_int(rng->pool, lower, upper); + return ssp_rng_uniform_uint64(rng->pool, lower, upper); } static double @@ -223,17 +223,17 @@ static res_T rng_bucket_read(void* data, FILE* file) { (void)data, (void)file; - FATAL("A bucket RNG can't be de-serialized\n"); + return RES_BAD_OP; } static res_T rng_bucket_write(const void* data, FILE* file) { (void)data, (void)file; - FATAL("A bucket RNG can't be serialized\n"); + return RES_BAD_OP; } -static void +static res_T rng_bucket_init(struct mem_allocator* allocator, void* data) { struct rng_bucket* rng = (struct rng_bucket*)data; @@ -243,6 +243,7 @@ rng_bucket_init(struct mem_allocator* allocator, void* data) rng->pool = NULL; rng->name = SIZE_MAX; rng->count = 0; + return RES_OK; } static void @@ -254,16 +255,24 @@ rng_bucket_release(void* data) SSP(rng_proxy_ref_put(rng->proxy)); } +static double +rng_bucket_entropy(const void* data) +{ + (void)data; + return 0; +} + static const struct ssp_rng_type rng_bucket = { rng_bucket_init, rng_bucket_release, rng_bucket_set, rng_bucket_get, - rng_bucket_uniform_int, + rng_bucket_uniform_uint64, rng_bucket_uniform_double, rng_bucket_canonical, rng_bucket_read, rng_bucket_write, + rng_bucket_entropy, 0, /* Dummy value */ ULONG_MAX, /* Dummy value */ sizeof(struct rng_bucket) diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c @@ -92,7 +92,7 @@ test_rng(const struct ssp_rng_type* type) } FOR_EACH(i, 0, NRAND) { - datai0[i] = ssp_rng_uniform_int(rng, 1, 79); + datai0[i] = ssp_rng_uniform_uint64(rng, 1, 79); CHECK(datai0[i] >= 1, 1); CHECK(datai0[i] <= 79, 1); }