## Random Numbers

This page describes the random-number generator in PYTHIA and how it can be replaced by an external one.

### Internal random numbers

The `Rndm` class generates random numbers, using the Marsaglia-Zaman-Tsang algorithm [Mar90].

Random numbers `R` uniformly distributed in `0 < R < 1` are obtained with

```
Rndm::flat();
```
There are also methods to generate according to an exponential, to x * exp(-x), to a Gaussian, or picked among a set of possibilities, which make use of `flat()`.

If the random number generator is not initialized before, it will be so the first time it is asked to generate a random number, and then with the default seed, 19780503. This means that, by default, all runs will use identically the same random number sequence. This is convenient for debugging purposes, but dangerous if you intend to run several "identical" jobs to boost statistics. You can initialize, or reinitialize, with your own choice of seed with a

```
Rndm::init(seed);
```
Here values `0 < seed < 900 000 000` gives so many different random number sequences, while `seed = 0` will call the `Stdlib time(0)` function to provide a "random" `seed`, and `seed < 0` will revert back to the default `seed`.

The `Pythia` class defines a flag and a mode, that allows the `seed` to be set in the `Pythia::init` call. That would be the standard way for a user to pick the random number sequence in a run.

### External random numbers

`RndmEngine` is a base class for the external handling of random-number generation. The user-written derived class is called if a pointer to it has been handed in with the `pythia.rndmEnginePtr()` method. Since the default Marsaglia-Zaman-Tsang algorithm is quite good, chances are that any replacement would be a step down, but this may still be required by consistency with other program elements in big experimental frameworks.

There is only one pure virtual method in `RndmEngine`, to generate one random number flat in the range between 0 and 1:

```
virtual double flat() = 0;
```
Note that methods for initialization are not provided in the base class, in part since input parameters may be specific to the generator used, in part since initialization can as well be taken care of externally to the `Pythia` code.

An example illustrating how to run with an external random number generator is provided in `main23.cc`.

### MIXMAX random numbers

The MIXMAX class of random number generators utilizes matrix-recursion based on Anosov-Kolmogorov C-K systems, with the ability to create a large number of statistically independent sequences of random numbers based on different initial seeds. This is particularly advantageous in creating statistically independent samples when running a large number of parallel jobs, each with a different initial seed. In the plugin header `Pythia8Plugins/MixMax.h` an implementation of a MIXMAX random number generator is provided [Sav91,Sav15], courtesy of Konstantin Savvidy, as well as a PYTHIA interface through the `MixMaxRndm` class. In this implementation a dimensionality of 17 is used, as this has been found to provide faster access to large numbers of independent sequences. A timing comparison between the external MIXMAX random number generator, and the default internal PYTHIA random number generator is provided in the example `main23.cc`. The MIXMAX random number generator is found to be comparable in speed to the default generator. The primary methods of the `MixMaxRndm` class are given here.

MixMaxRndm::MixMaxRndm(int seed0, int seed1, int seed2, int seed3)
for the given four 32-bit seed numbers. The sequence of numbers produced from this set of seeds is guaranteed not to collide with another if at least one bit of the four seeds is different, and, less than 10^100 random numbers are thrown.

### The methods

We here collect a more complete and formal overview of the `Rndm` class methods.

Rndm::Rndm()
construct a random number generator, but does not initialize it.

Rndm::Rndm(int seed)
construct a random number generator, and initialize it for the given seed number.

bool Rndm::rndmEnginePtr( RndmEngine* rndmPtr)
pass in pointer for external random number generation.

void Rndm::init(int seed = 0)
initialize, or reinitialize, the random number generator for the given seed number. Not necessary if the seed was already set in the constructor.

double Rndm::flat()
generate next random number uniformly between 0 and 1.

double Rndm::exp()
generate random numbers according to exp(-x).

double Rndm::xexp()
generate random numbers according to x exp(-x).

double Rndm::gauss()
generate random numbers according to exp(-x^2/2).

pair<double, double> Rndm::gauss2()
generate a pair of random numbers according to exp( -(x^2 + y^2) / 2). Is faster than two calls to `gauss()`.

pair<Vec4, Vec4> Rndm::phaseSpace2(double eCM, double m1, double m2)
generate a pair of vectors according to the phase space distribution of two particles at the specified eCM and with the specified masses.

int Rndm::pick(const vector<double>& prob)
pick one option among vector of (positive) probabilities.

bool Rndm::dumpState(string fileName)
save the current state of the random number generator to a binary file. This involves two integers and 100 double-precision numbers. Intended for debug purposes. Note that binary files may be platform-dependent and thus not transportable.

save the current state of the random number generator as a `struct RndmState`. This can then later be used within the same run, e.g. as input to another `Pythia` instance. It circumvents the intermediate file of `dumpState`, but cannot be saved for a later run.
set the state of the random number generator by reading in a `struct RndmState` saved by the above command. Comments as above.
if you want to construct an external random number generator (or generator interface) then you must implement this method in your class derived from the `RndmEningen` base class, to give a random number between 0 and 1.