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