--- title: "Introduction to rTRNG" author: "Riccardo Porreca, Roland Schmid" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Introduction to rTRNG} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, collapse = TRUE) linking_ok <- rTRNG::check_rTRNG_linking() ``` ### 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](https://www.numbercrunch.de/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. ```{r TRNG.Random} 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_trng`, e.g. `runif_trng` for the uniform distribution. ```{r runif_trng} x <- runif_trng(10) x ``` ### 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`. ```{r TRNG.Engine} 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_trng` function. ```{r runif_trng-engine} x <- runif_trng(10, engine = rng) x ``` ### 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_trng` with argument `parallelGrain > 0` and relies on `RcppParallel`, where the number of parallel threads is controlled via `RcppParallel::setThreadOptions`. ```{r ex-parallelGrain} 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) ``` ### 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 sourceCpp, eval=linking_ok} // [[Rcpp::depends(rTRNG)]] // TRNG >= 4.22 requires C++11 // [[Rcpp::plugins(cpp11)]] #include #include #include 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() */ ``` ```{r sourceCpp-R, echo=FALSE, eval=linking_ok} exampleCpp() ``` ### 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 ```{r check-linking, eval=FALSE} rTRNG::check_rTRNG_linking() ```