random.cc

This module abstracts the concept of a random number generator. The base types are:

class random_gen
{
public:
  virtual double rand()=0;
};

class affinerand: public random_gen
{
public:
  double scale, offset;
  affinerand(double s=1, double o=0, random_gen *g=NULL);
  void Set_gen(random_gen*);
  void set_gen(TCL_args args) {Set_gen(args);}
  template <class T> void new_gen(const T&);
  double rand() {return scale*gen->rand()+offset;}
};

random_gen is an abstract base class representing a random number generator. affinerand performs a simple affine transformation on the contained random generator. The random_gen* argument to affine_rand() may be used to set the random generator employed. If NULL (default) is passed for this parameter, a uniform random generator of type urand is created and used. After creation, you can either set the random generator to be something else using Set_gen, or create a new random generator of the same type as the passed argument using new_gen. The set_gen method is callable from TCL, and takes a named random_gen object as an argument. The class's destructor will delete a generator created with newgen, but not delete an object passed by setgen. For example, a normal distribution with mean m and standard deviation s can be obtained with the declaration:

affinerand(s,m).newgen(gaussrand());

The other classes are:

class urand: public random_gen
{
public:
  double rand();
  void Seed(int s);
  void seed(TCL_args args) {Seed(args);}
#if defined(UNURAN) || defined(GNUSL)
  void Set_gen(char *);
  void set_gen(TCL_args args) {Set_gen(args);}
  urand(const char* descr) {Set_gen(descr);}
#endif
};

class gaussrand: public random_gen
{
public:
  urand uni;
  double rand();
};

urand simply returns a uniform random variate in [0,1]. The basic Eco Lab code contains a uniform generator which is simply an interface to the standard library rand() call, and a Gaussian random generator, which is based on the algorithm described in Abramowitz and Stegun (1964) sec. 26.8.6.a(2).

gaussrand returns a normal variate with mean 0 and standard deviation 1. Use gaussrand coupled with affinerand to change the mean and standard deviation:

affinerand gen(2,.5,new gaussrand);
defines a gaussian generator variable gen with standard deviation 2 and mean .5.

As of Eco Lab.4.D7, replacements for these routines using freely available libraries, unuran and GNUSL are available. The Makefile will select the UNURAN library if available, otherwise the GNU Scientific Library will be selected. If neither of these packages are available, the original basic behaviour is selected. Please read the section on problems with the basic random number library.

Both UNURAN and GNUSL provide a text interface to selecting and configuring the uniform random generator. The method Set_gen provides a way passing PRNG parameters to the underlying PRNG generator. By default the Mersenne Twister algorithm is used, which is acknowledged as being one of the most efficient random generator available. The algorithms available through PRNG are:

EICG
explicit inversive congruential generator
ICG
inversive congruential generator
LCG
linear congruential generator
QCG
quadratic congruential generator
MT19937
Mersenne Twister
MEICG
modified explicit inversive congruential generator
DICG
digital inversive congruential generator

The set available through GNUSL are:

mt19937
Mersenne Twister
ranlxs0,ranlxs1,ranlxs2,ranlxd1,ranlxd2
Lüscher's RANLUX at different levels of precision and luxury.
cmrg
combined multiple recursive generator by L'Ecuyer
mrg
fifth-order multiple recursive generator by L'Ecuyer, Blouin and Coutre
taus,taus2
maximally equidistributed combined Tausworthe generator by L'Ecuyer
gfsr4
Four-tap shift-register-sequence random-number generator by Ziff.
Note that only the generator can be selected through the GNUSL string interface -- parameters cannot be set. The GNUSL documentation recommends mt19937, taus or gfsr4 for general purpose simulation. mt19937 is the default.

class distrand: public random_gen
{
public:
  int nsamp;  /* no. of sample points in distribution */
  int width;  /* digits of precision (base 16) used from prob. distribution */
  double min, max;  /* distribution endpoints */
  distrand(): nsamp(10), width(3), min(0), max(1);
  void Init(int argc, char *argv[]);
  void init(double (*f)(double));
  double rand();
};

#ifdef UNURAN
class unuran: public random_gen
{
public:
  urand uni;
  UNUR_RAN *get_gen(); //get pointer to UNUR_RAN object for UNURAN API use
  /* specify a random generator according to unuran's string interface */
  void Set_gen(const char *descr);
  void set_gen(TCL_args args) {Set_gen(args);}
  unuran();
  unuran(const char* descr) {Set_gen(descr);}
  double rand();
};
#endif

distrand returns a deviate from an arbitrary distribution function (which needn't be normalised) supplied to Init (or init). The instance variables nsamp=10, width=3, min=0 and max=1 should be modified before calling init. Init provides a TCL interface -- it takes one argument, the name of a TCL procedure implementing the distribution. This class implements the method due to Marsaglia[4]. The UNURAN and GNUSL libraries provide other, perhaps better routines for doing the same things.

Finally, unuran allows an arbitrary UNURAN generator to be specified using UNURAN's string interface. For example, gaussrand is equivalent to unuran("normal()"). The string interface is powerful and comprehensive, with a large number of predefined distributions and methods provided, and the ability to specify arbitrary distributions. It obviates the need to use distrand, which is a rather obsolete algorithm.

GNUSL does not provide a string interace to its general nonuniform distributions. For the moment, you will need to implement your own object interfaces to which ever routines you want to use. You may use the gaussrand example as a template.



Subsections