00001 /** 00002 * \file RandomEngine.hpp 00003 * \brief Header for RandomEngine. 00004 * 00005 * Written by <a href="http://charles.karney.info/">Charles Karney</a> 00006 * <charles@karney.com> and licensed under the LGPL. For more information, see 00007 * http://charles.karney.info/random/ 00008 **********************************************************************/ 00009 00010 #if !defined(RANDOMENGINE_HPP) 00011 #define RANDOMENGINE_HPP "$Id: RandomEngine.hpp 6489 2008-11-10 21:37:47Z ckarney $" 00012 00013 #include "RandomLib/RandomSeed.hpp" 00014 #include "RandomLib/RandomAlgorithm.hpp" 00015 #include "RandomLib/RandomMixer.hpp" 00016 #include <limits> 00017 #include <string> 00018 00019 #if HAVE_BOOST_SERIALIZATION 00020 #include <boost/serialization/nvp.hpp> 00021 #include <boost/serialization/split_member.hpp> 00022 #include <boost/serialization/vector.hpp> 00023 #endif 00024 00025 namespace RandomLib { 00026 /** 00027 * \brief Uniform random number generator. 00028 * 00029 * This implements a generic random number generator. Such a generator 00030 * requires two data holders RandomSeed, to hold the seed, and RandomEngine, 00031 * to hold the state. In addition we need two piece of machinery, a "Mixer" 00032 * to convert the seed into an initial state and an "Algorithm" to advance the 00033 * state. 00034 * 00035 * RandomSeed is responsible for setting and reporting the seed. 00036 * 00037 * Mixer has no state and implements only static methods. It needs to have 00038 * the following public interface 00039 * - typedef mixer_t: a RandomType giving the output type 00040 * - unsigned version: an identifying version number 00041 * - static std::string Name(): an identifying name for the mixer 00042 * - static method SeedToState: converts a seed into n words of state. 00043 * 00044 * Algorithm has no state and implements only static methods. It needs to have 00045 * the following public interface 00046 * - typedef engine_t: a RandomType giving the output type 00047 * - typedef internal_type: a integer type used by Transition. This is 00048 * usually the same as engine_t::type. However it allows the use of 00049 * vector instructions on some platforms. We require that engine_t::type 00050 * and internal_type line up properly in a union so that there is no need 00051 * to convert the data explicity between interal_type and engine_t::type. 00052 * - unsigned version: an identifying version number 00053 * - static std::string Name(): an identifying name for the mixer 00054 * - enum N: the size of the state in units of engine_t. 00055 * - static method Transition: steps the generator forwards or backwards. 00056 * - static method Generate: tempers the state immediately prior to output 00057 * - static method NormalizeState: force the initial state (the result of 00058 * the Mixer) into a legal state. 00059 * - static method CheckState accumulates the checksum for the state into 00060 * check. In addition it throws an exception if the state is bad. 00061 * 00062 * RandomEngine is the glue that holds everything together. It repacks 00063 * the mixer_t data from Mixer into engine_t if necessary. It deals with 00064 * delivering individual random results, stepping the state forwards and 00065 * backwards, leapfrogging the generator, I/O of the generator, etc. 00066 * 00067 * Written by <a href="http://charles.karney.info/"> Charles Karney</a> 00068 * <charles@karney.com> and licensed under the LGPL. For more information, 00069 * see http://charles.karney.info/random/ 00070 **********************************************************************/ 00071 template<class Algorithm, class Mixer> 00072 class RandomEngine : public RandomSeed { 00073 private: 00074 /** 00075 * The result RandomType (carried over from the \a Algorithm). 00076 **********************************************************************/ 00077 typedef typename Algorithm::engine_t result_t; 00078 /** 00079 * The RandomType used by the \a Mixer. 00080 **********************************************************************/ 00081 typedef typename Mixer::mixer_t mixer_t; 00082 /** 00083 * The internal_type used by the Algorithm::Transition(). 00084 **********************************************************************/ 00085 typedef typename Algorithm::internal_type engine_type; 00086 public: 00087 /** 00088 * The number of random bits produced by Ran(). 00089 **********************************************************************/ 00090 enum { 00091 width = result_t::width, 00092 }; 00093 00094 /** 00095 * A type large enough to hold \e width bits. This is used for the 00096 * internal state of the generator and the result returned by Ran(). 00097 **********************************************************************/ 00098 typedef typename result_t::type result_type; 00099 00100 /** 00101 * The minimum result returned by Ran(). 00102 **********************************************************************/ 00103 static const result_type min = result_t::min; 00104 00105 /** 00106 * The maximum result returned by Ran() = 2<sup><i>w</i></sup> - 1 00107 **********************************************************************/ 00108 static const result_type max = result_t::max; 00109 00110 protected: 00111 00112 /** 00113 * The mask for the result_t. 00114 **********************************************************************/ 00115 static const result_type mask = result_t::mask; 00116 00117 private: 00118 /** 00119 * A version number "RandLib0" to ensure safety of Save/Load. The next 7 00120 * bytes can be regarded as a "signature" and the 8th byte a version 00121 * number. 00122 **********************************************************************/ 00123 static const u64::type version = 0x52616e644c696230ULL; // 'RandLib0' 00124 /** 00125 * Marker for uninitialized object 00126 **********************************************************************/ 00127 static const unsigned UNINIT = 0xffffffffU; 00128 enum { 00129 /** 00130 * The size of the state in units of result_type 00131 **********************************************************************/ 00132 N = Algorithm::N, 00133 /** 00134 * The size of the state in units of mixer_t::type 00135 **********************************************************************/ 00136 NU = (N * width + mixer_t::width - 1) / mixer_t::width, 00137 /** 00138 * The size of the state in units of engine_type. 00139 **********************************************************************/ 00140 NV = N * sizeof(result_type) / sizeof(engine_type), 00141 }; 00142 00143 /** 00144 * \brief Union for the state. 00145 * 00146 * A union to hold the state in the result_type, mixer_t::type, and 00147 * engine_type representations. 00148 **********************************************************************/ 00149 union { 00150 /** 00151 * the result_type representation returned by Ran() 00152 **********************************************************************/ 00153 result_type _state[N]; 00154 /** 00155 * the mixer_t::type representation returned by Mixer::SeedToState. 00156 **********************************************************************/ 00157 typename mixer_t::type _stateu[NU]; 00158 /** 00159 * the engine_type representation returned by Algorithm::Transition. 00160 **********************************************************************/ 00161 engine_type _statev[NV]; 00162 }; 00163 00164 /** 00165 * The index for the next random value 00166 **********************************************************************/ 00167 unsigned _ptr; 00168 /** 00169 * How many times has Transition() been called 00170 **********************************************************************/ 00171 long long _rounds; 00172 /** 00173 * Stride for leapfrogging 00174 **********************************************************************/ 00175 unsigned _stride; 00176 00177 public: 00178 00179 /** \name Constructors 00180 **********************************************************************/ 00181 ///@{ 00182 /** 00183 * Initialize from a vector. Only the low \e 32 bits of each element are 00184 * used. 00185 **********************************************************************/ 00186 template<typename IntType> 00187 explicit RandomEngine(const std::vector<IntType>& v) 00188 throw(std::bad_alloc) { Reseed(v); } 00189 /** 00190 * Initialize from a pair of iterators setting seed to [\a a, \a b). The 00191 * iterator must produce results which can be converted into seed_type. 00192 * Only the low \e 32 bits of each element are used. 00193 **********************************************************************/ 00194 template<typename InputIterator> 00195 RandomEngine(InputIterator a, InputIterator b) 00196 { Reseed(a, b); } 00197 /** 00198 * Initialize with seed [\a n]. Only the low \e width bits of \a n are 00199 * used. 00200 **********************************************************************/ 00201 explicit RandomEngine(seed_type n) throw(std::bad_alloc) 00202 { Reseed(n); } 00203 /** 00204 * Initialize with seed [SeedVector()] 00205 **********************************************************************/ 00206 RandomEngine() throw(std::bad_alloc) { Reseed(); } 00207 /** 00208 * Initialize from a string. See Reseed(const std::string& s) 00209 **********************************************************************/ 00210 explicit RandomEngine(const std::string& s) throw(std::bad_alloc) 00211 { Reseed(s); } 00212 00213 ///@} 00214 00215 /** \name Functions for returning random data 00216 **********************************************************************/ 00217 ///@{ 00218 /** 00219 * Return \e width bits of randomness. This is the natural unit of random 00220 * data produced random numnber generator. 00221 **********************************************************************/ 00222 result_type Ran() throw() { 00223 if (_ptr >= N) 00224 Next(); 00225 result_type y = _state[_ptr]; 00226 _ptr += _stride; 00227 00228 return Algorithm::Generate(y); 00229 } 00230 00231 /** 00232 * Return 32 bits of randomness. 00233 **********************************************************************/ 00234 u32::type Ran32() throw() { 00235 // return width > 32 ? u32::cast(Ran()) : Ran(); 00236 return u32::cast(Ran()); 00237 } 00238 00239 /** 00240 * Return 64 bits of randomness. 00241 **********************************************************************/ 00242 u64::type Ran64() throw() { 00243 const u64::type x = Ran(); 00244 return width > 32 ? x : u64::cast(Ran()) << (64 - width) | x; 00245 } 00246 00247 /** 00248 * Return \e width bits of randomness. Result is in [0, 00249 * 2<sup><i>w</i></sup>) 00250 **********************************************************************/ 00251 result_type operator()() throw() { return Ran(); } 00252 ///@} 00253 00254 /** \name Comparing Random objects 00255 **********************************************************************/ 00256 ///@{ 00257 /** 00258 * Test equality of two Random objects. This test that the seeds match and 00259 * that they have produced the same number of random numbers. 00260 **********************************************************************/ 00261 bool operator==(const RandomEngine& r) const throw() 00262 // Ensure that the two Random objects behave the same way. Note however 00263 // that the internal states may still be different, e.g., the following all 00264 // result in Random objects which are == (with Count() == 0) but which all 00265 // have different internal states: 00266 // 00267 // Random r(0); _ptr == UNINIT 00268 // r.StepCount( 1); r.StepCount(-1); _ptr == 0, _rounds == 0 00269 // r.StepCount(-1); r.StepCount( 1); _ptr == N, _rounds == -1 00270 { return Count() == r.Count() && _seed == r._seed && 00271 _stride == r._stride; } 00272 /** 00273 * Test inequality of two Random objects. See Random::operator== 00274 **********************************************************************/ 00275 bool operator!=(const RandomEngine& r) const throw() 00276 { return !operator==(r); } 00277 ///@} 00278 00279 /** \name Writing to and reading from a stream 00280 **********************************************************************/ 00281 ///@{ 00282 /** 00283 * Save the state of the Random object to an output stream. Format is a 00284 * sequence of unsigned 32-bit integers written either in decimal (\a bin 00285 * false, text format) or in network order with most significant byte first 00286 * (\a bin true, binary format). Data consists of: 00287 * 00288 * - RandomLib magic string + version (2 words) 00289 * - Algorithm version (1 word) 00290 * - Mixer version (1 word) 00291 * - _seed.size() (1 word) 00292 * - _seed data (_seed.size() words) 00293 * - _ptr (1 word) 00294 * - _stride (1 word) 00295 * - if _ptr != UNINIT, _rounds (2 words) 00296 * - if _ptr != UNINIT, _state (N words or 2 N words) 00297 * - checksum 00298 * 00299 * Shortest possible saved result consists of 8 words. This corresponds to 00300 * RandomSeed() = [] and Count() = 0. 00301 **********************************************************************/ 00302 void Save(std::ostream& os, bool bin = true) const 00303 throw(std::ios::failure); 00304 /** 00305 * Restore the state of the Random object from an input stream. If \a bin, 00306 * read in binary, else use text format. See documentation of 00307 * RandomEngine::Save for the format. Include error checking on date to 00308 * make sure the input has not been corrupted. If an error occurs while 00309 * reading, the Random object is unchanged. 00310 **********************************************************************/ 00311 void Load(std::istream& is, bool bin = true) 00312 throw(std::ios::failure, std::out_of_range, std::bad_alloc) { 00313 // Read state into temporary so as not to change object on error. 00314 RandomEngine t(is, bin); 00315 _seed.reserve(t._seed.size()); 00316 *this = t; 00317 } 00318 ///@} 00319 00320 /** \name Basic I/O 00321 **********************************************************************/ 00322 ///@{ 00323 /** 00324 * Write the state of a generator to stream \a os as text 00325 **********************************************************************/ 00326 friend std::ostream& operator<<(std::ostream& os, const RandomEngine& r) { 00327 r.Save(os, false); 00328 return os; 00329 } 00330 00331 /** 00332 * Read the state of a generator from stream \a is as text 00333 **********************************************************************/ 00334 friend std::istream& operator>>(std::istream& is, RandomEngine& r) { 00335 r.Load(is, false); 00336 return is; 00337 } 00338 ///@} 00339 00340 /** \name Examining and advancing the Random generator 00341 **********************************************************************/ 00342 ///@{ 00343 /** 00344 * Return the number of random numbers used. This needs to return a long 00345 * long result since it can reasonably exceed 2<sup>31</sup>. (On a 1GHz 00346 * machine, it takes about a minute to produce 2<sup>32</sup> random 00347 * numbers.) More precisely this is the (zero-based) index of the next 00348 * random number to be produced. (This distinction is important when 00349 * leapfrogging is in effect.) 00350 **********************************************************************/ 00351 long long Count() const throw() 00352 { return _ptr == UNINIT ? 0 : _rounds * N + _ptr; } 00353 /** 00354 * Step the generator forwards of backwarks so that the value returned 00355 * by Count() is \a n 00356 **********************************************************************/ 00357 void SetCount(long long n) throw() { StepCount(n - Count()); } 00358 /** 00359 * Step the generator forward \a n steps. \a n can be negative. 00360 **********************************************************************/ 00361 void StepCount(long long n) throw(); 00362 /** 00363 * Resets the sequence. Equivalent to SetCount(0), but works by 00364 * reinitializing the Random object from its seed, rather than by stepping 00365 * the sequence backwards. In addition, this undoes leapfrogging. 00366 **********************************************************************/ 00367 void Reset() throw() { _ptr = UNINIT; _stride = 1; } 00368 ///@} 00369 00370 /** \name Leapfrogging 00371 **********************************************************************/ 00372 ///@{ 00373 /** 00374 * Set leapfrogging stride to a positive number \a n and increment Count() 00375 * by \a k < \a n. If the current Count() is \a i, then normally the next 00376 * 3 random numbers would have (zero-based) indices \a i, \a i + 1, \a i + 00377 * 2, and the new Count() is \a i + 2. However, after SetStride(\a n, \a 00378 * k) the next 3 random numbers have indices \a i + \a k, \a i + \a k + \a 00379 * n, \a i + \a k + 2\a n, and the new Count() is \a i + \a k + 3\a n. 00380 * With leapfrogging in effect, the time to produce raw random numbers is 00381 * roughly proportional to 1 + (\a n - 1)/2. Reseed(...) and Reset() both 00382 * reset the stride back to 1. See \ref leapfrog "Leapfrogging" for a 00383 * description of how to use this facility. 00384 **********************************************************************/ 00385 void SetStride(unsigned n = 1, unsigned k = 0) 00386 throw(std::invalid_argument) { 00387 // Limit stride to UNINIT/2. This catches negative numbers that have 00388 // been cast into unsigned. In reality the stride should be no more than 00389 // 10-100. 00390 if (n == 0 || n > UNINIT/2) 00391 throw std::invalid_argument("RandomEngine: Invalid stride"); 00392 if (k >= n) 00393 throw std::invalid_argument("RandomEngine: Invalid index"); 00394 _stride = n; 00395 StepCount(k); 00396 } 00397 /** 00398 * Return leapfrogging stride. 00399 **********************************************************************/ 00400 unsigned GetStride() const throw() { return _stride; } 00401 ///@} 00402 00403 /** 00404 * Tests basic engine. Throws out_of_range errors on bad results. 00405 **********************************************************************/ 00406 static void SelfTest(); 00407 00408 /** 00409 * Return the name of the generator. This incorporates the names of the \a 00410 * Algorithm and \a Mixer. 00411 **********************************************************************/ 00412 static std::string Name() throw() { 00413 return "RandomEngine<" + Algorithm::Name() + "," + Mixer::Name() + ">"; 00414 } 00415 00416 private: 00417 /** 00418 * Compute initial state from seed 00419 **********************************************************************/ 00420 void Init() throw(); 00421 /** 00422 * The interface to Transition used by Ran(). 00423 **********************************************************************/ 00424 void Next() throw() { 00425 if (_ptr == UNINIT) 00426 Init(); 00427 _rounds += _ptr/N; 00428 Algorithm::Transition(_ptr/N, _statev); 00429 _ptr %= N; 00430 } 00431 00432 u32::type Check(u64::type v, u32::type e, u32::type m) const 00433 throw(std::out_of_range); 00434 00435 static result_type SelfTestResult(unsigned k) throw () { 00436 return 0; 00437 } 00438 00439 /** 00440 * Read from an input stream. Potentially corrupts object. This private 00441 * constructor is used by RandomEngine::Load so that it can avoid 00442 * corrupting its state on bad input. 00443 **********************************************************************/ 00444 explicit RandomEngine(std::istream& is, bool bin) 00445 throw(std::ios::failure, std::out_of_range, std::bad_alloc); 00446 00447 #if HAVE_BOOST_SERIALIZATION 00448 friend class boost::serialization::access; 00449 /** 00450 * Save to a boost archive. Boost versioning isn't very robust. (It 00451 * allows a RandomGenerator32 to be read back in as a RandomGenerator64. 00452 * It doesn't interact well with templates.) So we do our own versioning 00453 * and supplement this with a checksum. 00454 **********************************************************************/ 00455 template<class Archive> void save(Archive& ar, const unsigned int) const { 00456 u64::type _version = version; 00457 u32::type _eversion = Algorithm::version, 00458 _mversion = Mixer::version, 00459 _checksum = Check(_version, _eversion, _mversion); 00460 ar & boost::serialization::make_nvp("version" , _version ) 00461 & boost::serialization::make_nvp("eversion", _eversion) 00462 & boost::serialization::make_nvp("mversion", _mversion) 00463 & boost::serialization::make_nvp("seed" , _seed ) 00464 & boost::serialization::make_nvp("ptr" , _ptr ) 00465 & boost::serialization::make_nvp("stride" , _stride ); 00466 if (_ptr != UNINIT) 00467 ar & boost::serialization::make_nvp("rounds", _rounds ) 00468 & boost::serialization::make_nvp("state" , _state ); 00469 ar & boost::serialization::make_nvp("checksum", _checksum); 00470 } 00471 /** 00472 * Load from a boost archive. Do this safely so that the current object is 00473 * not corrupted if the archive is bogus. 00474 **********************************************************************/ 00475 template<class Archive> void load(Archive& ar, const unsigned int) { 00476 u64::type _version; 00477 u32::type _eversion, _mversion, _checksum; 00478 ar & boost::serialization::make_nvp("version" , _version ) 00479 & boost::serialization::make_nvp("eversion", _eversion ) 00480 & boost::serialization::make_nvp("mversion", _mversion ); 00481 RandomEngine<Algorithm, Mixer> t(std::vector<seed_type>(0)); 00482 ar & boost::serialization::make_nvp("seed" , t._seed ) 00483 & boost::serialization::make_nvp("ptr" , t._ptr ) 00484 & boost::serialization::make_nvp("stride" , t._stride ); 00485 if (t._ptr != UNINIT) 00486 ar & boost::serialization::make_nvp("rounds", t._rounds ) 00487 & boost::serialization::make_nvp("state" , t._state ); 00488 ar & boost::serialization::make_nvp("checksum", _checksum ); 00489 if (t.Check(_version, _eversion, _mversion) != _checksum) 00490 throw std::out_of_range("RandomEngine: Checksum failure"); 00491 _seed.reserve(t._seed.size()); 00492 *this = t; 00493 } 00494 /** 00495 * Glue the boost save and load functionality together -- a bit of boost 00496 * magic. 00497 **********************************************************************/ 00498 template<class Archive> 00499 void serialize(Archive &ar, const unsigned int file_version) 00500 { boost::serialization::split_member(ar, *this, file_version); } 00501 #endif 00502 00503 }; 00504 00505 typedef RandomEngine<MT19937 <Random_u32>, MixerSFMT> MRandomGenerator32; 00506 typedef RandomEngine<MT19937 <Random_u64>, MixerSFMT> MRandomGenerator64; 00507 typedef RandomEngine<SFMT19937<Random_u32>, MixerSFMT> SRandomGenerator32; 00508 typedef RandomEngine<SFMT19937<Random_u64>, MixerSFMT> SRandomGenerator64; 00509 00510 } // namespace RandomLib 00511 00512 #endif // RANDOMENGINE_HPP