Rcpp 中的 C++ 内置随机工件

C++ builtin random artifacts in Rcpp

我正在维护一个名为 iRF 的 R 包,一个大问题是它不可重现。换句话说,我无法通过设置 set.seed 来获得相同的结果。为了本题的目的,让我们关注函数RIT。您不需要弄清楚它的作用;只看 RNG 处理部分。

定义在R/RIT.R, which calls either RIT_1class or RIT_2class depending on the input type. Both RIT_[1|2]class functions are defined in src/ExportedFunctionsRIT.cpp, which in turn calls helper functions defined in src/RITmain.h and src/RITaux.h.

我正在使用 Rcpp 属性,因此 RIT_[1|2]class 中的随机性应该由隐式 RNGScope 正确处理,如前所述 。但是,这个代码库很难通过两种方式解决,

  1. 函数 RIT_basic and RIT_minhash 使用 // [[Rcpp::plugins(openmp)]]。幸运的是,原作者给每个线程一个单独的种子,所以希望我可以用 seeds[i] = rand() * (i+1) 使它具有确定性,但你可以告诉我这还不够,因为我在这里问。
// Set up vector of seeds for RNG
vector<unsigned int> seeds(n_cores);
for (int i=0; i<n_cores; i++) {
  seeds[i] = chrono::high_resolution_clock::now().time_since_epoch().count()*(i+1);
}
  1. 其中一个函数,CreateHT uses random_device rd;. I'm not familiar with C++ but a quick search 显示它生成 "non-deterministic random numbers"。
void CreateHt(...) {
  // Ht is p by L
  random_device rd; //seed for Random Number Generator(RNG)
  mt19937_64 mt(rd()); //Use Mersenne Twister as RNG

  ...
    shuffle(perm.begin(), perm.end(), mt);
  ...
}

根据我的理解,rand()random_device 都是 C++ 的内置随机工件。我怎样才能让他们尊重.Random.seed

您不应使用 rand()、c.f。 https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful。特别是 rand() 不是线程安全的,因此将它与 OpenMP 结合使用是行不通的。但是,使用 C++11 的 random header 也不是一个好主意,因为 WRE 不鼓励使用它。没有给出原因,但可能是实现定义的分布函数。

可能的备选方案:

  • 使用R的RNG。 Rcpp 在 RRcpp 命名空间中提供了许多包装函数。此外 R_unif_index 有助于获得范围内的 无偏 整数。

  • 使用 BH 包提供的 boost.random 中的 RNG。通过调用 R 的 RNG 为它们播种,使一切都可重现。

  • 也可以在这里使用rTRNG, sitmo or my own dqrng. This is particularly helpful in the context of parallel RNGs. Seeding via R's RNG等替代包。