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