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