#### GitHub: SyncRNG

## Synchronised Random Numbers in R and Python

Recently I stumbled upon a problem while working on benchmarking machine learning methods. I wanted to do cross-validation (CV) on different methods, but some were implemented in R through certain libraries, and some were implemented in Python through scikit-learn. The problem was that in order to have proper cross-validation, it had to be possible to create the same train and test folds in both languages.

A possible solution to this problem is to explicitly generate all folds in one language, and then save them in datafiles to be loaded from the other language. Although possible, this would lead to a lot of redundant datasets, and in my case disk usage was getting a bit scarce. So instead I opted for the alternative: generating the CV folds in both languages using the same random numbers.

Both R and NumPy (which scikit-learn uses underneath) implement the Mersenne-Twister random number generator (RNG). However, the implementations differ such that setting the same seed does not yield the same sequence of random numbers in both languages. Unfortunately for me, that meant I had to implement my own RNG in both languages separately.

Initially I started with implementing the Mersenne-Twister RNG in R and Python separately. This soon gave me problems because bitwise operations on integers in R can lead to NA values being generated. So instead, I chose to implement the RNG in C, and link this to both R and Python. Because I wanted fast random number generation and a small state vector, I changed the Mersenne-Twister for a Tausworthe RNG, which is a very efficient random number generator with a state of only 4 integers. The implementation I chose comes straight from Pierre L’Ecuyers 1999 paper entitled Tables of Maximally Equidistributed Combined LFSR Generators.

I implemented the Tausworthe RNG in C, and used the same C file to write the R
and Python interfaces to the RNG. This way, I could create both an R library
and a Python package without writing the C code twice. The different sections
of the C file are separated using a compile macro, so the R library doesn’t
contain the Python code, and visa versa. The Python interface contains a bit
more defines to support both Python 2 and 3. The resulting package was dubbed
*SyncRNG*.

The Python package implements a *SyncRNG* class and the R library implements a
*SyncRNG* reference class, to support comparable usage of the RNG. For
instance, in Python the package can be used as follows:

```
>>> from SyncRNG import SyncRNG
>>> s = SyncRNG(seed=123)
>>> r = s.randi()
```

and in R:

```
> library(SyncRNG)
> s <- SyncRNG(seed=123)
> r <- r$randi()
```

As you can see usage of the classes is syntactically very similar. In both
languages a shuffle method is implemented for the *SyncRNG* class, which
returns a shuffled instance of a supplied vector. This I can then use to
shuffle a list of indices which in turn can be used to create train and test
folds for cross validation. Because the random numbers are guaranteed to be
the same, I can be confident that the CV folds will be also, which solves my
original problem.

You can install *SyncRNG* in Python through pip, and in R through CRAN. For
the source code, see GitHub.