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