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