00001 /** 00002 * \file RandomSeed.hpp 00003 * \brief Header for RandomSeed 00004 * 00005 * This provides a base class for random generators. 00006 * 00007 * Written by <a href="http://charles.karney.info/"> Charles Karney</a> 00008 * <charles@karney.com> and licensed under the LGPL. For more 00009 * information, see http://charles.karney.info/random/ 00010 **********************************************************************/ 00011 00012 #if !defined(RANDOMSEED_HPP) 00013 #define RANDOMSEED_HPP "$Id: RandomSeed.hpp 6424 2008-01-31 04:03:13Z ckarney $" 00014 00015 #include <iostream> 00016 #include <stdexcept> 00017 #include <vector> 00018 #include <algorithm> // For std::transform 00019 #include <sstream> // For VectorToString 00020 #include "RandomLib/RandomType.hpp" 00021 00022 namespace RandomLib { 00023 /** 00024 * \brief A base class for random generators 00025 * 00026 * This provides facilities for managing the seed and for converting the seed 00027 * into random generator state. 00028 * 00029 * The seed is taken to be a vector of unsigned longs of arbitrary length. 00030 * (Only the low 32 bit of each element of the vector are used.) The class 00031 * provides several methods for setting the seed, static functions for 00032 * producing "random" and "unique" seeds, and facilities for converting the 00033 * seed to a string so that it can be printed easily. 00034 * 00035 * The seeding algorithms are those used by 00036 * <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html"> 00037 * MT19937</a> with some modifications to make all states accessible and to 00038 * minimize the likelihood of different seeds giving the same state. 00039 * 00040 * Finally some low-level routines are provided to facilitate the creation of 00041 * I/O methods for the random generator. 00042 * 00043 * A random generator class can be written based on this class. The 00044 * generator class would use the base class methods for setting the seed and 00045 * for converting the seed into state. It would provide the machinery for 00046 * advancing the state and for producing random data. It is also responsible 00047 * for the routine to save and restore the generator state (including the 00048 * seed). 00049 * 00050 * Written by <a href="http://charles.karney.info/"> Charles Karney</a> 00051 * <charles@karney.com> and licensed under the LGPL. The seeding algorithms 00052 * are adapted from those of 00053 * <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html"> 00054 * MT19937</a>. For more information, see http://charles.karney.info/random/ 00055 **********************************************************************/ 00056 class RandomSeed { 00057 public: 00058 typedef Random_u32 u32; 00059 typedef Random_u64 u64; 00060 00061 virtual ~RandomSeed() throw() = 0; 00062 /** 00063 * A type large enough to hold the seed words. This is needs to hold 32 00064 * bits and is an unsigned long for portability. 00065 **********************************************************************/ 00066 typedef RandomType<32, unsigned long> seed_t; 00067 typedef seed_t::type seed_type; 00068 00069 /** \name Resetting the seed 00070 **********************************************************************/ 00071 ///@{ 00072 /** 00073 * Set the seed to a vector \a v. Only the low \e 32 bits of each element 00074 * are used. 00075 **********************************************************************/ 00076 template<typename IntType> void Reseed(const std::vector<IntType>& v) 00077 throw(std::bad_alloc) { 00078 Reseed(v.begin(), v.end()); 00079 } 00080 /** 00081 * Set the seed to [\a a, \a b) from a pair of iterators. The iterator 00082 * must produce results which can be converted into seed_type. Only the 00083 * low 32 bits of each element are used. 00084 **********************************************************************/ 00085 template<typename InputIterator> 00086 void Reseed(InputIterator a, InputIterator b) 00087 throw(std::bad_alloc) { 00088 // Read new seed into temporary so as not to change object on error. 00089 std::vector<seed_type> t; 00090 std::transform(a, b, back_inserter(t), 00091 seed_t::cast<typename std::iterator_traits<InputIterator>::value_type>); 00092 _seed.swap(t); 00093 Reset(); 00094 } 00095 /** 00096 * Set the seed to [\a n]. Only the low 32 bits of \a n are used. 00097 **********************************************************************/ 00098 void Reseed(seed_type n) throw(std::bad_alloc) { 00099 // Reserve space for new seed so as not to change object on error. 00100 _seed.reserve(1); 00101 _seed.resize(1); 00102 _seed[0] = seed_t::cast(n); 00103 Reset(); 00104 } 00105 /** 00106 * Set the seed to [SeedVector()] 00107 **********************************************************************/ 00108 void Reseed() throw(std::bad_alloc) { Reseed(SeedVector()); } 00109 /** 00110 * Set the seed from the string \e s using Random::StringToVector 00111 **********************************************************************/ 00112 void Reseed(const std::string& s) throw(std::bad_alloc) { 00113 // Read new seed into temporary so as not to change object on error. 00114 std::vector<seed_type> t = StringToVector(s); 00115 _seed.swap(t); 00116 Reset(); 00117 } 00118 ///@} 00119 00120 /** \name Examining the seed 00121 **********************************************************************/ 00122 ///@{ 00123 /** 00124 * Return reference to the seed vector (read-only) 00125 **********************************************************************/ 00126 const std::vector<seed_type>& Seed() const throw() { return _seed; } 00127 /** 00128 * Format the current seed suitable for printing. 00129 **********************************************************************/ 00130 std::string SeedString() const throw(std::bad_alloc) 00131 { return VectorToString(_seed); } 00132 ///@} 00133 00134 /** \name Resetting the random seed 00135 **********************************************************************/ 00136 ///@{ 00137 /** 00138 * Resets the sequence to its just-seeded state. This needs to be declared 00139 * vitual here so that the Reseed functions can call it after saving the 00140 * seed. 00141 **********************************************************************/ 00142 virtual void Reset() throw() = 0; 00143 ///@} 00144 00145 /** \name Static functions for seed management 00146 **********************************************************************/ 00147 ///@{ 00148 /** 00149 * Return a 32 bits of data suitable for seeding the random generator. The 00150 * result is obtained by combining data from /dev/urandom, gettimeofday, 00151 * time, and getpid to provide a reasonably "random" word of data. 00152 **********************************************************************/ 00153 static seed_type SeedWord(); 00154 /** 00155 * Return a vector of unsigned longs suitable for seeding the random 00156 * generator. The vector is almost certainly unique; however, the results 00157 * of successive calls to Random::SeedVector() will be correlated. If 00158 * several Random objects are required within a single program execution, 00159 * call Random::SeedVector once, print it out (!), push_back additional 00160 * data to identify the instance (e.g., loop index, thread ID, etc.), and 00161 * use the result to seed the Random object. 00162 **********************************************************************/ 00163 static std::vector<seed_type> SeedVector(); 00164 /** 00165 * Convert a vector into a string suitable for printing or as an argument 00166 * for Random::Reseed(const std::string& s). 00167 **********************************************************************/ 00168 template<typename IntType> 00169 static std::string VectorToString(const std::vector<IntType>& v) 00170 throw(std::ios::failure) { 00171 std::ostringstream os; 00172 os << "["; 00173 for (typename std::vector<IntType>::const_iterator n = v.begin(); 00174 n != v.end(); ++n) { 00175 if (n != v.begin()) 00176 os << ","; 00177 // Normalize in case this is called by user. 00178 os << seed_t::cast(*n); 00179 } 00180 os << "]"; 00181 return os.str(); 00182 } 00183 /** 00184 * Convert a string into a vector of seed_type suitable for printing or as 00185 * an argument for Random::Reseed(const std::vector<seed_type>& v). Reads 00186 * consecutive digits in string. Thus "[1,2,3]" => [1,2,3]; "-0.123e-4" => 00187 * [0,123,4], etc. strtoul understands C's notation for octal and 00188 * hexadecimal, for example "012 10 0xa" => [10,10,10]. Reading of a 00189 * number stops at the first illegal character for the base. Thus 00190 * "2006-04-08" => [2006,4,0,8] (i.e., 08 becomes two numbers). Note that 00191 * input numbers greater than ULONG_MAX overflow to ULONG_MAX, which 00192 * probably will result in the number being interpreted as LONG_MASK. 00193 **********************************************************************/ 00194 static std::vector<seed_type> StringToVector(const std::string& s) 00195 throw(std::bad_alloc); 00196 ///@} 00197 00198 protected: 00199 /** 00200 * The seed vector 00201 **********************************************************************/ 00202 std::vector<seed_type> _seed; 00203 00204 }; 00205 00206 inline RandomSeed::~RandomSeed() throw() {}; 00207 00208 } // namespace RandomLib 00209 00210 #endif // RANDOMSEED_HPP