CLHEP 2.4.6.4
C++ Class Library for High Energy Physics
Loading...
Searching...
No Matches
MixMaxRng.cc
Go to the documentation of this file.
1//
2// -*- C++ -*-
3//
4// -----------------------------------------------------------------------
5// HEP Random
6// --- MixMaxRng ---
7// class implementation file
8// -----------------------------------------------------------------------
9//
10// This file interfaces the MixMax PseudoRandom Number Generator
11// proposed by:
12//
13// G.K.Savvidy and N.G.Ter-Arutyunian,
14// On the Monte Carlo simulation of physical systems,
15// J.Comput.Phys. 97, 566 (1991);
16// Preprint EPI-865-16-86, Yerevan, Jan. 1986
17// http://dx.doi.org/10.1016/0021-9991(91)90015-D
18//
19// K.Savvidy
20// "The MIXMAX random number generator"
21// Comp. Phys. Commun. (2015)
22// http://dx.doi.org/10.1016/j.cpc.2015.06.003
23//
24// K.Savvidy and G.Savvidy
25// "Spectrum and Entropy of C-systems. MIXMAX random number generator"
26// Chaos, Solitons & Fractals, Volume 91, (2016) pp. 33-38
27// http://dx.doi.org/10.1016/j.chaos.2016.05.003
28//
29// =======================================================================
30// Implementation by Konstantin Savvidy - Copyright 2004-2017
31// =======================================================================
32
33#include "CLHEP/Random/defs.h"
34#include "CLHEP/Random/Random.h"
35#include "CLHEP/Random/MixMaxRng.h"
36#include "CLHEP/Random/engineIDulong.h"
37#include "CLHEP/Utility/atomic_int.h"
38
39#include <atomic>
40#include <cmath>
41#include <iostream>
42#include <string.h> // for strcmp
43#include <vector>
44
45const unsigned long MASK32=0xffffffff;
46
47namespace CLHEP {
48
49namespace {
50 // Number of instances with automatic seed selection
51 CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
52}
53
54static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
55
58{
59 int numEngines = ++numberOfEngines;
60 setSeed(static_cast<long>(numEngines));
61}
62
65{
66 theSeed=seed;
67 setSeed(seed);
68}
69
70MixMaxRng::MixMaxRng(std::istream& is)
72{
73 get(is);
74}
75
77{
78}
79
81 : HepRandomEngine(rng)
82{
83 S.V = rng.S.V;
84 S.sumtot= rng.S.sumtot;
85 S.counter= rng.S.counter;
86}
87
89{
90 // Check assignment to self
91 //
92 if (this == &rng) { return *this; }
93
94 // Copy base class data
95 //
96 HepRandomEngine::operator=(rng);
97
98 S.V = rng.S.V;
99 S.sumtot= rng.S.sumtot;
100 S.counter= rng.S.counter;
101
102 return *this;
103}
104
105void MixMaxRng::saveStatus( const char filename[] ) const
106{
107 // Create a C file-handle or an object that can accept the same output
108 FILE *fh= fopen(filename, "w");
109 if( fh )
110 {
111 int j;
112 fprintf(fh, "mixmax state, file version 1.0\n" );
113 fprintf(fh, "N=%u; V[N]={", rng_get_N() );
114 for (j=0; (j< (rng_get_N()-1) ); j++) {
115 fprintf(fh, "%llu, ", S.V[j] );
116 }
117 fprintf(fh, "%llu", S.V[rng_get_N()-1] );
118 fprintf(fh, "}; " );
119 fprintf(fh, "counter=%u; ", S.counter );
120 fprintf(fh, "sumtot=%llu;\n", S.sumtot );
121 fclose(fh);
122 }
123}
124
125void MixMaxRng::restoreStatus( const char filename[] )
126{
127 // a function for reading the state from a file
128 FILE* fin;
129 if( ( fin = fopen(filename, "r") ) )
130 {
131 char l=0;
132 while ( l != '{' ) { // 0x7B = "{"
133 l=fgetc(fin); // proceed until hitting opening bracket
134 }
135 ungetc(' ', fin);
136 }
137 else
138 {
139 fprintf(stderr, "mixmax -> read_state: error reading file %s\n", filename);
140 throw std::runtime_error("Error in reading state file");
141 }
142
143 myuint_t vecVal;
144 //printf("mixmax -> read_state: starting to read state from file\n");
145 if (!fscanf(fin, "%llu", &S.V[0]) )
146 {
147 fprintf(stderr, "mixmax -> read_state: error reading file %s\n", filename);
148 throw std::runtime_error("Error in reading state file");
149 }
150
151 int i;
152 for( i = 1; i < rng_get_N(); i++)
153 {
154 if (!fscanf(fin, ", %llu", &vecVal) )
155 {
156 fprintf(stderr, "mixmax -> read_state: error reading vector component i=%d from file %s\n", i, filename);
157 throw std::runtime_error("Error in reading state file");
158 }
159 if( vecVal <= MixMaxRng::M61 )
160 {
161 S.V[i] = vecVal;
162 }
163 else
164 {
165 fprintf(stderr, "mixmax -> read_state: Invalid state vector value= %llu"
166 " ( must be less than %llu ) "
167 " obtained from reading file %s\n"
168 , vecVal, MixMaxRng::M61, filename);
169 }
170 }
171
172 int counter;
173 if (!fscanf( fin, "}; counter=%i; ", &counter))
174 {
175 fprintf(stderr, "mixmax -> read_state: error reading counter from file %s\n", filename);
176 throw std::runtime_error("Error in reading state file");
177 }
178 if( counter <= rng_get_N() )
179 {
180 S.counter= counter;
181 }
182 else
183 {
184 fprintf(stderr, "mixmax -> read_state: Invalid counter = %d"
185 " Must be 0 <= counter < %u\n" , counter, rng_get_N());
186 print_state();
187 throw std::runtime_error("Error in reading state counter");
188 }
189 precalc();
190 myuint_t sumtot;
191 if (!fscanf( fin, "sumtot=%llu\n", &sumtot))
192 {
193 fprintf(stderr, "mixmax -> read_state: error reading checksum from file %s\n", filename);
194 throw std::runtime_error("Error in reading state file");
195 }
196
197 if (S.sumtot != sumtot)
198 {
199 fprintf(stderr, "mixmax -> checksum error while reading state from file %s - corrupted?\n", filename);
200 throw std::runtime_error("Error in reading state checksum");
201 }
202 fclose(fin);
203}
204
206{
207 std::cout << std::endl;
208 std::cout << "------- MixMaxRng engine status -------" << std::endl;
209
210 std::cout << " Current state vector is:" << std::endl;
211 print_state();
212 std::cout << "---------------------------------------" << std::endl;
213}
214
215void MixMaxRng::setSeed(long longSeed, int /* extraSeed */)
216{
217 //seed_uniquestream(0,0,0,longSeed);
218 theSeed = longSeed;
219 seed_spbox(longSeed);
220}
221
222// Preferred Seeding method
223// the values of 'Seeds' must be valid 32-bit integers
224// Higher order bits will be ignored!!
225
226void MixMaxRng::setSeeds(const long* Seeds, int seedNum)
227{
228 myID_t seed0, seed1= 0, seed2= 0, seed3= 0;
229
230 if( seedNum < 1 ) { // Assuming at least 2 seeds in vector...
231 seed0= static_cast<myID_t>(Seeds[0]) & MASK32;
232 seed1= static_cast<myID_t>(Seeds[1]) & MASK32;
233 }
234 else
235 {
236 if( seedNum < 4 ) {
237 seed0= static_cast<myID_t>(Seeds[0]) & MASK32;
238 if( seedNum > 1){ seed1= static_cast<myID_t>(Seeds[1]) & MASK32; }
239 if( seedNum > 2){ seed2= static_cast<myID_t>(Seeds[2]) & MASK32; }
240 }
241 if( seedNum >= 4 ) {
242 seed0= static_cast<myID_t>(Seeds[0]) & MASK32;
243 seed1= static_cast<myID_t>(Seeds[1]) & MASK32;
244 seed2= static_cast<myID_t>(Seeds[2]) & MASK32;
245 seed3= static_cast<myID_t>(Seeds[3]) & MASK32;
246 }
247 }
248 theSeed = Seeds[0];
249 theSeeds = Seeds;
250 seed_uniquestream(seed3, seed2, seed1, seed0);
251}
252
254{
255 return "MixMaxRng";
256}
257
258constexpr int MixMaxRng::rng_get_N()
259{
260 return N;
261}
262
263constexpr long long int MixMaxRng::rng_get_SPECIAL()
264{
265 return SPECIAL;
266}
267
268constexpr int MixMaxRng::rng_get_SPECIALMUL()
269{
270 return SPECIALMUL;
271}
272
273double MixMaxRng::generate(int i)
274{
275 S.counter++;
276#if defined(__clang__) || defined(__llvm__)
277 return INV_M61*static_cast<double>(S.V[i]);
278#elif defined(__GNUC__) && (__GNUC__ < 7) && (!defined(__ICC)) && defined(__x86_64__) && defined(__SSE2_MATH__)
279 int64_t Z=S.V[i];
280 double F=0.0;
281 //#warning Using the inline assembler
282 /* using SSE inline assemly to zero the xmm register, just before int64 -> double conversion,
283 not necessary in GCC-5 or better, but huge penalty on earlier compilers
284 */
285 __asm__ __volatile__( "pxor %0, %0;"
286 "cvtsi2sdq %1, %0;"
287 :"=x"(F)
288 :"r"(Z)
289 );
290 return F*INV_M61;
291#else
292 //#warning other method
293 return convert1double(S.V[i]); //get_next_float_packbits();
294#endif
295}
296
297double MixMaxRng::iterate()
298{
299 myuint_t* Y=S.V.data();
300 myuint_t tempP, tempV;
301 Y[0] = ( tempV = S.sumtot);
302 myuint_t sumtot = Y[0], ovflow = 0; // will keep a running sum of all new elements
303 tempP = 0; // will keep a partial sum of all old elements
304 myuint_t tempPO;
305 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[1] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[1] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
306 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[2] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[2] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
307 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[3] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[3] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
308 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[4] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[4] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
309 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[5] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[5] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
310 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[6] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[6] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
311 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[7] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[7] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
312 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[8] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[8] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
313 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[9] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[9] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
314 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[10]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[10] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
315 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[11]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[11] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
316 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[12]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[12] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
317 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[13]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[13] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
318 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[14]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[14] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
319 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[15]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[15] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
320 tempPO = MULWU(tempP); tempP = modadd(tempP, Y[16]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[16] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
321 S.sumtot = MIXMAX_MOD_MERSENNE(MIXMAX_MOD_MERSENNE(sumtot) + (ovflow <<3 ));
322
323 S.counter=2;
324 return double(S.V[1])*INV_M61;
325}
326
327void MixMaxRng::flatArray(const int size, double* vect )
328{
329 // fill_array( S, size, arrayDbl );
330 for (int i=0; i<size; ++i) { vect[i] = flat(); }
331}
332
333MixMaxRng::operator double()
334{
335 return flat();
336}
337
338MixMaxRng::operator float()
339{
340 return float( flat() );
341}
342
343MixMaxRng::operator unsigned int()
344{
345 return static_cast<unsigned int>(get_next());
346 // clhep_get_next returns a 64-bit integer, of which the lower 61 bits
347 // are random and upper 3 bits are zero
348}
349
350std::ostream & MixMaxRng::put ( std::ostream& os ) const
351{
352 char beginMarker[] = "MixMaxRng-begin";
353 char endMarker[] = "MixMaxRng-end";
354
355 long pr = os.precision(24);
356 os << beginMarker << " ";
357 os << theSeed << "\n";
358 for (int i=0; i<rng_get_N(); ++i) {
359 os << S.V[i] << "\n";
360 }
361 os << S.counter << "\n";
362 os << S.sumtot << "\n";
363 os << endMarker << "\n";
364 os.precision(pr);
365 return os;
366}
367
368std::vector<unsigned long> MixMaxRng::put () const
369{
370 std::vector<unsigned long> v;
371 v.push_back (engineIDulong<MixMaxRng>());
372 for (int i=0; i<rng_get_N(); ++i)
373 {
374 v.push_back(static_cast<unsigned long>(S.V[i] & MASK32));
375 // little-ended order on all platforms
376 v.push_back(static_cast<unsigned long>(S.V[i] >> 32 ));
377 // pack uint64 into a data structure which is 32-bit on some platforms
378 }
379 v.push_back(static_cast<unsigned long>(S.counter));
380 v.push_back(static_cast<unsigned long>(S.sumtot & MASK32));
381 v.push_back(static_cast<unsigned long>(S.sumtot >> 32));
382 return v;
383}
384
385std::istream & MixMaxRng::get ( std::istream& is)
386{
387 char beginMarker [MarkerLen];
388 is >> std::ws;
389 is.width(MarkerLen); // causes the next read to the char* to be <=
390 // that many bytes, INCLUDING A TERMINATION \0
391 // (Stroustrup, section 21.3.2)
392 is >> beginMarker;
393 if (strcmp(beginMarker,"MixMaxRng-begin")) {
394 is.clear(std::ios::badbit | is.rdstate());
395 std::cerr << "\nInput stream mispositioned or"
396 << "\nMixMaxRng state description missing or"
397 << "\nwrong engine type found." << std::endl;
398 return is;
399 }
400 return getState(is);
401}
402
404{
405 return "MixMaxRng-begin";
406}
407
408std::istream & MixMaxRng::getState ( std::istream& is )
409{
410 char endMarker[MarkerLen];
411 is >> theSeed;
412 for (int i=0; i<rng_get_N(); ++i) is >> S.V[i];
413 is >> S.counter;
414 myuint_t checksum;
415 is >> checksum;
416 is >> std::ws;
417 is.width(MarkerLen);
418 is >> endMarker;
419 if (strcmp(endMarker,"MixMaxRng-end")) {
420 is.clear(std::ios::badbit | is.rdstate());
421 std::cerr << "\nMixMaxRng state description incomplete."
422 << "\nInput stream is probably mispositioned now.\n";
423 return is;
424 }
425 if ( S.counter < 0 || S.counter > rng_get_N() ) {
426 std::cerr << "\nMixMaxRng::getState(): "
427 << "vector read wrong value of counter from file!"
428 << "\nInput stream is probably mispositioned now.\n";
429 return is;
430 }
431 precalc();
432 if ( checksum != S.sumtot) {
433 std::cerr << "\nMixMaxRng::getState(): "
434 << "checksum disagrees with value stored in file!"
435 << "\nInput stream is probably mispositioned now.\n";
436 return is;
437 }
438 return is;
439}
440
441bool MixMaxRng::get (const std::vector<unsigned long> & v)
442{
443 if ((v[0] & 0xffffffffUL) != engineIDulong<MixMaxRng>()) {
444 std::cerr <<
445 "\nMixMaxRng::get(): vector has wrong ID word - state unchanged\n";
446 return false;
447 }
448 return getState(v);
449}
450
451bool MixMaxRng::getState (const std::vector<unsigned long> & v)
452{
453 if (v.size() != VECTOR_STATE_SIZE ) {
454 std::cerr <<
455 "\nMixMaxRng::getState(): vector has wrong length - state unchanged\n";
456 return false;
457 }
458 for (int i=1; i<2*rng_get_N() ; i=i+2) {
459 S.V[i/2]= ( (v[i] & MASK32) | ( (myuint_t)(v[i+1]) << 32 ) );
460 // unpack from a data structure which is 32-bit on some platforms
461 }
462 S.counter = (int)v[2*rng_get_N()+1];
463 precalc();
464 if ( ( (v[2*rng_get_N()+2] & MASK32)
465 | ( (myuint_t)(v[2*rng_get_N()+3]) << 32 ) ) != S.sumtot) {
466 std::cerr << "\nMixMaxRng::getState(): vector has wrong checksum!"
467 << "\nInput vector is probably mispositioned now.\n";
468 return false;
469 }
470 return true;
471}
472
473myuint_t MixMaxRng ::MOD_MULSPEC(myuint_t k)
474{
475 switch (N)
476 {
477 case 17:
478 return 0;
479 break;
480 case 8:
481 return 0;
482 break;
483 case 240:
484 return fmodmulM61( 0, SPECIAL , (k) );
485 break;
486 default:
487 std::cerr << "MIXMAX ERROR: " << "Disallowed value of parameter N\n";
488 std::terminate();
489 break;
490 }
491}
492
493myuint_t MixMaxRng::MULWU (myuint_t k)
494{
495 return (( (k)<<(SPECIALMUL) & M61) ^ ( (k) >> (BITS-SPECIALMUL)) );
496}
497
498myuint_t MixMaxRng::iterate_raw_vec(myuint_t* Y, myuint_t sumtotOld)
499{
500 // operates with a raw vector, uses known sum of elements of Y
501 int i;
502
503 myuint_t tempP, tempV;
504 Y[0] = ( tempV = sumtotOld);
505 myuint_t sumtot = Y[0], ovflow = 0; // will keep a running sum of all new elements
506 tempP = 0; // will keep a partial sum of all old elements
507 for (i=1; (i<N); i++)
508 {
509 myuint_t tempPO = MULWU(tempP);
510 tempP = modadd(tempP, Y[i]);
511 tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); // new Y[i] = old Y[i] + old partial * m
512 Y[i] = tempV;
513 sumtot += tempV; if (sumtot < tempV) {ovflow++;}
514 }
515 return MIXMAX_MOD_MERSENNE(MIXMAX_MOD_MERSENNE(sumtot) + (ovflow <<3 ));
516}
517
518myuint_t MixMaxRng::get_next()
519{
520 int i;
521 i=S.counter;
522
523 if ((i<=(N-1)) )
524 {
525 S.counter++;
526 return S.V[i];
527 }
528 else
529 {
530 S.sumtot = iterate_raw_vec(S.V.data(), S.sumtot);
531 S.counter=2;
532 return S.V[1];
533 }
534}
535
536myuint_t MixMaxRng::precalc()
537{
538 int i;
539 myuint_t temp;
540 temp = 0;
541 for (i=0; i < N; i++){
542 temp = MIXMAX_MOD_MERSENNE(temp + S.V[i]);
543 }
544 S.sumtot = temp;
545 return temp;
546}
547
548double MixMaxRng::get_next_float_packbits()
549{
550 myuint_t Z=get_next();
551 return convert1double(Z);
552}
553
554void MixMaxRng::seed_vielbein(unsigned int index)
555{
556 int i;
557 if (index<N)
558 {
559 for (i=0; i < N; i++){
560 S.V[i] = 0;
561 }
562 S.V[index] = 1;
563 }
564 else
565 {
566 std::terminate();
567 }
568 S.counter = N; // set the counter to N if iteration should happen right away
569 S.sumtot = 1;
570}
571
572void MixMaxRng::seed_spbox(myuint_t seed)
573{
574 // a 64-bit LCG from Knuth line 26, in combination with a bit swap is used to seed
575
576 const myuint_t MULT64=6364136223846793005ULL;
577 int i;
578
579 myuint_t sumtot=0,ovflow=0;
580 if (seed == 0) throw std::runtime_error("try seeding with nonzero seed next time");
581
582 myuint_t l = seed;
583
584 for (i=0; i < N; i++){
585 l*=MULT64; l = (l << 32) ^ (l>>32);
586 S.V[i] = l & M61;
587 sumtot += S.V[(i)]; if (sumtot < S.V[(i)]) {ovflow++;}
588 }
589 S.counter = N; // set the counter to N if iteration should happen right away
590 S.sumtot = MIXMAX_MOD_MERSENNE(MIXMAX_MOD_MERSENNE(sumtot) + (ovflow <<3 ));
591}
592
593void MixMaxRng::seed_uniquestream( myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID )
594{
595 seed_vielbein(0);
596 S.sumtot = apply_bigskip(S.V.data(), S.V.data(), clusterID, machineID, runID, streamID );
597 S.counter = 1;
598}
599
600myuint_t MixMaxRng::apply_bigskip( myuint_t* Vout, myuint_t* Vin, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID )
601{
602 /*
603 makes a derived state vector, Vout, from the mother state vector Vin
604 by skipping a large number of steps, determined by the given seeding ID's
605
606 it is mathematically guaranteed that the substreams derived in this way from the SAME (!!!) Vin will not collide provided
607 1) at least one bit of ID is different
608 2) less than 10^100 numbers are drawn from the stream
609 (this is good enough : a single CPU will not exceed this in the lifetime of the universe, 10^19 sec,
610 even if it had a clock cycle of Planch time, 10^44 Hz )
611
612 Caution: never apply this to a derived vector, just choose some mother vector Vin, for example the unit vector by seed_vielbein(X,0),
613 and use it in all your runs, just change runID to get completely nonoverlapping streams of random numbers on a different day.
614
615 clusterID and machineID are provided for the benefit of large organizations who wish to ensure that a simulation
616 which is running in parallel on a large number of clusters and machines will have non-colliding source of random numbers.
617
618 did i repeat it enough times? the non-collision guarantee is absolute, not probabilistic
619
620 */
621
622 const myuint_t skipMat17[128][17] =
623 #include "CLHEP/Random/mixmax_skip_N17.icc"
624 ;
625
626 const myuint_t* skipMat[128];
627 for (int i=0; i<128; i++) { skipMat[i] = skipMat17[i];}
628
629 myID_t IDvec[4] = {streamID, runID, machineID, clusterID};
630 int r,i,j, IDindex;
631 myID_t id;
632 myuint_t Y[N], cum[N];
633 myuint_t coeff;
634 myuint_t* rowPtr;
635 myuint_t sumtot=0;
636
637 for (i=0; i<N; i++) { Y[i] = Vin[i]; sumtot = modadd( sumtot, Vin[i]); } ;
638 for (IDindex=0; IDindex<4; IDindex++)
639 { // go from lower order to higher order ID
640 id=IDvec[IDindex];
641 //printf("now doing ID at level %d, with ID = %d\n", IDindex, id);
642 r = 0;
643 while (id)
644 {
645 if (id & 1)
646 {
647 rowPtr = (myuint_t*)skipMat[r + IDindex*8*sizeof(myID_t)];
648 for (i=0; i<N; i++){ cum[i] = 0; }
649 for (j=0; j<N; j++)
650 { // j is lag, enumerates terms of the poly
651 // for zero lag Y is already given
652 coeff = rowPtr[j]; // same coeff for all i
653 for (i =0; i<N; i++){
654 cum[i] = fmodmulM61( cum[i], coeff , Y[i] ) ;
655 }
656 sumtot = iterate_raw_vec(Y, sumtot);
657 }
658 sumtot=0;
659 for (i=0; i<N; i++){ Y[i] = cum[i]; sumtot = modadd( sumtot, cum[i]); } ;
660 }
661 id = (id >> 1); r++; // bring up the r-th bit in the ID
662 }
663 }
664 sumtot=0;
665 for (i=0; i<N; i++){ Vout[i] = Y[i]; sumtot = modadd( sumtot, Y[i]); }
666 // returns sumtot, and copy the vector over to Vout
667 return (sumtot) ;
668}
669
670#if defined(__x86_64__)
671 myuint_t MixMaxRng::mod128(__uint128_t s)
672 {
673 myuint_t s1;
674 s1 = ( ( ((myuint_t)s)&M61 ) + ( ((myuint_t)(s>>64)) * 8 ) + ( ((myuint_t)s) >>BITS) );
675 return MIXMAX_MOD_MERSENNE(s1);
676 }
677 myuint_t MixMaxRng::fmodmulM61(myuint_t cum, myuint_t a, myuint_t b)
678 {
679 __uint128_t temp;
680 temp = (__uint128_t)a*(__uint128_t)b + cum;
681 return mod128(temp);
682 }
683#else // on all other platforms, including 32-bit linux, PPC and PPC64, ARM and all Windows
684 myuint_t MixMaxRng::fmodmulM61(myuint_t cum, myuint_t s, myuint_t a)
685 {
686 const myuint_t MASK32=0xFFFFFFFFULL;
687 myuint_t o,ph,pl,ah,al;
688 o=(s)*a;
689 ph = ((s)>>32);
690 pl = (s) & MASK32;
691 ah = a>>32;
692 al = a & MASK32;
693 o = (o & M61) + ((ph*ah)<<3) + ((ah*pl+al*ph + ((al*pl)>>32))>>29) ;
694 o += cum;
695 o = (o & M61) + ((o>>61));
696 return o;
697 }
698#endif
699
700myuint_t MixMaxRng::modadd(myuint_t foo, myuint_t bar)
701{
702#if defined(__x86_64__) && defined(__GNUC__) && (!defined(__ICC))
703 //#warning Using assembler routine in modadd
704 myuint_t out;
705 /* Assembler trick suggested by Andrzej Gòˆrlich */
706 __asm__ ("addq %2, %0; "
707 "btrq $61, %0; "
708 "adcq $0, %0; "
709 :"=r"(out)
710 :"0"(foo), "r"(bar)
711 );
712 return out;
713#else
714 return MIXMAX_MOD_MERSENNE(foo+bar);
715#endif
716}
717
718void MixMaxRng::print_state() const
719{
720 int j;
721 std::cout << "mixmax state, file version 1.0\n";
722 std::cout << "N=" << rng_get_N() << "; V[N]={";
723 for (j=0; (j< (rng_get_N()-1) ); j++) {
724 std::cout << S.V[j] << ", ";
725 }
726 std::cout << S.V[rng_get_N()-1];
727 std::cout << "}; ";
728 std::cout << "counter= " << S.counter;
729 std::cout << "sumtot= " << S.sumtot << "\n";
730}
731
732MixMaxRng MixMaxRng::Branch()
733{
734 S.sumtot = iterate_raw_vec(S.V.data(), S.sumtot); S.counter = 1;
735 MixMaxRng tmp=*this;
736 tmp.BranchInplace(0); // daughter id
737 return tmp;
738}
739
740void MixMaxRng::BranchInplace(int id)
741{
742 // Dont forget to iterate the mother, when branching the daughter, or else will have collisions!
743 // a 64-bit LCG from Knuth line 26, is used to mangle a vector component
744 constexpr myuint_t MULT64=6364136223846793005ULL;
745 myuint_t tmp=S.V[id];
746 S.V[1] *= MULT64; S.V[id] &= M61;
747 S.sumtot = MIXMAX_MOD_MERSENNE( S.sumtot + S.V[id] - tmp + M61);
748 S.sumtot = iterate_raw_vec(S.V.data(), S.sumtot);// printf("iterating!\n");
749 S.counter = 1;
750}
751
752} // namespace CLHEP
const unsigned long MASK32
Definition: MixMaxRng.cc:45
#define MIXMAX_MOD_MERSENNE(k)
Definition: MixMaxRng.h:123
#define CLHEP_ATOMIC_INT_TYPE
Definition: atomic_int.h:25
void restoreStatus(const char filename[]="MixMaxRngState.conf")
Definition: MixMaxRng.cc:125
void showStatus() const
Definition: MixMaxRng.cc:205
void flatArray(const int size, double *vect)
Definition: MixMaxRng.cc:327
void setSeed(long seed, int dum=0)
Definition: MixMaxRng.cc:215
static std::string beginTag()
Definition: MixMaxRng.cc:403
void saveStatus(const char filename[]="MixMaxRngState.conf") const
Definition: MixMaxRng.cc:105
virtual std::istream & get(std::istream &is)
Definition: MixMaxRng.cc:385
MixMaxRng & operator=(const MixMaxRng &rng)
Definition: MixMaxRng.cc:88
virtual std::istream & getState(std::istream &is)
Definition: MixMaxRng.cc:408
std::vector< unsigned long > put() const
Definition: MixMaxRng.cc:368
double flat()
Definition: MixMaxRng.h:67
void setSeeds(const long *seeds, int seedNum=0)
Definition: MixMaxRng.cc:226
static std::string engineName()
Definition: MixMaxRng.cc:253
#define double(obj)
Definition: excDblThrow.cc:32
std::uint32_t myID_t
Definition: MixMaxRng.h:48
unsigned long long int myuint_t
Definition: MixMaxRng.h:49