star-sp

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

commit d54a904d6e0c37bad83371ff434aefa1484f6c89
parent a19b7723ac366fa0a1a5084e6493dce6420aa063
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 14 Oct 2021 14:21:46 +0200

Merge branch 'release_0.12'

Diffstat:
MREADME.md | 18++++++++++++++++++
Mcmake/CMakeLists.txt | 9+++++++--
Msrc/ssp.h | 94+++++++++++++++++++++++++------------------------------------------------------
Msrc/ssp_ran.c | 22++++++++--------------
Msrc/ssp_ranst_discrete.c | 3+--
Msrc/ssp_ranst_gaussian.c | 6++----
Msrc/ssp_ranst_piecewise_linear.c | 11++++-------
Msrc/ssp_rng.c | 221++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/ssp_rng_c.h | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/ssp_rng_proxy.c | 27++++++++++++++-------------
Msrc/test_ssp_ran_circle.h | 2+-
Msrc/test_ssp_ran_discrete.c | 2+-
Msrc/test_ssp_ran_gaussian.h | 2+-
Msrc/test_ssp_ran_hemisphere.h | 4++--
Msrc/test_ssp_ran_hg.h | 2+-
Msrc/test_ssp_ran_piecewise_linear.h | 2+-
Msrc/test_ssp_ran_sphere.h | 2+-
Msrc/test_ssp_ran_sphere_cap.h | 2+-
Msrc/test_ssp_ran_spherical_zone.h | 2+-
Msrc/test_ssp_ran_tetrahedron.h | 2+-
Msrc/test_ssp_ran_triangle.h | 2+-
Msrc/test_ssp_ran_uniform_disk.h | 4++--
Msrc/test_ssp_rng.c | 41++++++++++++++++++++---------------------
Msrc/test_ssp_rng_proxy.c | 76++++++++++++++++++++++++++++++++++++++--------------------------------------
24 files changed, 371 insertions(+), 294 deletions(-)

diff --git a/README.md b/README.md @@ -34,6 +34,24 @@ variable to the directory that contains the `boost` include directory. ## Release notes +### Version 0.12 + +Ensures C++11 compliance to correct gcc 11 compilation errors. On the other +hand, this introduces API breaks. + +According to the C++11 standard, the min/max values of a +UniformRandomBitGenerator must be static constant expressions. But until now, +gcc has been flexible enough to allow the use of UniformRandomBitGenerators +with regular min/max values. At run time, the caller could thus define its own +RNG type as provided by the struct `ssp_rng_type` data structure. +Unfortunately, since its version 11, gcc is more severe and refuses to compile +this code. + +This version updates the API to respect this C++11 constraint. The +`ssp_rng_type` is no longer a structure; it becomes an enumeration which is +then instantiated internally in a specific UniformRandomBitGenerator with +min/max values resolved at compilation time. + ### Version 0.11.1 Sets the CMake minimum version to 3.1 in the Random123Config.cmake file: since diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -70,12 +70,17 @@ endif() rcmake_append_runtime_dirs(_runtime_dirs RSys ${Boost_LIBRARY_DIRS}) +if(CMAKE_COMPILER_IS_GNUCXX) + # Random123 warning that cannot be disabled by a GCC pragma + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-expansion-to-defined") +endif() + ################################################################################ # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 11) -set(VERSION_PATCH 1) +set(VERSION_MINOR 12) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SSP_FILES_SRC diff --git a/src/ssp.h b/src/ssp.h @@ -67,89 +67,53 @@ struct ssp_ranst_piecewise_linear_float; /* Forward declaration of external types */ struct mem_allocator; -/* Generic Random Number Generator type descriptor */ -struct ssp_rng_type { - res_T (*init)(struct mem_allocator* allocator, void* state); - void (*release)(void* state); - res_T (*set)(void* state, const uint64_t seed); - - uint64_t (*get)(void* state); - res_T (*discard)(void* state, uint64_t n); - res_T (*read)(void* state, FILE* file); - res_T (*read_cstr)(void* state, const char* cstr); - res_T (*write)(const void* state, FILE* file); - res_T (*write_cstr)(const void* state, char* buf, const size_t sz, size_t* len); - double (*entropy)(const void* state); - - uint64_t min; - uint64_t max; - size_t sizeof_state; - size_t alignof_state; +enum ssp_rng_type { + /* David Jones's Keep It Simple Stupid builtin PRNG type. Suitable for fast + * basic randomness */ + SSP_RNG_KISS, + /* 64-bits Mersenne Twister builtin PRNG type of Matsumoto and Nishimura */ + SSP_RNG_MT19937_64, + /* 48-bits RANLUX builtin PRNG type of Lusher and James, 1994 */ + SSP_RNG_RANLUX48, + /* A random_device RNG is a uniformly-distributed integer random number + * generator that produces non-deterministic random numbers. It may be + * implemented in terms of an implementation-defined pseudo-random number + * engine if a non-deterministic source (e.g. a hardware device) is not + * available to the implementation. In this case each random_device object + * may generate the same number sequence. */ + SSP_RNG_RANDOM_DEVICE, + /* Counter Based RNG threefry of Salmon, Moraes, Dror & Shaw */ + SSP_RNG_THREEFRY, +#ifdef WITH_R123_AES + /* Counter Based RNG aes of Salmon, Moraes, Dror & Shaw */ + SSP_RNG_AES, +#endif + SSP_RNG_TYPES_COUNT__, + SSP_RNG_TYPE_NULL = SSP_RNG_TYPES_COUNT__ }; -static FINLINE char -ssp_rng_type_eq(const struct ssp_rng_type* t0, const struct ssp_rng_type* t1) -{ - ASSERT(t0 && t1); - return t0->init == t1->init - && t0->release == t1->release - && t0->set == t1->set - && t0->get == t1->get - && t0->discard == t1->discard - && t0->read == t1->read - && t0->read_cstr == t1->read_cstr - && t0->write == t1->write - && t0->write_cstr == t1->write_cstr - && t0->entropy == t1->entropy - && t0->min == t1->min - && t0->max == t1->max - && t0->sizeof_state == t1->sizeof_state - && t0->alignof_state == t1->alignof_state; -} - /* Arguments of the ssp_rng_proxy_create2 function */ struct ssp_rng_proxy_create2_args { const struct ssp_rng* rng; /* Original RNG state. May be NULL*/ - const struct ssp_rng_type* type; /* Type of the RN if 'rng' is NULL */ + enum ssp_rng_type type; /* Type of the RN if 'rng' is NULL */ size_t sequence_offset; /* #RNs before the 1st valid sequence */ size_t sequence_size; /* #RNs in a sequence */ size_t sequence_pitch; /* #RNs between sequences. Must be >= sequence_size */ size_t nbuckets; /* #buckets of continuous RNs in a sequence */ }; -#define SSP_RNG_PROXY_CREATE2_ARGS_NULL__ {NULL, NULL, 0, 0, 0, 0} +#define SSP_RNG_PROXY_CREATE2_ARGS_NULL__ {NULL, SSP_RNG_TYPE_NULL, 0, 0, 0, 0} static const struct ssp_rng_proxy_create2_args SSP_RNG_PROXY_CREATE2_ARGS_NULL = SSP_RNG_PROXY_CREATE2_ARGS_NULL__; BEGIN_DECLS -/* David Jones's Keep It Simple Stupid builtin PRNG type. Suitable for fast - * basic randomness */ -SSP_API const struct ssp_rng_type ssp_rng_kiss; -/* 64-bits Mersenne Twister builtin PRNG type of Matsumoto and Nishimura, 2000 */ -SSP_API const struct ssp_rng_type ssp_rng_mt19937_64; -/* 48-bits RANLUX builtin PRNG type of Lusher and James, 1994 */ -SSP_API const struct ssp_rng_type ssp_rng_ranlux48; -/* A random_device RNG is a uniformly-distributed integer random number generator - * that produces non-deterministic random numbers. It may be implemented in - * terms of an implementation-defined pseudo-random number engine if a - * non-deterministic source (e.g. a hardware device) is not available to the - * implementation. In this case each random_device object may generate the same - * number sequence. */ -SSP_API const struct ssp_rng_type ssp_rng_random_device; -/* Counter Based RNG threefry of Salmon, Moraes, Dror & Shaw */ -SSP_API const struct ssp_rng_type ssp_rng_threefry; -#ifdef WITH_R123_AES -/* Counter Based RNG aes of Salmon, Moraes, Dror & Shaw */ -SSP_API const struct ssp_rng_type ssp_rng_aes; -#endif - /******************************************************************************* * Random Number Generator API ******************************************************************************/ SSP_API res_T ssp_rng_create (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */ - const struct ssp_rng_type* type, + const enum ssp_rng_type type, struct ssp_rng** rng); SSP_API res_T @@ -163,7 +127,7 @@ ssp_rng_ref_get SSP_API res_T ssp_rng_get_type (const struct ssp_rng* rng, - struct ssp_rng_type* type); + enum ssp_rng_type* type); SSP_API res_T ssp_rng_set @@ -252,7 +216,7 @@ ssp_rng_entropy SSP_API res_T ssp_rng_proxy_create (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */ - const struct ssp_rng_type* type, + const enum ssp_rng_type type, const size_t nbuckets, struct ssp_rng_proxy** proxy); @@ -300,7 +264,7 @@ ssp_rng_proxy_create_rng SSP_API res_T ssp_rng_proxy_get_type (const struct ssp_rng_proxy* proxy, - struct ssp_rng_type* type); + enum ssp_rng_type* type); /******************************************************************************* * Miscellaneous distributions diff --git a/src/ssp_ran.c b/src/ssp_ran.c @@ -49,19 +49,17 @@ cosf2sinf(const float d) double ssp_ran_exp(struct ssp_rng* rng, const double mu) { - ASSERT(rng && mu > 0); - rng_cxx rng_cxx(*rng); + ASSERT(rng && mu >= 0); RAN_NAMESPACE::exponential_distribution<double> distribution(mu); - return distribution(rng_cxx); + return wrap_ran(*rng, distribution); } float ssp_ran_exp_float(struct ssp_rng* rng, const float mu) { - ASSERT(rng && mu > 0); - rng_cxx rng_cxx(*rng); + ASSERT(rng && mu >= 0); RAN_NAMESPACE::exponential_distribution<float> distribution(mu); - return distribution(rng_cxx); + return wrap_ran(*rng, distribution); } double @@ -129,9 +127,8 @@ ssp_ran_gaussian const double sigma) { ASSERT(rng); - rng_cxx rng_cxx(*rng); RAN_NAMESPACE::normal_distribution<double> distribution(mu, sigma); - return distribution(rng_cxx); + return wrap_ran(*rng, distribution); } float @@ -141,9 +138,8 @@ ssp_ran_gaussian_float const float sigma) { ASSERT(rng); - rng_cxx rng_cxx(*rng); RAN_NAMESPACE::normal_distribution<float> distribution(mu, sigma); - return distribution(rng_cxx); + return wrap_ran(*rng, distribution); } double @@ -173,9 +169,8 @@ ssp_ran_lognormal const double sigma) { ASSERT(rng); - rng_cxx rng_cxx(*rng); RAN_NAMESPACE::lognormal_distribution<double> distribution(zeta, sigma); - return distribution(rng_cxx); + return wrap_ran(*rng, distribution); } float @@ -185,9 +180,8 @@ ssp_ran_lognormal_float const float sigma) { ASSERT(rng); - rng_cxx rng_cxx(*rng); RAN_NAMESPACE::lognormal_distribution<float> distribution(zeta, sigma); - return distribution(rng_cxx); + return wrap_ran(*rng, distribution);; } double diff --git a/src/ssp_ranst_discrete.c b/src/ssp_ranst_discrete.c @@ -179,8 +179,7 @@ ssp_ranst_discrete_ref_put(struct ssp_ranst_discrete* ran) size_t ssp_ranst_discrete_get(struct ssp_rng* rng, const struct ssp_ranst_discrete* ran) { - class rng_cxx r(*rng); - return ran->distrib->operator()(r); + return wrap_ran(*rng, *ran->distrib); } double diff --git a/src/ssp_ranst_gaussian.c b/src/ssp_ranst_gaussian.c @@ -248,18 +248,16 @@ double ssp_ranst_gaussian_get (const struct ssp_ranst_gaussian* ran, struct ssp_rng* rng) { - class rng_cxx r(*rng); ASSERT(ran->K1 > 0); - return ran->distrib->operator()(r); + return wrap_ran(*rng, *ran->distrib); } float ssp_ranst_gaussian_float_get (const struct ssp_ranst_gaussian_float* ran, struct ssp_rng* rng) { - class rng_cxx r(*rng); ASSERT(ran->K1 > 0); - return ran->distrib->operator()(r); + return wrap_ran(*rng, *ran->distrib); } double diff --git a/src/ssp_ranst_piecewise_linear.c b/src/ssp_ranst_piecewise_linear.c @@ -256,8 +256,7 @@ ssp_ranst_piecewise_linear_get (const struct ssp_ranst_piecewise_linear* ran, struct ssp_rng* rng) { - class rng_cxx r(*rng); - return ran->distrib->operator()(r); + return wrap_ran(*rng, *ran->distrib); } float @@ -265,8 +264,7 @@ ssp_ranst_piecewise_linear_float_get (const struct ssp_ranst_piecewise_linear_float* ran, struct ssp_rng* rng) { - class rng_cxx r(*rng); - return ran->distrib->operator()(r); + return wrap_ran(*rng, *ran->distrib); } double @@ -275,7 +273,7 @@ ssp_ranst_piecewise_linear_pdf double x) { ASSERT(ran); - if (x<ran->distrib->min() || x>ran->distrib->max()) + if(x<ran->distrib->min() || x>ran->distrib->max()) return 0; const auto& inter = ran->distrib->intervals(); @@ -311,4 +309,4 @@ ssp_ranst_piecewise_linear_float_pdf return ((float)dens[idx+1] * (x-inter[idx]) + (float)dens[idx] * (inter[idx+1]-x)) / (inter[idx+1] - inter[idx]); -} -\ No newline at end of file +} diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -34,32 +34,6 @@ #include <rsys/dynamic_array_char.h> #include <rsys/mem_allocator.h> -/* disable some warnings in Random123 includes */ -#ifdef COMPILER_GCC - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wconversion" /* unsafe conversion */ - #pragma GCC diagnostic ignored "-Wshadow" - #pragma GCC diagnostic ignored "-Wunused-parameter" /* in Random123/aes.h */ -#elif defined(COMPILER_CL) - #pragma warning(push) - #pragma warning(disable:4100) /* unreferenced formal parameter */ - #pragma warning(disable:4127) /* conditional expression is constant */ - #pragma warning(disable:4512) /* assignment operator could not be generated */ - #pragma warning(disable:4521) /* multiple copy constructors specified */ -#endif - -#include <Random123/conventional/Engine.hpp> -#include <Random123/threefry.h> -#ifdef WITH_R123_AES - #include <Random123/aes.h> -#endif - -#ifdef COMPILER_GCC - #pragma GCC diagnostic pop -#elif defined(COMPILER_CL) - #pragma warning(pop) -#endif - #include <sstream> #include <cstring> #include <limits> @@ -204,7 +178,7 @@ rng_kiss_discard(void* data, uint64_t n) } /* Exported type */ -const struct ssp_rng_type ssp_rng_kiss = { +static const struct rng_desc rng_kiss = { rng_kiss_init, rng_kiss_release, rng_kiss_set, @@ -405,7 +379,7 @@ rng_cxx_entropy<RAN_NAMESPACE::random_device>(const void* data) } /* 64-bits Mersenne Twister PRNG */ -const struct ssp_rng_type ssp_rng_mt19937_64 = { +static const struct rng_desc rng_mt19937_64 = { rng_cxx_init<RAN_NAMESPACE::mt19937_64>, rng_cxx_release<RAN_NAMESPACE::mt19937_64>, rng_cxx_set<RAN_NAMESPACE::mt19937_64>, @@ -423,7 +397,7 @@ const struct ssp_rng_type ssp_rng_mt19937_64 = { }; /* 48-bits RANLUX PRNG */ -const struct ssp_rng_type ssp_rng_ranlux48 = { +static const struct rng_desc rng_ranlux48 = { rng_cxx_init<RAN_NAMESPACE::ranlux48>, rng_cxx_release<RAN_NAMESPACE::ranlux48>, rng_cxx_set<RAN_NAMESPACE::ranlux48>, @@ -441,7 +415,7 @@ const struct ssp_rng_type ssp_rng_ranlux48 = { }; /* random_device generator */ -const struct ssp_rng_type ssp_rng_random_device = { +static const struct rng_desc rng_random_device = { rng_cxx_init<RAN_NAMESPACE::random_device>, rng_cxx_release<RAN_NAMESPACE::random_device>, rng_cxx_set<RAN_NAMESPACE::random_device>, @@ -483,7 +457,7 @@ rng_cxx_init<aes_T>(struct mem_allocator* allocator, void* data) #endif /* threefry generator */ -const struct ssp_rng_type ssp_rng_threefry = { +static const struct rng_desc rng_threefry = { rng_cxx_init<threefry_T>, rng_cxx_release<threefry_T>, rng_cxx_set<threefry_T>, @@ -502,7 +476,7 @@ const struct ssp_rng_type ssp_rng_threefry = { #ifdef WITH_R123_AES /* aes generator */ -const struct ssp_rng_type ssp_rng_aes = { +static const struct rng_desc rng_aes = { rng_cxx_init<aes_T>, rng_cxx_release<aes_T>, rng_cxx_set<aes_T>, @@ -523,20 +497,6 @@ const struct ssp_rng_type ssp_rng_aes = { /******************************************************************************* * Helper functions ******************************************************************************/ -static char -check_type(const struct ssp_rng_type* type) -{ - ASSERT(type); - return NULL != type->init - && NULL != type->release - && NULL != type->set - && NULL != type->get - && NULL != type->read - && NULL != type->write - && NULL != type->entropy - && type->min <= type->max; -} - static void rng_release(ref_T* ref) { @@ -544,8 +504,8 @@ rng_release(ref_T* ref) ASSERT(ref); rng = CONTAINER_OF(ref, struct ssp_rng, ref); if(rng->state) { - if(rng->type.release) { - rng->type.release(rng->state); + if(rng->desc.release) { + rng->desc.release(rng->state); } MEM_RM(rng->allocator, rng->state); } @@ -558,56 +518,40 @@ rng_release(ref_T* ref) res_T ssp_rng_create (struct mem_allocator* mem_allocator, - const struct ssp_rng_type* type, + const enum ssp_rng_type type, struct ssp_rng** out_rng) { - struct mem_allocator* allocator; - struct ssp_rng* rng = NULL; - size_t log2r; res_T res = RES_OK; - if(!type || !out_rng || !check_type(type)) { - res = RES_BAD_ARG; - goto error; - } - - allocator = mem_allocator ? mem_allocator : &mem_default_allocator; - - /* Align the rng on 16 bytes since its 'r' attrib is a long double that on - * Linux 64-bits systems must be aligned on 16 bytes. */ - rng = (struct ssp_rng*)MEM_ALLOC_ALIGNED(allocator, sizeof(*rng), 16); - if(!rng) { - res = RES_MEM_ERR; - goto error; - } - memset(rng, 0, sizeof(struct ssp_rng)); - rng->allocator = allocator; - ref_init(&rng->ref); - - rng->state = - MEM_ALLOC_ALIGNED(rng->allocator, type->sizeof_state, type->alignof_state); - if(!rng->state) { - res = RES_MEM_ERR; - goto error; + switch(type) { + case SSP_RNG_KISS: + res = rng_create(mem_allocator, &rng_kiss, out_rng); + break; + case SSP_RNG_MT19937_64: + res = rng_create(mem_allocator, &rng_mt19937_64, out_rng); + break; + case SSP_RNG_RANLUX48: + res = rng_create(mem_allocator, &rng_ranlux48, out_rng); + break; + case SSP_RNG_RANDOM_DEVICE: + res = rng_create(mem_allocator, &rng_random_device, out_rng); + break; + case SSP_RNG_THREEFRY: + res = rng_create(mem_allocator, &rng_threefry, out_rng); +#ifdef WITH_R123_AES + break; + case SSP_RNG_AES: + res = rng_create(mem_allocator, &rng_aes, out_rng); + break; +#endif + default: res = RES_BAD_ARG; break; } - res = type->init(allocator, rng->state); if(res != RES_OK) goto error; - rng->type = *type; - - /* Precompute some values for the canonical distribution */ - rng->r = (long double)rng->type.max - (long double)rng->type.min + 1.0L; - log2r = (size_t)(std::log(rng->r) / std::log(2.0L)); - rng->dbl_k = std::max<size_t>(1UL, (53 + log2r - 1UL) / log2r); - rng->flt_k = std::max<size_t>(1UL, (24 + log2r - 1UL) / log2r); + (*out_rng)->type = type; exit: - if(out_rng) *out_rng = rng; return res; error: - if(rng) { - SSP(rng_ref_put(rng)); - rng = NULL; - } goto exit; } @@ -628,7 +572,7 @@ ssp_rng_ref_put(struct ssp_rng* rng) } res_T -ssp_rng_get_type(const struct ssp_rng* rng, struct ssp_rng_type* type) +ssp_rng_get_type(const struct ssp_rng* rng, enum ssp_rng_type* type) { if(!rng || !type) return RES_BAD_ARG; *type = rng->type; @@ -639,7 +583,7 @@ uint64_t ssp_rng_get(struct ssp_rng* rng) { if(!rng) FATAL("The Random Number Generator is NULL\n"); - return rng->type.get(rng->state); + return rng->desc.get(rng->state); } uint64_t @@ -647,8 +591,8 @@ 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"); - rng_cxx rng_cxx(*rng); - return RAN_NAMESPACE::uniform_int_distribution<uint64_t>(lower, upper)(rng_cxx); + RAN_NAMESPACE::uniform_int_distribution<uint64_t> distrib(lower, upper); + return wrap_ran(*rng, distrib); } double @@ -656,8 +600,8 @@ ssp_rng_uniform_double (struct ssp_rng* rng, const double lower, const double upper) { if(!rng) FATAL("The Random Number Generator is NULL\n"); - rng_cxx rng_cxx(*rng); - return RAN_NAMESPACE::uniform_real_distribution<double>(lower, upper)(rng_cxx); + RAN_NAMESPACE::uniform_real_distribution<double> distrib(lower, upper); + return wrap_ran(*rng, distrib); } float @@ -665,8 +609,8 @@ ssp_rng_uniform_float (struct ssp_rng* rng, const float lower, const float upper) { if(!rng) FATAL("The Random Number Generator is NULL\n"); - rng_cxx rng_cxx(*rng); - return RAN_NAMESPACE::uniform_real_distribution<float>(lower, upper)(rng_cxx); + RAN_NAMESPACE::uniform_real_distribution<float> distrib(lower, upper); + return wrap_ran(*rng, distrib); } double @@ -683,7 +627,7 @@ ssp_rng_canonical(struct ssp_rng* rng) double sum = 0; double tmp = 1; for(; k !=0; --k) { - sum += (double)(rng->type.get(rng->state) - rng->type.min) * tmp; + sum += (double)(rng->desc.get(rng->state) - rng->desc.min) * tmp; tmp = (double)(tmp*rng->r); } return sum/tmp; @@ -709,7 +653,7 @@ ssp_rng_canonical_float(struct ssp_rng* rng) float sum = 0; float tmp = 1; for(; k !=0; --k) { - sum += (float)(rng->type.get(rng->state) - rng->type.min) * tmp; + sum += (float)(rng->desc.get(rng->state) - rng->desc.min) * tmp; tmp = (float)(tmp*rng->r); } r = sum/tmp; @@ -722,42 +666,42 @@ uint64_t ssp_rng_min(struct ssp_rng* rng) { if(!rng) FATAL("The Random Number Generator is NULL\n"); - return rng->type.min; + return rng->desc.min; } uint64_t ssp_rng_max(struct ssp_rng* rng) { if(!rng) FATAL("The Random Number Generator is NULL\n"); - return rng->type.max; + return rng->desc.max; } res_T ssp_rng_set(struct ssp_rng* rng, const uint64_t seed) { if(!rng) return RES_BAD_ARG; - return rng->type.set(rng->state, seed); + return rng->desc.set(rng->state, seed); } res_T ssp_rng_read(struct ssp_rng* rng, FILE* stream) { if(!rng || !stream) return RES_BAD_ARG; - return rng->type.read(rng->state, stream); + return rng->desc.read(rng->state, stream); } res_T ssp_rng_read_cstr(struct ssp_rng* rng, const char* cstr) { if(!rng || !cstr) return RES_BAD_ARG; - return rng->type.read_cstr(rng->state, cstr); + return rng->desc.read_cstr(rng->state, cstr); } res_T ssp_rng_write(const struct ssp_rng* rng, FILE* stream) { if(!rng || !stream) return RES_BAD_ARG; - return rng->type.write(rng->state, stream); + return rng->desc.write(rng->state, stream); } res_T @@ -768,19 +712,78 @@ ssp_rng_write_cstr size_t* len) { if(!rng) return RES_BAD_ARG; - return rng->type.write_cstr(rng->state, buf, bufsz, len); + return rng->desc.write_cstr(rng->state, buf, bufsz, len); } 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); + if (!rng) FATAL("The Random Number Generator is NULL\n"); + return rng->desc.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); + if (!rng) FATAL("The Random Number Generator is NULL\n"); + return rng->desc.discard(rng->state, n); +} + +/******************************************************************************* + * Local function + ******************************************************************************/ +res_T +rng_create + (struct mem_allocator* mem_allocator, + const struct rng_desc* desc, + struct ssp_rng** out_rng) +{ + struct mem_allocator* allocator; + struct ssp_rng* rng = NULL; + size_t log2r; + res_T res = RES_OK; + + if(!desc || !out_rng) { + res = RES_BAD_ARG; + goto error; + } + + allocator = mem_allocator ? mem_allocator : &mem_default_allocator; + + /* Align the rng on 16 bytes since its 'r' attrib is a long double that on + * Linux 64-bits systems must be aligned on 16 bytes. */ + rng = (struct ssp_rng*)MEM_ALLOC_ALIGNED(allocator, sizeof(*rng), 16); + if(!rng) { + res = RES_MEM_ERR; + goto error; + } + memset(rng, 0, sizeof(struct ssp_rng)); + rng->allocator = allocator; + ref_init(&rng->ref); + rng->desc = *desc; + + rng->state = MEM_ALLOC_ALIGNED + (rng->allocator, rng->desc.sizeof_state, rng->desc.alignof_state); + if(!rng->state) { + res = RES_MEM_ERR; + goto error; + } + res = rng->desc.init(allocator, rng->state); + if(res != RES_OK) goto error; + + /* Precompute some values for the canonical distribution */ + rng->r = (long double)rng->desc.max - (long double)rng->desc.min + 1.0L; + log2r = (size_t)(std::log(rng->r) / std::log(2.0L)); + rng->dbl_k = std::max<size_t>(1UL, (53 + log2r - 1UL) / log2r); + rng->flt_k = std::max<size_t>(1UL, (24 + log2r - 1UL) / log2r); + +exit: + if(out_rng) *out_rng = rng; + return res; +error: + if(rng) { + SSP(rng_ref_put(rng)); + rng = NULL; + } + goto exit; } diff --git a/src/ssp_rng_c.h b/src/ssp_rng_c.h @@ -32,6 +32,34 @@ #ifndef SSP_RNG_C_H #define SSP_RNG_C_H +#include <rsys/rsys.h> + +/* disable some warnings in Random123 includes */ +#ifdef COMPILER_GCC + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wconversion" /* unsafe conversion */ + #pragma GCC diagnostic ignored "-Wshadow" + #pragma GCC diagnostic ignored "-Wunused-parameter" /* in Random123/aes.h */ +#elif defined(COMPILER_CL) + #pragma warning(push) + #pragma warning(disable:4100) /* unreferenced formal parameter */ + #pragma warning(disable:4127) /* conditional expression is constant */ + #pragma warning(disable:4512) /* assignment operator could not be generated */ + #pragma warning(disable:4521) /* multiple copy constructors specified */ +#endif + +#include <Random123/conventional/Engine.hpp> +#include <Random123/threefry.h> +#ifdef WITH_R123_AES + #include <Random123/aes.h> +#endif + +#ifdef COMPILER_GCC + #pragma GCC diagnostic pop +#elif defined(COMPILER_CL) + #pragma warning(pop) +#endif + #include "ssp.h" #include <rsys/ref_count.h> @@ -56,8 +84,30 @@ #define RAN_NAMESPACE std #endif +/* Generic Random Number Generator type descriptor */ +struct rng_desc { + res_T (*init)(struct mem_allocator* allocator, void* state); + void (*release)(void* state); + res_T (*set)(void* state, const uint64_t seed); + + uint64_t (*get)(void* state); + res_T (*discard)(void* state, uint64_t n); + res_T (*read)(void* state, FILE* file); + res_T (*read_cstr)(void* state, const char* cstr); + res_T (*write)(const void* state, FILE* file); + res_T (*write_cstr)(const void* state, char* buf, const size_t sz, size_t* out_sz); + double (*entropy)(const void* state); + + uint64_t min; + uint64_t max; + + size_t sizeof_state; + size_t alignof_state; +}; + struct ssp_rng { - struct ssp_rng_type type; + struct rng_desc desc; + enum ssp_rng_type type; void* state; struct mem_allocator* allocator; @@ -69,19 +119,68 @@ struct ssp_rng { ref_T ref; }; +/******************************************************************************* + * Local API + ******************************************************************************/ +extern LOCAL_SYM res_T +rng_create + (struct mem_allocator* allocator, + const struct rng_desc* desc, + struct ssp_rng** out_rng); + +/******************************************************************************* + * C++ Wrappers + ******************************************************************************/ +template<typename ResultType, uint64_t Min, uint64_t Max> class rng_cxx /* Wrap a SSP random generator into a CXX object */ { public: FINLINE rng_cxx(struct ssp_rng& _rng) : rng(_rng) {} - FINLINE uint64_t operator()() { return rng.type.get(rng.state); } - FINLINE uint64_t min() const { return rng.type.min; } - FINLINE uint64_t max() const { return rng.type.max; } + FINLINE uint64_t operator()() { return rng.desc.get(rng.state); } + static constexpr uint64_t min() { return Min; } + static constexpr uint64_t max() { return Max; } - typedef uint64_t result_type; + typedef ResultType result_type; private: struct ssp_rng& rng; }; +template<typename Ran> typename Ran::result_type +wrap_ran(struct ssp_rng& rng, Ran& ran) +{ + #define RNG_CXX(Type) rng_cxx<Type::result_type, Type::min(), Type::max()> + switch(rng.type) { + case SSP_RNG_KISS: { + class rng_cxx<uint64_t, 0, UINT32_MAX> rng_cxx(rng); + return ran(rng_cxx); + } + case SSP_RNG_MT19937_64: { + class RNG_CXX(RAN_NAMESPACE::mt19937_64) rng_cxx(rng); + return ran(rng_cxx); + } + case SSP_RNG_RANLUX48: { + class RNG_CXX(RAN_NAMESPACE::ranlux48) rng_cxx(rng); + return ran(rng_cxx); + } + case SSP_RNG_RANDOM_DEVICE: { + class RNG_CXX(RAN_NAMESPACE::random_device) rng_cxx(rng); + return ran(rng_cxx); + } + case SSP_RNG_THREEFRY: { + class RNG_CXX(r123::Engine<r123::Threefry4x64>) rng_cxx(rng); + return ran(rng_cxx); + } +#ifdef WITH_R123_AES + case SSP_RNG_AES: { + class RNG_CXX(r123::Engine<r123::AESNI4x32>) rng_cxx(rng); + return ran(rng_cxx); + } +#endif + default: FATAL("Unreachable code\n"); + } + #undef RNG_CXX +} + #endif /* SSP_RNG_C_H */ diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c @@ -77,7 +77,7 @@ enum rng_proxy_sig { * +---------+---------+- -+---------+---------+---------+- * Unique random sequence */ struct ssp_rng_proxy { - struct ssp_rng_type type; /* Type of the RNGs managed by the proxy */ + enum ssp_rng_type type; /* Type of the RNGs managed by the proxy */ struct ssp_rng* rng; /* Main `type' RNG */ @@ -419,7 +419,7 @@ rng_bucket_discard(void* data, uint64_t n) return ssp_rng_discard(rng->pool, n); } -static const struct ssp_rng_type RNG_BUCKET_NULL = { +static const struct rng_desc RNG_BUCKET_NULL = { rng_bucket_init, rng_bucket_release, rng_bucket_set, @@ -508,7 +508,7 @@ rng_proxy_setup res = rng_state_cache_init (proxy->allocator, sequence_pitch, proxy->states+ibucket); if(res != RES_OK) goto error; - res = ssp_rng_create(proxy->allocator, &proxy->type, proxy->pools+ibucket); + res = ssp_rng_create(proxy->allocator, proxy->type, proxy->pools+ibucket); if(res != RES_OK) goto error; proxy->buckets[ibucket] = 0; } @@ -541,7 +541,7 @@ rng_proxy_release(ref_T* ref) res_T ssp_rng_proxy_create (struct mem_allocator* mem_allocator, - const struct ssp_rng_type* type, + const enum ssp_rng_type type, const size_t nbuckets, struct ssp_rng_proxy** out_proxy) { @@ -613,7 +613,7 @@ ssp_rng_proxy_create2 if(!args->rng) { res = ssp_rng_create(allocator, args->type, &proxy->rng); if(res != RES_OK) goto error; - proxy->type = *args->type; + proxy->type = args->type; /* Create the proxy RNG from a submitted RNG state */ } else { @@ -625,12 +625,12 @@ ssp_rng_proxy_create2 if(res != RES_OK) goto error; /* Bucket RNG is not allowed to be a proxy RNG */ - if(proxy->type.init == rng_bucket_init) { + if(args->rng->desc.init == rng_bucket_init) { res = RES_BAD_ARG; goto error; } - res = ssp_rng_create(allocator, &proxy->type, &proxy->rng); + res = ssp_rng_create(allocator, proxy->type, &proxy->rng); if(res != RES_OK) goto error; /* Initialise the RNG proxy state from the state of the submitted RNG */ @@ -723,7 +723,7 @@ ssp_rng_proxy_create_rng struct ssp_rng** out_rng) { struct ssp_rng* rng = NULL; - struct ssp_rng_type type = RNG_BUCKET_NULL; + struct rng_desc desc = RNG_BUCKET_NULL; struct rng_bucket* bucket = NULL; res_T res = RES_OK; @@ -738,12 +738,13 @@ ssp_rng_proxy_create_rng } /* Update the dummy rng bucket min/max value with the min/max values of the - * RNG type on which the proxy relies */ - type.min = proxy->type.min; - type.max = proxy->type.max; + * RNG desc on which the proxy relies */ + desc.min = proxy->rng->desc.min; + desc.max = proxy->rng->desc.max; - res = ssp_rng_create(proxy->allocator, &type, &rng); + res = rng_create(proxy->allocator, &desc, &rng); if(res != RES_OK) goto error; + rng->type = proxy->type; bucket = (struct rng_bucket*)rng->state; bucket->name = ibucket; bucket->proxy = proxy; @@ -769,7 +770,7 @@ error: res_T ssp_rng_proxy_get_type (const struct ssp_rng_proxy* proxy, - struct ssp_rng_type* type) + enum ssp_rng_type* type) { if(!proxy || !type) return RES_BAD_ARG; *type = proxy->type; diff --git a/src/test_ssp_ran_circle.h b/src/test_ssp_ran_circle.h @@ -70,7 +70,7 @@ TEST(void) int i = 0, j = 9; CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng) == RES_OK); CHK(EQ_EPS(RAN_CIRCLE_UNIFORM_PDF(), 1/(2*(REAL)PI), (REAL)1.e-6)); FOR_EACH(i, 0, NSAMPS) { diff --git a/src/test_ssp_ran_discrete.c b/src/test_ssp_ran_discrete.c @@ -50,7 +50,7 @@ main(int argc, char** argv) (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_THREEFRY, &rng) == RES_OK); CHK(ssp_ranst_discrete_create(NULL, NULL) == RES_BAD_ARG); CHK(ssp_ranst_discrete_create(NULL, &ran) == RES_OK); diff --git a/src/test_ssp_ran_gaussian.h b/src/test_ssp_ran_gaussian.h @@ -85,7 +85,7 @@ TEST() mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng) == RES_OK); CHK(RANST_GAUSSIAN_CREATE(NULL, NULL) == RES_BAD_ARG); CHK(RANST_GAUSSIAN_CREATE(NULL, &gaussian) == RES_OK); diff --git a/src/test_ssp_ran_hemisphere.h b/src/test_ssp_ran_hemisphere.h @@ -101,8 +101,8 @@ TEST() mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng0) == RES_OK); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng1) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng0) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng1) == RES_OK); samps0[0][0] = 0; samps0[0][1] = 0; samps0[0][2] = 1; f = RAN_HEMISPHERE_UNIFORM(rng1, samps0[0], samps1[0], NULL); diff --git a/src/test_ssp_ran_hg.h b/src/test_ssp_ran_hg.h @@ -69,7 +69,7 @@ TEST() mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_THREEFRY, &rng) == RES_OK); FOR_EACH(i, 0, NG) { /* for any value of g... */ diff --git a/src/test_ssp_ran_piecewise_linear.h b/src/test_ssp_ran_piecewise_linear.h @@ -84,7 +84,7 @@ TEST() mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng) == RES_OK); CHK(RANST_PIECEWISE_LINEAR_CREATE(NULL, NULL) == RES_BAD_ARG); CHK(RANST_PIECEWISE_LINEAR_CREATE(NULL, &pwl) == RES_OK); diff --git a/src/test_ssp_ran_sphere.h b/src/test_ssp_ran_sphere.h @@ -69,7 +69,7 @@ TEST() mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng) == RES_OK); FOR_EACH(i, 0, NSAMPS) { f = RAN_SPHERE_UNIFORM(rng, samps[i], &samps[i][3]); diff --git a/src/test_ssp_ran_sphere_cap.h b/src/test_ssp_ran_sphere_cap.h @@ -75,7 +75,7 @@ TEST(void) int i, j; mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng) == RES_OK); CHK(RAN_SPHERE_CAP_UNIFORM_LOCAL(rng, 1, samps[0], &pdf) == samps[0]); CHK(samps[0][0] == 0); diff --git a/src/test_ssp_ran_spherical_zone.h b/src/test_ssp_ran_spherical_zone.h @@ -76,7 +76,7 @@ TEST(void) int i, j; mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng) == RES_OK); heights[0] = heights[1] = 1; CHK(RAN_SPHERICAL_ZONE_UNIFORM_LOCAL(rng, heights, samps[0], &pdf) == samps[0]); diff --git a/src/test_ssp_ran_tetrahedron.h b/src/test_ssp_ran_tetrahedron.h @@ -86,7 +86,7 @@ TEST() mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng) == RES_OK); FOR_EACH(j, 0, 100) { FOR_EACH(i, 0, 3) { diff --git a/src/test_ssp_ran_triangle.h b/src/test_ssp_ran_triangle.h @@ -86,7 +86,7 @@ TEST() mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_MT19937_64, &rng) == RES_OK); FOR_EACH(i, 0, 3) { A[i] = RNG_UNIFORM_R(rng, 0, 1); diff --git a/src/test_ssp_ran_uniform_disk.h b/src/test_ssp_ran_uniform_disk.h @@ -85,8 +85,8 @@ TEST() mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng0) == RES_OK); - CHK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng1) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_THREEFRY, &rng0) == RES_OK); + CHK(ssp_rng_create(&allocator, SSP_RNG_THREEFRY, &rng1) == RES_OK); up[0] = RNG_UNIFORM_R(rng1, -1, 1); up[1] = RNG_UNIFORM_R(rng1, -1, 1); diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c @@ -38,10 +38,10 @@ #define NRAND 1024 static void /* Really basic test */ -test_rng(const struct ssp_rng_type* type) +test_rng(const enum ssp_rng_type type) { FILE* stream; - struct ssp_rng_type type2; + enum ssp_rng_type type2; struct ssp_rng* rng = NULL; struct ssp_rng* rng1 = NULL; struct ssp_rng* rng2 = NULL; @@ -56,23 +56,22 @@ test_rng(const struct ssp_rng_type* type) char* cstr = NULL; int i, j; res_T r; - 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); + 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); - CHK(type != NULL); - CHK(ssp_rng_create(NULL, NULL, NULL) == RES_BAD_ARG); - CHK(ssp_rng_create(&allocator, NULL, NULL) == RES_BAD_ARG); + CHK(ssp_rng_create(NULL, -1, NULL) == RES_BAD_ARG); + CHK(ssp_rng_create(&allocator, -1, NULL) == RES_BAD_ARG); CHK(ssp_rng_create(NULL, type, NULL) == RES_BAD_ARG); CHK(ssp_rng_create(&allocator, type, NULL) == RES_BAD_ARG); - CHK(ssp_rng_create(NULL, NULL, &rng) == RES_BAD_ARG); - CHK(ssp_rng_create(&allocator, NULL, &rng) == RES_BAD_ARG); + CHK(ssp_rng_create(NULL, -1, &rng) == RES_BAD_ARG); + CHK(ssp_rng_create(&allocator, -1, &rng) == RES_BAD_ARG); r = ssp_rng_create(NULL, type, &rng); #ifdef WITH_R123_AES - if (r == RES_BAD_OP && type == &ssp_rng_aes) { + if(r == RES_BAD_OP && type == SSP_RNG_AES) { printf("AES-NI instructions not available on this CPU and system.\n"); mem_shutdown_proxy_allocator(&allocator); check_memory_allocator(&allocator); @@ -85,7 +84,7 @@ test_rng(const struct ssp_rng_type* type) CHK(ssp_rng_get_type(rng, NULL) == RES_BAD_ARG); CHK(ssp_rng_get_type(NULL, &type2) == RES_BAD_ARG); CHK(ssp_rng_get_type(rng, &type2) == RES_OK); - CHK(ssp_rng_type_eq(type, &type2) == 1); + CHK(type == type2); CHK(ssp_rng_ref_get(NULL) == RES_BAD_ARG); CHK(ssp_rng_ref_get(rng) == RES_OK); @@ -100,8 +99,8 @@ test_rng(const struct ssp_rng_type* type) CHK(ssp_rng_create(NULL, type, &rng1) == RES_OK); CHK(ssp_rng_create(NULL, type, &rng2) == RES_OK); CHK(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); + if(type != SSP_RNG_RANDOM_DEVICE) { + FOR_EACH(i, 0, 10) ssp_rng_get(rng2); CHK(ssp_rng_get(rng1) == ssp_rng_get(rng2)); } @@ -267,18 +266,18 @@ main(int argc, char** argv) exit(0); } if(!strcmp(argv[1], "kiss")) { - test_rng(&ssp_rng_kiss); + test_rng(SSP_RNG_KISS); } else if(!strcmp(argv[1], "mt19937_64")) { - test_rng(&ssp_rng_mt19937_64); + test_rng(SSP_RNG_MT19937_64); } else if(!strcmp(argv[1], "ranlux48")) { - test_rng(&ssp_rng_ranlux48); + test_rng(SSP_RNG_RANLUX48); } else if(!strcmp(argv[1], "random_device")) { - test_rng(&ssp_rng_random_device); + test_rng(SSP_RNG_RANDOM_DEVICE); } else if(!strcmp(argv[1], "threefry")) { - test_rng(&ssp_rng_threefry); + test_rng(SSP_RNG_THREEFRY); #ifdef WITH_R123_AES } else if(!strcmp(argv[1], "aes")) { - test_rng(&ssp_rng_aes); + test_rng(SSP_RNG_AES); #endif } else { fprintf(stderr, "Unknown RNG `%s'\n", argv[1]); diff --git a/src/test_ssp_rng_proxy.c b/src/test_ssp_rng_proxy.c @@ -38,24 +38,24 @@ static void test_creation(void) { struct ssp_rng_proxy* proxy; - struct ssp_rng_type type; + enum ssp_rng_type type; - CHK(ssp_rng_proxy_create(NULL, NULL, 0, NULL) == RES_BAD_ARG); - CHK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 0, NULL) == RES_BAD_ARG); - CHK(ssp_rng_proxy_create(NULL, NULL, 4, NULL) == RES_BAD_ARG); - CHK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 4, NULL) == RES_BAD_ARG); - CHK(ssp_rng_proxy_create(NULL, NULL, 0, &proxy) == RES_BAD_ARG); - CHK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 0, &proxy) == RES_BAD_ARG); - CHK(ssp_rng_proxy_create(NULL, NULL, 4, &proxy) == RES_BAD_ARG); - CHK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 4, &proxy) == RES_OK); + CHK(ssp_rng_proxy_create(NULL, -1, 0, NULL) == RES_BAD_ARG); + CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 0, NULL) == RES_BAD_ARG); + CHK(ssp_rng_proxy_create(NULL, -1, 4, NULL) == RES_BAD_ARG); + CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, NULL) == RES_BAD_ARG); + CHK(ssp_rng_proxy_create(NULL, -1, 0, &proxy) == RES_BAD_ARG); + CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 0, &proxy) == RES_BAD_ARG); + CHK(ssp_rng_proxy_create(NULL, -1, 4, &proxy) == RES_BAD_ARG); + CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, &proxy) == RES_OK); CHK(ssp_rng_proxy_get_type(NULL, NULL) == RES_BAD_ARG); CHK(ssp_rng_proxy_get_type(proxy, NULL) == RES_BAD_ARG); CHK(ssp_rng_proxy_get_type(NULL, &type) == RES_BAD_ARG); CHK(ssp_rng_proxy_get_type(proxy, &type) == RES_OK); - CHK(ssp_rng_type_eq(&type, &ssp_rng_kiss) == 0); - CHK(ssp_rng_type_eq(&type, &ssp_rng_mt19937_64) == 1); + CHK(type != SSP_RNG_KISS); + CHK(type == SSP_RNG_MT19937_64); CHK(ssp_rng_proxy_ref_get(NULL) == RES_BAD_ARG); CHK(ssp_rng_proxy_ref_get(proxy) == RES_OK); @@ -64,9 +64,9 @@ test_creation(void) CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); CHK(ssp_rng_proxy_create - (&mem_default_allocator, &ssp_rng_threefry, 1, &proxy) == RES_OK); + (&mem_default_allocator, SSP_RNG_THREEFRY, 1, &proxy) == RES_OK); CHK(ssp_rng_proxy_get_type(proxy, &type) == RES_OK); - CHK(ssp_rng_type_eq(&type, &ssp_rng_threefry) == 1); + CHK(type == SSP_RNG_THREEFRY); CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); } @@ -78,16 +78,16 @@ test_creation2(void) CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); - args.type = &ssp_rng_mt19937_64; + args.type = SSP_RNG_MT19937_64; args.sequence_offset = 0; args.sequence_size = 32; args.sequence_pitch = 32; args.nbuckets = 1; CHK(ssp_rng_proxy_create2(NULL, &args, NULL) == RES_BAD_ARG); - args.type = NULL; + args.type = SSP_RNG_TYPE_NULL; CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); - args.type = &ssp_rng_mt19937_64; + args.type = SSP_RNG_MT19937_64; args.sequence_size= 0; CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); args.sequence_size = 32; @@ -125,13 +125,13 @@ test_creation2(void) static void test_rng_from_proxy(void) { - struct ssp_rng_type type; + enum ssp_rng_type type; struct ssp_rng_proxy* proxy; struct ssp_rng* rng[4]; uint64_t r[4]; size_t i, j, k; - CHK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 4, &proxy) == RES_OK); + CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, &proxy) == RES_OK); CHK(ssp_rng_proxy_create_rng(NULL, 0, NULL) == RES_BAD_ARG); CHK(ssp_rng_proxy_create_rng(proxy, 0, NULL) == RES_BAD_ARG); @@ -147,9 +147,9 @@ test_rng_from_proxy(void) CHK(ssp_rng_get_type(rng[0], &type) == RES_OK); FOR_EACH(i, 1, 4) { - struct ssp_rng_type type2; + enum ssp_rng_type type2; CHK(ssp_rng_get_type(rng[i], &type2) == RES_OK); - CHK(ssp_rng_type_eq(&type, &type2) == 1); + CHK(type == type2); } FOR_EACH(i, 0, NRANDS) { @@ -178,7 +178,7 @@ test_rng_from_proxy2(void) CHK((r[2] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL); CHK((r[3] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL); - args.type = &ssp_rng_mt19937_64; + args.type = SSP_RNG_MT19937_64; args.sequence_size = block_sz; args.sequence_pitch = block_sz; args.nbuckets = 4; @@ -215,7 +215,7 @@ test_rng_from_proxy2(void) CHK(ssp_rng_ref_put(rng[2]) == RES_OK); CHK(ssp_rng_ref_put(rng[3]) == RES_OK); - args.type = &ssp_rng_mt19937_64; + args.type = SSP_RNG_MT19937_64; args.sequence_size = block_sz; args.sequence_pitch = 2*block_sz; args.nbuckets = 2; @@ -273,12 +273,12 @@ test_multi_proxies(void) struct ssp_rng* rng3; size_t i; - CHK(ssp_rng_proxy_create(NULL, &ssp_rng_threefry, 1, &proxy1) == RES_OK); - CHK(ssp_rng_proxy_create(NULL, &ssp_rng_threefry, 1, &proxy2) == RES_OK); + CHK(ssp_rng_proxy_create(NULL, SSP_RNG_THREEFRY, 1, &proxy1) == RES_OK); + CHK(ssp_rng_proxy_create(NULL, SSP_RNG_THREEFRY, 1, &proxy2) == RES_OK); CHK(ssp_rng_proxy_create_rng(proxy1, 0, &rng1) == RES_OK); CHK(ssp_rng_proxy_create_rng(proxy2, 0, &rng2) == RES_OK); - ssp_rng_create(NULL, &ssp_rng_threefry, &rng3); + ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng3); CHK(ssp_rng_proxy_ref_put(proxy1) == RES_OK); CHK(ssp_rng_proxy_ref_put(proxy2) == RES_OK); @@ -301,11 +301,11 @@ test_proxy_from_rng(void) struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL; struct ssp_rng_proxy* proxy; struct ssp_rng* rng[4]; - struct ssp_rng_type type; + enum ssp_rng_type type; uint64_t r[4]; size_t i, j, k; - CHK(ssp_rng_create(NULL, &ssp_rng_threefry, &rng[0]) == RES_OK); + CHK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng[0]) == RES_OK); CHK(ssp_rng_discard(rng[0], COUNT) == RES_OK); CHK(ssp_rng_proxy_create_from_rng(NULL, NULL, 0, NULL) == RES_BAD_ARG); @@ -332,9 +332,9 @@ test_proxy_from_rng(void) CHK(ssp_rng_get_type(rng[0], &type) == RES_OK); FOR_EACH(i, 1, 4) { - struct ssp_rng_type type2; + enum ssp_rng_type type2; CHK(ssp_rng_get_type(rng[i], &type2) == RES_OK); - CHK(ssp_rng_type_eq(&type, &type2) == 1); + CHK(type == type2); } FOR_EACH(i, 0, NRANDS) { @@ -354,7 +354,7 @@ test_proxy_from_rng(void) CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); CHK(ssp_rng_ref_put(rng[0]) == RES_OK); - CHK(ssp_rng_create(NULL, &ssp_rng_threefry, &rng[0]) == RES_OK); + CHK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng[0]) == RES_OK); CHK(ssp_rng_discard(rng[0], 100) == RES_OK); args.rng = rng[0]; @@ -385,7 +385,7 @@ test_read(void) uint64_t r[4]; size_t i, j, k; - CHK(ssp_rng_create(NULL, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); CHK(ssp_rng_discard(rng, COUNT) == RES_OK); stream = tmpfile(); @@ -393,7 +393,7 @@ test_read(void) CHK(ssp_rng_write(rng, stream) == RES_OK); rewind(stream); - CHK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 4, &proxy) == RES_OK); + CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, &proxy) == RES_OK); CHK(ssp_rng_proxy_read(NULL, NULL) == RES_BAD_ARG); CHK(ssp_rng_proxy_read(proxy, NULL) == RES_BAD_ARG); CHK(ssp_rng_proxy_read(NULL, stream) == RES_BAD_ARG); @@ -432,7 +432,7 @@ test_write(void) stream = tmpfile(); CHK(stream != NULL); - CHK(ssp_rng_proxy_create(NULL, &ssp_rng_ranlux48, 1, &proxy) == RES_OK); + CHK(ssp_rng_proxy_create(NULL, SSP_RNG_RANLUX48, 1, &proxy) == RES_OK); CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK); CHK(ssp_rng_proxy_write(NULL, NULL) == RES_BAD_ARG); @@ -440,7 +440,7 @@ test_write(void) CHK(ssp_rng_proxy_write(NULL, stream) == RES_BAD_ARG); CHK(ssp_rng_proxy_write(proxy, stream) == RES_OK); - CHK(ssp_rng_create(NULL, &ssp_rng_ranlux48, &rng1) == RES_OK); + CHK(ssp_rng_create(NULL, SSP_RNG_RANLUX48, &rng1) == RES_OK); r = ssp_rng_get(rng0); CHK(r == ssp_rng_get(rng1)); @@ -472,7 +472,7 @@ test_cache(void) * Mersenne Twister RNG type since its internal state is the greatest one of * the proposed builtin type and is thus the one that will fill quickly the * cache stream. */ - args.type = &ssp_rng_mt19937_64; + args.type = SSP_RNG_MT19937_64; args.sequence_size = 4; args.sequence_pitch = 4; args.nbuckets = 2; @@ -484,7 +484,7 @@ test_cache(void) CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK); CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK); - CHK(ssp_rng_create(NULL, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); FOR_EACH(i, 0, nrands*2) { if((i / 2) % 2) { CHK(ssp_rng_get(rng1) == ssp_rng_get(rng)); @@ -500,7 +500,7 @@ test_cache(void) CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK); CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK); - CHK(ssp_rng_create(NULL, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); /* Generate several RNs for the first RNG only to make under pressure the * cache stream of 'rng1'. The cache stream limit is set to 32 MB and the @@ -518,7 +518,7 @@ test_cache(void) CHK(ssp_rng_ref_put(rng) == RES_OK); /* Check the cache mechanisme of rng1 */ - CHK(ssp_rng_create(NULL, &ssp_rng_mt19937_64, &rng) == RES_OK); + CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); CHK(ssp_rng_discard(rng, 2) == RES_OK); FOR_EACH(i, 0, nrands) { CHK(ssp_rng_get(rng1) == ssp_rng_get(rng));