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