RandomSeed.hpp
Go to the documentation of this file.
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