diff --git a/ChangeLog b/ChangeLog index a2e06e29..c0269add 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2023-08-08 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): RcppArmadillo 0.12.6.2.0 + * inst/NEWS.Rd: Idem + * configure.ac: Idem + * configure: Idem + + * inst/include/armadillo: Armadillo 12.6.2 + * inst/include/armadillo_bits/: Idem + 2023-07-26 Dirk Eddelbuettel * DESCRIPTION (Version, Date): RcppArmadillo 0.12.6.1.0 diff --git a/DESCRIPTION b/DESCRIPTION index 721558f6..2872f71a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: RcppArmadillo Type: Package Title: 'Rcpp' Integration for the 'Armadillo' Templated Linear Algebra Library -Version: 0.12.6.1.0 -Date: 2024-07-26 +Version: 0.12.6.2.0 +Date: 2024-08-08 Author: Dirk Eddelbuettel, Romain Francois, Doug Bates, Binxiang Ni, and Conrad Sanderson Maintainer: Dirk Eddelbuettel Description: 'Armadillo' is a templated C++ linear algebra library (by Conrad diff --git a/configure b/configure index 26114258..0bf4f391 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for RcppArmadillo 0.12.6.1.0. +# Generated by GNU Autoconf 2.71 for RcppArmadillo 0.12.6.2.0. # # Report bugs to . # @@ -610,8 +610,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='RcppArmadillo' PACKAGE_TARNAME='rcpparmadillo' -PACKAGE_VERSION='0.12.6.1.0' -PACKAGE_STRING='RcppArmadillo 0.12.6.1.0' +PACKAGE_VERSION='0.12.6.2.0' +PACKAGE_STRING='RcppArmadillo 0.12.6.2.0' PACKAGE_BUGREPORT='edd@debian.org' PACKAGE_URL='' @@ -1229,7 +1229,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures RcppArmadillo 0.12.6.1.0 to adapt to many kinds of systems. +\`configure' configures RcppArmadillo 0.12.6.2.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1291,7 +1291,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of RcppArmadillo 0.12.6.1.0:";; + short | recursive ) echo "Configuration of RcppArmadillo 0.12.6.2.0:";; esac cat <<\_ACEOF @@ -1372,7 +1372,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -RcppArmadillo configure 0.12.6.1.0 +RcppArmadillo configure 0.12.6.2.0 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -1486,7 +1486,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by RcppArmadillo $as_me 0.12.6.1.0, which was +It was created by RcppArmadillo $as_me 0.12.6.2.0, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -3944,7 +3944,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by RcppArmadillo $as_me 0.12.6.1.0, which was +This file was extended by RcppArmadillo $as_me 0.12.6.2.0, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -3999,7 +3999,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -RcppArmadillo config.status 0.12.6.1.0 +RcppArmadillo config.status 0.12.6.2.0 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 0cc55b65..ef38b0bb 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ AC_PREREQ([2.69]) ## Process this file with autoconf to produce a configure script. -AC_INIT([RcppArmadillo],[0.12.6.1.0],[edd@debian.org]) +AC_INIT([RcppArmadillo],[0.12.6.2.0],[edd@debian.org]) ## Set R_HOME, respecting an environment variable if one is set : ${R_HOME=$(R RHOME)} diff --git a/inst/NEWS.Rd b/inst/NEWS.Rd index 972dc5e4..8dbb1d95 100644 --- a/inst/NEWS.Rd +++ b/inst/NEWS.Rd @@ -3,6 +3,22 @@ \newcommand{\ghpr}{\href{https://github.com/RcppCore/RcppArmadillo/pull/#1}{##1}} \newcommand{\ghit}{\href{https://github.com/RcppCore/RcppArmadillo/issues/#1}{##1}} +\section{Changes in RcppArmadillo version 0.12.6.1.0 (2023-08-08)}{ + \itemize{ + \item Upgraded to Armadillo release 12.6.2 (Cortisol Retox) + \itemize{ + \item use thread-safe Mersenne Twister as the default RNG on all + platforms + \item use unique RNG seed for each thread within multi-threaded + execution (such as OpenMP) + \item explicitly document \code{arma_rng::set_seed()} and + \code{arma_rng::set_seed_random() } + } + \itemize None of the changes above affect R use as \pkg{RcppArmadillo} + connects the RNGs used by R to Armadillo + } +} + \section{Changes in RcppArmadillo version 0.12.6.1.0 (2023-07-26)}{ \itemize{ \item Upgraded to Armadillo release 12.6.1 (Cortisol Retox) diff --git a/inst/include/armadillo b/inst/include/armadillo index 31ca6dbf..59694d1c 100644 --- a/inst/include/armadillo +++ b/inst/include/armadillo @@ -50,10 +50,10 @@ #include #include #include +#include #if !defined(ARMA_DONT_USE_STD_MUTEX) #include - #include #endif // #if defined(ARMA_HAVE_CXX17) diff --git a/inst/include/armadillo_bits/SpValProxy_bones.hpp b/inst/include/armadillo_bits/SpValProxy_bones.hpp index 48f5756c..af9a52d4 100644 --- a/inst/include/armadillo_bits/SpValProxy_bones.hpp +++ b/inst/include/armadillo_bits/SpValProxy_bones.hpp @@ -28,9 +28,9 @@ template class SpValProxy { public: - + typedef typename T1::elem_type eT; // Convenience typedef - + friend class SpMat; friend class SpSubview; @@ -49,16 +49,17 @@ class SpValProxy //! Overload all of the potential operators. //! First, the ones that could modify a value. - arma_inline SpValProxy& operator=(const eT rhs); - arma_inline SpValProxy& operator+=(const eT rhs); - arma_inline SpValProxy& operator-=(const eT rhs); - arma_inline SpValProxy& operator*=(const eT rhs); - arma_inline SpValProxy& operator/=(const eT rhs); - - arma_inline SpValProxy& operator++(); - arma_inline SpValProxy& operator--(); - arma_inline eT operator++(const int); - arma_inline eT operator--(const int); + inline SpValProxy& operator= (const eT rhs); + inline SpValProxy& operator+=(const eT rhs); + inline SpValProxy& operator-=(const eT rhs); + inline SpValProxy& operator*=(const eT rhs); + inline SpValProxy& operator/=(const eT rhs); + + inline SpValProxy& operator++(); + inline SpValProxy& operator--(); + + inline eT operator++(const int); + inline eT operator--(const int); //! This will work for any other operations that do not modify a value. arma_inline operator eT() const; diff --git a/inst/include/armadillo_bits/SpValProxy_meat.hpp b/inst/include/armadillo_bits/SpValProxy_meat.hpp index f264f498..242ec07e 100644 --- a/inst/include/armadillo_bits/SpValProxy_meat.hpp +++ b/inst/include/armadillo_bits/SpValProxy_meat.hpp @@ -56,48 +56,43 @@ SpValProxy::operator=(const SpValProxy& rhs) template -arma_inline +inline SpValProxy& SpValProxy::operator=(const eT rhs) { if(rhs != eT(0)) // A nonzero element is being assigned. { - if(val_ptr) { // The value exists and merely needs to be updated. *val_ptr = rhs; parent.invalidate_cache(); } - else { // The value is nonzero and must be inserted. val_ptr = &parent.insert_element(row, col, rhs); } - } else // A zero is being assigned.~ { - if(val_ptr) { // The element exists, but we need to remove it, because it is being set to 0. parent.delete_element(row, col); val_ptr = nullptr; } - + // If the element does not exist, we do not need to do anything at all. - } - + return *this; } template -arma_inline +inline SpValProxy& SpValProxy::operator+=(const eT rhs) { @@ -123,7 +118,7 @@ SpValProxy::operator+=(const eT rhs) template -arma_inline +inline SpValProxy& SpValProxy::operator-=(const eT rhs) { @@ -142,20 +137,19 @@ SpValProxy::operator-=(const eT rhs) val_ptr = &parent.insert_element(row, col, -rhs); } } - + return *this; } template -arma_inline +inline SpValProxy& SpValProxy::operator*=(const eT rhs) { if(rhs != eT(0)) { - if(val_ptr) { // The value already exists and merely needs to be updated. @@ -163,44 +157,38 @@ SpValProxy::operator*=(const eT rhs) parent.invalidate_cache(); check_zero(); } - } else { - if(val_ptr) { // Since we are multiplying by zero, the value can be deleted. parent.delete_element(row, col); val_ptr = nullptr; } - } - + return *this; } template -arma_inline +inline SpValProxy& SpValProxy::operator/=(const eT rhs) { if(rhs != eT(0)) // I hope this is true! { - if(val_ptr) { *val_ptr /= rhs; parent.invalidate_cache(); check_zero(); } - } else { - if(val_ptr) { *val_ptr /= rhs; // That is where it gets ugly. @@ -211,27 +199,25 @@ SpValProxy::operator/=(const eT rhs) val_ptr = nullptr; } } - else { eT val = eT(0) / rhs; // This may vary depending on type and implementation. - + if(val != eT(0)) { // Ok, now we have to insert it. val_ptr = &parent.insert_element(row, col, val); } - } } - + return *this; } template -arma_inline +inline SpValProxy& SpValProxy::operator++() { @@ -241,19 +227,18 @@ SpValProxy::operator++() parent.invalidate_cache(); check_zero(); } - else { val_ptr = &parent.insert_element(row, col, eT(1)); } - + return *this; } template -arma_inline +inline SpValProxy& SpValProxy::operator--() { @@ -263,19 +248,18 @@ SpValProxy::operator--() parent.invalidate_cache(); check_zero(); } - else { val_ptr = &parent.insert_element(row, col, eT(-1)); } - + return *this; } template -arma_inline +inline typename T1::elem_type SpValProxy::operator++(const int) { @@ -285,12 +269,11 @@ SpValProxy::operator++(const int) parent.invalidate_cache(); check_zero(); } - else { val_ptr = &parent.insert_element(row, col, eT(1)); } - + if(val_ptr) // It may have changed to now be 0. { return *(val_ptr) - eT(1); @@ -304,7 +287,7 @@ SpValProxy::operator++(const int) template -arma_inline +inline typename T1::elem_type SpValProxy::operator--(const int) { @@ -314,12 +297,11 @@ SpValProxy::operator--(const int) parent.invalidate_cache(); check_zero(); } - else { val_ptr = &parent.insert_element(row, col, eT(-1)); } - + if(val_ptr) // It may have changed to now be 0. { return *(val_ptr) + eT(1); diff --git a/inst/include/armadillo_bits/arma_rng.hpp b/inst/include/armadillo_bits/arma_rng.hpp index 6c5eb058..da1b4f7a 100644 --- a/inst/include/armadillo_bits/arma_rng.hpp +++ b/inst/include/armadillo_bits/arma_rng.hpp @@ -20,55 +20,63 @@ //! @{ -#if defined(ARMA_RNG_ALT) - #undef ARMA_USE_EXTERN_RNG +#undef ARMA_USE_CXX11_RNG +#define ARMA_USE_CXX11_RNG + +#undef ARMA_USE_THREAD_LOCAL +#define ARMA_USE_THREAD_LOCAL + +#if (defined(ARMA_RNG_ALT) || defined(ARMA_DONT_USE_CXX11_RNG)) + #undef ARMA_USE_CXX11_RNG #endif +#if defined(ARMA_DONT_USE_THREAD_LOCAL) + #undef ARMA_USE_THREAD_LOCAL +#endif -// NOTE: mt19937_64_instance_warmup is used as a workaround + +// NOTE: ARMA_WARMUP_PRODUCER enables a workaround // NOTE: for thread_local issue on macOS 11 and/or AppleClang 12.0 // NOTE: see https://gitlab.com/conradsnicta/armadillo-code/-/issues/173 // NOTE: if this workaround causes problems, please report it and -// NOTE: disable the workaround by uncommenting the code block below: +// NOTE: disable the workaround by commenting out the code block below: -// #if defined(__APPLE__) || defined(__apple_build_version__) -// #if !defined(ARMA_DONT_DISABLE_EXTERN_RNG) -// #undef ARMA_USE_EXTERN_RNG -// #endif -// #endif +#if defined(__APPLE__) || defined(__apple_build_version__) + #undef ARMA_WARMUP_PRODUCER + #define ARMA_WARMUP_PRODUCER +#endif +#if defined(ARMA_DONT_WARMUP_PRODUCER) + #undef ARMA_WARMUP_PRODUCER +#endif // NOTE: workaround for another thread_local issue on macOS // NOTE: where GCC (not Clang) may not have support for thread_local #if (defined(__APPLE__) && defined(__GNUG__) && !defined(__clang__)) - #if !defined(ARMA_DONT_DISABLE_EXTERN_RNG) - #undef ARMA_USE_EXTERN_RNG - #endif + #undef ARMA_USE_THREAD_LOCAL #endif +// NOTE: disable use of thread_local on MinGW et al; +// NOTE: i don't have the patience to keep looking into these broken platforms +#if (defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) || defined(__MSYS__) || defined(__MSYS2__)) + #undef ARMA_USE_THREAD_LOCAL +#endif -#if defined(ARMA_USE_EXTERN_RNG) - extern thread_local std::mt19937_64 mt19937_64_instance; - - #if defined(__APPLE__) || defined(__apple_build_version__) - namespace - { - struct mt19937_64_instance_warmup - { - inline mt19937_64_instance_warmup() - { - typename std::mt19937_64::result_type junk = mt19937_64_instance(); - arma_ignore(junk); - } - }; - - static mt19937_64_instance_warmup mt19937_64_instance_warmup_run; - } - #endif +#if defined(ARMA_FORCE_USE_THREAD_LOCAL) + #undef ARMA_USE_THREAD_LOCAL + #define ARMA_USE_THREAD_LOCAL +#endif + +#if (!defined(ARMA_USE_THREAD_LOCAL)) + #undef ARMA_GUARD_PRODUCER + #define ARMA_GUARD_PRODUCER #endif +#if (defined(ARMA_DONT_GUARD_PRODUCER) || defined(ARMA_DONT_USE_STD_MUTEX)) + #undef ARMA_GUARD_PRODUCER +#endif class arma_rng @@ -77,7 +85,7 @@ class arma_rng #if defined(ARMA_RNG_ALT) typedef arma_rng_alt::seed_type seed_type; - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) typedef std::mt19937_64::result_type seed_type; #else typedef arma_rng_cxx03::seed_type seed_type; @@ -85,12 +93,24 @@ class arma_rng #if defined(ARMA_RNG_ALT) static constexpr int rng_method = 2; - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) static constexpr int rng_method = 1; #else static constexpr int rng_method = 0; #endif + #if defined(ARMA_USE_CXX11_RNG) + inline static std::mt19937_64& get_producer(); + inline static void warmup_producer(std::mt19937_64& producer); + + inline static void lock_producer(); + inline static void unlock_producer(); + + #if defined(ARMA_GUARD_PRODUCER) + inline static std::mutex& get_producer_mutex(); + #endif + #endif + inline static void set_seed(const seed_type val); inline static void set_seed_random(); @@ -102,6 +122,101 @@ class arma_rng +#if defined(ARMA_USE_CXX11_RNG) + +inline +std::mt19937_64& +arma_rng::get_producer() + { + #if defined(ARMA_USE_THREAD_LOCAL) + + // use a thread-safe RNG, with each thread having its own unique starting seed + + static std::atomic mt19937_64_producer_counter(0); + + static thread_local std::mt19937_64 mt19937_64_producer( std::mt19937_64::default_seed + mt19937_64_producer_counter++ ); + + arma_rng::warmup_producer(mt19937_64_producer); + + #else + + // use a plain RNG in case we don't have thread_local + + static std::mt19937_64 mt19937_64_producer( std::mt19937_64::default_seed ); + + arma_rng::warmup_producer(mt19937_64_producer); + + #endif + + return mt19937_64_producer; + } + + +inline +void +arma_rng::warmup_producer(std::mt19937_64& producer) + { + #if defined(ARMA_WARMUP_PRODUCER) + + static std::atomic_flag warmup_done = ATOMIC_FLAG_INIT; // init to false + + if(warmup_done.test_and_set() == false) + { + typename std::mt19937_64::result_type junk = producer(); + + arma_ignore(junk); + } + + #else + + arma_ignore(producer); + + #endif + } + + +inline +void +arma_rng::lock_producer() + { + #if defined(ARMA_GUARD_PRODUCER) + + std::mutex& producer_mutex = arma_rng::get_producer_mutex(); + + producer_mutex.lock(); + + #endif + } + + +inline +void +arma_rng::unlock_producer() + { + #if defined(ARMA_GUARD_PRODUCER) + + std::mutex& producer_mutex = arma_rng::get_producer_mutex(); + + producer_mutex.unlock(); + + #endif + } + + +#if defined(ARMA_GUARD_PRODUCER) + inline + std::mutex& + arma_rng::get_producer_mutex() + { + static std::mutex producer_mutex; + + return producer_mutex; + } +#endif + +#endif + + inline void arma_rng::set_seed(const arma_rng::seed_type val) @@ -110,9 +225,11 @@ arma_rng::set_seed(const arma_rng::seed_type val) { arma_rng_alt::set_seed(val); } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { - mt19937_64_instance.seed(val); + arma_rng::lock_producer(); + arma_rng::get_producer().seed(val); + arma_rng::unlock_producer(); } #else { @@ -141,7 +258,7 @@ arma_rng::set_seed_random() if(rd.entropy() > double(0)) { seed1 = static_cast( rd() ); } - if(seed1 != seed_type(0)) { have_seed = true; } + have_seed = (seed1 != seed_type(0)); } catch(...) {} @@ -162,12 +279,9 @@ arma_rng::set_seed_random() if(f.good()) { f.read((char*)(&(tmp.b[0])), sizeof(seed_type)); } - if(f.good()) - { - seed2 = tmp.a; + if(f.good()) { seed2 = tmp.a; } - if(seed2 != seed_type(0)) { have_seed = true; } - } + have_seed = (seed2 != seed_type(0)); } catch(...) {} } @@ -199,7 +313,7 @@ arma_rng::set_seed_random() } } - arma_rng::set_seed( seed1 + seed2 + seed3 + seed4 ); + arma_rng::set_seed(seed1 + seed2 + seed3 + seed4); } @@ -218,11 +332,17 @@ struct arma_rng::randi { return eT( arma_rng_alt::randi_val() ); } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { constexpr double scale = double(std::numeric_limits::max()) / double(std::mt19937_64::max()); - return eT( double(mt19937_64_instance()) * scale ); + arma_rng::lock_producer(); + + const eT out = eT(double(arma_rng::get_producer()()) * scale); + + arma_rng::unlock_producer(); + + return out; } #else { @@ -241,7 +361,7 @@ struct arma_rng::randi { return arma_rng_alt::randi_max_val(); } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { return std::numeric_limits::max(); } @@ -262,11 +382,17 @@ struct arma_rng::randi { arma_rng_alt::randi_fill(mem, N, a, b); } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::uniform_int_distribution local_i_distr(a, b); - for(uword i=0; i local_u_distr; - for(uword i=0; i < N; ++i) { mem[i] = eT( local_u_distr(mt19937_64_instance) ); } + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + + for(uword i=0; i < N; ++i) { mem[i] = eT( local_u_distr(producer) ); } + + arma_rng::unlock_producer(); } #else { @@ -358,11 +496,17 @@ struct arma_rng::randu for(uword i=0; i < N; ++i) { mem[i] = eT( arma_rng_alt::randu_val() * r + a ); } } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::uniform_real_distribution local_u_distr(a,b); - for(uword i=0; i < N; ++i) { mem[i] = eT( local_u_distr(mt19937_64_instance) ); } + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + + for(uword i=0; i < N; ++i) { mem[i] = eT( local_u_distr(producer) ); } + + arma_rng::unlock_producer(); } #else { @@ -396,12 +540,18 @@ struct arma_rng::randu< std::complex > return std::complex(a, b); } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::uniform_real_distribution local_u_distr; - const T a = T( local_u_distr(mt19937_64_instance) ); - const T b = T( local_u_distr(mt19937_64_instance) ); + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + + const T a = T( local_u_distr(producer) ); + const T b = T( local_u_distr(producer) ); + + arma_rng::unlock_producer(); return std::complex(a, b); } @@ -431,17 +581,23 @@ struct arma_rng::randu< std::complex > mem[i] = std::complex(a, b); } } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::uniform_real_distribution local_u_distr; + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + for(uword i=0; i < N; ++i) { - const T a = T( local_u_distr(mt19937_64_instance) ); - const T b = T( local_u_distr(mt19937_64_instance) ); + const T a = T( local_u_distr(producer) ); + const T b = T( local_u_distr(producer) ); mem[i] = std::complex(a, b); } + + arma_rng::unlock_producer(); } #else { @@ -491,17 +647,23 @@ struct arma_rng::randu< std::complex > mem[i] = std::complex(tmp1, tmp2); } } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::uniform_real_distribution local_u_distr(a,b); + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + for(uword i=0; i < N; ++i) { - const T tmp1 = T( local_u_distr(mt19937_64_instance) ); - const T tmp2 = T( local_u_distr(mt19937_64_instance) ); + const T tmp1 = T( local_u_distr(producer) ); + const T tmp2 = T( local_u_distr(producer) ); mem[i] = std::complex(tmp1, tmp2); } + + arma_rng::unlock_producer(); } #else { @@ -552,11 +714,17 @@ struct arma_rng::randn { return eT( arma_rng_alt::randn_val() ); } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::normal_distribution local_n_distr; - return eT( local_n_distr(mt19937_64_instance) ); + arma_rng::lock_producer(); + + const eT out = eT( local_n_distr(arma_rng::get_producer()) ); + + arma_rng::unlock_producer(); + + return out; } #else { @@ -575,12 +743,18 @@ struct arma_rng::randn { arma_rng_alt::randn_dual_val(out1, out2); } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::normal_distribution local_n_distr; - out1 = eT( local_n_distr(mt19937_64_instance) ); - out2 = eT( local_n_distr(mt19937_64_instance) ); + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + + out1 = eT( local_n_distr(producer) ); + out2 = eT( local_n_distr(producer) ); + + arma_rng::unlock_producer(); } #else { @@ -605,11 +779,17 @@ struct arma_rng::randn if(i < N) { mem[i] = eT( arma_rng_alt::randn_val() ); } } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::normal_distribution local_n_distr; - for(uword i=0; i < N; ++i) { mem[i] = eT( local_n_distr(mt19937_64_instance) ); } + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + + for(uword i=0; i < N; ++i) { mem[i] = eT( local_n_distr(producer) ); } + + arma_rng::unlock_producer(); } #else { @@ -657,11 +837,17 @@ struct arma_rng::randn mem[i] = (val_i * sd) + mu; } } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::normal_distribution local_n_distr(mu, sd); - for(uword i=0; i < N; ++i) { mem[i] = eT( local_n_distr(mt19937_64_instance) ); } + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + + for(uword i=0; i < N; ++i) { mem[i] = eT( local_n_distr(producer) ); } + + arma_rng::unlock_producer(); } #else { @@ -741,17 +927,23 @@ struct arma_rng::randn< std::complex > { for(uword i=0; i < N; ++i) { mem[i] = std::complex( arma_rng::randn< std::complex >() ); } } - #elif defined(ARMA_USE_EXTERN_RNG) + #elif defined(ARMA_USE_CXX11_RNG) { std::normal_distribution local_n_distr; + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + for(uword i=0; i < N; ++i) { - const T a = T( local_n_distr(mt19937_64_instance) ); - const T b = T( local_n_distr(mt19937_64_instance) ); + const T a = T( local_n_distr(producer) ); + const T b = T( local_n_distr(producer) ); mem[i] = std::complex(a,b); } + + arma_rng::unlock_producer(); } #else { @@ -818,11 +1010,17 @@ struct arma_rng::randg void fill(eT* mem, const uword N, const double a, const double b) { - #if defined(ARMA_USE_EXTERN_RNG) + #if defined(ARMA_USE_CXX11_RNG) { std::gamma_distribution local_g_distr(a,b); - for(uword i=0; i