Proper save/restore of RNG state in boost::random behaving unexpectedly -


i have small test program attempts save , restore state of random number generator using boost::random, not behaving documentation indicates. boost docs:

classes model pseudo-random number generator should model streamable concept, i.e. implement operator<< , operator>>. if so, operator<< writes current state of pseudo-random number generator given ostream operator>> can restore state @ later time. state shall written in platform-independent manner, assumed locales used writing , reading same. pseudo-random number generator restored state , original @ just-written state shall equivalent.

as understand it, if rng state saved , number pulled it, state should change. if state later restored, should allow exact same number generated generator has been rolled back. made test program examines this, @ first glance seems state not restored. consider code:

 unsigned int s = static_cast<unsigned int>(std::time(0)); //typedef boost::minstd_rand base_generator_type; typedef boost::mt19937 base_generator_type; base_generator_type randgen(s); boost::uniform_01<base_generator_type> getrand(randgen); //boost::normal_distribution<float> noise(0,1); //boost::variate_generator<base_generator_type, //boost::normal_distribution<float> > getrand(randgen, noise); double numsbefore[2], numsrightafter[2], numsnew[4]; //generate short sequence, save it, , display numsbefore[0] = getrand(); numsbefore[1] = getrand(); cout << "first sequence, before save: " << numsbefore[0] << " " << numsbefore[1] << endl; //save current rng state file using stream interface std::ofstream rngfileout("test_rngfile.txt"); rngfileout << randgen; rngfileout.close(); //generate next 2 numbers , display numsrightafter[0] = getrand(); numsrightafter[1] = getrand(); cout << "next, right after save: " << numsrightafter[0] << " " << numsrightafter[1] << endl; //read in rng state saved, rng, restoring state //to such prior recent 2 calls randgen() std::ifstream rngfilein("test_rngfile.txt", ifstream::in); if(!rngfilein.good()) { cout << "couldn't read file\n"; return 0; } rngfilein >> randgen; rngfilein.close(); //declare , initialize new variate generator newly-restored generator boost::uniform_01<base_generator_type> getrand2(randgen); // boost::variate_generator<base_generator_type, // boost::normal_distribution<float> > getrand2(randgen, noise); //copy new variate function old one, allow use //the old 1 on restored generator getrand = getrand2; //generate next sequence //the first 2 should same recent 2 called //the next 2 should new random numbers numsnew[0] = getrand(); numsnew[1] = getrand(); numsnew[2] = getrand(); numsnew[3] = getrand(); cout << "restored, next: " << numsnew[0] << " " << numsnew[1] << " " << numsnew[2] << " " << numsnew[3] << endl; 

the output given time seed is:

first sequence, before save: 0.970021 0.266862
next, right after save: 0.110485 0.267466
restored, next: 0.970021 0.266862 0.110485 0.267466


the code's comments illustrate think should happening. also, lines include commented code same test different generator , different distribution. same problem occurs of those: next 2 values taken generator randgen after state has been restored not same 2 generated after save, should be.

upon closer inspection (debugging), appears calls variate generator getrand() not change state of generator randgen @ no matter how many times call getrand() on it, , when save it, remains same if created, , thus, when pull again after restoration, starts beginning.

shouldn't each call generator cause state advance? how getting sequences not same numbers if rng state never changes? generator i'm viewing/saving not "real" one, or something?

also, assignment operation of getrand = getrand2 might sketchy = operator defined those,and replacing last 4 calls getrand2() doesn't make difference.

is generator i'm viewing/saving not "real" one, or something?

that indeed case. uniform_01 constructor you're using makes copy of provided engine, rather taking reference.

if you're using boost 1.39 or later, can use instead:

boost::uniform_01<> getrand; getrand(randgen); 

if you're stuck on older boost , don't need getrand copyable, changing uniform_01's type parameter base_generator_type base_generator_type& should work.


Comments

Popular posts from this blog

javascript - backbone.js Collection.add() doesn't `construct` (`initialize`) an object -

php - Get uncommon values from two or more arrays -

Adding duplicate array rows in Php -