CLHEP 2.4.6.4
C++ Class Library for High Energy Physics
Loading...
Searching...
No Matches
TripleRand.cc
Go to the documentation of this file.
1//
2// -*- C++ -*-
3//
4// -----------------------------------------------------------------------
5// Hep Random
6// --- TripleRand ---
7// class implementation file
8// -----------------------------------------------------------------------
9// A canopy pseudo-random number generator. Using the Tausworthe
10// exclusive-or shift register, a simple Integer Coungruence generator, and
11// the Hurd 288 total bit shift register, all XOR'd with each other, we
12// provide an engine that should be a fairly good "mother" generator.
13// =======================================================================
14// Ken Smith - Initial draft started: 23rd Jul 1998
15// - Added conversion operators: 6th Aug 1998
16// J. Marraffino - Added some explicit casts to deal with
17// machines where sizeof(int) != sizeof(long) 22 Aug 1998
18// M. Fischler - Modified use of the various exponents of 2
19// to avoid per-instance space overhead and
20// correct the rounding procedure 15 Sep 1998
21// - modify constructors so that no sequence can
22// ever accidentally be produced by differnt
23// seeds, and so that exxcept for the default
24// constructor, the seed fully determines the
25// sequence. 15 Sep 1998
26// M. Fischler - Eliminated dependency on hepString 13 May 1999
27// M. Fischler - Eliminated Taus() and Cong() which were
28// causing spurions warnings on SUN CC 27 May 1999
29// M. Fischler - Put endl at end of puts of Tausworth and 10 Apr 2001
30// integerCong
31// M. Fischler - In restore, checkFile for file not found 03 Dec 2004
32// M. Fischler - Methods put, get for instance save/restore 12/8/04
33// M. Fischler - split get() into tag validation and
34// getState() for anonymous restores 12/27/04
35// M. Fischler - put/get for vectors of ulongs 3/14/05
36// M. Fischler - State-saving using only ints, for portability 4/12/05
37//
38// =======================================================================
39
40#include "CLHEP/Random/TripleRand.h"
41#include "CLHEP/Random/defs.h"
42#include "CLHEP/Random/engineIDulong.h"
43#include "CLHEP/Utility/atomic_int.h"
44
45#include <atomic>
46#include <iostream>
47#include <string.h> // for strcmp
48#include <string>
49#include <vector>
50
51namespace CLHEP {
52
53namespace {
54 // Number of instances with automatic seed selection
55 CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
56}
57
58static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
59
60//********************************************************************
61// TripleRand
62//********************************************************************
63
64std::string TripleRand::name() const {return "TripleRand";}
65
68 numEngines(numberOfEngines++),
69 tausworthe (1234567 + numEngines + 175321),
70 integerCong(69607 * tausworthe + 54329, numEngines),
71 hurd(19781127 + integerCong)
72{
73 theSeed = 1234567;
74}
75
78 numEngines(0),
79 tausworthe ((unsigned int)seed + 175321),
80 integerCong(69607 * tausworthe + 54329, 1313),
81 hurd(19781127 + integerCong)
82{
83 theSeed = seed;
84}
85
86TripleRand::TripleRand(std::istream & is)
88 numEngines(0)
89{
90 is >> *this;
91}
92
93TripleRand::TripleRand(int rowIndex, int colIndex)
95 numEngines(numberOfEngines),
96 tausworthe (rowIndex + numEngines * colIndex + 175321),
97 integerCong(69607 * tausworthe + 54329, 19),
98 hurd(19781127 + integerCong)
99{
100 theSeed = rowIndex;
101}
102
104
106 unsigned int ic ( integerCong );
107 unsigned int t ( tausworthe );
108 unsigned int h ( hurd );
109 return ( (t ^ ic ^ h) * twoToMinus_32() + // most significant part
110 (h >> 11) * twoToMinus_53() + // fill in remaining bits
111 nearlyTwoToMinus_54() // make sure non-zero
112 );
113}
114
115void TripleRand::flatArray(const int size, double* vect) {
116 for (int i = 0; i < size; ++i) {
117 vect[i] = flat();
118 }
119}
120
121void TripleRand::setSeed(long seed, int) {
122 theSeed = seed;
123 tausworthe = Tausworthe((unsigned int)seed + 175321);
124 integerCong = IntegerCong(69607 * tausworthe + 54329, 1313);
125 hurd = Hurd288Engine( 19781127 + integerCong );
126}
127
128void TripleRand::setSeeds(const long * seeds, int) {
129 setSeed(seeds ? *seeds : 1234567, 0);
130 theSeeds = seeds;
131}
132
133void TripleRand::saveStatus(const char filename[]) const {
134 std::ofstream outFile(filename, std::ios::out);
135 if (!outFile.bad()) {
136 outFile << "Uvec\n";
137 std::vector<unsigned long> v = put();
138 #ifdef TRACE_IO
139 std::cout << "Result of v = put() is:\n";
140 #endif
141 for (unsigned int i=0; i<v.size(); ++i) {
142 outFile << v[i] << "\n";
143 #ifdef TRACE_IO
144 std::cout << v[i] << " ";
145 if (i%6==0) std::cout << "\n";
146 #endif
147 }
148 #ifdef TRACE_IO
149 std::cout << "\n";
150 #endif
151 }
152#ifdef REMOVED
153 outFile << std::setprecision(20) << theSeed << " ";
154 tausworthe.put ( outFile );
155 integerCong.put( outFile);
156 outFile << ConstHurd() << std::endl;
157#endif
158}
159
160void TripleRand::restoreStatus(const char filename[]) {
161 std::ifstream inFile(filename, std::ios::in);
162 if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
163 std::cerr << " -- Engine state remains unchanged\n";
164 return;
165 }
166 if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
167 std::vector<unsigned long> v;
168 unsigned long xin;
169 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
170 inFile >> xin;
171 #ifdef TRACE_IO
172 std::cout << "ivec = " << ivec << " xin = " << xin << " ";
173 if (ivec%3 == 0) std::cout << "\n";
174 #endif
175 if (!inFile) {
176 inFile.clear(std::ios::badbit | inFile.rdstate());
177 std::cerr << "\nTripleRand state (vector) description improper."
178 << "\nrestoreStatus has failed."
179 << "\nInput stream is probably mispositioned now." << std::endl;
180 return;
181 }
182 v.push_back(xin);
183 }
184 getState(v);
185 return;
186 }
187
188 if (!inFile.bad()) {
189// inFile >> theSeed; removed -- encompased by possibleKeywordInput
190 tausworthe.get ( inFile );
191 integerCong.get( inFile );
192 inFile >> Hurd();
193 }
194}
195
197 std::cout << std::setprecision(20) << std::endl;
198 std::cout << "-------- TripleRand engine status ---------"
199 << std::endl;
200 std::cout << "Initial seed = " << theSeed << std::endl;
201 std::cout << "Tausworthe generator = " << std::endl;
202 tausworthe.put( std::cout );
203 std::cout << "IntegerCong generator = " << std::endl;
204 integerCong.put( std::cout );
205 std::cout << "Hurd288Engine generator= " << std::endl << ConstHurd();
206 std::cout << std::endl << "-----------------------------------------"
207 << std::endl;
208}
209
210TripleRand::operator double() {
211 return flat();
212}
213
214TripleRand::operator float() {
215 return (float)
216 ( ( integerCong ^ tausworthe ^ (unsigned int)hurd ) * twoToMinus_32()
217 + nearlyTwoToMinus_54() );
218 // make sure non-zero!
219}
220
221TripleRand::operator unsigned int() {
222 return integerCong ^ tausworthe ^ (unsigned int)hurd;
223}
224
225Hurd288Engine & TripleRand::Hurd() { return hurd; }
226
227const Hurd288Engine & TripleRand::ConstHurd() const
228 { return hurd; }
229
230std::ostream & TripleRand::put (std::ostream & os ) const {
231 char beginMarker[] = "TripleRand-begin";
232 os << beginMarker << "\nUvec\n";
233 std::vector<unsigned long> v = put();
234 for (unsigned int i=0; i<v.size(); ++i) {
235 os << v[i] << "\n";
236 }
237 return os;
238#ifdef REMOVED
239 char endMarker[] = "TripleRand-end";
240 int pr=os.precision(20);
241 os << " " << beginMarker << "\n";
242 os << theSeed << "\n";
243 tausworthe.put( os );
244 integerCong.put( os );
245 os << ConstHurd();
246 os << " " << endMarker << "\n";
247 os.precision(pr);
248 return os;
249#endif
250}
251
252std::vector<unsigned long> TripleRand::put () const {
253 std::vector<unsigned long> v;
254 v.push_back (engineIDulong<TripleRand>());
255 tausworthe.put(v);
256 integerCong.put(v);
257 std::vector<unsigned long> vHurd = hurd.put();
258 for (unsigned int i = 0; i < vHurd.size(); ++i) {
259 v.push_back (vHurd[i]);
260 }
261 return v;
262}
263
264std::istream & TripleRand::get (std::istream & is) {
265 char beginMarker [MarkerLen];
266 is >> std::ws;
267 is.width(MarkerLen); // causes the next read to the char* to be <=
268 // that many bytes, INCLUDING A TERMINATION \0
269 // (Stroustrup, section 21.3.2)
270 is >> beginMarker;
271 if (strcmp(beginMarker,"TripleRand-begin")) {
272 is.clear(std::ios::badbit | is.rdstate());
273 std::cerr << "\nInput mispositioned or"
274 << "\nTripleRand state description missing or"
275 << "\nwrong engine type found." << std::endl;
276 return is;
277 }
278 return getState(is);
279}
280
281std::string TripleRand::beginTag ( ) {
282 return "TripleRand-begin";
283}
284
285std::istream & TripleRand::getState (std::istream & is) {
286 if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
287 std::vector<unsigned long> v;
288 unsigned long uu;
289 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
290 is >> uu;
291 if (!is) {
292 is.clear(std::ios::badbit | is.rdstate());
293 std::cerr << "\nTripleRand state (vector) description improper."
294 << "\ngetState() has failed."
295 << "\nInput stream is probably mispositioned now." << std::endl;
296 return is;
297 }
298 v.push_back(uu);
299 }
300 getState(v);
301 return (is);
302 }
303
304// is >> theSeed; Removed, encompassed by possibleKeywordInput()
305
306 char endMarker [MarkerLen];
307 tausworthe.get( is );
308 integerCong.get( is );
309 is >> Hurd();
310 is >> std::ws;
311 is.width(MarkerLen);
312 is >> endMarker;
313 if (strcmp(endMarker,"TripleRand-end")) {
314 is.clear(std::ios::badbit | is.rdstate());
315 std::cerr << "\nTripleRand state description incomplete."
316 << "\nInput stream is probably mispositioned now." << std::endl;
317 return is;
318 }
319 return is;
320}
321
322bool TripleRand::get (const std::vector<unsigned long> & v) {
323 if ((v[0] & 0xffffffffUL) != engineIDulong<TripleRand>()) {
324 std::cerr <<
325 "\nTripleRand get:state vector has wrong ID word - state unchanged\n";
326 return false;
327 }
328 if (v.size() != VECTOR_STATE_SIZE) {
329 std::cerr << "\nTripleRand get:state vector has wrong size: "
330 << v.size() << " - state unchanged\n";
331 return false;
332 }
333 return getState(v);
334}
335
336bool TripleRand::getState (const std::vector<unsigned long> & v) {
337 std::vector<unsigned long>::const_iterator iv = v.begin()+1;
338 if (!tausworthe.get(iv)) return false;
339 if (!integerCong.get(iv)) return false;
340 std::vector<unsigned long> vHurd;
341 while (iv != v.end()) {
342 vHurd.push_back(*iv++);
343 }
344 if (!hurd.get(vHurd)) {
345 std::cerr <<
346 "\nTripleRand get from vector: problem getting the hurd sub-engine state\n";
347 return false;
348 }
349 return true;
350}
351
352//********************************************************************
353// Tausworthe
354//********************************************************************
355
356TripleRand::Tausworthe::Tausworthe() {
357 words[0] = 1234567;
358 for (wordIndex = 1; wordIndex < 4; ++wordIndex) {
359 words[wordIndex] = 69607 * words[wordIndex-1] + 54329;
360 }
361}
362
363TripleRand::Tausworthe::Tausworthe(unsigned int seed) {
364 words[0] = seed;
365 for (wordIndex = 1; wordIndex < 4; ++wordIndex) {
366 words[wordIndex] = 69607 * words[wordIndex-1] + 54329;
367 }
368}
369
370TripleRand::Tausworthe::operator unsigned int() {
371
372// Mathematically: Consider a sequence of bits b[n]. Repeatedly form
373// b[0]' = b[127] ^ b[97]; b[n]' = b[n-1]. This sequence will have a very
374// long period (2**127-1 according to Tausworthe's work).
375
376// The actual method used relies on the fact that the operations needed to
377// form bit 0 for up to 96 iterations never depend on the results of the
378// previous ones. So you can actually compute many bits at once. In fact
379// you can compute 32 at once -- despite 127 - 97 < 32 -- but 24 was used in
380// the method used in Canopy, where they wanted only single-precision float
381// randoms. I will do 32 here.
382
383// When you do it this way, this looks disturbingly like the dread lagged XOR
384// Fibonacci. And indeed, it is a lagged Fibonacii, F(4,3, op) with the op
385// being the XOR of a combination of shifts of the two numbers. Although
386// Tausworthe asserted excellent properties, I would be scared to death.
387// However, the shifting and bit swapping really does randomize this in a
388// serious way.
389
390// Statements have been made to the effect that shift register sequences fail
391// the parking lot test because they achieve randomness by multiple foldings,
392// and this produces a characteristic pattern. We observe that in this
393// specific algorithm, which has a fairly long lever arm, the foldings become
394// effectively random. This is evidenced by the fact that the generator
395// does pass the Diehard tests, including the parking lot test.
396
397// To avoid shuffling of variables in memory, you either have to use circular
398// pointers (and those give you ifs, which are also costly) or compute at least
399// a few iterations at once. We do the latter. Although there is a possible
400// trade of room for more speed, by computing and saving 256 instead of 128
401// bits at once, I will stop at this level of optimization.
402
403// To remind: Each (32-bit) step takes the XOR of bits [127-96] with bits
404// [95-64] and places it in bits [0-31]. But in the first step, we designate
405// word0 as bits [0-31], in the second step, word 1 (since the bits it holds
406// will no longer be needed), then word 2, then word 3. After this, the
407// stream contains 128 random bits which we will use as 4 valid 32-bit
408// random numbers.
409
410// Thus at the start of the first step, word[0] contains the newest (used)
411// 32-bit random, and word[3] the oldest. After four steps, word[0] again
412// contains the newest (now unused) random, and word[3] the oldest.
413// Bit 0 of word[0] is logically the newest bit, and bit 31 of word[3]
414// the oldest.
415
416 if (wordIndex <= 0) {
417 for (wordIndex = 0; wordIndex < 4; ++wordIndex) {
418 words[wordIndex] = ( (words[(wordIndex+1) & 3] << 1 ) |
419 (words[wordIndex] >> 31) )
420 ^ ( (words[(wordIndex+1) & 3] << 31) |
421 (words[wordIndex] >> 1) );
422 }
423 }
424 return words[--wordIndex] & 0xffffffff;
425}
426
427void TripleRand::Tausworthe::put( std::ostream & os ) const {
428 char beginMarker[] = "Tausworthe-begin";
429 char endMarker[] = "Tausworthe-end";
430
431 long pr=os.precision(20);
432 os << " " << beginMarker << " ";
433 os << std::setprecision(20);
434 for (int i = 0; i < 4; ++i) {
435 os << words[i] << " ";
436 }
437 os << wordIndex;
438 os << " " << endMarker << " ";
439 os << std::endl;
440 os.precision(pr);
441}
442
443void TripleRand::Tausworthe::put(std::vector<unsigned long> & v) const {
444 for (int i = 0; i < 4; ++i) {
445 v.push_back(static_cast<unsigned long>(words[i]));
446 }
447 v.push_back(static_cast<unsigned long>(wordIndex));
448}
449
450void TripleRand::Tausworthe::get( std::istream & is ) {
451 char beginMarker [MarkerLen];
452 char endMarker [MarkerLen];
453
454 is >> std::ws;
455 is.width(MarkerLen);
456 is >> beginMarker;
457 if (strcmp(beginMarker,"Tausworthe-begin")) {
458 is.clear(std::ios::badbit | is.rdstate());
459 std::cerr << "\nInput mispositioned or"
460 << "\nTausworthe state description missing or"
461 << "\nwrong engine type found." << std::endl;
462 }
463 for (int i = 0; i < 4; ++i) {
464 is >> words[i];
465 }
466 is >> wordIndex;
467 is >> std::ws;
468 is.width(MarkerLen);
469 is >> endMarker;
470 if (strcmp(endMarker,"Tausworthe-end")) {
471 is.clear(std::ios::badbit | is.rdstate());
472 std::cerr << "\nTausworthe state description incomplete."
473 << "\nInput stream is probably mispositioned now." << std::endl;
474 }
475}
476
477bool
478TripleRand::Tausworthe::get(std::vector<unsigned long>::const_iterator & iv){
479 for (int i = 0; i < 4; ++i) {
480 words[i] = (unsigned int)*iv++;
481 }
482 wordIndex = (int)*iv++;
483 return true;
484}
485
486//********************************************************************
487// IntegerCong
488//********************************************************************
489
490TripleRand::IntegerCong::IntegerCong()
491: state((unsigned int)3758656018U),
492 multiplier(66565),
493 addend(12341)
494{
495}
496
497TripleRand::IntegerCong::IntegerCong(unsigned int seed, int streamNumber)
498: state(seed),
499 multiplier(65536 + 1024 + 5 + (8 * 1017 * streamNumber)),
500 addend(12341)
501{
502 // As to the multiplier, the following comment was made:
503 // We want our multipliers larger than 2^16, and equal to
504 // 1 mod 4 (for max. period), but not equal to 1 mod 8
505 // (for max. potency -- the smaller and higher dimension the
506 // stripes, the better)
507
508 // All of these will have fairly long periods. Depending on the choice
509 // of stream number, some of these will be quite decent when considered
510 // as independent random engines, while others will be poor. Thus these
511 // should not be used as stand-alone engines; but when combined with a
512 // generator known to be good, they allow creation of millions of good
513 // independent streams, without fear of two streams accidentally hitting
514 // nearby places in the good random sequence.
515}
516
517TripleRand::IntegerCong::operator unsigned int() {
518 return state = (state * multiplier + addend) & 0xffffffff;
519}
520
521void TripleRand::IntegerCong::put( std::ostream & os ) const {
522 char beginMarker[] = "IntegerCong-begin";
523 char endMarker[] = "IntegerCong-end";
524
525 long pr=os.precision(20);
526 os << " " << beginMarker << " ";
527 os << state << " " << multiplier << " " << addend;
528 os << " " << endMarker << " ";
529 os << std::endl;
530 os.precision(pr);
531}
532
533void TripleRand::IntegerCong::put(std::vector<unsigned long> & v) const {
534 v.push_back(static_cast<unsigned long>(state));
535 v.push_back(static_cast<unsigned long>(multiplier));
536 v.push_back(static_cast<unsigned long>(addend));
537}
538
539void TripleRand::IntegerCong::get( std::istream & is ) {
540 char beginMarker [MarkerLen];
541 char endMarker [MarkerLen];
542
543 is >> std::ws;
544 is.width(MarkerLen);
545 is >> beginMarker;
546 if (strcmp(beginMarker,"IntegerCong-begin")) {
547 is.clear(std::ios::badbit | is.rdstate());
548 std::cerr << "\nInput mispositioned or"
549 << "\nIntegerCong state description missing or"
550 << "\nwrong engine type found." << std::endl;
551 }
552 is >> state >> multiplier >> addend;
553 is >> std::ws;
554 is.width(MarkerLen);
555 is >> endMarker;
556 if (strcmp(endMarker,"IntegerCong-end")) {
557 is.clear(std::ios::badbit | is.rdstate());
558 std::cerr << "\nIntegerCong state description incomplete."
559 << "\nInput stream is probably mispositioned now." << std::endl;
560 }
561}
562
563bool
564TripleRand::IntegerCong::get(std::vector<unsigned long>::const_iterator & iv) {
565 state = (unsigned int)*iv++;
566 multiplier = (unsigned int)*iv++;
567 addend = (unsigned int)*iv++;
568 return true;
569}
570
571} // namespace CLHEP
#define CLHEP_ATOMIC_INT_TYPE
Definition: atomic_int.h:25
static double twoToMinus_32()
static double twoToMinus_53()
static double nearlyTwoToMinus_54()
static bool checkFile(std::istream &file, const std::string &filename, const std::string &classname, const std::string &methodname)
Definition: RandomEngine.cc:49
virtual std::ostream & put(std::ostream &os) const
virtual std::istream & get(std::istream &is)
virtual std::istream & get(std::istream &is)
Definition: TripleRand.cc:264
static const unsigned int VECTOR_STATE_SIZE
Definition: TripleRand.h:102
virtual std::istream & getState(std::istream &is)
Definition: TripleRand.cc:285
std::vector< unsigned long > put() const
Definition: TripleRand.cc:252
void flatArray(const int size, double *vect)
Definition: TripleRand.cc:115
virtual ~TripleRand()
Definition: TripleRand.cc:103
std::string name() const
Definition: TripleRand.cc:64
void saveStatus(const char filename[]="TripleRand.conf") const
Definition: TripleRand.cc:133
void setSeed(long seed, int)
Definition: TripleRand.cc:121
void showStatus() const
Definition: TripleRand.cc:196
void restoreStatus(const char filename[]="TripleRand.conf")
Definition: TripleRand.cc:160
void setSeeds(const long *seeds, int)
Definition: TripleRand.cc:128
static std::string engineName()
Definition: TripleRand.h:96
static std::string beginTag()
Definition: TripleRand.cc:281
#define double(obj)
Definition: excDblThrow.cc:32
bool possibleKeywordInput(IS &is, const std::string &key, T &t)
Definition: RandomEngine.h:168