star-sp

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

commit 90e5d6683bff699f729097fc920b0cda88121e3d
parent 3b4dec0ae6068382fef1282d2b075efd98552f03
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 18 Mar 2019 10:32:28 +0100

API breaks: respect C++11 standard to fix gcc 11 compilation errors

According to the C++11 standard, the min/max value of an
UniformRandomBitGenerator must be static compile time constants.
However, up to now GCC was flexible enough to allow the use of
UniformRandomBitGenerators with runtime min/max values. At runtime, the
caller can 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 commit updates the API to respect this (dubious) C++11 constraint.
The ssp_rng_type is no more a structure; it becomes an enumerate that is
then internally instantiated into specific UniformRandomBitGenerators
with compile time min/max.

Unfortunately, the compilation time increases because of the class used
to encapsulate the C++ code: this class must be generic and must
therefore be resolved during compilation whereas previously it was a
common class. No performance gains were observed by this new
constraint. Only the disadvantages...

"A standard papier is just so much toilet paper when it conflicts with
reality" (Linus Torvald)

Diffstat:
Mcmake/CMakeLists.txt | 5+++++
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++++++++++++++++++++++++++++++++++++++--------------------------------------
23 files changed, 351 insertions(+), 292 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -70,6 +70,11 @@ 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 ################################################################################ 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));