MTwistEngine.cc

Go to the documentation of this file.
00001 // $Id:$
00002 // -*- C++ -*-
00003 //
00004 // -----------------------------------------------------------------------
00005 //                             HEP Random
00006 //                        --- MTwistEngine ---
00007 //                      class implementation file
00008 // -----------------------------------------------------------------------
00009 // A "fast, compact, huge-period generator" based on M. Matsumoto and 
00010 // T. Nishimura, "Mersenne Twister: A 623-dimensionally equidistributed 
00011 // uniform pseudorandom number generator", to appear in ACM Trans. on
00012 // Modeling and Computer Simulation.  It is a twisted GFSR generator
00013 // with a Mersenne-prime period of 2^19937-1, uniform on open interval (0,1)
00014 // =======================================================================
00015 // Ken Smith      - Started initial draft:                    14th Jul 1998
00016 //                - Optimized to get pow() out of flat() method
00017 //                - Added conversion operators:                6th Aug 1998
00018 // J. Marraffino  - Added some explicit casts to deal with
00019 //                  machines where sizeof(int) != sizeof(long)  22 Aug 1998
00020 // M. Fischler    - Modified constructors such that no two
00021 //                  seeds will match sequences, no single/double
00022 //                  seeds will match, explicit seeds give 
00023 //                  determined results, and default will not 
00024 //                  match any of the above or other defaults.
00025 //                - Modified use of the various exponents of 2
00026 //                  to avoid per-instance space overhead and
00027 //                  correct the rounding procedure              16 Sep 1998
00028 // J. Marfaffino  - Remove dependence on hepString class        13 May 1999
00029 // M. Fischler    - In restore, checkFile for file not found    03 Dec 2004
00030 // M. Fischler    - Methods for distrib. instacne save/restore  12/8/04    
00031 // M. Fischler    - split get() into tag validation and 
00032 //                  getState() for anonymous restores           12/27/04    
00033 // M. Fischler    - put/get for vectors of ulongs               3/14/05
00034 // M. Fischler    - State-saving using only ints, for portability 4/12/05
00035 // M. Fischler    - Improved seeding in setSeed  (Savanah bug #17479) 11/15/06
00036 //                - (Possible optimization - now that the seeding is improved,
00037 //                  is it still necessary for ctor to "warm up" by discarding
00038 //                  2000 iterations?)
00039 //                  
00040 // =======================================================================
00041 
00042 #include "CLHEP/Random/Random.h"
00043 #include "CLHEP/Random/MTwistEngine.h"
00044 #include "CLHEP/Random/engineIDulong.h"
00045 #include <string.h>     // for strcmp
00046 #include <cstdlib>      // for std::abs(int)
00047 
00048 namespace CLHEP {
00049 
00050 static const int MarkerLen = 64; // Enough room to hold a begin or end marker. 
00051 
00052 std::string MTwistEngine::name() const {return "MTwistEngine";}
00053 
00054 int MTwistEngine::numEngines = 0;
00055 int MTwistEngine::maxIndex = 215;
00056 
00057 MTwistEngine::MTwistEngine() 
00058 : HepRandomEngine()
00059 {
00060   int cycle = std::abs(int(numEngines/maxIndex));
00061   int curIndex = std::abs(int(numEngines%maxIndex));
00062   long mask = ((cycle & 0x007fffff) << 8);
00063   long seedlist[2];
00064   HepRandom::getTheTableSeeds( seedlist, curIndex );
00065   seedlist[0] = (seedlist[0])^mask;
00066   seedlist[1] = 0;
00067   setSeeds( seedlist, numEngines );
00068   count624=0;
00069   ++numEngines;
00070   for( int i=0; i < 2000; ++i ) flat();      // Warm up just a bit
00071 }
00072 
00073 MTwistEngine::MTwistEngine(long seed)  
00074 : HepRandomEngine()
00075 {
00076   long seedlist[2]={seed,17587};
00077   setSeeds( seedlist, 0 );
00078   count624=0;
00079   for( int i=0; i < 2000; ++i ) flat();      // Warm up just a bit
00080 }
00081 
00082 MTwistEngine::MTwistEngine(int rowIndex, int colIndex) 
00083 : HepRandomEngine()
00084 {
00085   int cycle = std::abs(int(rowIndex/maxIndex));
00086   int row = std::abs(int(rowIndex%maxIndex));
00087   int col = std::abs(int(colIndex%2));
00088   long mask = (( cycle & 0x000007ff ) << 20 );
00089   long seedlist[2];
00090   HepRandom::getTheTableSeeds( seedlist, row );
00091   seedlist[0] = (seedlist[col])^mask;
00092   seedlist[1] = 690691;
00093   setSeeds(seedlist, 4444772);
00094   count624=0;
00095   for( int i=0; i < 2000; ++i ) flat();      // Warm up just a bit
00096 }
00097 
00098 MTwistEngine::MTwistEngine( std::istream& is )  
00099 : HepRandomEngine()
00100 {
00101   is >> *this;
00102 }
00103 
00104 MTwistEngine::~MTwistEngine() {}
00105 
00106 double MTwistEngine::flat() {
00107   unsigned int y;
00108 
00109    if( count624 >= N ) {
00110     register int i;
00111 
00112     for( i=0; i < NminusM; ++i ) {
00113       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00114       mt[i] = mt[i+M]       ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00115     }
00116 
00117     for(    ; i < N-1    ; ++i ) {
00118       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00119       mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00120     }
00121 
00122     y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff);
00123     mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00124 
00125     count624 = 0;
00126   }
00127 
00128   y = mt[count624];
00129   y ^= ( y >> 11);
00130   y ^= ((y << 7 ) & 0x9d2c5680);
00131   y ^= ((y << 15) & 0xefc60000);
00132   y ^= ( y >> 18);
00133 
00134   return                      y * twoToMinus_32()  +    // Scale to range 
00135          (mt[count624++] >> 11) * twoToMinus_53()  +    // fill remaining bits
00136                             nearlyTwoToMinus_54();      // make sure non-zero
00137 }
00138 
00139 void MTwistEngine::flatArray( const int size, double *vect ) {
00140   for( int i=0; i < size; ++i) vect[i] = flat();
00141 }
00142 
00143 void MTwistEngine::setSeed(long seed, int k) {
00144 
00145   // MF 11/15/06 - Change seeding algorithm to a newer one recommended 
00146   //               by Matsumoto: The original algorithm was 
00147   //               mt[i] = (69069 * mt[i-1]) & 0xffffffff and this gives
00148   //               problems when the seed bit pattern has lots of zeros
00149   //               (for example, 0x08000000).  Savanah bug #17479.
00150 
00151   theSeed = seed ? seed : 4357;
00152   int mti;
00153   const int N1=624;
00154   mt[0] = (unsigned int) (theSeed&0xffffffffUL);
00155   for (mti=1; mti<N1; mti++) {
00156     mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 
00157         /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
00158         /* In the previous versions, MSBs of the seed affect   */
00159         /* only MSBs of the array mt[].                        */
00160         /* 2002/01/09 modified by Makoto Matsumoto             */
00161     mt[mti] &= 0xffffffffUL;
00162         /* for >32 bit machines */
00163   }
00164   for( int i=1; i < 624; ++i ) {
00165     mt[i] ^= k;                 // MF 9/16/98: distinguish starting points
00166   }
00167   // MF 11/15/06 This distinction of starting points based on values of k
00168   //             is kept even though the seeding algorithm itself is improved.
00169 }
00170 
00171 void MTwistEngine::setSeeds(const long *seeds, int k) {
00172   setSeed( (*seeds ? *seeds : 43571346), k );
00173   int i;
00174   for( i=1; i < 624; ++i ) {
00175     mt[i] = ( seeds[1] + mt[i] ) & 0xffffffff; // MF 9/16/98 
00176   }
00177   theSeeds = seeds;
00178 }
00179 
00180 void MTwistEngine::saveStatus( const char filename[] ) const
00181 {
00182    std::ofstream outFile( filename, std::ios::out ) ;
00183    if (!outFile.bad()) {
00184      outFile << theSeed << std::endl;
00185      for (int i=0; i<624; ++i) outFile <<std::setprecision(20) << mt[i] << " ";
00186      outFile << std::endl;
00187      outFile << count624 << std::endl;
00188    }
00189 }
00190 
00191 void MTwistEngine::restoreStatus( const char filename[] )
00192 {
00193    std::ifstream inFile( filename, std::ios::in);
00194    if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
00195      std::cerr << "  -- Engine state remains unchanged\n";
00196      return;
00197    }
00198 
00199    if (!inFile.bad() && !inFile.eof()) {
00200      inFile >> theSeed;
00201      for (int i=0; i<624; ++i) inFile >> mt[i];
00202      inFile >> count624;
00203    }
00204 }
00205 
00206 void MTwistEngine::showStatus() const
00207 {
00208    std::cout << std::endl;
00209    std::cout << "--------- MTwist engine status ---------" << std::endl;
00210    std::cout << std::setprecision(20);
00211    std::cout << " Initial seed      = " << theSeed << std::endl;
00212    std::cout << " Current index     = " << count624 << std::endl;
00213    std::cout << " Array status mt[] = " << std::endl;
00214    for (int i=0; i<624; i+=5) {
00215      std::cout << mt[i]   << " " << mt[i+1] << " " << mt[i+2] << " " 
00216                << mt[i+3] << " " << mt[i+4] << std::endl;
00217    }
00218    std::cout << "----------------------------------------" << std::endl;
00219 }
00220 
00221 MTwistEngine::operator float() {
00222   unsigned int y;
00223 
00224   if( count624 >= N ) {
00225     register int i;
00226 
00227     for( i=0; i < NminusM; ++i ) {
00228       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00229       mt[i] = mt[i+M]       ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00230     }
00231 
00232     for(    ; i < N-1    ; ++i ) {
00233       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00234       mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00235     }
00236 
00237     y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff);
00238     mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00239 
00240     count624 = 0;
00241   }
00242 
00243   y = mt[count624++];
00244   y ^= ( y >> 11);
00245   y ^= ((y << 7 ) & 0x9d2c5680);
00246   y ^= ((y << 15) & 0xefc60000);
00247   y ^= ( y >> 18);
00248 
00249   return (float)(y * twoToMinus_32());
00250 }
00251 
00252 MTwistEngine::operator unsigned int() {
00253   unsigned int y;
00254 
00255   if( count624 >= N ) {
00256     register int i;
00257 
00258     for( i=0; i < NminusM; ++i ) {
00259       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00260       mt[i] = mt[i+M]       ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00261     }
00262 
00263     for(    ; i < N-1    ; ++i ) {
00264       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00265       mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00266     }
00267 
00268     y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff);
00269     mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00270 
00271     count624 = 0;
00272   }
00273 
00274   y = mt[count624++];
00275   y ^= ( y >> 11);
00276   y ^= ((y << 7 ) & 0x9d2c5680);
00277   y ^= ((y << 15) & 0xefc60000);
00278   y ^= ( y >> 18);
00279 
00280   return y;
00281 }
00282 
00283 std::ostream & MTwistEngine::put ( std::ostream& os ) const
00284 {
00285    char beginMarker[] = "MTwistEngine-begin";
00286    char endMarker[]   = "MTwistEngine-end";
00287 
00288    int pr = os.precision(20);
00289    os << " " << beginMarker << " ";
00290    os << theSeed << " ";
00291    for (int i=0; i<624; ++i) {
00292      os << mt[i] << "\n";
00293    }
00294    os << count624 << " ";
00295    os << endMarker << "\n";
00296    os.precision(pr);
00297    return os;
00298 }
00299 
00300 std::vector<unsigned long> MTwistEngine::put () const {
00301   std::vector<unsigned long> v;
00302   v.push_back (engineIDulong<MTwistEngine>());
00303   for (int i=0; i<624; ++i) {
00304      v.push_back(static_cast<unsigned long>(mt[i]));
00305   }
00306   v.push_back(count624); 
00307   return v;
00308 }
00309 
00310 std::istream &  MTwistEngine::get ( std::istream& is )
00311 {
00312   char beginMarker [MarkerLen];
00313   is >> std::ws;
00314   is.width(MarkerLen);  // causes the next read to the char* to be <=
00315                         // that many bytes, INCLUDING A TERMINATION \0 
00316                         // (Stroustrup, section 21.3.2)
00317   is >> beginMarker;
00318   if (strcmp(beginMarker,"MTwistEngine-begin")) {
00319      is.clear(std::ios::badbit | is.rdstate());
00320      std::cerr << "\nInput stream mispositioned or"
00321                << "\nMTwistEngine state description missing or"
00322                << "\nwrong engine type found." << std::endl;
00323      return is;
00324    }
00325   return getState(is);
00326 }
00327 
00328 std::string MTwistEngine::beginTag ( )  { 
00329   return "MTwistEngine-begin"; 
00330 }
00331 
00332 std::istream &  MTwistEngine::getState ( std::istream& is )
00333 {
00334   char endMarker   [MarkerLen];
00335   is >> theSeed;
00336   for (int i=0; i<624; ++i)  is >> mt[i];
00337   is >> count624;
00338   is >> std::ws;
00339   is.width(MarkerLen);  
00340   is >> endMarker;
00341   if (strcmp(endMarker,"MTwistEngine-end")) {
00342      is.clear(std::ios::badbit | is.rdstate());
00343      std::cerr << "\nMTwistEngine state description incomplete."
00344                << "\nInput stream is probably mispositioned now." << std::endl;
00345      return is;
00346    }
00347    return is;
00348 }
00349 
00350 bool MTwistEngine::get (const std::vector<unsigned long> & v) {
00351   if ((v[0] & 0xffffffffUL) != engineIDulong<MTwistEngine>()) {
00352     std::cerr << 
00353         "\nMTwistEngine get:state vector has wrong ID word - state unchanged\n";
00354     return false;
00355   }
00356   return getState(v);
00357 }
00358 
00359 bool MTwistEngine::getState (const std::vector<unsigned long> & v) {
00360   if (v.size() != VECTOR_STATE_SIZE ) {
00361     std::cerr << 
00362         "\nMTwistEngine get:state vector has wrong length - state unchanged\n";
00363     return false;
00364   }
00365   for (int i=0; i<624; ++i) {
00366      mt[i]=v[i+1];
00367   }
00368   count624 = v[625];
00369   return true;
00370 }
00371 
00372 }  // namespace CLHEP

Generated on Mon May 27 17:50:32 2013 for Geant4 by  doxygen 1.4.7