多线程播种 unif_rand()
Seeding for multithreaded unif_rand()
我想在多线程环境中播种 R 的内部 unif_rand()
。下面的代码在 2 个线程中生成一个由均匀随机数组成的 2 列矩阵。结果很有趣。
struct mtRunif: public RcppParallel::Worker
{
int Nrow; // number of rows in matrix.
double *v; // point to the 0th element of the 0th column.
void operator() (std::size_t st, std::size_t end)
{
// st = 0 in the 0th thread, 1 in the 1st thread.
double *vst = v + st * Nrow;
for(int i = 0; i < Nrow; ++i)
{
vst[i] = unif_rand();
}
}
mtRunif(int Nrow, double *v): Nrow(Nrow), v(v)
{
RcppParallel::parallelFor(0, 2, *this);
}
};
// [[Rcpp::export]]
NumericMatrix testSeeding(int sampleSize)
{
NumericMatrix rst(sampleSize, 2);
mtRunif(sampleSize, &*rst.begin());
return rst;
}
/***R
N = 100
set.seed(42); tmp = testSeeding(N)
set.seed(42); tmp2 = testSeeding(N)
# see if sequences are identical
range(tmp[, 1] - tmp2[, 1]); range(tmp[, 2] - tmp2[, 2])
# [1] 0 0
# [1] 0 0
N = 1000
set.seed(42); tmp = testSeeding(N)
set.seed(42); tmp2 = testSeeding(N)
range(tmp[, 1] - tmp2[, 1]); range(tmp[, 2] - tmp2[, 2])
# [1] -0.9655154 0.8989870
# [1] -0.969356 0.963239
*/
结果表明 set.seed()
控制小样本大小的所有线程中的随机性?最初我预计 set.seed()
在不超过 1 个线程中有效。我不想利用这个结论,因为它可能是绝对错误的。另一方面,unif_rand()
是否有类似于 std::rand()
的 std::srand()
的播种函数?
谢谢!
简而言之:由于 R 内部的原因,您不能使用 R 执行此操作,并且已被广泛记录。
还有关于 RNG 和流的统计问题。因此,您很可能想研究适合从多线程绘制的 "streaming RNGs"。 CRAN上有一些
以及不再在 CRAN 上的旧 sprng。
广告 dqrng in the comments I realized that I had not written any documentation on how to use the RNGs from that package for parallel usage. So I started a new vignette 后,这将是下一个版本的一部分。这是其中一个示例,与您尝试做的非常相似:
#include <Rcpp.h>
// [[Rcpp::depends(dqrng)]]
#include <pcg_random.hpp>
#include <dqrng_distribution.h>
// [[Rcpp::depends(RcppParallel)]]
#include <RcppParallel.h>
// [[Rcpp::plugins(cpp11)]]
struct RandomFill : public RcppParallel::Worker {
RcppParallel::RMatrix<double> output;
uint64_t seed;
dqrng::normal_distribution dist{0.0, 1.0};
RandomFill(Rcpp::NumericMatrix output, const uint64_t seed) : output(output), seed(seed) {};
void operator()(std::size_t begin, std::size_t end) {
pcg64 rng(seed, end); // ctor with seed and stream id
auto gen = std::bind(dist, rng);
std::generate(output.begin() + begin * output.nrow(),
output.begin() + end * output.nrow(),
std::ref(gen));
}
};
// [[Rcpp::export]]
Rcpp::NumericMatrix parallel_random_matrix(const int n, const int m, const int ncores) {
Rcpp::NumericMatrix res(n, m);
RandomFill randomFill(res, 42);
RcppParallel::parallelFor(0, m, randomFill, m/ncores + 1);
return res;
}
/*** R
res <- parallel_random_matrix(1e6, 8, 4)
head(res)
*/
结果:
> res <- parallel_random_matrix(1e6, 8, 4)
> head(res)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 0.7114429 -0.19759808 -0.47149983 0.6046378 -0.3709571 -0.8089533 0.8185977 0.49010575
[2,] 0.8721661 -0.47654248 1.10411136 -1.6290995 -1.3276661 -0.2585322 -1.2437521 0.90325167
[3,] -1.4959624 0.61068373 -0.54343828 -0.4623555 -1.1779352 -2.8068283 -0.4341252 1.74490995
[4,] 0.5087201 -0.05175746 0.19007581 -0.7869679 0.9672267 -0.5009787 -0.5283977 1.42487290
[5,] -0.8191448 -0.77348120 -0.03458304 0.7243224 1.0594094 -0.6951184 -0.5456669 0.00894037
[6,] 1.2289518 -2.33539762 0.40222707 -2.3346460 -0.5796549 -0.3092356 2.8961294 0.16773085
顺便说一句,请不要起诉 std::rand()
。如果你想使用标准库,那么请在 C++11 中使用类似 std::mt19937
from random
的东西。
我想在多线程环境中播种 R 的内部 unif_rand()
。下面的代码在 2 个线程中生成一个由均匀随机数组成的 2 列矩阵。结果很有趣。
struct mtRunif: public RcppParallel::Worker
{
int Nrow; // number of rows in matrix.
double *v; // point to the 0th element of the 0th column.
void operator() (std::size_t st, std::size_t end)
{
// st = 0 in the 0th thread, 1 in the 1st thread.
double *vst = v + st * Nrow;
for(int i = 0; i < Nrow; ++i)
{
vst[i] = unif_rand();
}
}
mtRunif(int Nrow, double *v): Nrow(Nrow), v(v)
{
RcppParallel::parallelFor(0, 2, *this);
}
};
// [[Rcpp::export]]
NumericMatrix testSeeding(int sampleSize)
{
NumericMatrix rst(sampleSize, 2);
mtRunif(sampleSize, &*rst.begin());
return rst;
}
/***R
N = 100
set.seed(42); tmp = testSeeding(N)
set.seed(42); tmp2 = testSeeding(N)
# see if sequences are identical
range(tmp[, 1] - tmp2[, 1]); range(tmp[, 2] - tmp2[, 2])
# [1] 0 0
# [1] 0 0
N = 1000
set.seed(42); tmp = testSeeding(N)
set.seed(42); tmp2 = testSeeding(N)
range(tmp[, 1] - tmp2[, 1]); range(tmp[, 2] - tmp2[, 2])
# [1] -0.9655154 0.8989870
# [1] -0.969356 0.963239
*/
结果表明 set.seed()
控制小样本大小的所有线程中的随机性?最初我预计 set.seed()
在不超过 1 个线程中有效。我不想利用这个结论,因为它可能是绝对错误的。另一方面,unif_rand()
是否有类似于 std::rand()
的 std::srand()
的播种函数?
谢谢!
简而言之:由于 R 内部的原因,您不能使用 R 执行此操作,并且已被广泛记录。
还有关于 RNG 和流的统计问题。因此,您很可能想研究适合从多线程绘制的 "streaming RNGs"。 CRAN上有一些
以及不再在 CRAN 上的旧 sprng。
广告 dqrng in the comments I realized that I had not written any documentation on how to use the RNGs from that package for parallel usage. So I started a new vignette 后,这将是下一个版本的一部分。这是其中一个示例,与您尝试做的非常相似:
#include <Rcpp.h>
// [[Rcpp::depends(dqrng)]]
#include <pcg_random.hpp>
#include <dqrng_distribution.h>
// [[Rcpp::depends(RcppParallel)]]
#include <RcppParallel.h>
// [[Rcpp::plugins(cpp11)]]
struct RandomFill : public RcppParallel::Worker {
RcppParallel::RMatrix<double> output;
uint64_t seed;
dqrng::normal_distribution dist{0.0, 1.0};
RandomFill(Rcpp::NumericMatrix output, const uint64_t seed) : output(output), seed(seed) {};
void operator()(std::size_t begin, std::size_t end) {
pcg64 rng(seed, end); // ctor with seed and stream id
auto gen = std::bind(dist, rng);
std::generate(output.begin() + begin * output.nrow(),
output.begin() + end * output.nrow(),
std::ref(gen));
}
};
// [[Rcpp::export]]
Rcpp::NumericMatrix parallel_random_matrix(const int n, const int m, const int ncores) {
Rcpp::NumericMatrix res(n, m);
RandomFill randomFill(res, 42);
RcppParallel::parallelFor(0, m, randomFill, m/ncores + 1);
return res;
}
/*** R
res <- parallel_random_matrix(1e6, 8, 4)
head(res)
*/
结果:
> res <- parallel_random_matrix(1e6, 8, 4)
> head(res)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 0.7114429 -0.19759808 -0.47149983 0.6046378 -0.3709571 -0.8089533 0.8185977 0.49010575
[2,] 0.8721661 -0.47654248 1.10411136 -1.6290995 -1.3276661 -0.2585322 -1.2437521 0.90325167
[3,] -1.4959624 0.61068373 -0.54343828 -0.4623555 -1.1779352 -2.8068283 -0.4341252 1.74490995
[4,] 0.5087201 -0.05175746 0.19007581 -0.7869679 0.9672267 -0.5009787 -0.5283977 1.42487290
[5,] -0.8191448 -0.77348120 -0.03458304 0.7243224 1.0594094 -0.6951184 -0.5456669 0.00894037
[6,] 1.2289518 -2.33539762 0.40222707 -2.3346460 -0.5796549 -0.3092356 2.8961294 0.16773085
顺便说一句,请不要起诉 std::rand()
。如果你想使用标准库,那么请在 C++11 中使用类似 std::mt19937
from random
的东西。