QDP++
qdp_random.cc
Go to the documentation of this file.
1//
2// Random number generator support
3
4
5#include "qdp.h"
6
7namespace QDP {
8
9// Random number generator namespace
10/*
11 * A collection of routines and data for supporting random numbers
12 *
13 * It is a linear congruential with modulus m = 2**47, increment c = 0,
14 * and multiplier a = (2**36)*m3 + (2**24)*m2 + (2**12)*m1 + m0.
15 */
16
17namespace RNG
18{
27
29 int numbits(int x)
30 {
31 int num = 1;
32 int iceiling = 2;
33 while (iceiling <= x)
34 {
35 num++;
36 iceiling *= 2;
37 }
38
39 return num;
40 }
41
42
45 {
47
48 Seed seed = 11;
49 RNG::setrn(seed);
50 }
51
52
54 void initRNG()
55 {
56
57 int old_profile_level = setProfileLevel(0);
58
59 /* Multiplier used. Use big integer arithmetic */
60 Seed seed_tmp3;
61 Seed seed_tmp2;
62 Seed seed_tmp1;
63 Seed seed_tmp0;
64
65 seed_tmp3 = 1222;
66 seed_tmp2 = (seed_tmp3 << 12) | 1498;
67 seed_tmp1 = (seed_tmp2 << 12) | 712;
68 seed_tmp0 = (seed_tmp1 << 12) | 1645;
69
70 ran_mult = seed_tmp0;
71
72 // Find the number of bits it takes to represent the total lattice volume.
73 // NOTE: there are no lattice size restrictions here.
74 int nbits = numbits(Layout::vol());
75
76 /* Get the lattice coordinate of each site (note the origin is 0) and
77 * build up a lexicographic ordering for the lattice. The definition
78 * here is totally arbitrary and only this routine needs to worry
79 * about it. The lexicographic value of site K is
80 *
81 * lexoc(k) = sum_{i = 1, ndim} x(k,i)*L^i + 1
82 */
83 LatticeInteger lexoc;
85
86 for(int m=Nd-2; m>=0; --m)
87 {
88 lexoc *= Layout::lattSize()[m];
89 lexoc += Layout::latticeCoordinate(m);
90 }
91
92 lexoc += 1;
93
94 /*
95 * Setup single multiplier ( a^1 ) on each site
96 */
97 LatticeSeed laa;
98 laa = ran_mult;
99
100 /*
101 * Calculate the multiplier a^n where n = lexicographic numbering of the site.
102 * Put one into each an_f, then multiply them by a^(2^i) under the context
103 * flag where i is the bit number of the lexicographic numbering.
104 * In other words, the very first site is multiplied by a.
105 */
106 LatticeSeed lattice_ran_mult_tmp;
107
108 lattice_ran_mult_tmp = 1;
109
110 LatticeSeed laamult;
111 LatticeBoolean lbit;
112
113 for(int i=0; i<nbits; ++i)
114 {
115 lbit = (lexoc & 1) > 0;
116
117 laamult = lattice_ran_mult_tmp * laa;
118 copymask(lattice_ran_mult_tmp,lbit,laamult);
119
120 lexoc >>= 1;
121 laamult = laa * laa;
122 laa = laamult;
123 }
124
125 // Calculate separately the multiplier for the highest lexicographically ordered site.
126 // NOTE: I'm changing the meaning here slightly, but in an important way.
127 // Technically, ran_mult_n = ran_mult^{vol} . Instead, I'm going to throw
128 // away an rng call after every lattice call. So, I will DEFINE
129 //
130 // ran_mult_n = ran_mult^{vol + 1}
131 //
132 bool bit;
133 Seed aa;
134 Seed aamult;
135
136 int ibit = Layout::vol();
137 aa = ran_mult;
138// ran_mult_n = 1; // produces def ran_mult_n = ran_mult^{vol}
139 ran_mult_n = ran_mult; // produces def ran_mult_n = ran_mult^{vol+1}
140
141 for(int i=0; i<nbits; ++i)
142 {
143 bit = (ibit & 1) > 0;
144
145 aamult = ran_mult_n * aa;
146 if (bit)
147 ran_mult_n = aamult;
148
149 ibit >>= 1;
150 aamult = aa * aa;
151 aa = aamult;
152 }
153
155 if( lattice_ran_mult == 0x0 ) {
156 QDP_error_exit("Unable to allocate ran_mult\n");
157 }
158
159 *lattice_ran_mult = lattice_ran_mult_tmp;
160
161 QDPIO::cout << "Finished init of RNG" << std::endl;
162
163 setProfileLevel(old_profile_level);
164
165
166 }
167
168
170 {
172 delete lattice_ran_mult;
173 }
174
175
177 void setrn(const Seed& seed)
178 {
179 ran_seed = seed;
180 }
181
182
184 void savern(Seed& seed)
185 {
186 seed = ran_seed;
187 }
188
189
191
195 float sranf(Seed& seed, Seed& skewed_seed, const Seed& seed_mult)
196 {
197 /* Calculate the random number and update the seed according to the
198 * following algorithm
199 *
200 * FILL(twom11,TWOM11);
201 * FILL(twom12,TWOM12);
202 * i3 = ran_seed(3)*ran_mult(0) + ran_seed(2)*ran_mult(1)
203 * + ran_seed(1)*ran_mult(2) + ran_seed(0)*ran_mult(3);
204 * i2 = ran_seed(2)*ran_mult(0) + ran_seed(1)*ran_mult(1)
205 * + ran_seed(0)*ran_mult(2);
206 * i1 = ran_seed(1)*ran_mult(0) + ran_seed(0)*ran_mult(1);
207 * i0 = ran_seed(0)*ran_mult(0);
208 *
209 * ran_seed(0) = mod(i0, 4096);
210 * i1 = i1 + i0/4096;
211 * ran_seed(1) = mod(i1, 4096);
212 * i2 = i2 + i1/4096;
213 * ran_seed(2) = mod(i2, 4096);
214 * ran_seed(3) = mod(i3 + i2/4096, 2048);
215 *
216 * sranf = twom11*(TO_REAL32(VALUE(ran_seed(3)))
217 * + twom12*(TO_REAL32(VALUE(ran_seed(2)))
218 * + twom12*(TO_REAL32(VALUE(ran_seed(1)))
219 * + twom12*(TO_REAL32(VALUE(ran_seed(0)))))));
220 */
221 Real _sranf;
222 float _ssranf;
223 Seed ran_tmp;
224
225 _sranf = seedToFloat(skewed_seed);
226 cast_rep(_ssranf, _sranf);
227
228 ran_tmp = seed * seed_mult;
229 seed = ran_tmp;
230
231 ran_tmp = skewed_seed * seed_mult;
232 skewed_seed = ran_tmp;
233
234 return _ssranf;
235 }
236
237
239
243 void sranf(float* d, int N, Seed& seed, ILatticeSeed& skewed_seed, const Seed& seed_mult)
244 {
245 /* Calculate the random number and update the seed according to the
246 * following algorithm
247 *
248 * FILL(twom11,TWOM11);
249 * FILL(twom12,TWOM12);
250 * i3 = ran_seed(3)*ran_mult(0) + ran_seed(2)*ran_mult(1)
251 * + ran_seed(1)*ran_mult(2) + ran_seed(0)*ran_mult(3);
252 * i2 = ran_seed(2)*ran_mult(0) + ran_seed(1)*ran_mult(1)
253 * + ran_seed(0)*ran_mult(2);
254 * i1 = ran_seed(1)*ran_mult(0) + ran_seed(0)*ran_mult(1);
255 * i0 = ran_seed(0)*ran_mult(0);
256 *
257 * ran_seed(0) = mod(i0, 4096);
258 * i1 = i1 + i0/4096;
259 * ran_seed(1) = mod(i1, 4096);
260 * i2 = i2 + i1/4096;
261 * ran_seed(2) = mod(i2, 4096);
262 * ran_seed(3) = mod(i3 + i2/4096, 2048);
263 *
264 * sranf = twom11*(TO_REAL32(VALUE(ran_seed(3)))
265 * + twom12*(TO_REAL32(VALUE(ran_seed(2)))
266 * + twom12*(TO_REAL32(VALUE(ran_seed(1)))
267 * + twom12*(TO_REAL32(VALUE(ran_seed(0)))))));
268 */
269 ILatticeReal _sranf;
270 Seed ran_tmp1;
271 ILatticeSeed ran_tmp2;
272
273 _sranf = seedToFloat(skewed_seed);
274 for(int i=0; i < N; ++i)
275 {
276 cast_rep(d[i], getSite(_sranf,i));
277 }
278
279 ran_tmp1 = seed * seed_mult;
280 seed = ran_tmp1;
281
282 ran_tmp2 = skewed_seed * seed_mult;
283 skewed_seed = ran_tmp2;
284 }
285
286};
287
288} // namespace QDP;
Seed ILatticeSeed
OScalar< PScalar< PScalar< RScalar< REAL > > > > Real
OLattice< PScalar< PSeed< RScalar< INTEGER32 > > > > LatticeSeed
Real ILatticeReal
OScalar< PScalar< PSeed< RScalar< INTEGER32 > > > > Seed
OLattice< PScalar< PScalar< RScalar< INTEGER32 > > > > LatticeInteger
OLattice< PScalar< PScalar< RScalar< LOGICAL > > > > LatticeBoolean
void copymask(IScalar< T > &d, const IScalar< T1 > &mask, const IScalar< T > &s1)
dest = (mask) ? s1 : dest
Definition qdp_inner.h:1656
void cast_rep(T &d, const IScalar< T1 > &s1)
dest [float type] = source [int type]
Definition qdp_inner.h:1664
UnaryReturn< IScalar< T >, FnGetSite >::Type_t getSite(const IScalar< T > &s1, int innersite)
Definition qdp_inner.h:1605
const int Nd
Definition qdp_params.h:24
const multi1d< int > & lattSize()
Virtual grid (problem grid) lattice size.
LatticeInteger latticeCoordinate(int mu)
coord[mu] <- mu : fill with lattice coord in mu direction
int vol()
Total lattice volume.
StandardOutputStream cout
Definition qdp_stdio.cc:21
Random number generator namespace.
Definition qdp_random.cc:18
float sranf(Seed &seed, Seed &skewed_seed, const Seed &seed_mult)
Scalar random number generator. Done on the front end. *‍/.
Seed ran_mult_n
RNG multiplier raised to the volume+1.
Definition qdp_random.cc:24
int numbits(int x)
Find the number of bits required to represent x.
Definition qdp_random.cc:29
void savern(Seed &seed)
Return a copy of the random number seed.
Seed ran_mult
RNG multiplier.
Definition qdp_random.cc:22
void initDefaultRNG()
Initialize the random number generator with a default seed.
Definition qdp_random.cc:44
LatticeSeed * lattice_ran_mult
The lattice of skewed RNG multipliers.
Definition qdp_random.cc:26
void initRNG()
Initialize the internals of the random number generator.
Definition qdp_random.cc:54
void setrn(const Seed &seed)
Initialize the random number generator seed.
Seed ran_seed
Global (current) seed.
Definition qdp_random.cc:20
void finalizeRNG()
Yet another random number generator.
MakeReturn< UnaryNode< FnSeedToFloat, typenameCreateLeaf< QDPExpr< T1, C1 > >::Leaf_t >, typenameUnaryReturn< C1, FnSeedToFloat >::Type_t >::Expression_t seedToFloat(const QDPExpr< T1, C1 > &l)
Definition qdp.h:5037
void QDP_error_exit(const char *format,...)
Simple error display and abort routine.
Definition qdp_util.cc:93
int setProfileLevel(int n)
Primary include file for QDP.