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:
The set available through GNUSL are:
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.