c++ - Mersenne twister warm up vs. reproducibility -


in current c++11 project need perform m simulations. each simulation m = 1, ..., m, randomly generate data set using std::mt19937 object, constructed follows:

std::mt19937 generator(m); datasetfactory dsf(generator); 

according https://stackoverflow.com/a/15509942/1849221 , https://stackoverflow.com/a/14924350/1849221, mersenne twister prng benefits warm phase, absent in code. report convenience proposed snippet of code:

#include <random>  std::mt19937 get_prng() {     std::uint_least32_t seed_data[std::mt19937::state_size];     std::random_device r;     std::generate_n(seed_data, std::mt19937::state_size, std::ref(r));     std::seed_seq q(std::begin(seed_data), std::end(seed_data));     return std::mt19937{q}; } 

the problem in case need reproducibility of results, i.e., among different executions, each simulation, data set has same. that's reason why in current solution use current simulation seed mersenne twister prng. seems me usage of std::random_device prevents data being same (afaik, exact purpose of std::random_device).

edit: different executions mean re-launching executable.

how can introduce afore-mentioned warm phase in code without affecting reproducibility? thanks.

possible solution #1

here's tentative implementation based on second proposal @stevejessop

#include <random>  std::mt19937 get_generator(unsigned int seed) {         std::minstd_rand0 lc_generator(seed);         std::uint_least32_t seed_data[std::mt19937::state_size];          std::generate_n(seed_data, std::mt19937::state_size, std::ref(lc_generator));         std::seed_seq q(std::begin(seed_data), std::end(seed_data));         return std::mt19937{q};     } 

possible solution #2

here's tentative implementation based on joint contribution @stevejassop , @andréneve. sha256 function adapted https://stackoverflow.com/a/10632725/1849221

#include <openssl/sha.h> #include <sstream> #include <iomanip> #include <random>   std::string sha256(const std::string str) {     unsigned char hash[sha256_digest_length];     sha256_ctx sha256;     sha256_init(&sha256);     sha256_update(&sha256, str.c_str(), str.size());     sha256_final(hash, &sha256);      std::stringstream ss;     for(int = 0; < sha256_digest_length; i++)          ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];      return ss.str(); }  std::mt19937 get_generator(unsigned int seed) {     std::string seed_str = sha256(std::to_string(seed));     std::seed_seq q(seed_str.begin(), seed_str.end());     return std::mt19937{q}; } 

compile with: -i/opt/ssl/include/ -l/opt/ssl/lib/ -lcrypto

two options:

  1. follow proposal have, instead of using std::random_device r; generate seed sequence mt, use different prng seeded m. choose 1 doesn't suffer mt needing warmup when used small seed data: suspect lcg do. massive overkill, use prng based on secure hash. lot "key stretching" in cryptography, if you've heard of that. in fact use standard key stretching algorithm, you're using generate long seed sequence rather large key material.

  2. continue using m seed mt, discard large constant amount of data before starting simulation. say, ignore advice use strong seed , instead run mt long enough reach decent internal state. don't know off-hand how data need discard, expect internet does.


Comments

Popular posts from this blog

Why does Ruby on Rails generate add a blank line to the end of a file? -

keyboard - Smiles and long press feature in Android -

node.js - Bad Request - node js ajax post -