star-sp

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

commit 4da2e6bed1087fa334d8d11e41f2057c07cff459
parent 411db4829bbecfbdd9504cd8c7caeb844fcc6855
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Sat, 13 Jun 2015 14:57:37 +0200

Add threefry and aes counter based RNG (from Random123).

aes is currently activated with MSVC compiler only.

Diffstat:
Mcmake/CMakeLists.txt | 14++++++++++++--
Acmake/Random123Config.cmake | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ssp.h | 22+++++++++++++++-------
Msrc/ssp_rng.c | 87++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/test_ssp_rng.c | 24+++++++++++++++++++++---
5 files changed, 188 insertions(+), 13 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -39,6 +39,10 @@ option(NO_TEST "Disable the test" OFF) ################################################################################ # Check dependencies ################################################################################ +get_filename_component(_current_source_dir ${CMAKE_CURRENT_LIST_FILE} PATH) +set(Random123_DIR ${_current_source_dir}/) + +find_package(Random123 REQUIRED) find_package(RCMake 0.1 REQUIRED) find_package(RSys 0.2 REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) @@ -49,9 +53,11 @@ 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 COMPONENTS random) - include_directories(${RSys_INCLUDE_DIR} ${Boost_INCLUDE_DIRS}) + include_directories(${RSys_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${Random123_INCLUDE_DIR}) + # Random123 AES generator compiles on MSVC + add_definitions(-DWITH_R123_AES) else() - include_directories(${RSys_INCLUDE_DIR}) + include_directories(${RSys_INCLUDE_DIR} ${Random123_INCLUDE_DIR}) endif() rcmake_append_runtime_dirs(_runtime_dirs RSys) @@ -130,6 +136,10 @@ if(NOT NO_TEST) 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) + register_test(test_ssp_rng_threefry test_ssp_rng threefry) + if(MSVC) + register_test(test_ssp_rng_aes test_ssp_rng aes) + endif() new_test(test_ssp_ran_hemisphere ${MATH_LIB}) new_test(test_ssp_rng_proxy) endif() diff --git a/cmake/Random123Config.cmake b/cmake/Random123Config.cmake @@ -0,0 +1,54 @@ +# Copyright (C) |Meso|Star> 2015 (contact@meso-star.com) +# +# This software is a computer program whose purpose is to generate files +# used to build the Star-3D library. +# +# This software is governed by the CeCILL license under French law and +# abiding by the rules of distribution of free software. You can use, +# modify and/or redistribute the software under the terms of the CeCILL +# license as circulated by CEA, CNRS and INRIA at the following URL +# "http://www.cecill.info". +# +# As a counterpart to the access to the source code and rights to copy, +# modify and redistribute granted by the license, users are provided only +# with a limited warranty and the software's author, the holder of the +# economic rights, and the successive licensors have only limited +# liability. +# +# In this respect, the user's attention is drawn to the risks associated +# with loading, using, modifying and/or developing or reproducing the +# software by the user in light of its specific status of free software, +# that may mean that it is complicated to manipulate, and that also +# therefore means that it is reserved for developers and experienced +# professionals having in-depth computer knowledge. Users are therefore +# encouraged to load and test the software's suitability as regards their +# requirements in conditions enabling the security of their systems and/or +# data to be ensured and, more generally, to use and operate it in the +# same conditions as regards security. +# +# The fact that you are presently reading this means that you have had +# knowledge of the CeCILL license and that you accept its terms. + +cmake_minimum_required(VERSION 2.6) + +# Try to find the Random123 devel. Once done this will define: +# - Random123_FOUND: system has Random123 +# - Random123_INCLUDE_DIR: the include directory +# - Random123: Link this to use Random123 + +find_path(Random123_INCLUDE_DIR Random123/threefry.h) +find_library(Random123_LIBRARY Random123 DOC "Path to the library Random123.") + +# Create the imported library target +if(CMAKE_HOST_WIN32) + set(_property IMPORTED_IMPLIB) +else(CMAKE_HOST_WIN32) + set(_property IMPORTED_LOCATION) +endif(CMAKE_HOST_WIN32) +add_library(Random123 SHARED IMPORTED) + +# Check the package +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Random123 DEFAULT_MSG + Random123_INCLUDE_DIR) + diff --git a/src/ssp.h b/src/ssp.h @@ -89,14 +89,22 @@ 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; - -/* A random_device RNG is a uniformly-distributed integer random number generator - * that produces non-deterministic random numbers. It may 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. */ +/* +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; +/* 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 diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -33,7 +33,6 @@ #include <rsys/mem_allocator.h> -#include <cstring> #ifdef COMPILER_CL /* The random C++11 library is bugged on MSVC 12. Use the boost version */ #include <boost/random.hpp> @@ -47,7 +46,33 @@ #define RAN_NAMESPACE std #endif +#ifdef COMPILER_GCC + #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" /* conversion to ‘yyy’ from ‘xxx’ may alter its value */ +#elif defined(COMPILER_CL) +// disable some warnings in Random123 includes +#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> /******************************************************************************* * KISS PRNG @@ -364,6 +389,66 @@ const struct ssp_rng_type ssp_rng_random_device = { }; /******************************************************************************* +* Random123 Counter Based RNG +******************************************************************************/ + +typedef r123::Engine<r123::Threefry4x64> threefry_t; + +#ifdef WITH_R123_AES +typedef r123::Engine<r123::AESNI4x32> aes_t; + +template<> +res_T +rng_cxx_init<aes_t>(struct mem_allocator* allocator, void* data) +{ + (void) allocator; + if (!haveAESNI()) { + // AES-NI instructions not available on this hardware + return RES_BAD_OP; + } + ASSERT(data); + new (data) aes_t; + return RES_OK; +} +#endif + +/* threefry generator */ +const struct ssp_rng_type ssp_rng_threefry = { + rng_cxx_init<threefry_t>, + rng_cxx_release<threefry_t>, + rng_cxx_set<threefry_t>, + rng_cxx_get<threefry_t>, + rng_cxx_uniform_uint64<threefry_t>, + rng_cxx_uniform_double<threefry_t>, + rng_cxx_canonical<threefry_t>, + rng_cxx_read<threefry_t>, + rng_cxx_write<threefry_t>, + rng_cxx_entropy<threefry_t>, + std::numeric_limits<threefry_t::result_type>::min(), + std::numeric_limits<threefry_t::result_type>::max(), + sizeof(threefry_t) +}; + +#ifdef WITH_R123_AES +/* aes generator */ +const struct ssp_rng_type ssp_rng_aes = { + rng_cxx_init<aes_t>, + rng_cxx_release<aes_t>, + rng_cxx_set<aes_t>, + rng_cxx_get<aes_t>, + rng_cxx_uniform_uint64<aes_t>, + rng_cxx_uniform_double<aes_t>, + rng_cxx_canonical<aes_t>, + rng_cxx_read<aes_t>, + rng_cxx_write<aes_t>, + rng_cxx_entropy<aes_t>, + std::numeric_limits<aes_t::result_type>::min(), + std::numeric_limits<aes_t::result_type>::max(), + sizeof(aes_t) +}; +#endif + +/******************************************************************************* * Helper functions ******************************************************************************/ static char diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c @@ -49,6 +49,7 @@ test_rng(const struct ssp_rng_type* type) double dataf[NRAND]; char buf[512]; 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); @@ -62,7 +63,14 @@ test_rng(const struct ssp_rng_type* type) CHECK(ssp_rng_create(&allocator, type, NULL), RES_BAD_ARG); CHECK(ssp_rng_create(NULL, NULL, &rng), RES_BAD_ARG); CHECK(ssp_rng_create(&allocator, NULL, &rng), RES_BAD_ARG); - CHECK(ssp_rng_create(NULL, type, &rng), RES_OK); + r = ssp_rng_create(NULL, type, &rng); +#ifdef WITH_R123_AES + if (r == RES_BAD_OP && type == &ssp_rng_aes) { + printf("AES-NI instructions not available on this CPU and system.\n"); + return; + } +#endif + CHECK(r, RES_OK); CHECK(ssp_rng_ref_get(NULL), RES_BAD_ARG); CHECK(ssp_rng_ref_get(rng), RES_OK); @@ -170,8 +178,12 @@ test_rng(const struct ssp_rng_type* type) int main(int argc, char** argv) { - if(argc <= 1) { - fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48|random_device>\n", argv[0]); + if (argc <= 1) { +#ifdef WITH_R123_AES + fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48|random_device|threefry|aes>\n", argv[0]); +#else + fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48|random_device|threefry>\n", argv[0]); +#endif exit(0); } if(!strcmp(argv[1], "kiss")) { @@ -182,6 +194,12 @@ main(int argc, char** argv) test_rng(&ssp_rng_ranlux48); } else if(!strcmp(argv[1], "random_device")) { test_rng(&ssp_rng_random_device); + } else if(!strcmp(argv[1], "threefry")) { + test_rng(&ssp_rng_threefry); +#ifdef WITH_R123_AES + } else if(!strcmp(argv[1], "aes")) { + test_rng(&ssp_rng_aes); +#endif } else { fprintf(stderr, "Unknown RNG `%s'\n", argv[1]); ASSERT(0);