RandomMixer.hpp
Go to the documentation of this file.
00001 /**
00002  * \file RandomMixer.hpp
00003  * \brief Header for Mixer classes.
00004  *
00005  * Mixer classes convert a seed vector into a random generator state.  An
00006  * important property of this method is that "close" seeds should produce
00007  * "widely separated" states.  This allows the seeds to be set is some
00008  * systematic fashion to produce a set of uncorrelation random number
00009  * sequences.
00010  *
00011  * Written by Charles Karney <charles@karney.com> and licensed under the LGPL.
00012  * For more information, see http://randomlib.sourceforge.net/
00013  **********************************************************************/
00014 
00015 #if !defined(RANDOMMIXER_HPP)
00016 #define RANDOMMIXER_HPP "$Id: RandomMixer.hpp 6723 2010-01-11 14:20:10Z ckarney $"
00017 
00018 #include <vector>
00019 #include <string>
00020 #include "RandomLib/RandomSeed.hpp"
00021 
00022 namespace RandomLib {
00023 
00024   /**
00025    * \brief The original MT19937 mixing functionality
00026    *
00027    * This implements the functionality of init_by_array in MT19937
00028    * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c
00029    * and init_by_array64 in MT19937_64
00030    * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c
00031    * with the following changes:
00032    * - in the case of an zero-length seed array, behave in the same way if
00033    *   MT19937 and MT19937_64 are called without initialization in which case,
00034    *   e.g., init_genrand(5489UL) is called.  (init_by_array does not allow
00035    *   calling with a zero-length seed.)
00036    * - init_by_array64 accepts a seed array of 64-bit unsigned ints.  Here with
00037    *   seed is an array of 32-bit unsigned ints and these are repacked into
00038    *   64-bit quantities internally using a LSB convention.  Thus, to mimic the
00039    *   MT19937_64 sample invocation with a seed array {0x12345ULL, 0x23456ULL,
00040    *   0x34567ULL, 0x45678ULL}, MixerMT0<Random_u64>::SeedToState needs to
00041    *   be invoked with a seed vector [0x12345UL, 0, 0x23456UL, 0, 0x34567UL, 0,
00042    *   0x45678UL, 0].  (Actually the last 0 is unnecessary.)
00043    *
00044    * The template parameter \a RandomType switches between the 32-bit and
00045    * 64-bit versions.
00046    *
00047    * MixerMT0 is specific to the MT19937 generators and should not be used
00048    * for other generators (e.g., SFMT19937).  In addition, MixerMT0 has
00049    * known defects and should only be used to check the operation of the
00050    * MT19937 engines against the original implementation.  These defects are
00051    * described in the MixerMT1 which is a modification of MixerMT0
00052    * which corrects these defects.  For production use MixerMT1 or,
00053    * perferably, MixerSFMT should be used.
00054    **********************************************************************/
00055 
00056   template<class RandomType> class MixerMT0 {
00057   public:
00058     /**
00059      * The RandomType controlling the output of MixerMT1::SeedToState
00060      **********************************************************************/
00061     typedef RandomType mixer_t;
00062     /**
00063      * A version number which should be unique to this RandomMixer.  This
00064      * prevents RandomEngine::Load from loading a saved generator with a
00065      * different RandomMixer.  Here the version is "MxMT" or "MxMU".
00066      **********************************************************************/
00067     static const unsigned version = 0x4d784d54UL + (mixer_t::width == 64);
00068   private:
00069     /**
00070      * The unsigned type corresponding to mixer_t.
00071      **********************************************************************/
00072     typedef typename mixer_t::type mixer_type;
00073     /**
00074      * The mask for mixter_t.
00075      **********************************************************************/
00076     static const mixer_type mask = mixer_t::mask;
00077   public:
00078     /**
00079      * Mix the seed vector, \e seed, into the state array, \e state, of size \e
00080      * n.
00081      **********************************************************************/
00082     static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
00083                             mixer_type state[], unsigned n) throw();
00084     /**
00085      * Return the name of this class.
00086      **********************************************************************/
00087     static std::string Name() throw() {
00088       return "MixerMT0<Random_u" +
00089         std::string(mixer_t::width == 32 ? "32" : "64") + ">";
00090     }
00091   private:
00092     static const mixer_type a0 = 5489ULL, a1 = 19650218UL,
00093       b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL,
00094       c = mixer_t::width == 32 ?    1664525ULL : 3935559000370003845ULL,
00095       d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL;
00096   };
00097 
00098   /**
00099    * \brief The modified MT19937 mixing functionality
00100    *
00101    * MixerMT0 has two defects
00102    * - The zeroth word of the state is set to a constant (independent of the
00103    *   seed).  This is a relatively minor defect which halves the accessible
00104    *   state space for MT19937 (but the resulting state space is still huge).
00105    *   (Actually, for the 64-bit version, it reduces the accessible states by
00106    *   2<sup>33</sup>.  On the other hand the 64-bit has better mixing
00107    *   properies.)
00108    * - Close seeds, for example, [1] and [1,0], result in the same state.  This
00109    *   is a potentially serious flaw which might result is identical random
00110    *   number sequences being generated instead of independent sequences.
00111    *
00112    * MixerMT1 fixes these defects in a straightforward manner.  The
00113    * resulting algorithm was included in one of the proposals for Random Number
00114    * Generation for C++0X, see Brown, et al.,
00115    * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2079.pdf
00116    *
00117    * The template parameter \a RandomType switches between the 32-bit and
00118    * 64-bit versions.
00119    *
00120    * MixerMT1 still has a weakness in that it doesn't thoroughly mix the
00121    * state.  This is illustrated by an example given to me by Makoto Matsumoto:
00122    * Consider a seed of length \e N and suppose we consider all \e
00123    * W<sup><i>N</i>/2</sup> values for the first half of the seed (here \e W =
00124    * 2<sup><i>width</i></sup>).  MixerMT1 has a bottleneck in the way that
00125    * the state is initialized which results in the second half of the state
00126    * only taking on \e W<sup>2</sup> possible values.  MixerSFMT mixes the
00127    * seed into the state much more thoroughly.
00128    **********************************************************************/
00129 
00130   template<class RandomType> class MixerMT1 {
00131   public:
00132     /**
00133      * The RandomType controlling the output of MixerMT1::SeedToState
00134      **********************************************************************/
00135     typedef RandomType mixer_t;
00136     /**
00137      * A version number which should be unique to this RandomMixer.  This
00138      * prevents RandomEngine::Load from loading a saved generator with a
00139      * different RandomMixer.  Here the version is "MxMV" or "MxMW".
00140      **********************************************************************/
00141     static const unsigned version = 0x4d784d56UL + (mixer_t::width == 64);
00142   private:
00143     /**
00144      * The unsigned type corresponding to mixer_t.
00145      **********************************************************************/
00146     typedef typename mixer_t::type mixer_type;
00147     /**
00148      * The mask for mixter_t.
00149      **********************************************************************/
00150     static const mixer_type mask = mixer_t::mask;
00151   public:
00152     /**
00153      * Mix the seed vector, \e seed, into the state array, \e state, of size \e
00154      * n.
00155      **********************************************************************/
00156     static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
00157                             mixer_type state[], unsigned n) throw();
00158     /**
00159      * Return the name of this class.
00160      **********************************************************************/
00161     static std::string Name() throw() {
00162       return "MixerMT1<Random_u" +
00163         std::string(mixer_t::width == 32 ? "32" : "64") + ">";
00164     }
00165   private:
00166     static const mixer_type a = 5489ULL,
00167       b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL,
00168       c = mixer_t::width == 32 ?    1664525ULL : 3935559000370003845ULL,
00169       d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL;
00170   };
00171 
00172   /**
00173    * \brief The SFMT mixing functionality
00174    *
00175    * MixerSFMT is adapted from SFMT's init_by_array Mutsuo Saito given in
00176    * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/SFMT-src-1.2.tar.gz
00177    * and is part of the C++0X proposal; see P. Becker, Working Draft, Standard
00178    * for Programming Language C++, Oct. 2007, Sec. 26.4.7.1,
00179    * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf
00180    *
00181    * MixerSFMT contains a single change is to allow it to function properly
00182    * when the size of the state is small.
00183    *
00184    * MixerSFMT mixes the seed much more thoroughly than MixerMT1 and, in
00185    * particular, it removes the mixing bottleneck present in MixerMT1.
00186    * Thus it is the recommended mixing scheme for all production work.
00187    **********************************************************************/
00188 
00189   class MixerSFMT {
00190   public:
00191     /**
00192      * The RandomType controlling the output of MixerMT1::SeedToState
00193      **********************************************************************/
00194     typedef Random_u32 mixer_t;
00195     /**
00196      * A version number which should be unique to this RandomMixer.  This
00197      * prevents RandomEngine::Load from loading a saved generator with a
00198      * different RandomMixer.  Here the version is "MxSM".
00199      **********************************************************************/
00200     static const unsigned version = 0x4d78534dUL;
00201   private:
00202     /**
00203      * The unsigned type corresponding to mixer_t.
00204      **********************************************************************/
00205     typedef mixer_t::type mixer_type;
00206     /**
00207      * The mask for mixter_t.
00208      **********************************************************************/
00209     static const mixer_type mask = mixer_t::mask;
00210   public:
00211     /**
00212      * Mix the seed vector, \e seed, into the state array, \e state, of size \e
00213      * n.
00214      **********************************************************************/
00215     static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
00216                             mixer_type state[], unsigned n) throw();
00217     /**
00218      * Return the name of this class.
00219      **********************************************************************/
00220     static std::string Name() throw() { return "MixerSFMT"; }
00221   private:
00222     static const mixer_type a = 0x8b8b8b8bUL, b = 1664525UL, c = 1566083941UL;
00223   };
00224 
00225 } // namespace RandomLib
00226 
00227 #endif  // RANDOMMIXER_HPP