Geant4  10.02.p03
mixmax.h
Go to the documentation of this file.
1 // $Id:$
2 // -*- C++ -*-
3 //
4 // -----------------------------------------------------------------------
5 // MixMax Matrix PseudoRandom Number Generator
6 // --- MixMax ---
7 // class header file
8 // -----------------------------------------------------------------------
9 //
10 //
11 // Created by Konstantin Savvidy on Sun Feb 22 2004.
12 // The code is released under
13 // GNU Lesser General Public License v3
14 //
15 // Generator described in
16 // N.Z.Akopov, G.K.Savvidy and N.G.Ter-Arutyunian, Matrix Generator of Pseudorandom Numbers,
17 // J.Comput.Phys. 97, 573 (1991);
18 // Preprint EPI-867(18)-86, Yerevan Jun.1986;
19 //
20 // and
21 //
22 // K.Savvidy
23 // The MIXMAX random number generator
24 // Comp. Phys. Commun. (2015)
25 // http://dx.doi.org/10.1016/j.cpc.2015.06.003
26 //
27 // -----------------------------------------------------------------------
28 
29 #ifndef CLHEP_MIXMAX_H_
30 #define CLHEP_MIXMAX_H_ 1
31 
32 #include <stdio.h>
33 #include <stdint.h>
34 
35 #define USE_INLINE_ASM YES
36 
37 namespace CLHEP {
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 const int N = 256;
44 /* The currently recommended N are 3150, 1260, 508, 256, 240, 88
45  Since the algorithm is linear in N, the cost per number is almost independent of N.
46  */
47 
48 #ifndef __LP64__
49 typedef uint64_t myuint;
50 //#warning but no problem, 'myuint' is 'uint64_t'
51 #else
52 typedef unsigned long long int myuint;
53 //#warning but no problem, 'myuint' is 'unsigned long long int'
54 #endif
55 
57 {
58  myuint V[N];
59  myuint sumtot;
60  int counter;
61  FILE* fh;
62 };
63 
64 typedef struct rng_state_st rng_state_t; // C struct alias
65 
66 int rng_get_N(void); // get the N programmatically, useful for checking the value for which the library was compiled
67 
68 rng_state_t *rng_alloc(); /* allocate the state */
69 int rng_free(rng_state_t* X); /* free memory occupied by the state */
70 rng_state_t *rng_copy(myuint *Y); /* init from vector, takes the vector Y,
71  returns pointer to the newly allocated and initialized state */
72 void read_state(rng_state_t* X, const char filename[] );
74  int iterate(rng_state_t* X);
75  myuint iterate_raw_vec(myuint* Y, myuint sumtotOld);
76 
77 
78 // FUNCTIONS FOR SEEDING
79 
80 typedef uint32_t myID_t;
81 
82 void seed_uniquestream(rng_state_t* X, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID );
83 /*
84  best choice: will make a state vector from which you can get at least 10^100 numbers
85  guaranteed mathematically to be non-colliding with any other stream prepared from another set of 32bit IDs,
86  so long as it is different by at least one bit in at least one of the four IDs
87  -- useful if you are running a parallel simulation with many clusters, many CPUs each
88  */
89 
90 void seed_spbox(rng_state_t* X, myuint seed); // non-linear method, makes certified unique vectors, probability for streams to collide is < 1/10^4600
91 
92 void seed_vielbein(rng_state_t* X, unsigned int i); // seeds with the i-th unit vector, i = 0..N-1, for testing only
93 
94 
95 
96 // FUNCTIONS FOR GETTING RANDOM NUMBERS
97 
98 #ifdef __MIXMAX_C
99  myuint get_next(rng_state_t* X); // returns 64-bit int, which is between 1 and 2^61-1 inclusive
100  double get_next_float(rng_state_t* X); // returns double precision floating point number in (0,1]
101 #endif //__MIXMAX_C
102 
103 void fill_array(rng_state_t* X, unsigned int n, double *array); // fastest method: set n to a multiple of N (e.g. n=256)
104 
105 void iterate_and_fill_array(rng_state_t* X, double *array); // fills the array with N numbers
106 
107 myuint precalc(rng_state_t* X);
108 /* needed if the state has been changed by something other than iterate, but no worries, seeding functions call this for you when necessary */
109 myuint apply_bigskip(myuint* Vout, myuint* Vin, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID );
110 // applies a skip of some number of steps calculated from the four IDs
111 void branch_inplace( rng_state_t* Xin, myID_t* ID ); // almost the same as apply_bigskip, but in-place and from a vector of IDs
112 
113 
114 #define BITS 61
115 
116 /* magic with Mersenne Numbers */
117 
118 #define M61 2305843009213693951ULL
119 
120  myuint modadd(myuint foo, myuint bar);
121  myuint modmulM61(myuint s, myuint a);
122  myuint fmodmulM61(myuint cum, myuint s, myuint a);
123 
124 #define MERSBASE M61 //xSUFF(M61)
125 #define MOD_PAYNE(k) ((((k)) & MERSBASE) + (((k)) >> BITS) ) // slightly faster than my old way, ok for addition
126 #define MOD_REM(k) ((k) % MERSBASE ) // latest Intel CPU is supposed to do this in one CPU cycle, but on my machines it seems to be 20% slower than the best tricks
127 #define MOD_MERSENNE(k) MOD_PAYNE(k)
128 
129 #define INV_MERSBASE (0.43368086899420177360298E-18L)
130 
131 
132 // the charpoly is irreducible for the combinations of N and SPECIAL and has maximal period for N=508, 256, half period for 1260, and 1/12 period for 3150
133 
134 // #if (N==256)
135 #define SPECIALMUL 0
136 #define SPECIAL 487013230256099064ULL // s=487013230256099064, m=1 -- good old MIXMAX
137 #define MOD_MULSPEC(k) fmodmulM61( 0, SPECIAL , (k) );
138 /*
139 #elif (N==17)
140 #define SPECIALMUL 36 // m=2^37+1
141 
142 #elif (N==8)
143 #define SPECIALMUL 53 // m=2^53+1
144 
145 #elif (N==40)
146 #define SPECIALMUL 42 // m=2^42+1
147 
148 #elif (N==96)
149 #define SPECIALMUL 55 // m=2^55+1
150 
151 #elif (N==64)
152 #define SPECIALMUL 55 // m=2^55 (!!!) and m=2^37+2
153 
154 #elif (N==120)
155 #define SPECIALMUL 51 // m=2^51+1 and a SPECIAL=+1 (!!!)
156 #define SPECIAL 1
157 #define MOD_MULSPEC(k) (k);
158 
159 #else
160 #warning Not a verified N, you are on your own!
161 #define SPECIALMUL 58
162 
163 #endif // list of interesting N for modulus M61 ends here
164 */
165 
166 #ifndef __MIXMAX_C // c++ can put code into header files, why cant we? (with the inline declaration, should be safe from duplicate-symbol error)
167 
168 #define get_next(X) GET_BY_MACRO(X)
169 #define get_next_float(X) get_next_float_BY_MACRO(X)
170 
171 #endif // __MIXMAX_C
172 
173 inline myuint GET_BY_MACRO(rng_state_t* X) {
174  int i;
175  i=X->counter;
176 
177  if (i<=(N-1) ){
178  X->counter++;
179  return X->V[i];
180  }else{
181  X->sumtot = iterate_raw_vec(X->V, X->sumtot);
182  X->counter=2;
183  return X->V[1];
184  }
185 }
186 
187 
189  int64_t Z=(int64_t)get_next(X);
190 #if defined(__x86_64__) && defined(__SSE__) && defined(__AVX__) && defined(USE_INLINE_ASM)
191  double F;
192  __asm__ __volatile__( "pxor %0, %0;"
193  //"cvtsi2sdq %1, %0;"
194  :"=x"(F)
195  //:"r"(Z)
196  );
197  F=Z;
198  return F*INV_MERSBASE;
199 #else
200  return Z*INV_MERSBASE;
201 #endif
202  }
203 
204 
205 
206 // ERROR CODES - exit() is called with these
207 #define ARRAY_INDEX_OUT_OF_BOUNDS 0xFF01
208 #define SEED_WAS_ZERO 0xFF02
209 #define ERROR_READING_STATE_FILE 0xFF03
210 #define ERROR_READING_STATE_COUNTER 0xFF04
211 #define ERROR_READING_STATE_CHECKSUM 0xFF05
212 
213 #ifdef __cplusplus
214 }
215 #endif
216 
217 //#define HOOKUP_GSL 1
218 
219 #ifdef HOOKUP_GSL // if you need to use mixmax through GSL, pass -DHOOKUP_GSL=1 to the compiler
220 
221 #include <gsl/gsl_rng.h>
222 unsigned long gsl_get_next(void *vstate);
223 double gsl_get_next_float(void *vstate);
224 void seed_for_gsl(void *vstate, unsigned long seed);
225 
226 static const gsl_rng_type mixmax_type =
227 {"MIXMAX", /* name */
228  MERSBASE, /* RAND_MAX */
229  1, /* RAND_MIN */
230  sizeof (rng_state_t),
231  &seed_for_gsl,
232  &gsl_get_next,
233  &gsl_get_next_float
234 };
235 
236 unsigned long gsl_get_next(void *vstate) {
237  rng_state_t* X= (rng_state_t*)vstate;
238  return (unsigned long)get_next(X);
239 }
240 
241 double gsl_get_next_float(void *vstate) {
242  rng_state_t* X= (rng_state_t*)vstate;
243  return ( (double)get_next(X)) * INV_MERSBASE;
244 }
245 
246 void seed_for_gsl(void *vstate, unsigned long seed){
247  rng_state_t* X= (rng_state_t*)vstate;
248  seed_spbox(X,(myuint)seed);
249 }
250 
251 const gsl_rng_type *gsl_rng_ran3 = &mixmax_type;
252 
253 
254 #endif // HOOKUP_GSL
255 
256 } // namespace CLHEP
257 
258 #endif // closing CLHEP_MIXMAX_H_
const int N
Definition: mixmax.h:43
void print_state(rng_state_t *X)
Definition: mixmax.cc:270
int rng_get_N(void)
Definition: mixmax.cc:237
myuint GET_BY_MACRO(rng_state_t *X)
Definition: mixmax.h:173
myuint get_next(rng_state_t *X)
Definition: mixmax.cc:82
void seed_vielbein(rng_state_t *X, unsigned int i)
Definition: mixmax.cc:185
uint32_t myID_t
Definition: mixmax.h:80
uint64_t myuint
Definition: mixmax.h:49
int rng_free(rng_state_t *X)
Definition: mixmax.cc:159
Float_t Y
myuint fmodmulM61(myuint cum, myuint s, myuint a)
Definition: mixmax.cc:255
void seed_uniquestream(rng_state_t *X, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID)
Definition: mixmax.cc:431
int iterate(rng_state_t *X)
Definition: mixmax.cc:39
Float_t X
myuint V[N]
Definition: mixmax.h:58
Char_t n[5]
void seed_spbox(rng_state_t *X, myuint seed)
Definition: mixmax.cc:202
static const double bar
myuint modmulM61(myuint s, myuint a)
double get_next_float(rng_state_t *X)
Definition: mixmax.cc:86
Float_t Z
rng_state_t * rng_alloc()
Definition: mixmax.cc:151
rng_state_t * rng_copy(myuint *Y)
Definition: mixmax.cc:165
myuint apply_bigskip(myuint *Vout, myuint *Vin, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID)
#define MERSBASE
Definition: mixmax.h:124
myuint iterate_raw_vec(myuint *Y, myuint sumtotOld)
Definition: mixmax.cc:52
void iterate_and_fill_array(rng_state_t *X, double *array)
Definition: mixmax.cc:110
static const double s
void branch_inplace(rng_state_t *Xin, myID_t *ID)
myuint precalc(rng_state_t *X)
Definition: mixmax.cc:225
myuint modadd(myuint foo, myuint bar)
Definition: mixmax.cc:135
void fill_array(rng_state_t *X, unsigned int n, double *array)
Definition: mixmax.cc:90
Definition: DoubConv.h:18
#define INV_MERSBASE
Definition: mixmax.h:129
double get_next_float_BY_MACRO(rng_state_t *X)
Definition: mixmax.h:188
void read_state(rng_state_t *X, const char filename[])
Definition: mixmax.cc:283
struct rng_state_st rng_state_t
Definition: mixmax.h:64