rTRNG: Advanced Parallel RNG in R
Want to share your content on Rbloggers? click here if you have a blog, or here if you don't.
Following on the recent CRAN release of
rTRNG, it’s
time to show its features and usage more in detail.
rTRNG is
a new package for advanced parallel Random Number Generation in R. It relies
on TRNG (Tina’s Random Number
Generator), a stateoftheart C++ pseudorandom number generator library for
sequential and parallel Monte Carlo simulations. In particular, parallel
random number generators 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 subsequence(s), thus enabling
techniques such as blocksplitting and leapfrogging suitable to parallel
algorithms.
Background and Motivation
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 independentsamples and
largescale nature of Monte Carlo simulations make the corresponding computation
suited for parallel execution, at least in theory. In practice, pseudorandom
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.
Advanced Parallel RNG in R
rTRNG provides the R user with access to the functionality of the underlying
TRNG C++ library. It makes use of
Rcpp and
RcppParallel
to expose the creation, manipulation and use of pseudorandom streams to R.
Moreover, the TRNG library and its headers are made available to other projects
combining R with C++.
An
introduction to rTRNG
(pdf)
was given at the useR!2017 conference, and is also available as
vignette("rTRNG.useR2017", "rTRNG")
.
A second vignette, vignette("mcMat", "rTRNG")
, shows rTRNG in action for
the flexible and consistent (parallel) simulation of a matrix of Monte Carlo
variates, represented in the picture above.
The concrete application of such techniques to the simulation of credit defaults
was presented at the
R/Finance 2017
conference, showing how rTRNG can be used for fast subportfolio simulation,
riskinsight and scenario assessment. The code and data underlying this applied
usecase are hosted on
GitHub,
as is the corresponding
R Markdown output.
Below we illustrate, using simple examples, the several ways rTRNG can be
used.
BaseRlike usage
Similar to baseR (see ?Random
), rTRNG allows to select and manipulate a
current TRNG generator of a given kind (e.g. yarn2), and to draw from it
using any of the provided r
functions:
<span class="n">library</span><span class="p">(</span><span class="n">rTRNG</span><span class="p">)</span><span class="w">
</span><span class="n">TRNGkind</span><span class="p">(</span><span class="s2">"yarn2"</span><span class="p">)</span><span class="w">
</span><span class="n">TRNGseed</span><span class="p">(</span><span class="m">12358</span><span class="p">)</span><span class="w">
</span><span class="n">runif_trng</span><span class="p">(</span><span class="m">15</span><span class="p">)</span><span class="w">
</span><span class="c1">## [1] 0.580259813 0.339434026 0.221393682 0.369402388 0.542678773</span><span class="w">
</span><span class="c1">## [6] 0.002851459 0.123996486 0.346813776 0.121799416 0.947124450</span><span class="w">
</span><span class="c1">## [11] 0.336516569 0.128926181 0.380379891 0.550692382 0.436002654</span><span class="w">
</span>
The special jump
and split
operations can be applied to the current
generator in a similar way:
<span class="n">TRNGseed</span><span class="p">(</span><span class="m">12358</span><span class="p">)</span><span class="w">
</span><span class="n">TRNGjump</span><span class="p">(</span><span class="m">6</span><span class="p">)</span><span class="w"> </span><span class="c1"># advance by 6 the internal state</span><span class="w">
</span><span class="n">TRNGsplit</span><span class="p">(</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="m">3</span><span class="p">)</span><span class="w"> </span><span class="c1"># generate one element every 5 starting from the 3rd</span><span class="w">
</span><span class="n">runif_trng</span><span class="p">(</span><span class="m">2</span><span class="p">)</span><span class="w">
</span><span class="c1">## [1] 0.1217994 0.5506924</span><span class="w">
</span><span class="c1"># => compare to the full sequence above</span><span class="w">
</span>
Direct manipulation of generators
Reference objects wrapping the underlying C++ TRNG generators can be created
and manipulated in OOPstyle, for greater flexibility in using parallel RNGs in
R:
<span class="n">rng</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">yarn2</span><span class="o">$</span><span class="n">new</span><span class="p">()</span><span class="w">
</span><span class="n">rng</span><span class="o">$</span><span class="n">seed</span><span class="p">(</span><span class="m">12358</span><span class="p">)</span><span class="w">
</span><span class="n">rng</span><span class="o">$</span><span class="n">jump</span><span class="p">(</span><span class="m">6</span><span class="p">)</span><span class="w">
</span><span class="n">rng</span><span class="o">$</span><span class="n">split</span><span class="p">(</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="m">3</span><span class="p">)</span><span class="w">
</span><span class="n">runif_trng</span><span class="p">(</span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">engine</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rng</span><span class="p">)</span><span class="w">
</span><span class="c1">## [1] 0.1217994 0.5506924</span><span class="w">
</span>
Parallel generation
Fairplaying, multithreaded generation of random variates from R can be
anabled in r
via argument parallelGrain > 0
, where the number of
parallel threads is controlled via RcppParallel::setThreadOptions()
:
<span class="n">TRNGseed</span><span class="p">(</span><span class="m">12358</span><span class="p">)</span><span class="w">
</span><span class="n">RcppParallel</span><span class="o">::</span><span class="n">setThreadOptions</span><span class="p">(</span><span class="n">numThreads</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span><span class="n">x_parallel</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">runif_trng</span><span class="p">(</span><span class="m">1e5</span><span class="p">,</span><span class="w"> </span><span class="n">parallelGrain</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">100</span><span class="p">)</span><span class="w">
</span><span class="n">TRNGseed</span><span class="p">(</span><span class="m">12358</span><span class="p">)</span><span class="w">
</span><span class="n">x_serial</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">runif_trng</span><span class="p">(</span><span class="m">1e5</span><span class="p">)</span><span class="w">
</span><span class="n">identical</span><span class="p">(</span><span class="n">x_serial</span><span class="p">,</span><span class="w"> </span><span class="n">x_parallel</span><span class="p">)</span><span class="w">
</span><span class="c1">## [1] TRUE</span><span class="w">
</span>
Standalone C++ code
The TRNG C++ library is made available by rTRNG to standalone C++ code
compiled with Rcpp::sourceCpp()
thanks to the Rcpp::depends
attribute:
<span class="c1">// [[Rcpp::depends(rTRNG)]]
</span><span class="cp">#include <Rcpp.h>
#include <trng/yarn2.hpp>
#include <trng/uniform_dist.hpp>
</span><span class="c1">// [[Rcpp::export]]
</span><span class="n">Rcpp</span><span class="o">::</span><span class="n">NumericVector</span> <span class="n">exampleCpp</span><span class="p">()</span> <span class="p">{</span>
<span class="n">trng</span><span class="o">::</span><span class="n">yarn2</span> <span class="n">rng</span><span class="p">(</span><span class="mi">12358</span><span class="p">);</span>
<span class="n">rng</span><span class="p">.</span><span class="n">jump</span><span class="p">(</span><span class="mi">6</span><span class="p">);</span>
<span class="n">rng</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> <span class="c1">// 0based index
</span> <span class="n">Rcpp</span><span class="o">::</span><span class="n">NumericVector</span> <span class="n">x</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
<span class="n">trng</span><span class="o">::</span><span class="n">uniform_dist</span><span class="o"><></span><span class="n">unif</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">unif</span><span class="p">(</span><span class="n">rng</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">x</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">exampleCpp</span><span class="p">()</span><span class="w">
</span><span class="c1">## [1] 0.1217994 0.5506924</span><span class="w">
</span>
R packages
Creating an R package with C++ code using the TRNG library via rTRNG is
achieved by

adding
Imports: rTRNG
andLinkingTo: rTRNG
to the DESCRIPTION file 
importing one symbol in the NAMESPACE:
importFrom(rTRNG, TRNG.Version)

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()")
 Makevars:
Rbloggers.com offers daily email updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/datascience job.
Want to share your content on Rbloggers? click here if you have a blog, or here if you don't.