diff --git a/DESCRIPTION b/DESCRIPTION index f684e68..1036106 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: dqrng Type: Package Title: Fast Pseudo Random Number Generators -Version: 0.3.1.4 +Version: 0.3.1.5 Authors@R: c( person("Ralf", "Stubner", email = "ralf.stubner@gmail.com", role = c("aut", "cre")), person("daqana GmbH", role = "cph"), diff --git a/NEWS.md b/NEWS.md index 2013334..c5e5dbf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ ## Breaking changes * The default RNG has changed from Xoroshiro128+ to Xoroshiro128++. The older generators Xoroshiro128+ and Xoshiro256+ are still available but should only be used for backward compatibility or for generating floating point numbers, i.e. not sampling etc. ([#57](https://github.com/daqana/dqrng/pull/57) fixing [#56](https://github.com/daqana/dqrng/issues/56)) +* The `dqrng::rng64_t` type has been changed to use `Rcpp::XPtr` instead of `std::shared_ptr` and the functions from `dqrng_sample.h` now expect a reference to `dqrng::random_64bit_generator` instead of `dqrng::rng64_t` ([#70](https://github.com/daqana/dqrng/pull/70) fixing [#63](https://github.com/daqana/dqrng/issues/63)) ## Other changes diff --git a/R/RcppExports.R b/R/RcppExports.R index e49afe7..387fca1 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -52,12 +52,12 @@ dqrrademacher <- function(n) { .Call(`_dqrng_dqrrademacher`, n) } -dqsample_int <- function(m, n, replace = FALSE, probs = NULL, offset = 0L) { - .Call(`_dqrng_dqsample_int`, m, n, replace, probs, offset) +dqsample_int <- function(n, size, replace = FALSE, probs = NULL, offset = 0L) { + .Call(`_dqrng_dqsample_int`, n, size, replace, probs, offset) } -dqsample_num <- function(m, n, replace = FALSE, probs = NULL, offset = 0L) { - .Call(`_dqrng_dqsample_num`, m, n, replace, probs, offset) +dqsample_num <- function(n, size, replace = FALSE, probs = NULL, offset = 0L) { + .Call(`_dqrng_dqsample_num`, n, size, replace, probs, offset) } #' Generate seed as a integer vector diff --git a/inst/include/dqrng.h b/inst/include/dqrng.h index 5279ad7..1bdce43 100644 --- a/inst/include/dqrng.h +++ b/inst/include/dqrng.h @@ -22,6 +22,6 @@ #include "dqrng_RcppExports.h" namespace dqrng { -random_64bit_accessor::random_64bit_accessor() : gen(dqrng::get_rng().get()) {} +random_64bit_accessor::random_64bit_accessor() : gen(dqrng::get_rng()) {} } // namespace dqrng #endif // dqrng_H diff --git a/inst/include/dqrng_RcppExports.h b/inst/include/dqrng_RcppExports.h index 3654b17..389c006 100644 --- a/inst/include/dqrng_RcppExports.h +++ b/inst/include/dqrng_RcppExports.h @@ -183,11 +183,11 @@ namespace dqrng { return Rcpp::as(rcpp_result_gen); } - inline Rcpp::XPtr get_rng() { + inline Rcpp::XPtr get_rng() { typedef SEXP(*Ptr_get_rng)(); static Ptr_get_rng p_get_rng = NULL; if (p_get_rng == NULL) { - validateSignature("Rcpp::XPtr(*get_rng)()"); + validateSignature("Rcpp::XPtr(*get_rng)()"); p_get_rng = (Ptr_get_rng)R_GetCCallable("dqrng", "_dqrng_get_rng"); } RObject rcpp_result_gen; @@ -200,7 +200,7 @@ namespace dqrng { throw Rcpp::LongjumpException(rcpp_result_gen); if (rcpp_result_gen.inherits("try-error")) throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); - return Rcpp::as >(rcpp_result_gen); + return Rcpp::as >(rcpp_result_gen); } inline Rcpp::IntegerVector dqrrademacher(size_t n) { @@ -223,7 +223,7 @@ namespace dqrng { return Rcpp::as(rcpp_result_gen); } - inline Rcpp::IntegerVector dqsample_int(int m, int n, bool replace = false, Rcpp::Nullable probs = R_NilValue, int offset = 0) { + inline Rcpp::IntegerVector dqsample_int(int n, int size, bool replace = false, Rcpp::Nullable probs = R_NilValue, int offset = 0) { typedef SEXP(*Ptr_dqsample_int)(SEXP,SEXP,SEXP,SEXP,SEXP); static Ptr_dqsample_int p_dqsample_int = NULL; if (p_dqsample_int == NULL) { @@ -232,7 +232,7 @@ namespace dqrng { } RObject rcpp_result_gen; { - rcpp_result_gen = p_dqsample_int(Shield(Rcpp::wrap(m)), Shield(Rcpp::wrap(n)), Shield(Rcpp::wrap(replace)), Shield(Rcpp::wrap(probs)), Shield(Rcpp::wrap(offset))); + rcpp_result_gen = p_dqsample_int(Shield(Rcpp::wrap(n)), Shield(Rcpp::wrap(size)), Shield(Rcpp::wrap(replace)), Shield(Rcpp::wrap(probs)), Shield(Rcpp::wrap(offset))); } if (rcpp_result_gen.inherits("interrupted-error")) throw Rcpp::internal::InterruptedException(); @@ -243,7 +243,7 @@ namespace dqrng { return Rcpp::as(rcpp_result_gen); } - inline Rcpp::NumericVector dqsample_num(double m, double n, bool replace = false, Rcpp::Nullable probs = R_NilValue, int offset = 0) { + inline Rcpp::NumericVector dqsample_num(double n, double size, bool replace = false, Rcpp::Nullable probs = R_NilValue, int offset = 0) { typedef SEXP(*Ptr_dqsample_num)(SEXP,SEXP,SEXP,SEXP,SEXP); static Ptr_dqsample_num p_dqsample_num = NULL; if (p_dqsample_num == NULL) { @@ -252,7 +252,7 @@ namespace dqrng { } RObject rcpp_result_gen; { - rcpp_result_gen = p_dqsample_num(Shield(Rcpp::wrap(m)), Shield(Rcpp::wrap(n)), Shield(Rcpp::wrap(replace)), Shield(Rcpp::wrap(probs)), Shield(Rcpp::wrap(offset))); + rcpp_result_gen = p_dqsample_num(Shield(Rcpp::wrap(n)), Shield(Rcpp::wrap(size)), Shield(Rcpp::wrap(replace)), Shield(Rcpp::wrap(probs)), Shield(Rcpp::wrap(offset))); } if (rcpp_result_gen.inherits("interrupted-error")) throw Rcpp::internal::InterruptedException(); diff --git a/inst/include/dqrng_generator.h b/inst/include/dqrng_generator.h index b42ff99..82ac633 100644 --- a/inst/include/dqrng_generator.h +++ b/inst/include/dqrng_generator.h @@ -24,8 +24,11 @@ #include #include #include +#include + namespace dqrng { +using rng64_t = Rcpp::XPtr; using default_64bit_generator = ::dqrng::xoroshiro128plusplus; template @@ -188,37 +191,37 @@ inline void random_64bit_wrapper::seed(result_type seed, result_type stre template typename std::enable_if::value, rng64_t>::type generator () { - return std::make_shared>(); + return rng64_t(new random_64bit_wrapper()); } template typename std::enable_if::value, rng64_t>::type generator () { - return std::make_shared(); + return rng64_t(new RNG()); } template typename std::enable_if::value, rng64_t>::type generator (uint64_t seed) { - return std::make_shared>(seed); + return rng64_t(new random_64bit_wrapper(seed)); } template typename std::enable_if::value, rng64_t>::type generator (uint64_t seed) { - return std::make_shared(seed); + return rng64_t(new RNG(seed)); } template typename std::enable_if::value, rng64_t>::type generator (uint64_t seed, uint64_t stream) { - return std::make_shared>(seed, stream); + return rng64_t(new random_64bit_wrapper(seed, stream)); } template typename std::enable_if::value, rng64_t>::type generator (uint64_t seed, uint64_t stream) { - return std::make_shared(seed, stream); + return rng64_t(new RNG(seed, stream)); } } // namespace dqrng diff --git a/inst/include/dqrng_sample.h b/inst/include/dqrng_sample.h index 4e1558b..1358661 100644 --- a/inst/include/dqrng_sample.h +++ b/inst/include/dqrng_sample.h @@ -1,5 +1,5 @@ // Copyright 2018-2019 Ralf Stubner (daqana GmbH) -// Copyright 2022 Ralf Stubner +// Copyright 2022-2023 Ralf Stubner // // This file is part of dqrng. // @@ -21,62 +21,59 @@ #include #include -#include +#include #include namespace dqrng { namespace sample { -template -inline Rcpp::Vector replacement(dqrng::rng64_t &rng, INT m, INT n, int offset) { - using storage_t = typename Rcpp::traits::storage_type::type; - Rcpp::Vector result(Rcpp::no_init(n)); +template +inline VEC replacement(dqrng::random_64bit_generator &rng, INT n, INT size, int offset) { + VEC result(size); std::generate(result.begin(), result.end(), - [m, offset, rng] () {return static_cast(offset + (*rng)(m));}); + [n, offset, &rng] () {return (offset + rng(n));}); return result; } -template -inline Rcpp::Vector no_replacement_shuffle(dqrng::rng64_t &rng, INT m, INT n, int offset) { - using storage_t = typename Rcpp::traits::storage_type::type; - Rcpp::Vector tmp(Rcpp::no_init(m)); - std::iota(tmp.begin(), tmp.end(), static_cast(offset)); - for (INT i = 0; i < n; ++i) { - std::swap(tmp[i], tmp[i + (*rng)(m - i)]); +template +inline VEC no_replacement_shuffle(dqrng::random_64bit_generator &rng, INT n, INT size, int offset) { + VEC tmp(n); + std::iota(tmp.begin(), tmp.end(), (offset)); + for (INT i = 0; i < size; ++i) { + std::swap(tmp[i], tmp[i + rng(n - i)]); } - if (m == n) + if (n == size) return tmp; else - return Rcpp::Vector(tmp.begin(), tmp.begin() + n); + return VEC(tmp.begin(), tmp.begin() + size); } -template -inline Rcpp::Vector no_replacement_set(dqrng::rng64_t &rng, INT m, INT n, int offset) { - using storage_t = typename Rcpp::traits::storage_type::type; - Rcpp::Vector result(Rcpp::no_init(n)); - SET elems(m, n); - for (INT i = 0; i < n; ++i) { - INT v = (*rng)(m); - while (!elems.insert(v)) { - v = (*rng)(m); - } - result(i) = static_cast(offset + v); +template +inline VEC no_replacement_set(dqrng::random_64bit_generator &rng, INT n, INT size, int offset) { + VEC result(size); + SET elems(n, size); + for (INT i = 0; i < size; ++i) { + INT v; + do { + v = rng(n); + } while (!elems.insert(v)); + result[i] = (offset + v); } return result; } -template -inline Rcpp::Vector sample(dqrng::rng64_t &rng, INT m, INT n, bool replace, int offset = 0) { - if (replace || n <= 1) { - return dqrng::sample::replacement(rng, m, n, offset); +template +inline VEC sample(dqrng::random_64bit_generator &rng, INT n, INT size, bool replace, int offset = 0) { + if (replace || size <= 1) { + return dqrng::sample::replacement(rng, n, size, offset); } else { - if (!(m >= n)) - Rcpp::stop("Argument requirements not fulfilled: m >= n"); - if (m < 2 * n) { - return dqrng::sample::no_replacement_shuffle(rng, m, n, offset); - } else if (m < 1000 * n) { - return dqrng::sample::no_replacement_set(rng, m, n, offset); + if (!(n >= size)) + Rcpp::stop("Argument requirements not fulfilled: n >= size"); + if (n < 2 * size) { + return dqrng::sample::no_replacement_shuffle(rng, n, size, offset); + } else if (n < 1000 * size) { + return dqrng::sample::no_replacement_set(rng, n, size, offset); } else { - return dqrng::sample::no_replacement_set>(rng, m, n, offset); + return dqrng::sample::no_replacement_set>(rng, n, size, offset); } } } diff --git a/inst/include/dqrng_types.h b/inst/include/dqrng_types.h index bee3efa..bc0aad4 100644 --- a/inst/include/dqrng_types.h +++ b/inst/include/dqrng_types.h @@ -21,8 +21,8 @@ #define DQRNG_TYPES_H 1 #include -#include #include +#include namespace dqrng { @@ -53,11 +53,9 @@ class random_64bit_generator { } }; -using rng64_t = std::shared_ptr; - class random_64bit_accessor : public random_64bit_generator { private: - dqrng::random_64bit_generator *gen; + Rcpp::XPtr gen; protected: virtual void output(std::ostream& ost) const override { diff --git a/inst/include/minimal_int_set.h b/inst/include/minimal_int_set.h index a002fe9..de21742 100644 --- a/inst/include/minimal_int_set.h +++ b/inst/include/minimal_int_set.h @@ -26,7 +26,7 @@ // Common interface: // * ctor (m, n) // * bool insert(entry, check = true) -// returns true if insert succesfull and check == true +// returns true if insert successful and check == true namespace dqrng { template diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 9f302b5..91ee9dc 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -286,7 +286,7 @@ RcppExport SEXP _dqrng_rexp(SEXP rateSEXP) { return rcpp_result_gen; } // get_rng -Rcpp::XPtr get_rng(); +Rcpp::XPtr get_rng(); static SEXP _dqrng_get_rng_try() { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; @@ -351,23 +351,23 @@ RcppExport SEXP _dqrng_dqrrademacher(SEXP nSEXP) { return rcpp_result_gen; } // dqsample_int -Rcpp::IntegerVector dqsample_int(int m, int n, bool replace, Rcpp::Nullable probs, int offset); -static SEXP _dqrng_dqsample_int_try(SEXP mSEXP, SEXP nSEXP, SEXP replaceSEXP, SEXP probsSEXP, SEXP offsetSEXP) { +Rcpp::IntegerVector dqsample_int(int n, int size, bool replace, Rcpp::Nullable probs, int offset); +static SEXP _dqrng_dqsample_int_try(SEXP nSEXP, SEXP sizeSEXP, SEXP replaceSEXP, SEXP probsSEXP, SEXP offsetSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; - Rcpp::traits::input_parameter< int >::type m(mSEXP); Rcpp::traits::input_parameter< int >::type n(nSEXP); + Rcpp::traits::input_parameter< int >::type size(sizeSEXP); Rcpp::traits::input_parameter< bool >::type replace(replaceSEXP); Rcpp::traits::input_parameter< Rcpp::Nullable >::type probs(probsSEXP); Rcpp::traits::input_parameter< int >::type offset(offsetSEXP); - rcpp_result_gen = Rcpp::wrap(dqsample_int(m, n, replace, probs, offset)); + rcpp_result_gen = Rcpp::wrap(dqsample_int(n, size, replace, probs, offset)); return rcpp_result_gen; END_RCPP_RETURN_ERROR } -RcppExport SEXP _dqrng_dqsample_int(SEXP mSEXP, SEXP nSEXP, SEXP replaceSEXP, SEXP probsSEXP, SEXP offsetSEXP) { +RcppExport SEXP _dqrng_dqsample_int(SEXP nSEXP, SEXP sizeSEXP, SEXP replaceSEXP, SEXP probsSEXP, SEXP offsetSEXP) { SEXP rcpp_result_gen; { - rcpp_result_gen = PROTECT(_dqrng_dqsample_int_try(mSEXP, nSEXP, replaceSEXP, probsSEXP, offsetSEXP)); + rcpp_result_gen = PROTECT(_dqrng_dqsample_int_try(nSEXP, sizeSEXP, replaceSEXP, probsSEXP, offsetSEXP)); } Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); if (rcpp_isInterrupt_gen) { @@ -388,23 +388,23 @@ RcppExport SEXP _dqrng_dqsample_int(SEXP mSEXP, SEXP nSEXP, SEXP replaceSEXP, SE return rcpp_result_gen; } // dqsample_num -Rcpp::NumericVector dqsample_num(double m, double n, bool replace, Rcpp::Nullable probs, int offset); -static SEXP _dqrng_dqsample_num_try(SEXP mSEXP, SEXP nSEXP, SEXP replaceSEXP, SEXP probsSEXP, SEXP offsetSEXP) { +Rcpp::NumericVector dqsample_num(double n, double size, bool replace, Rcpp::Nullable probs, int offset); +static SEXP _dqrng_dqsample_num_try(SEXP nSEXP, SEXP sizeSEXP, SEXP replaceSEXP, SEXP probsSEXP, SEXP offsetSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; - Rcpp::traits::input_parameter< double >::type m(mSEXP); Rcpp::traits::input_parameter< double >::type n(nSEXP); + Rcpp::traits::input_parameter< double >::type size(sizeSEXP); Rcpp::traits::input_parameter< bool >::type replace(replaceSEXP); Rcpp::traits::input_parameter< Rcpp::Nullable >::type probs(probsSEXP); Rcpp::traits::input_parameter< int >::type offset(offsetSEXP); - rcpp_result_gen = Rcpp::wrap(dqsample_num(m, n, replace, probs, offset)); + rcpp_result_gen = Rcpp::wrap(dqsample_num(n, size, replace, probs, offset)); return rcpp_result_gen; END_RCPP_RETURN_ERROR } -RcppExport SEXP _dqrng_dqsample_num(SEXP mSEXP, SEXP nSEXP, SEXP replaceSEXP, SEXP probsSEXP, SEXP offsetSEXP) { +RcppExport SEXP _dqrng_dqsample_num(SEXP nSEXP, SEXP sizeSEXP, SEXP replaceSEXP, SEXP probsSEXP, SEXP offsetSEXP) { SEXP rcpp_result_gen; { - rcpp_result_gen = PROTECT(_dqrng_dqsample_num_try(mSEXP, nSEXP, replaceSEXP, probsSEXP, offsetSEXP)); + rcpp_result_gen = PROTECT(_dqrng_dqsample_num_try(nSEXP, sizeSEXP, replaceSEXP, probsSEXP, offsetSEXP)); } Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); if (rcpp_isInterrupt_gen) { @@ -449,7 +449,7 @@ static int _dqrng_RcppExport_validate(const char* sig) { signatures.insert("double(*rnorm)(double,double)"); signatures.insert("Rcpp::NumericVector(*dqrexp)(size_t,double)"); signatures.insert("double(*rexp)(double)"); - signatures.insert("Rcpp::XPtr(*get_rng)()"); + signatures.insert("Rcpp::XPtr(*get_rng)()"); signatures.insert("Rcpp::IntegerVector(*dqrrademacher)(size_t)"); signatures.insert("Rcpp::IntegerVector(*dqsample_int)(int,int,bool,Rcpp::Nullable,int)"); signatures.insert("Rcpp::NumericVector(*dqsample_num)(double,double,bool,Rcpp::Nullable,int)"); diff --git a/src/dqrng.cpp b/src/dqrng.cpp index a66a960..781dcc9 100644 --- a/src/dqrng.cpp +++ b/src/dqrng.cpp @@ -153,8 +153,8 @@ double rexp(double rate = 1.0) { //' @keywords internal // [[Rcpp::export(rng = false)]] -Rcpp::XPtr get_rng() { - return Rcpp::XPtr(rng.get(), false); +Rcpp::XPtr get_rng() { + return Rcpp::XPtr(rng); } //' @rdname dqrng-functions @@ -180,28 +180,28 @@ Rcpp::IntegerVector dqrrademacher(size_t n) { } // [[Rcpp::export(rng = false)]] -Rcpp::IntegerVector dqsample_int(int m, - int n, +Rcpp::IntegerVector dqsample_int(int n, + int size, bool replace = false, Rcpp::Nullable probs = R_NilValue, int offset = 0) { - if (!(m > 0 && n >= 0)) - Rcpp::stop("Argument requirements not fulfilled: m > 0 && n >= 0"); - return dqrng::sample::sample(rng, uint32_t(m), uint32_t(n), replace, offset); + if (!(n > 0 && size >= 0)) + Rcpp::stop("Argument requirements not fulfilled: n > 0 && size >= 0"); + return dqrng::sample::sample(*rng, uint32_t(n), uint32_t(size), replace, offset); } // [[Rcpp::export(rng = false)]] -Rcpp::NumericVector dqsample_num(double m, - double n, +Rcpp::NumericVector dqsample_num(double n, + double size, bool replace = false, Rcpp::Nullable probs = R_NilValue, int offset = 0) { + if (!(n > 0 && size >= 0)) + Rcpp::stop("Argument requirements not fulfilled: n > 0 && size >= 0"); #ifndef LONG_VECTOR_SUPPORT Rcpp::stop("Long vectors are not supported"); #else - if (!(m > 0 && n >= 0)) - Rcpp::stop("Argument requirements not fulfilled: m > 0 && n >= 0"); - return dqrng::sample::sample(rng, uint64_t(m), uint64_t(n), replace, offset); + return dqrng::sample::sample(*rng, uint64_t(n), uint64_t(size), replace, offset); #endif } diff --git a/tests/testthat/test-sample.R b/tests/testthat/test-sample.R index e91361b..45e3ceb 100644 --- a/tests/testthat/test-sample.R +++ b/tests/testthat/test-sample.R @@ -128,14 +128,14 @@ test_that("sampling with weights gives warning", { test_that("error cases", { dqset.seed(seed) - expect_error(dqsample(10, 20), "Argument requirements not fulfilled: m >= n") + expect_error(dqsample(10, 20), "Argument requirements not fulfilled: n >= size") expect_silent(dqsample(10, 20, replace = TRUE)) - expect_error(dqsample(10, -20), "Argument requirements not fulfilled: m > 0 && n >= 0") - expect_error(dqsample(-10, -20), "Argument requirements not fulfilled: m > 0 && n >= 0") + expect_error(dqsample(10, -20), "Argument requirements not fulfilled: n > 0 && size >= 0") + expect_error(dqsample(-10, -20), "Argument requirements not fulfilled: n > 0 && size >= 0") # -10 is treated as a one-element vector by dqsample but not by dqsample.int - expect_error(dqsample(-10, 20), "Argument requirements not fulfilled: m >= n") - expect_error(dqsample.int(-10, 20), "Argument requirements not fulfilled: m > 0 && n >= 0") + expect_error(dqsample(-10, 20), "Argument requirements not fulfilled: n >= size") + expect_error(dqsample.int(-10, 20), "Argument requirements not fulfilled: n > 0 && size >= 0") skip_if(.Machine$sizeof.pointer <= 4, "No long-vector support") - expect_error(dqsample(1e10, -20), "Argument requirements not fulfilled: m > 0 && n >= 0") + expect_error(dqsample(1e10, -20), "Argument requirements not fulfilled: n > 0 && size >= 0") }) diff --git a/vignettes/dqrng.Rmd b/vignettes/dqrng.Rmd index 6ad7415..4690099 100644 --- a/vignettes/dqrng.Rmd +++ b/vignettes/dqrng.Rmd @@ -211,6 +211,14 @@ public: private: result_type state; + +public: + friend std::ostream& operator<<(std::ostream& ost, const SplitMix& e) { + return ost << e.state; + } + friend std::istream& operator>>(std::istream& ist, SplitMix& e) { + return ist >> e.state; + } }; // [[Rcpp::export]] @@ -347,8 +355,6 @@ multiple_distributions(5) */ ``` - - ## Accessing the global RNG You may use the class `dqrng::random_64bit_accessor` to use the **seeded** diff --git a/vignettes/parallel.Rmd b/vignettes/parallel.Rmd index 1fd787c..2ec1524 100644 --- a/vignettes/parallel.Rmd +++ b/vignettes/parallel.Rmd @@ -177,7 +177,7 @@ struct RandomFill : public RcppParallel::Worker { void operator()(std::size_t begin, std::size_t end) { auto rng = dqrng::generator(seed, end); for (std::size_t col = begin; col < end; ++col) { - auto sampled = dqrng::sample::sample(rng, 100000, output.nrow(), true); + auto sampled = dqrng::sample::sample, uint32_t>(*rng, 100000, output.nrow(), true); RcppParallel::RMatrix::Column column = output.column(col); std::copy(sampled.begin(), sampled.end(), column.begin()); }