Set R's Seed in Rcpp (Sequential Case)

Intro

The goal behind this post is to quickly point out a solution for setting the random seed from within Rcpp. This is particularly helpful to control the reproducibility of the RNG.

RNG Seed Control from C++

By default in R, you can set a random seed using:

set.seed(seed_here)

However, the ability to modify the seed from within C++ is particularly problematic. This is most notably the case if you are trying to perform indirect inference.

In this case, I propose a quick function that is able to facilitate this.

#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]

//' Set the RNG Seed from within Rcpp
//' 
//' Within Rcpp, one can set the R session seed without triggering
//' the CRAN rng modifier check. 
//' @param seed A \code{unsigned int} that is the seed one wishes to use. 
//' @return A set RNG scope.
//' @examples
//' set.seed(10)
//' x = rnorm(5,0,1)
//' set_seed(10)
//' y = rnorm(5,0,1)
//' all.equal(x,y, check.attributes = F)
// [[Rcpp::export]]
void set_seed(unsigned int seed) {
  Rcpp::Environment base_env("package:base");
  Rcpp::Function set_seed_r = base_env["set.seed"];
  set_seed_r(seed);  
}

From there, you can invoke this function within other C++ code ala:

void gen_test(unsigned int n){
  arma::vec m(n);
  
  for(unsigned int i = 0; i < m.n_elem; i++){
    m(i) =  R::rnorm(10,5);
  }
  Rcpp::Rcout << m << std::endl;
}

// [[Rcpp::export]]
void test_seed(unsigned int seed, unsigned int n){
  set_seed(seed);

  Rcpp::Rcout << "First realization after setting seed to " << seed << "." << std::endl;
  gen_test(n);
  
  set_seed(seed);
  
  Rcpp::Rcout << "Second realization after setting seed to " << seed << "." << std::endl;
  
  gen_test(n);
}

Note that this approach is useful to control a seed that is begin used in a sequential manner (e.g. one after another). Unfortunately, under parallelization, the approach will fail horrible since the seed will be constantly reset. At a later time, I’ll address the use of engines and RNG within C++ (std / boost) that is able to be used in parallel. (This means that R::r* functions are unable to be used.)

Testing Solution

A quick test from both the R and Rcpp functions reveal that is a valid approach for seed control.

# Set values
seed = 1335
obs = 6

# Generation from R:
set.seed(seed)
as.matrix(rnorm(obs,10,5))
##           [,1]
## [1,] 10.518265
## [2,]  9.901971
## [3,] 13.124864
## [4,] 10.656016
## [5,] 13.169765
## [6,] 12.631096
# C++ Controlled Set
test_seed(seed,obs)
## First realization after setting seed to 1335.
##    10.5183
##     9.9020
##    13.1249
##    10.6560
##    13.1698
##    12.6311
## 
## Second realization after setting seed to 1335.
##    10.5183
##     9.9020
##    13.1249
##    10.6560
##    13.1698
##    12.6311
comments powered by Disqus