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
正确处理,如前所述 。但是,这个代码库很难通过两种方式解决,
- 函数
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);
}
- 其中一个函数,
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 在 R
和 Rcpp
命名空间中提供了许多包装函数。此外 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等替代包。
我正在维护一个名为 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
正确处理,如前所述
- 函数
RIT_basic
andRIT_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);
}
- 其中一个函数,
CreateHT
usesrandom_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 在
R
和Rcpp
命名空间中提供了许多包装函数。此外R_unif_index
有助于获得范围内的 无偏 整数。使用 BH 包提供的
boost.random
中的 RNG。通过调用 R 的 RNG 为它们播种,使一切都可重现。也可以在这里使用
rTRNG
,sitmo
or my owndqrng
. This is particularly helpful in the context of parallel RNGs. Seeding via R's RNG等替代包。