1 // $Id: Hurd288Engine.cc,v 1.7 2010/07/20 18:07:17 garren Exp $
2 // -*- C++ -*-
3 //
4 // -----------------------------------------------------------------------
5 //                           HEP Random
6 //                     --- Hurd288Engine ---
7 //                    class implementation file
8 // -----------------------------------------------------------------------
9 // An interconnected shift register based on the paper presented by Hurd in
10 // IEEE Transactions on Computers c23, 2 Feb 1974.
11 // =======================================================================
12 // Ken Smith      - Initial draft started:                    23rd Jul 1998
13 //                - Added conversion operators:                6th Aug 1998
14 // J. Marraffino  - Added some explicit casts to deal with
15 //                  machines where sizeof(int) != sizeof(long)  22 Aug 1998
16 // M. Fischler    - Modified use of the various exponents of 2
17 //                  to avoid per-instance space overhead and
18 //                  correct the rounding procedure              15 Sep 1998
19 //                - Modified various methods to avoid any
20 //                  possibility of predicting the next number
21 //                  based on the last several:  We skip one
22 //                  32-bit word per cycle.			15 Sep 1998
23 //                - modify word[0] in two of the constructors
24 //                  so that no sequence can ever accidentally
25 //                  be produced by differnt seeds.              15 Sep 1998
26 // J. Marraffino  - Remove dependence on hepString class        13 May 1999
27 // M. Fischler    - Put endl at end of a save                   10 Apr 2001
28 // M. Fischler    - In restore, checkFile for file not found    03 Dec 2004
29 // M. Fischler    - methods for distrib. instacne save/restore  12/8/04
30 // M. Fischler    - split get() into tag validation and
31 //                  getState() for anonymous restores           12/27/04
32 // M. Fischler    - put/get for vectors of ulongs		3/14/05
33 // M. Fischler    - State-saving using only ints, for portability 4/12/05
34 //
35 // =======================================================================
36 
37 #include "CLHEP/Random/defs.h"
38 #include "CLHEP/Random/Random.h"
39 #include "CLHEP/Random/Hurd288Engine.h"
40 #include "CLHEP/Random/engineIDulong.h"
41 #include "CLHEP/Utility/atomic_int.h"
42 
43 #include <string.h>	// for strcmp
44 #include <cstdlib>	// for std::abs(int)
45 
46 using namespace std;
47 
48 namespace CLHEP {
49 
50 namespace {
51   // Number of instances with automatic seed selection
52   CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
53 
54   // Maximum index into the seed table
55   const int maxIndex = 215;
56 }
57 
58 static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
59 
name() const60 std::string Hurd288Engine::name() const {return "Hurd288Engine";}
61 
f288(unsigned int a,unsigned int b,unsigned int c)62 static inline unsigned int f288(unsigned int a, unsigned int b, unsigned int c)
63 {
64   return ( ((b<<2) & 0x7ffc) | ((a<<2) & ~0x7ffc) | (a>>30) ) ^
65          ( (c<<1)|(c>>31) );
66 }
67 
Hurd288Engine()68 Hurd288Engine::Hurd288Engine()
69 : HepRandomEngine()
70 {
71   int numEngines = numberOfEngines++;
72   int cycle    = std::abs(int(numEngines/maxIndex));
73   int curIndex = std::abs(int(numEngines%maxIndex));
74   long mask = ((cycle & 0x007fffff) << 8);
75   long seedlist[2];
76   HepRandom::getTheTableSeeds( seedlist, curIndex );
77   seedlist[0] ^= mask;
78   seedlist[1] = 0;
79   setSeeds(seedlist, 0);
80   words[0] ^= 0x1324abcd;        // To make unique vs long or two unsigned
81   if (words[0]==0) words[0] = 1; // ints in the constructor
82 
83   for( int i=0; i < 100; ++i ) flat();       // warm up just a bit
84 }
85 
Hurd288Engine(std::istream & is)86 Hurd288Engine::Hurd288Engine( std::istream& is )
87 : HepRandomEngine()
88 {
89     is >> *this;
90 }
91 
Hurd288Engine(long seed)92 Hurd288Engine::Hurd288Engine( long seed )
93 : HepRandomEngine()
94 {
95   long seedlist[2]={seed,0};
96   setSeeds(seedlist, 0);
97   words[0] ^= 0xa5482134;        // To make unique vs default two unsigned
98   if (words[0]==0) words[0] = 1; // ints in the constructor
99   for( int i=0; i < 100; ++i ) flat();       // warm up just a bit
100 }
101 
Hurd288Engine(int rowIndex,int colIndex)102 Hurd288Engine::Hurd288Engine( int rowIndex, int colIndex )
103 : HepRandomEngine()
104 {
105   int cycle = std::abs(int(rowIndex/maxIndex));
106   int   row = std::abs(int(rowIndex%maxIndex));
107   int   col = colIndex & 0x1;
108   long mask = (( cycle & 0x000007ff ) << 20 );
109   long seedlist[2];
110   HepRandom::getTheTableSeeds( seedlist, row );
111   seedlist[0] = (seedlist[col])^mask;
112   seedlist[1]= 0;
113   setSeeds(seedlist, 0);
114   for( int i=0; i < 100; ++i ) flat();       // warm up just a bit
115 }
116 
~Hurd288Engine()117 Hurd288Engine::~Hurd288Engine() { }
118 
advance()119 void Hurd288Engine::advance() {
120 
121      unsigned int W0, W1, W2, W3, W4, W5, W6, W7, W8;
122 
123      W0 = words[0];
124      W1 = words[1];
125      W2 = words[2];
126      W3 = words[3];
127      W4 = words[4];
128      W5 = words[5];
129      W6 = words[6];
130      W7 = words[7];
131      W8 = words[8];
132      W1 ^= W0; W0 = f288(W2, W3, W0);
133      W2 ^= W1; W1 = f288(W3, W4, W1);
134      W3 ^= W2; W2 = f288(W4, W5, W2);
135      W4 ^= W3; W3 = f288(W5, W6, W3);
136      W5 ^= W4; W4 = f288(W6, W7, W4);
137      W6 ^= W5; W5 = f288(W7, W8, W5);
138      W7 ^= W6; W6 = f288(W8, W0, W6);
139      W8 ^= W7; W7 = f288(W0, W1, W7);
140      W0 ^= W8; W8 = f288(W1, W2, W8);
141      words[0] = W0 & 0xffffffff;
142      words[1] = W1 & 0xffffffff;
143      words[2] = W2 & 0xffffffff;
144      words[3] = W3 & 0xffffffff;
145      words[4] = W4 & 0xffffffff;
146      words[5] = W5 & 0xffffffff;
147      words[6] = W6 & 0xffffffff;
148      words[7] = W7 & 0xffffffff;
149      words[8] = W8 & 0xffffffff;
150      wordIndex = 9;
151 
152 } // advance()
153 
154 
flat()155 double Hurd288Engine::flat() {
156 
157   if( wordIndex <= 2 ) {	// MF 9/15/98:
158 				// skip word 0 and use two words per flat
159     advance();
160   }
161 
162   // LG 6/30/2010
163   // define the order of execution for --wordIndex
164   double x = words[--wordIndex] * twoToMinus_32() ; // most significant part
165   double y = (words[--wordIndex]>>11) * twoToMinus_53() + // fill in rest of bits
166                     nearlyTwoToMinus_54();        // make sure non-zero
167   return x + y;
168 }
169 
flatArray(const int size,double * vect)170 void Hurd288Engine::flatArray( const int size, double* vect ) {
171     for (int i = 0; i < size; ++i) {
172         vect[i] = flat();
173     }
174 }
175 
setSeed(long seed,int)176 void Hurd288Engine::setSeed( long seed, int ) {
177   words[0] = (unsigned int)seed;
178   for (wordIndex = 1; wordIndex < 9; ++wordIndex) {
179     words[wordIndex] = 69607 * words[wordIndex-1] + 54329;
180   }
181 }
182 
setSeeds(const long * seeds,int)183 void Hurd288Engine::setSeeds( const long* seeds, int ) {
184   setSeed( *seeds ? *seeds : 32767, 0 );
185   theSeeds = seeds;
186 }
187 
saveStatus(const char filename[]) const188 void Hurd288Engine::saveStatus( const char filename[] ) const {
189   std::ofstream outFile(filename, std::ios::out);
190   if( !outFile.bad() ) {
191     outFile << "Uvec\n";
192     std::vector<unsigned long> v = put();
193 		     #ifdef TRACE_IO
194 			 std::cout << "Result of v = put() is:\n";
195 		     #endif
196     for (unsigned int i=0; i<v.size(); ++i) {
197       outFile << v[i] << "\n";
198 		     #ifdef TRACE_IO
199 			   std::cout << v[i] << " ";
200 			   if (i%6==0) std::cout << "\n";
201 		     #endif
202     }
203 		     #ifdef TRACE_IO
204 			 std::cout << "\n";
205 		     #endif
206   }
207 #ifdef REMOVED
208     outFile << std::setprecision(20) << theSeed << " ";
209     outFile << wordIndex << " ";
210     for( int i = 0; i < 9; ++i ) {
211       outFile << words[i] << " ";
212     }
213     outFile << std::endl;
214 #endif
215 }
216 
restoreStatus(const char filename[])217 void Hurd288Engine::restoreStatus( const char filename[] ) {
218   std::ifstream inFile(filename, std::ios::in);
219   if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
220     std::cerr << "  -- Engine state remains unchanged\n";
221     return;
222   }
223   if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
224     std::vector<unsigned long> v;
225     unsigned long xin;
226     for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
227       inFile >> xin;
228 	       #ifdef TRACE_IO
229 	       std::cout << "ivec = " << ivec << "  xin = " << xin << "    ";
230 	       if (ivec%3 == 0) std::cout << "\n";
231 	       #endif
232       if (!inFile) {
233         inFile.clear(std::ios::badbit | inFile.rdstate());
234         std::cerr << "\nHurd288Engine state (vector) description improper."
235 	       << "\nrestoreStatus has failed."
236 	       << "\nInput stream is probably mispositioned now." << std::endl;
237         return;
238       }
239       v.push_back(xin);
240     }
241     getState(v);
242     return;
243   }
244 
245   if( !inFile.bad() ) {
246 //     inFile >> theSeed;  removed -- encompased by possibleKeywordInput
247     inFile >> wordIndex;
248     for( int i = 0; i < 9; ++i ) {
249         inFile >> words[i];
250     }
251   }
252 }
253 
showStatus() const254 void Hurd288Engine::showStatus() const {
255   std::cout << std::setprecision(20) << std::endl;
256   std::cout << "----------- Hurd2 engine status ----------" << std::endl;
257   std::cout << "Initial seed  = " << theSeed   << std::endl;
258   std::cout << "Current index = " << wordIndex << std::endl;
259   std::cout << "Current words = " << std::endl;
260   for( int i = 0; i < 9 ; ++i ) {
261     std::cout << "    " << words[i] << std::endl;
262   }
263   std::cout << "-------------------------------------------" << std::endl;
264 }
265 
operator double()266 Hurd288Engine::operator double() {
267   return flat();
268 }
269 
operator float()270 Hurd288Engine::operator float() {
271   if( wordIndex <= 1 ) {	// MF 9/15/98:  skip word 0
272     advance();
273   }
274   return words[--wordIndex ] * twoToMinus_32();
275 }
276 
operator unsigned int()277 Hurd288Engine::operator unsigned int() {
278   if( wordIndex <= 1 ) {	// MF 9/15/98:  skip word 0
279     advance();
280   }
281   return words[--wordIndex];
282 }
283 
put(std::ostream & os) const284 std::ostream& Hurd288Engine::put(std::ostream& os) const {
285   char beginMarker[] = "Hurd288Engine-begin";
286   os << beginMarker << "\nUvec\n";
287   std::vector<unsigned long> v = put();
288   for (unsigned int i=0; i<v.size(); ++i) {
289      os <<  v[i] <<  "\n";
290   }
291   return os;
292 #ifdef REMOVED
293   char endMarker[]   = "Hurd288Engine-end";
294   int pr = os.precision(20);
295   os << " " << beginMarker << " ";
296   os << theSeed  << " ";
297   os << wordIndex << " ";
298   for (int i = 0; i < 9; ++i) {
299     os << words[i]  << "\n";
300   }
301   os << endMarker   << "\n ";
302   os.precision(pr);
303   return os;
304 #endif
305 }
306 
put() const307 std::vector<unsigned long> Hurd288Engine::put () const {
308   std::vector<unsigned long> v;
309   v.push_back (engineIDulong<Hurd288Engine>());
310   v.push_back(static_cast<unsigned long>(wordIndex));
311   for (int i = 0; i < 9; ++i) {
312     v.push_back(static_cast<unsigned long>(words[i]));
313   }
314   return v;
315 }
316 
317 
get(std::istream & is)318 std::istream& Hurd288Engine::get(std::istream& is) {
319   char beginMarker [MarkerLen];
320   is >> std::ws;
321   is.width(MarkerLen);  // causes the next read to the char* to be <=
322 			// that many bytes, INCLUDING A TERMINATION \0
323 			// (Stroustrup, section 21.3.2)
324   is >> beginMarker;
325   if (strcmp(beginMarker,"Hurd288Engine-begin")) {
326     is.clear(std::ios::badbit | is.rdstate());
327     std::cerr << "\nInput mispositioned or"
328 	      << "\nHurd288Engine state description missing or"
329 	      << "\nwrong engine type found." << std::endl;
330     return is;
331   }
332   return getState(is);
333 }
334 
beginTag()335 std::string Hurd288Engine::beginTag ( )  {
336   return "Hurd288Engine-begin";
337 }
338 
getState(std::istream & is)339 std::istream& Hurd288Engine::getState(std::istream& is) {
340   if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
341     std::vector<unsigned long> v;
342     unsigned long uu;
343     for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
344       is >> uu;
345       if (!is) {
346         is.clear(std::ios::badbit | is.rdstate());
347         std::cerr << "\nHurd288Engine state (vector) description improper."
348 		<< "\ngetState() has failed."
349 	       << "\nInput stream is probably mispositioned now." << std::endl;
350         return is;
351       }
352       v.push_back(uu);
353     }
354     getState(v);
355     return (is);
356   }
357 
358 //  is >> theSeed;  Removed, encompassed by possibleKeywordInput()
359 
360   char endMarker   [MarkerLen];
361   is >> wordIndex;
362   for (int i = 0; i < 9; ++i) {
363     is >> words[i];
364   }
365   is >> std::ws;
366   is.width(MarkerLen);
367   is >> endMarker;
368   if (strcmp(endMarker,"Hurd288Engine-end")) {
369     is.clear(std::ios::badbit | is.rdstate());
370     std::cerr << "\nHurd288Engine state description incomplete."
371 	      << "\nInput stream is probably mispositioned now." << std::endl;
372     return is;
373   }
374   return is;
375 }
376 
get(const std::vector<unsigned long> & v)377 bool Hurd288Engine::get (const std::vector<unsigned long> & v) {
378   if ((v[0] & 0xffffffffUL) != engineIDulong<Hurd288Engine>()) {
379     std::cerr <<
380     	"\nHurd288Engine get:state vector has wrong ID word - state unchanged\n";
381     std::cerr << "The correct ID would be " << engineIDulong<Hurd288Engine>()
382     << "; the actual ID is " << v[0] << "\n";
383     return false;
384   }
385   return getState(v);
386 }
387 
getState(const std::vector<unsigned long> & v)388 bool Hurd288Engine::getState (const std::vector<unsigned long> & v) {
389   if (v.size() != VECTOR_STATE_SIZE ) {
390     std::cerr <<
391     	"\nHurd288Engine get:state vector has wrong length - state unchanged\n";
392     return false;
393   }
394   wordIndex = v[1];
395   for (int i = 0; i < 9; ++i) {
396     words[i] = v[i+2];
397   }
398   return true;
399 }
400 
401 }  // namespace CLHEP
402