Introduction to rTRNG

Riccardo Porreca, Roland Schmid

2019-04-27

Introduction

Monte Carlo simulations provide a powerful computational approach to address a wide variety of problems in several domains, such as physical sciences, engineering, computational biology and finance. The independent-samples and large-scale nature of Monte Carlo simulations make the corresponding computation suited for parallel execution, at least in theory. In practice, pseudo-random number generators (RNGs) are intrinsically sequential. This often prevents having a parallel Monte Carlo algorithm that is playing fair, meaning that results are independent of the architecture, parallelization techniques and number of parallel processes.

rTRNG is an R package for advanced parallel Random Number Generation in R. It relies on TRNG (Tina’s Random Number Generator), a state-of-the-art C++ pseudo-random number generator library for sequential and parallel Monte Carlo simulations. In particular, parallel random number engines provided by TRNG can be manipulated by jump and split operations. These allow to jump ahead by an arbitrary number of steps and to split a sequence into any desired sub-sequence(s), thus enabling techniques such as block-splitting and leapfrogging suitable to parallel algorithms.

Package rTRNG provides the R users with access to the functionality of the underlying TRNG C++ library, both in R and as part of other projects combining R with C++.

TRNG.Random

The TRNG.Random functionality (see ?TRNG.Random) provides a base-R-like access to TRNG random number engines by setting and manipulating the current engine in use.

library(rTRNG)
TRNGkind("yarn2")
TRNGseed(117)
TRNGjump(5) # advance by 5 the internal state
TRNGsplit(3, 2) # subsequence: one element every 3 starting from the 2nd

Random variates from the current engine are then generated using functions r<dist>_trng, e.g. runif_trng for the uniform distribution.

x <- runif_trng(10)
x
##  [1] 0.9085960 0.8689441 0.3540530 0.7378240 0.0052939 0.5866284 0.6862086
##  [8] 0.7088267 0.6622958 0.8182121

TRNG.Engine

Random number engines can be explicitly created and manipulated using reference objects from a number of classes (see ?TRNG.Engine), e.g. yarn2.

rng <- yarn2$new()
rng$seed(117)
# alternative: rng <- yarn2$new(117) 
rng$jump(5) 
rng$split(3, 2) 

The engine object is then passed as engine argument of any r<dist>_trng function.

x <- runif_trng(10, engine = rng)
x
##  [1] 0.9085960 0.8689441 0.3540530 0.7378240 0.0052939 0.5866284 0.6862086
##  [8] 0.7088267 0.6622958 0.8182121

Parallel generation

The parallel nature of TRNG random number engines allows fair-playing multi-threaded generation of random variates, with guaranteed equivalence to a purely-sequential generation. Parallel generation is available in r<dist>_trng with argument parallelGrain > 0 and relies on RcppParallel, where the number of parallel threads is controlled via RcppParallel::setThreadOptions.

TRNGseed(117)
RcppParallel::setThreadOptions(numThreads = 2)
x_parallel <- runif_trng(1e5, parallelGrain = 100)
TRNGseed(117)
x_serial <- runif_trng(1e5)
identical(x_serial, x_parallel)
## [1] TRUE

Standalone C++

C++ code using the C++ TRNG library and headers shipped with rTRNG can easily be compiled, specifying the Rcpp::depends attribute that allows Rcpp::sourceCpp to link correctly against the library.

// [[Rcpp::depends(rTRNG)]]
#include <Rcpp.h>
#include <trng/yarn2.hpp>
#include <trng/uniform_dist.hpp>
using namespace Rcpp;
using namespace trng;
// [[Rcpp::export]]
NumericVector exampleCpp() {
  yarn2 rng;
  rng.seed(117);
  // alternative: yarn2 rng(117); 
  rng.jump(5);
  rng.split(3, 1); // note the C++ 0-based index for the subsequence
  NumericVector x(10);
  uniform_dist<> unif(0, 1);
  for (unsigned int i = 0; i < 10; i++) {
    x[i] = unif(rng);
  }
  return x;
}
/*** R
exampleCpp()
*/
##  [1] 0.9085960 0.8689441 0.3540530 0.7378240 0.0052939 0.5866284 0.6862086
##  [8] 0.7088267 0.6622958 0.8182121

R packages

Creating an R package with C++ code using the TRNG library and headers through rTRNG is achieved by