Author: Riccardo Porreca, Roland Schmid
Date: 2022-03-14

# Introduction to rTRNG

#### Riccardo Porreca, Roland Schmid

#### 2022-03-14

### 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. Moreover, `Rcpp::plugins(cpp11)` is needed to enforce the C++11 standard required by TRNG >= 4.22.

    // [[Rcpp::depends(rTRNG)]]
    // TRNG >= 4.22 requires C++11
    // [[Rcpp::plugins(cpp11)]]
    #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

- adding `Imports: rTRNG` and `LinkingTo: rTRNG` to the DESCRIPTION file
- importing one symbol in the NAMESPACE: `importFrom(rTRNG, TRNG.Version)`
- enforcing compilation using C++11 in Makevars[.win] via `CXX_STD = CXX11`
- setting the relevant linker flags in Makevars[.win] via `rTRNG::LdFlags()`
  - Makevars: `PKG_LIBS += $(shell ${R_HOME}/bin/Rscript -e "rTRNG::LdFlags()")`
  - Makevars.win: `PKG_LIBS += $(shell "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" -e "rTRNG::LdFlags()")`

### Note about C++ code on macOS

C++ code using the TRNG library (sourced via `Rcpp::sourceCpp` or part of an R package) might fail on certain systems due to issues with building and linking against rTRNG. This is typically the case for macOS, and can generally be checked by running

    rTRNG::check_rTRNG_linking()