1 /*
2 *========================================================================
3 * See copyright in copyright.h and the accompanying file COPYING
4 *========================================================================
5 */
6
7 /*
8 *========================================================================
9 * This routine does all the required initialization and choose_rng,
10 * including memory allocation and prefilling of vectors. It is
11 * COMPLETELY outside the timing loops.
12 *========================================================================
13 */
14
15 #include "dieharder.h"
16
17 int select_rng(int gennum,char *genname,unsigned int initial_seed);
18
choose_rng()19 void choose_rng()
20 {
21
22 /*
23 * The way CLI dieharder seeding works is: a) If Seed is set (e.g.
24 * dieharder -S 1... ) then its value will be used to reseed the
25 * selected rng at the BEGINNING of each test, or test series for tests
26 * such as rgb_bitdist that work their way through a set of ntuples. If
27 * Seed is set for file-based random number generators, it forces a
28 * rewind at the beginning of the tests (which should have no effect on
29 * stdin-piped streams).
30 *
31 * Note that using the same seed for all the tests isn't that great from
32 * a testing point of view; it is primarily useful for validation runs or
33 * to conserve a limited supply of rands from a file by running different
34 * tests on the one set of rands.
35 *
36 * b) If Seed is NOT set (is equal to 0) then the selected rng is seeded
37 * one time using the reseed() function, which in turn uses e.g.
38 * /dev/random if available or the clock if it is not to generate a
39 * unique, moderately unpredictable seed. The generator will NOT be
40 * reseeded (or rewound) if more than one test is run on it, and distinct
41 * test results or assessments can be thought of as being drawn as iid
42 * samples.
43 *
44 * Note that results from different tests are likely to be CORRELATED if
45 * the same seed is used for each test -- a test with a surplus of some
46 * bit pattern -- say 000 -- will also have skewed distributions of all
47 * the larger patterns that contain 000.
48 */
49
50 /*
51 * select_rng() returns -1 if it cannot find the desired generator
52 * or encounters any other problem. In the CLI, this means that
53 * we must complain, list the available rngs, and exit. In an
54 * interactive UI, I imagine that one would get an error message
55 * and a chance to try again.
56 *
57 * MUST FIX THIS for the new combo multigenerator. All broken. At least
58 * this should force the output of generator names as usual, though.
59 */
60 if(select_rng(generator,generator_name,Seed) < 0){
61 list_rngs();
62 Exit(0);
63 }
64
65 /*
66 * This may or may not belong here. We may move it somewhere else
67 * if it needs to go. But it should WORK here, at least for the moment.
68 */
69 if(output_file){
70 output_rnds();
71 Exit(0);
72 }
73
74
75 }
76
77
78 /*
79 * ========================================================================
80 * select_rng()
81 *
82 * This code can be executed by either the CLI
83 * dieharder or rdieharder to select a generator based on EITHER generator
84 * name (via a brute force search) OR generator number. Number is more
85 * convenient for automation and obviously faster, name is perhaps easier
86 * to remember. Note that it produces NO OUTPUT under normal operation
87 * and returns -1 if it cannot find the generator however it was entered;
88 * it is the responsibility of the UI to handle the error and warn the
89 * user.
90 *
91 * The way it works is it checks name FIRST and if not null, it uses the
92 * name it finds. Otherwise it tries to use the number, where gennum=0
93 * actually corresponds to a generator. It does very minimal bounds
94 * checking and will just return -1 if it falls through without finding
95 * a generator corresponding to its arguments.
96 * ========================================================================
97 */
98
select_rng(int gennum,char * genname,unsigned int initial_seed)99 int select_rng(int gennum,char *genname,unsigned int initial_seed)
100 {
101
102 int i;
103
104 /*
105 * REALLY out of bounds we can just test for and return an error.
106 */
107 if((int) gnumbs[0] < 0 || (int) gnumbs[0] >= MAXRNGS){
108 return(-1);
109 }
110
111 /*
112 * We are FINALLY ready, I think, to implement the super/vector generator
113 * as soon as we get the talk all together and ready to go...
114 * (start here)
115 * See if a gennum name has been set (genname not null). If
116 * so, loop through all the gennums in dh_rng_types looking for a
117 * match and return a hit if there is one. Note that this
118 * routine just sets gennum and passes a (presumed valid)
119 * gennum on for further processing, hence it has to be first.
120 */
121 if(gnames[0][0] != 0){
122 gennum = -1;
123 for(i=0;i<1000;i++){
124 if(dh_rng_types[i]){
125 if(strncmp(dh_rng_types[i]->name,gnames[0],20) == 0){
126 gennum = i;
127 break;
128 }
129 }
130 }
131 if(gennum == -1) return(-1);
132 } else if(dh_rng_types[gnumbs[0]] != 0){
133 /*
134 * If we get here, then we are entering a gennum type by number.
135 * We check to be sure there is a gennum with the given
136 * number that CAN be used and return an error if there isn't.
137 */
138 gennum = gnumbs[0];
139 if(dh_rng_types[gennum]->name[0] == 0){
140 /*
141 * No generator with this name.
142 */
143 return(-1);
144 }
145 } else {
146 /*
147 * Couldn't find a generator at all. Should really never get here.
148 */
149 return(-1);
150 }
151
152 /*
153 * We need a sanity check for file input. File input is permitted
154 * iff we have a file name, if the output flag is not set, AND if
155 * gennum is either file_input or file_input_raw. Otherwise
156 * IF gennum is a file input type (primary condition) we punt.
157 *
158 * For the moment we actually return an error message, but we may
159 * want to pass the message back in a shared error buffer that
160 * rdh can pick up or ignore, ditto dh, on a -1 return.
161 */
162 if(strncmp("file_input",dh_rng_types[gennum]->name,10) == 0){
163 if(fromfile != 1){
164 fprintf(stderr,"Error: gennum %s uses file input but no filename has been specified",dh_rng_types[gennum]->name);
165 return(-1);
166 }
167 }
168
169 /*
170 * If we get here, in principle the gennum is valid and the right
171 * inputs are defined to run it (in the case of file_input). We therefore
172 * allocate the selected rng. However, we FIRST check to see if rng is
173 * not 0, and if it isn't 0 we assume that we're in a UI, that the user
174 * has just changed rngs, and that we need to free the previous rng and
175 * reset the bits buffers so they are empty.
176 */
177 if(rng){
178 MYDEBUG(D_SEED){
179 fprintf(stdout,"# choose_rng(): freeing old gennum %s\n",gsl_rng_name(rng));
180 }
181 gsl_rng_free(rng);
182 reset_bit_buffers();
183 }
184
185 /*
186 * We should now be "certain" that it is safe to allocate a new gennum
187 * without leaking memory.
188 */
189 MYDEBUG(D_SEED){
190 fprintf(stdout,"# choose_rng(): Creating and seeding gennum %s\n",dh_rng_types[gennum]->name);
191 }
192 rng = gsl_rng_alloc(dh_rng_types[gennum]);
193
194 /*
195 * OK, here's the deal on seeds. If strategy = 0, we set the seed
196 * ONE TIME right HERE to either a randomly selected seed or whatever
197 * has been entered for Seed, if nonzero.
198 *
199 * If strategy is not 0 (1 is fine) then no matter what we do below,
200 * we will RESET the seed to either a NEW random seed or the value of
201 * Seed at the beginning of each test.
202 *
203 * The default behavior for actual testing should obviously be
204 * -s(trategy)=0 or 1 and -S(eed)=0, a random seed from /dev/random
205 * used for the whole test or reseeded per test (with a new seed each
206 * time). -S(eed)=anything else can be used to fix a seed/strategy to
207 * match a previous run to reproduce it, or it can be used to set a seed
208 * to be used for each test individually, probably for a validation (of
209 * the test, not the rng) run. DO NOT USE THE LATTER FOR TESTING! The
210 * pvalues generated by test SERIES that e.g test ntuples over a range
211 * are obviously not independent if they all are started with the same
212 * seed (and hence test largely the same series).
213 *
214 * Regardless, the CURRENT seed is stored in the global seed variable,
215 * which we may need to move from libdieharder to the UI as I don't think
216 * we'll need to share a seed variable with any test.
217 *
218 * Note that for file input (not stdin) "reseed per test" is interpreted
219 * as "rewind per test". Otherwise dieharder will rewind the file (and
220 * complain) only if one hits EOF before all testing is done, and usually
221 * that means that at least the test where the rewind occurs is useless.
222 */
223
224 /*
225 * We really don't need to worry about the value of strategy here, just
226 * Seed. If it is is 0 we reseed randomly, otherwise we PROceed. We
227 * actually seed from the variable seed, not Seed (which then remembers
228 * the value as long as it remains valid).
229 */
230 if(Seed == 0){
231 seed = random_seed();
232 MYDEBUG(D_SEED){
233 fprintf(stdout,"# choose_rng(): Generating random seed %lu\n",seed);
234 }
235 } else {
236 seed = Seed;
237 MYDEBUG(D_SEED){
238 fprintf(stdout,"# choose_rng(): Setting fixed seed %lu\n",seed);
239 }
240 }
241
242 /*
243 * Set the seed. We do this here just so it is set for the timing
244 * test. It may or may not ever be reset.
245 */
246 gsl_rng_set(rng,seed);
247
248 /*
249 * Here we evaluate the speed of the generator if the rate flag is set.
250 */
251 if(tflag & TRATE){
252 time_rng();
253 }
254
255 /*
256 * Before we quit, we must count the number of significant bits in the
257 * selected rng AND create a mask. Note that several routines in bits
258 * WILL NOT WORK unless this is all set correctly, which actually
259 * complicates things because I stupidly didn't make this data into
260 * components of the rng object (difficult to do given that the latter is
261 * actually already defined in the GSL, admittedly).
262 */
263 random_max = gsl_rng_max(rng);
264 rmax = random_max;
265 rmax_bits = 0;
266 rmax_mask = 0;
267 while(rmax){
268 rmax >>= 1;
269 rmax_mask = rmax_mask << 1;
270 rmax_mask++;
271 rmax_bits++;
272 }
273
274 /*
275 * If we get here, we are all happy, and return false (no error).
276 */
277 return(0);
278
279 }
280
281
282 /*
283 * ========================================================================
284 * select_XOR()
285 *
286 * It is our profound wish to leave the code above mostly unmolested as we
287 * add the "special" XOR supergenerator. We therefore make this a
288 * separate routine altogether and add a call to this on a simple
289 * conditional up above.
290 * ========================================================================
291 */
292
select_XOR()293 int select_XOR()
294 {
295
296 int i,j;
297 int one_file;
298
299 /*
300 * See if a gennum name has been set (genname not null). If
301 * so, loop through all the gennums in dh_rng_types looking for a
302 * match and return a hit if there is one. Note that this
303 * routine just sets gennum and passes a (presumed valid)
304 * gennum on for further processing, hence it has to be first.
305 */
306 for(j = 0;j < gvcount;j++){
307 if(gnames[j][0] != 0){
308 gnumbs[j] = -1;
309 for(i=0;i<1000;i++){
310 if(dh_rng_types[i]){
311 if(strncmp(dh_rng_types[i]->name,gnames[j],20) == 0){
312 gnumbs[j] = i;
313 break;
314 }
315 }
316 }
317 if(gnumbs[j] == -1) return(-1);
318 }
319
320 }
321
322 /*
323 * If we get here, then gnumbs[j] contains only numbers. We check to be
324 * sure all the values are valid and the number CAN be used and
325 * return an error if any of them can't.
326 */
327 one_file = 0;
328 for(j = 0;j < gvcount;j++){
329
330 if(dh_rng_types[gnumbs[j]] == 0){
331 return(-1);
332 }
333
334 /*
335 * We need a sanity check for file input. File input is permitted
336 * iff we have a file name AND if gnumbs[j] is either file_input or
337 * file_input_raw.
338 */
339 if(strncmp("file_input",dh_rng_types[gnumbs[j]]->name,10) == 0){
340 one_file++;
341 if(fromfile != 1 || one_file > 1){
342 fprintf(stderr,"Error: generator %s uses file input but no filename has been specified",dh_rng_types[gnumbs[j]]->name);
343 return(-1);
344 }
345 }
346
347 }
348
349 /*
350 * If we get here, in principle the gnumbs vector is filled with valid
351 * rngs and the right inputs are defined to run them (in the case of a
352 * SINGLE file_input). We therefore allocate the selected rng. However,
353 * we FIRST check to see if rng is not 0, and if it isn't 0 we assume
354 * that we're in a UI, that the user has just changed rngs, and that we
355 * need to free the previous rng and reset the bits buffers so they are
356 * empty.
357 */
358 if(rng){
359 MYDEBUG(D_SEED){
360 fprintf(stdout,"# choose_rng(): freeing old gennum %s\n",gsl_rng_name(rng));
361 }
362 gsl_rng_free(rng);
363 reset_bit_buffers();
364 }
365
366 /*
367 * We should now be "certain" that it is safe to allocate the XOR rng
368 * without leaking memory and with a list of legitimate rngs.
369 */
370 MYDEBUG(D_SEED){
371 }
372 for(j = 0;j < gvcount;j++){
373 fprintf(stdout,"# choose_XOR(): generator[%i] = %s\n",j,dh_rng_types[gnumbs[j]]->name);
374 }
375 /*
376 * Change 14 to the actual number
377 */
378 rng = gsl_rng_alloc(dh_rng_types[14]);
379
380 /*
381 * OK, here's the deal on seeds. If strategy = 0, we set the seed
382 * ONE TIME right HERE to either a randomly selected seed or whatever
383 * has been entered for Seed, if nonzero.
384 *
385 * If strategy is not 0 (1 is fine) then no matter what we do below,
386 * we will RESET the seed to either a NEW random seed or the value of
387 * Seed at the beginning of each test.
388 *
389 * The default behavior for actual testing should obviously be
390 * -s(trategy)=0 or 1 and -S(eed)=0, a random seed from /dev/random
391 * used for the whole test or reseeded per test (with a new seed each
392 * time). -S(eed)=anything else can be used to fix a seed/strategy to
393 * match a previous run to reproduce it, or it can be used to set a seed
394 * to be used for each test individually, probably for a validation (of
395 * the test, not the rng) run. DO NOT USE THE LATTER FOR TESTING! The
396 * pvalues generated by test SERIES that e.g test ntuples over a range
397 * are obviously not independent if they all are started with the same
398 * seed (and hence test largely the same series).
399 *
400 * Regardless, the CURRENT seed is stored in the global seed variable,
401 * which we may need to move from libdieharder to the UI as I don't think
402 * we'll need to share a seed variable with any test.
403 *
404 * Note that for file input (not stdin) "reseed per test" is interpreted
405 * as "rewind per test". Otherwise dieharder will rewind the file (and
406 * complain) only if one hits EOF before all testing is done, and usually
407 * that means that at least the test where the rewind occurs is useless.
408 */
409
410 /*
411 * We really don't need to worry about the value of strategy here, just
412 * Seed. If it is is 0 we reseed randomly, otherwise we PROceed. We
413 * actually seed from the variable seed, not Seed (which then remembers
414 * the value as long as it remains valid).
415 */
416 if(Seed == 0){
417 seed = random_seed();
418 MYDEBUG(D_SEED){
419 fprintf(stdout,"# choose_rng(): Generating random seed %lu\n",seed);
420 }
421 } else {
422 seed = Seed;
423 MYDEBUG(D_SEED){
424 fprintf(stdout,"# choose_rng(): Setting fixed seed %lu\n",seed);
425 }
426 }
427
428 /*
429 * Set the seed. We do this here just so it is set for the timing
430 * test. It may or may not ever be reset.
431 */
432 gsl_rng_set(rng,seed);
433
434 /*
435 * Here we evaluate the speed of the generator if the rate flag is set.
436 */
437 if(tflag & TRATE){
438 time_rng();
439 }
440
441 /*
442 * We don't really need this anymore, I don't think. But we'll leave it
443 * for now.
444 */
445 random_max = gsl_rng_max(rng);
446 rmax = random_max;
447 rmax_bits = 0;
448 rmax_mask = 0;
449 while(rmax){
450 rmax >>= 1;
451 rmax_mask = rmax_mask << 1;
452 rmax_mask++;
453 rmax_bits++;
454 }
455
456 /*
457 * If we get here, we are all happy, and return false (no error).
458 */
459 return(0);
460
461 }
462