star-sp

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

commit 7ed7da09762e6a32f60d635a71e2d8b7952a3c1e
parent 6c7fa93fd5e0a6de489c8c27b391f70e5fe69892
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon,  1 Jun 2015 18:26:41 +0200

Add random_device generator from boost or C++11 standard lib.
This generator can be hardware based.
See std::random_device for reference documentation.

Diffstat:
Mcmake/CMakeLists.txt | 9+++++++--
Msrc/ssp.h | 10++++++++++
Msrc/ssp_rng.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_ssp_rng.c | 30+++++++++++++++++++-----------
4 files changed, 87 insertions(+), 13 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -48,7 +48,7 @@ include(rcmake_runtime) if(MSVC) # Currently, the C++11 random library on MSVC is bugged and consequently we # use the Boost library instead - find_package(Boost 1.58 REQUIRED) + find_package(Boost 1.58 REQUIRED COMPONENTS random) include_directories(${RSys_INCLUDE_DIR} ${Boost_INCLUDE_DIRS}) else() include_directories(${RSys_INCLUDE_DIR}) @@ -84,7 +84,11 @@ set_target_properties(ssp PROPERTIES SOVERSION ${VERSION_MAJOR}) target_link_libraries(ssp RSys) -if(CMAKE_COMPILER_IS_GNUCXX) +if(MSVC) + target_link_libraries(ssp ${Boost_LIBRARIES}) + # disable autolink + set_target_properties(ssp PROPERTIES COMPILE_FLAGS "/DBOOST_ALL_NO_LIB") +elseif(CMAKE_COMPILER_IS_GNUCXX) set_target_properties(ssp PROPERTIES COMPILE_FLAGS "-std=c++11") endif() @@ -125,6 +129,7 @@ if(NOT NO_TEST) register_test(test_ssp_rng_kiss test_ssp_rng kiss) register_test(test_ssp_rng_mt19937_64 test_ssp_rng mt19937_64) register_test(test_ssp_rng_ranlux48 test_ssp_rng ranlux48) + register_test(test_ssp_rng_random_device test_ssp_rng random_device) new_test(test_ssp_ran_hemisphere ${MATH_LIB}) new_test(test_ssp_rng_proxy) endif() diff --git a/src/ssp.h b/src/ssp.h @@ -89,6 +89,16 @@ SSP_API const struct ssp_rng_type ssp_rng_kiss; 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; +/* +random_device generator from Boost / C++11 +std::random_device is a uniformly-distributed integer random number generator +that produces non-deterministic random numbers. +std::random_device 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 std::random_device object may generate the same number sequence. +*/ +SSP_API const struct ssp_rng_type ssp_rng_random_device; /******************************************************************************* * Random Number Generator API diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -37,6 +37,7 @@ #ifdef COMPILER_CL /* The random C++11 library is bugged on MSVC 12. Use the boost version */ #include <boost/random.hpp> + #include <boost/random/random_device.hpp> #define RAN_NAMESPACE boost::random #pragma warning(push) @@ -181,6 +182,14 @@ rng_cxx_set(void* data, const uint64_t seed) return RES_OK; } +template<> +res_T +rng_cxx_set<RAN_NAMESPACE::random_device>(void* data, const uint64_t seed) +{ + (void) data; (void) seed; + return RES_BAD_OP; +} + template<typename RNG> static uint64_t rng_cxx_get(void* data) @@ -233,6 +242,14 @@ rng_cxx_write(const void* data, FILE* file) return i == stream.str().size() ? RES_OK : RES_IO_ERR; } +template<> +res_T +rng_cxx_write<RAN_NAMESPACE::random_device>(const void* data, FILE* file) +{ + (void) data; (void) file; + return RES_BAD_OP; +} + template<typename RNG> static res_T rng_cxx_read(void* data, FILE* file) @@ -250,6 +267,14 @@ rng_cxx_read(void* data, FILE* file) return stream.fail() ? RES_IO_ERR : RES_OK; } +template<> +res_T +rng_cxx_read<RAN_NAMESPACE::random_device>(void* data, FILE* file) +{ + (void) data; (void) file; + return RES_BAD_OP; +} + template<typename RNG> static res_T rng_cxx_init(struct mem_allocator* allocator, void* data) @@ -278,6 +303,15 @@ rng_cxx_entropy(const void* data) return 0; } +template<> +double +rng_cxx_entropy<RAN_NAMESPACE::random_device>(const void* data) +{ + const RAN_NAMESPACE::random_device* rng = (const RAN_NAMESPACE::random_device*)data; + ASSERT(rng); + return rng->entropy(); +} + /* 64-bits Mersenne Twister PRNG */ const struct ssp_rng_type ssp_rng_mt19937_64 = { rng_cxx_init<RAN_NAMESPACE::mt19937_64>, @@ -312,6 +346,23 @@ const struct ssp_rng_type ssp_rng_ranlux48 = { sizeof(RAN_NAMESPACE::ranlux48) }; +/* random_device generator */ +const struct ssp_rng_type ssp_rng_random_device = { + rng_cxx_init<RAN_NAMESPACE::random_device>, + rng_cxx_release<RAN_NAMESPACE::random_device>, + rng_cxx_set<RAN_NAMESPACE::random_device>, + rng_cxx_get<RAN_NAMESPACE::random_device>, + rng_cxx_uniform_uint64<RAN_NAMESPACE::random_device>, + rng_cxx_uniform_double<RAN_NAMESPACE::random_device>, + rng_cxx_canonical<RAN_NAMESPACE::random_device>, + rng_cxx_read<RAN_NAMESPACE::random_device>, + rng_cxx_write<RAN_NAMESPACE::random_device>, + rng_cxx_entropy<RAN_NAMESPACE::random_device>, + RAN_NAMESPACE::random_device::min(), + RAN_NAMESPACE::random_device::max(), + sizeof(RAN_NAMESPACE::random_device) +}; + /******************************************************************************* * Helper functions ******************************************************************************/ diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c @@ -49,6 +49,9 @@ test_rng(const struct ssp_rng_type* type) double dataf[NRAND]; char buf[512]; int i, j; + 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); mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -69,7 +72,7 @@ test_rng(const struct ssp_rng_type* type) CHECK(ssp_rng_create(&allocator, type, &rng), RES_OK); CHECK(ssp_rng_set(NULL, 0), RES_BAD_ARG); - CHECK(ssp_rng_set(rng, 0), RES_OK); + CHECK(ssp_rng_set(rng, 0), can_set ? RES_OK : RES_BAD_OP); FOR_EACH(i, 0, NRAND) { datai0[i] = ssp_rng_get(rng); @@ -80,7 +83,7 @@ test_rng(const struct ssp_rng_type* type) } } - CHECK(ssp_rng_set(rng, 0xDECAFBAD), RES_OK); + CHECK(ssp_rng_set(rng, 0xDECAFBAD), can_set ? RES_OK : RES_BAD_OP); FOR_EACH(i, 0, NRAND) { datai1[i] = ssp_rng_get(rng); NCHECK(datai1[i], datai0[i]); @@ -129,13 +132,16 @@ test_rng(const struct ssp_rng_type* type) time_dump(&t0, TIME_SEC|TIME_MSEC|TIME_USEC, NULL, buf, sizeof(buf)); printf("1,000,000 random numbers in %s\n", buf); + if (can_have_entropy) { + printf("Entropy for this implementation and system: %lf\n", ssp_rng_entropy(rng)); + } stream = tmpfile(); NCHECK(stream, NULL); CHECK(ssp_rng_write(NULL, NULL), RES_BAD_ARG); CHECK(ssp_rng_write(rng, NULL), RES_BAD_ARG); CHECK(ssp_rng_write(NULL, stream), RES_BAD_ARG); - CHECK(ssp_rng_write(rng, stream), RES_OK); + CHECK(ssp_rng_write(rng, stream), can_rw ? RES_OK : RES_BAD_OP); FOR_EACH(i, 0, NRAND) datai0[i] = ssp_rng_get(rng); @@ -143,15 +149,15 @@ test_rng(const struct ssp_rng_type* type) CHECK(ssp_rng_read(NULL, NULL), RES_BAD_ARG); CHECK(ssp_rng_read(rng, NULL), RES_BAD_ARG); CHECK(ssp_rng_read(NULL, stream), RES_BAD_ARG); -#ifndef COMPILER_CL - CHECK(ssp_rng_read(rng, stream), RES_IO_ERR); -#endif + CHECK(ssp_rng_read(rng, stream), can_rw ? RES_IO_ERR : RES_BAD_OP); rewind(stream); - CHECK(ssp_rng_read(rng, stream), RES_OK); + CHECK(ssp_rng_read(rng, stream), can_rw ? RES_OK : RES_BAD_OP); - FOR_EACH(i, 0, NRAND) { - uint64_t r = ssp_rng_get(rng); - CHECK(r, datai0[i]); + if (can_rw) { + FOR_EACH(i, 0, NRAND) { + uint64_t r = ssp_rng_get(rng); + CHECK(r, datai0[i]); + } } fclose(stream); @@ -164,7 +170,7 @@ int main(int argc, char** argv) { if(argc <= 1) { - fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48>\n", argv[0]); + fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48|random_device>\n", argv[0]); exit(0); } if(!strcmp(argv[1], "kiss")) { @@ -173,6 +179,8 @@ main(int argc, char** argv) test_rng(&ssp_rng_mt19937_64); } else if(!strcmp(argv[1], "ranlux48")) { test_rng(&ssp_rng_ranlux48); + } else if(!strcmp(argv[1], "random_device")) { + test_rng(&ssp_rng_random_device); } else { fprintf(stderr, "Unknown RNG `%s'\n", argv[1]); ASSERT(0);