CLHEP VERSION Reference Documentation
   
CLHEP Home Page     CLHEP Documentation     CLHEP Bug Reports

MTwistEngine.cc

Go to the documentation of this file.
00001 // $Id: MTwistEngine.cc,v 1.6 2010/06/16 17:24:53 garren Exp $
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 std::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/defs.h"
00043 #include "CLHEP/Random/Random.h"
00044 #include "CLHEP/Random/MTwistEngine.h"
00045 #include "CLHEP/Random/engineIDulong.h"
00046 #include <string.h>     // for strcmp
00047 #include <cstdlib>      // for std::abs(int)
00048 
00049 namespace CLHEP {
00050 
00051 static const int MarkerLen = 64; // Enough room to hold a begin or end marker. 
00052 
00053 std::string MTwistEngine::name() const {return "MTwistEngine";}
00054 
00055 int MTwistEngine::numEngines = 0;
00056 int MTwistEngine::maxIndex = 215;
00057 
00058 MTwistEngine::MTwistEngine() 
00059 : HepRandomEngine()
00060 {
00061   int cycle = std::abs(int(numEngines/maxIndex));
00062   int curIndex = std::abs(int(numEngines%maxIndex));
00063   long mask = ((cycle & 0x007fffff) << 8);
00064   long seedlist[2];
00065   HepRandom::getTheTableSeeds( seedlist, curIndex );
00066   seedlist[0] = (seedlist[0])^mask;
00067   seedlist[1] = 0;
00068   setSeeds( seedlist, numEngines );
00069   count624=0;
00070   ++numEngines;
00071   for( int i=0; i < 2000; ++i ) flat();      // Warm up just a bit
00072 }
00073 
00074 MTwistEngine::MTwistEngine(long seed)  
00075 : HepRandomEngine()
00076 {
00077   long seedlist[2]={seed,17587};
00078   setSeeds( seedlist, 0 );
00079   count624=0;
00080   for( int i=0; i < 2000; ++i ) flat();      // Warm up just a bit
00081 }
00082 
00083 MTwistEngine::MTwistEngine(int rowIndex, int colIndex) 
00084 : HepRandomEngine()
00085 {
00086   int cycle = std::abs(int(rowIndex/maxIndex));
00087   int row = std::abs(int(rowIndex%maxIndex));
00088   int col = std::abs(int(colIndex%2));
00089   long mask = (( cycle & 0x000007ff ) << 20 );
00090   long seedlist[2];
00091   HepRandom::getTheTableSeeds( seedlist, row );
00092   seedlist[0] = (seedlist[col])^mask;
00093   seedlist[1] = 690691;
00094   setSeeds(seedlist, 4444772);
00095   count624=0;
00096   for( int i=0; i < 2000; ++i ) flat();      // Warm up just a bit
00097 }
00098 
00099 MTwistEngine::MTwistEngine( std::istream& is )  
00100 : HepRandomEngine()
00101 {
00102   is >> *this;
00103 }
00104 
00105 MTwistEngine::~MTwistEngine() {}
00106 
00107 double MTwistEngine::flat() {
00108   unsigned int y;
00109 
00110    if( count624 >= N ) {
00111     register int i;
00112 
00113     for( i=0; i < NminusM; ++i ) {
00114       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00115       mt[i] = mt[i+M]       ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00116     }
00117 
00118     for(    ; i < N-1    ; ++i ) {
00119       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00120       mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00121     }
00122 
00123     y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff);
00124     mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00125 
00126     count624 = 0;
00127   }
00128 
00129   y = mt[count624];
00130   y ^= ( y >> 11);
00131   y ^= ((y << 7 ) & 0x9d2c5680);
00132   y ^= ((y << 15) & 0xefc60000);
00133   y ^= ( y >> 18);
00134 
00135   return                      y * twoToMinus_32()  +    // Scale to range 
00136          (mt[count624++] >> 11) * twoToMinus_53()  +    // fill remaining bits
00137                             nearlyTwoToMinus_54();      // make sure non-zero
00138 }
00139 
00140 void MTwistEngine::flatArray( const int size, double *vect ) {
00141   for( int i=0; i < size; ++i) vect[i] = flat();
00142 }
00143 
00144 void MTwistEngine::setSeed(long seed, int k) {
00145 
00146   // MF 11/15/06 - Change seeding algorithm to a newer one recommended 
00147   //               by Matsumoto: The original algorithm was 
00148   //               mt[i] = (69069 * mt[i-1]) & 0xffffffff and this gives
00149   //               problems when the seed bit pattern has lots of zeros
00150   //               (for example, 0x08000000).  Savanah bug #17479.
00151 
00152   theSeed = seed ? seed : 4357;
00153   int mti;
00154   const int N1=624;
00155   mt[0] = (unsigned int) (theSeed&0xffffffffUL);
00156   for (mti=1; mti<N1; mti++) {
00157     mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 
00158         /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
00159         /* In the previous versions, MSBs of the seed affect   */
00160         /* only MSBs of the array mt[].                        */
00161         /* 2002/01/09 modified by Makoto Matsumoto             */
00162     mt[mti] &= 0xffffffffUL;
00163         /* for >32 bit machines */
00164   }
00165   for( int i=1; i < 624; ++i ) {
00166     mt[i] ^= k;                 // MF 9/16/98: distinguish starting points
00167   }
00168   // MF 11/15/06 This distinction of starting points based on values of k
00169   //             is kept even though the seeding algorithm itself is improved.
00170 }
00171 
00172 void MTwistEngine::setSeeds(const long *seeds, int k) {
00173   setSeed( (*seeds ? *seeds : 43571346), k );
00174   int i;
00175   for( i=1; i < 624; ++i ) {
00176     mt[i] = ( seeds[1] + mt[i] ) & 0xffffffff; // MF 9/16/98 
00177   }
00178   theSeeds = seeds;
00179 }
00180 
00181 void MTwistEngine::saveStatus( const char filename[] ) const
00182 {
00183    std::ofstream outFile( filename, std::ios::out ) ;
00184    if (!outFile.bad()) {
00185      outFile << theSeed << std::endl;
00186      for (int i=0; i<624; ++i) outFile <<std::setprecision(20) << mt[i] << " ";
00187      outFile << std::endl;
00188      outFile << count624 << std::endl;
00189    }
00190 }
00191 
00192 void MTwistEngine::restoreStatus( const char filename[] )
00193 {
00194    std::ifstream inFile( filename, std::ios::in);
00195    if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
00196      std::cerr << "  -- Engine state remains unchanged\n";
00197      return;
00198    }
00199 
00200    if (!inFile.bad() && !inFile.eof()) {
00201      inFile >> theSeed;
00202      for (int i=0; i<624; ++i) inFile >> mt[i];
00203      inFile >> count624;
00204    }
00205 }
00206 
00207 void MTwistEngine::showStatus() const
00208 {
00209    std::cout << std::endl;
00210    std::cout << "--------- MTwist engine status ---------" << std::endl;
00211    std::cout << std::setprecision(20);
00212    std::cout << " Initial seed      = " << theSeed << std::endl;
00213    std::cout << " Current index     = " << count624 << std::endl;
00214    std::cout << " Array status mt[] = " << std::endl;
00215    for (int i=0; i<624; i+=5) {
00216      std::cout << mt[i]   << " " << mt[i+1] << " " << mt[i+2] << " " 
00217                << mt[i+3] << " " << mt[i+4] << std::endl;
00218    }
00219    std::cout << "----------------------------------------" << std::endl;
00220 }
00221 
00222 MTwistEngine::operator float() {
00223   unsigned int y;
00224 
00225   if( count624 >= N ) {
00226     register int i;
00227 
00228     for( i=0; i < NminusM; ++i ) {
00229       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00230       mt[i] = mt[i+M]       ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00231     }
00232 
00233     for(    ; i < N-1    ; ++i ) {
00234       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00235       mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00236     }
00237 
00238     y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff);
00239     mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00240 
00241     count624 = 0;
00242   }
00243 
00244   y = mt[count624++];
00245   y ^= ( y >> 11);
00246   y ^= ((y << 7 ) & 0x9d2c5680);
00247   y ^= ((y << 15) & 0xefc60000);
00248   y ^= ( y >> 18);
00249 
00250   return (float)(y * twoToMinus_32());
00251 }
00252 
00253 MTwistEngine::operator unsigned int() {
00254   unsigned int y;
00255 
00256   if( count624 >= N ) {
00257     register int i;
00258 
00259     for( i=0; i < NminusM; ++i ) {
00260       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00261       mt[i] = mt[i+M]       ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00262     }
00263 
00264     for(    ; i < N-1    ; ++i ) {
00265       y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
00266       mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00267     }
00268 
00269     y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff);
00270     mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
00271 
00272     count624 = 0;
00273   }
00274 
00275   y = mt[count624++];
00276   y ^= ( y >> 11);
00277   y ^= ((y << 7 ) & 0x9d2c5680);
00278   y ^= ((y << 15) & 0xefc60000);
00279   y ^= ( y >> 18);
00280 
00281   return y;
00282 }
00283 
00284 std::ostream & MTwistEngine::put ( std::ostream& os ) const
00285 {
00286    char beginMarker[] = "MTwistEngine-begin";
00287    char endMarker[]   = "MTwistEngine-end";
00288 
00289    int pr = os.precision(20);
00290    os << " " << beginMarker << " ";
00291    os << theSeed << " ";
00292    for (int i=0; i<624; ++i) {
00293      os << mt[i] << "\n";
00294    }
00295    os << count624 << " ";
00296    os << endMarker << "\n";
00297    os.precision(pr);
00298    return os;
00299 }
00300 
00301 std::vector<unsigned long> MTwistEngine::put () const {
00302   std::vector<unsigned long> v;
00303   v.push_back (engineIDulong<MTwistEngine>());
00304   for (int i=0; i<624; ++i) {
00305      v.push_back(static_cast<unsigned long>(mt[i]));
00306   }
00307   v.push_back(count624); 
00308   return v;
00309 }
00310 
00311 std::istream &  MTwistEngine::get ( std::istream& is )
00312 {
00313   char beginMarker [MarkerLen];
00314   is >> std::ws;
00315   is.width(MarkerLen);  // causes the next read to the char* to be <=
00316                         // that many bytes, INCLUDING A TERMINATION \0 
00317                         // (Stroustrup, section 21.3.2)
00318   is >> beginMarker;
00319   if (strcmp(beginMarker,"MTwistEngine-begin")) {
00320      is.clear(std::ios::badbit | is.rdstate());
00321      std::cerr << "\nInput stream mispositioned or"
00322                << "\nMTwistEngine state description missing or"
00323                << "\nwrong engine type found." << std::endl;
00324      return is;
00325    }
00326   return getState(is);
00327 }
00328 
00329 std::string MTwistEngine::beginTag ( )  { 
00330   return "MTwistEngine-begin"; 
00331 }
00332 
00333 std::istream &  MTwistEngine::getState ( std::istream& is )
00334 {
00335   char endMarker   [MarkerLen];
00336   is >> theSeed;
00337   for (int i=0; i<624; ++i)  is >> mt[i];
00338   is >> count624;
00339   is >> std::ws;
00340   is.width(MarkerLen);  
00341   is >> endMarker;
00342   if (strcmp(endMarker,"MTwistEngine-end")) {
00343      is.clear(std::ios::badbit | is.rdstate());
00344      std::cerr << "\nMTwistEngine state description incomplete."
00345                << "\nInput stream is probably mispositioned now." << std::endl;
00346      return is;
00347    }
00348    return is;
00349 }
00350 
00351 bool MTwistEngine::get (const std::vector<unsigned long> & v) {
00352   if ((v[0] & 0xffffffffUL) != engineIDulong<MTwistEngine>()) {
00353     std::cerr << 
00354         "\nMTwistEngine get:state vector has wrong ID word - state unchanged\n";
00355     return false;
00356   }
00357   return getState(v);
00358 }
00359 
00360 bool MTwistEngine::getState (const std::vector<unsigned long> & v) {
00361   if (v.size() != VECTOR_STATE_SIZE ) {
00362     std::cerr << 
00363         "\nMTwistEngine get:state vector has wrong length - state unchanged\n";
00364     return false;
00365   }
00366   for (int i=0; i<624; ++i) {
00367      mt[i]=v[i+1];
00368   }
00369   count624 = v[625];
00370   return true;
00371 }
00372 
00373 }  // namespace CLHEP

Generated on 15 Nov 2012 for CLHEP by  doxygen 1.4.7