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