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:
follow proposal have, instead of using
std::random_device r;
generate seed sequence mt, use different prng seededm
. 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.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
Post a Comment