diff options
author | Nao Pross <np@0hm.ch> | 2024-02-12 14:52:43 +0100 |
---|---|---|
committer | Nao Pross <np@0hm.ch> | 2024-02-12 14:52:43 +0100 |
commit | eda5bc26f44ee9a6f83dcf8c91f17296d7fc509d (patch) | |
tree | bc2efa38ff4e350f9a111ac87065cd7ae9a911c7 /src/armadillo/include/armadillo_bits/arma_rng.hpp | |
download | fsisotool-eda5bc26f44ee9a6f83dcf8c91f17296d7fc509d.tar.gz fsisotool-eda5bc26f44ee9a6f83dcf8c91f17296d7fc509d.zip |
Move into version control
Diffstat (limited to 'src/armadillo/include/armadillo_bits/arma_rng.hpp')
-rw-r--r-- | src/armadillo/include/armadillo_bits/arma_rng.hpp | 1042 |
1 files changed, 1042 insertions, 0 deletions
diff --git a/src/armadillo/include/armadillo_bits/arma_rng.hpp b/src/armadillo/include/armadillo_bits/arma_rng.hpp new file mode 100644 index 0000000..da1b4f7 --- /dev/null +++ b/src/armadillo/include/armadillo_bits/arma_rng.hpp @@ -0,0 +1,1042 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au) +// Copyright 2008-2016 National ICT Australia (NICTA) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + + +//! \addtogroup arma_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: 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 commenting out the code block below: + +#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__)) + #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_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 + { + public: + + #if defined(ARMA_RNG_ALT) + typedef arma_rng_alt::seed_type seed_type; + #elif defined(ARMA_USE_CXX11_RNG) + typedef std::mt19937_64::result_type seed_type; + #else + typedef arma_rng_cxx03::seed_type seed_type; + #endif + + #if defined(ARMA_RNG_ALT) + static constexpr int rng_method = 2; + #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(); + + template<typename eT> struct randi; + template<typename eT> struct randu; + template<typename eT> struct randn; + template<typename eT> struct randg; + }; + + + +#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<std::size_t> 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) + { + #if defined(ARMA_RNG_ALT) + { + arma_rng_alt::set_seed(val); + } + #elif defined(ARMA_USE_CXX11_RNG) + { + arma_rng::lock_producer(); + arma_rng::get_producer().seed(val); + arma_rng::unlock_producer(); + } + #else + { + arma_rng_cxx03::set_seed(val); + } + #endif + } + + + +arma_cold +inline +void +arma_rng::set_seed_random() + { + seed_type seed1 = seed_type(0); + seed_type seed2 = seed_type(0); + seed_type seed3 = seed_type(0); + seed_type seed4 = seed_type(0); + + bool have_seed = false; + + try + { + std::random_device rd; + + if(rd.entropy() > double(0)) { seed1 = static_cast<seed_type>( rd() ); } + + have_seed = (seed1 != seed_type(0)); + } + catch(...) {} + + + if(have_seed == false) + { + try + { + union + { + seed_type a; + unsigned char b[sizeof(seed_type)]; + } tmp; + + tmp.a = seed_type(0); + + std::ifstream f("/dev/urandom", std::ifstream::binary); + + if(f.good()) { f.read((char*)(&(tmp.b[0])), sizeof(seed_type)); } + + if(f.good()) { seed2 = tmp.a; } + + have_seed = (seed2 != seed_type(0)); + } + catch(...) {} + } + + + if(have_seed == false) + { + // get better-than-nothing seeds in case reading /dev/urandom failed + + const std::chrono::system_clock::time_point tp_now = std::chrono::system_clock::now(); + + auto since_epoch_usec = std::chrono::duration_cast<std::chrono::microseconds>(tp_now.time_since_epoch()).count(); + + seed3 = static_cast<seed_type>( since_epoch_usec & 0xFFFF ); + + union + { + uword* a; + unsigned char b[sizeof(uword*)]; + } tmp; + + tmp.a = (uword*)malloc(sizeof(uword)); + + if(tmp.a != nullptr) + { + for(size_t i=0; i<sizeof(uword*); ++i) { seed4 += seed_type(tmp.b[i]); } + + free(tmp.a); + } + } + + arma_rng::set_seed(seed1 + seed2 + seed3 + seed4); + } + + + +// + + + +template<typename eT> +struct arma_rng::randi + { + inline + operator eT () + { + #if defined(ARMA_RNG_ALT) + { + return eT( arma_rng_alt::randi_val() ); + } + #elif defined(ARMA_USE_CXX11_RNG) + { + constexpr double scale = double(std::numeric_limits<int>::max()) / double(std::mt19937_64::max()); + + arma_rng::lock_producer(); + + const eT out = eT(double(arma_rng::get_producer()()) * scale); + + arma_rng::unlock_producer(); + + return out; + } + #else + { + return eT( arma_rng_cxx03::randi_val() ); + } + #endif + } + + + inline + static + int + max_val() + { + #if defined(ARMA_RNG_ALT) + { + return arma_rng_alt::randi_max_val(); + } + #elif defined(ARMA_USE_CXX11_RNG) + { + return std::numeric_limits<int>::max(); + } + #else + { + return arma_rng_cxx03::randi_max_val(); + } + #endif + } + + + inline + static + void + fill(eT* mem, const uword N, const int a, const int b) + { + #if defined(ARMA_RNG_ALT) + { + arma_rng_alt::randi_fill(mem, N, a, b); + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::uniform_int_distribution<int> local_i_distr(a, b); + + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + + for(uword i=0; i<N; ++i) { mem[i] = eT(local_i_distr(producer)); } + + arma_rng::unlock_producer(); + } + #else + { + if(N == uword(1)) { arma_rng_cxx03::randi_fill(mem, uword(1), a, b); return; } + + typedef typename std::mt19937_64::result_type local_seed_type; + + std::mt19937_64 local_engine; + std::uniform_int_distribution<int> local_i_distr(a, b); + + local_engine.seed( local_seed_type(std::rand()) ); + + for(uword i=0; i<N; ++i) { mem[i] = eT(local_i_distr(local_engine)); } + } + #endif + } + }; + + + +// + + + +template<typename eT> +struct arma_rng::randu + { + inline + operator eT () + { + #if defined(ARMA_RNG_ALT) + { + return eT( arma_rng_alt::randu_val() ); + } + #elif defined(ARMA_USE_CXX11_RNG) + { + constexpr double scale = double(1.0) / double(std::mt19937_64::max()); + + arma_rng::lock_producer(); + + const eT out = eT( double(arma_rng::get_producer()()) * scale ); + + arma_rng::unlock_producer(); + + return out; + } + #else + { + return eT( arma_rng_cxx03::randu_val() ); + } + #endif + } + + + inline + static + void + fill(eT* mem, const uword N) + { + #if defined(ARMA_RNG_ALT) + { + for(uword i=0; i < N; ++i) { mem[i] = eT( arma_rng_alt::randu_val() ); } + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::uniform_real_distribution<double> local_u_distr; + + 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 + { + if(N == uword(1)) { mem[0] = eT( arma_rng_cxx03::randu_val() ); return; } + + typedef typename std::mt19937_64::result_type local_seed_type; + + std::mt19937_64 local_engine; + std::uniform_real_distribution<double> local_u_distr; + + local_engine.seed( local_seed_type(std::rand()) ); + + for(uword i=0; i < N; ++i) { mem[i] = eT( local_u_distr(local_engine) ); } + } + #endif + } + + + inline + static + void + fill(eT* mem, const uword N, const double a, const double b) + { + #if defined(ARMA_RNG_ALT) + { + const double r = b - a; + + for(uword i=0; i < N; ++i) { mem[i] = eT( arma_rng_alt::randu_val() * r + a ); } + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::uniform_real_distribution<double> local_u_distr(a,b); + + 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 + { + if(N == uword(1)) { mem[0] = eT( arma_rng_cxx03::randu_val() * (b - a) + a ); return; } + + typedef typename std::mt19937_64::result_type local_seed_type; + + std::mt19937_64 local_engine; + std::uniform_real_distribution<double> local_u_distr(a,b); + + local_engine.seed( local_seed_type(std::rand()) ); + + for(uword i=0; i < N; ++i) { mem[i] = eT( local_u_distr(local_engine) ); } + } + #endif + } + }; + + + +template<typename T> +struct arma_rng::randu< std::complex<T> > + { + arma_inline + operator std::complex<T> () + { + #if defined(ARMA_RNG_ALT) + { + const T a = T( arma_rng_alt::randu_val() ); + const T b = T( arma_rng_alt::randu_val() ); + + return std::complex<T>(a, b); + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::uniform_real_distribution<double> local_u_distr; + + 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<T>(a, b); + } + #else + { + const T a = T( arma_rng_cxx03::randu_val() ); + const T b = T( arma_rng_cxx03::randu_val() ); + + return std::complex<T>(a, b); + } + #endif + } + + + inline + static + void + fill(std::complex<T>* mem, const uword N) + { + #if defined(ARMA_RNG_ALT) + { + for(uword i=0; i < N; ++i) + { + const T a = T( arma_rng_alt::randu_val() ); + const T b = T( arma_rng_alt::randu_val() ); + + mem[i] = std::complex<T>(a, b); + } + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::uniform_real_distribution<double> 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(producer) ); + const T b = T( local_u_distr(producer) ); + + mem[i] = std::complex<T>(a, b); + } + + arma_rng::unlock_producer(); + } + #else + { + if(N == uword(1)) + { + const T a = T( arma_rng_cxx03::randu_val() ); + const T b = T( arma_rng_cxx03::randu_val() ); + + mem[0] = std::complex<T>(a, b); + + return; + } + + typedef typename std::mt19937_64::result_type local_seed_type; + + std::mt19937_64 local_engine; + std::uniform_real_distribution<double> local_u_distr; + + local_engine.seed( local_seed_type(std::rand()) ); + + for(uword i=0; i < N; ++i) + { + const T a = T( local_u_distr(local_engine) ); + const T b = T( local_u_distr(local_engine) ); + + mem[i] = std::complex<T>(a, b); + } + } + #endif + } + + + inline + static + void + fill(std::complex<T>* mem, const uword N, const double a, const double b) + { + #if defined(ARMA_RNG_ALT) + { + const double r = b - a; + + for(uword i=0; i < N; ++i) + { + const T tmp1 = T( arma_rng_alt::randu_val() * r + a ); + const T tmp2 = T( arma_rng_alt::randu_val() * r + a ); + + mem[i] = std::complex<T>(tmp1, tmp2); + } + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::uniform_real_distribution<double> 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(producer) ); + const T tmp2 = T( local_u_distr(producer) ); + + mem[i] = std::complex<T>(tmp1, tmp2); + } + + arma_rng::unlock_producer(); + } + #else + { + if(N == uword(1)) + { + const double r = b - a; + + const T tmp1 = T( arma_rng_cxx03::randu_val() * r + a); + const T tmp2 = T( arma_rng_cxx03::randu_val() * r + a); + + mem[0] = std::complex<T>(tmp1, tmp2); + + return; + } + + typedef typename std::mt19937_64::result_type local_seed_type; + + std::mt19937_64 local_engine; + std::uniform_real_distribution<double> local_u_distr(a,b); + + local_engine.seed( local_seed_type(std::rand()) ); + + for(uword i=0; i < N; ++i) + { + const T tmp1 = T( local_u_distr(local_engine) ); + const T tmp2 = T( local_u_distr(local_engine) ); + + mem[i] = std::complex<T>(tmp1, tmp2); + } + } + #endif + } + }; + + + +// + + + +template<typename eT> +struct arma_rng::randn + { + inline + operator eT () const + { + #if defined(ARMA_RNG_ALT) + { + return eT( arma_rng_alt::randn_val() ); + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::normal_distribution<double> local_n_distr; + + arma_rng::lock_producer(); + + const eT out = eT( local_n_distr(arma_rng::get_producer()) ); + + arma_rng::unlock_producer(); + + return out; + } + #else + { + return eT( arma_rng_cxx03::randn_val() ); + } + #endif + } + + + inline + static + void + dual_val(eT& out1, eT& out2) + { + #if defined(ARMA_RNG_ALT) + { + arma_rng_alt::randn_dual_val(out1, out2); + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::normal_distribution<double> local_n_distr; + + 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 + { + arma_rng_cxx03::randn_dual_val(out1, out2); + } + #endif + } + + + inline + static + void + fill(eT* mem, const uword N) + { + #if defined(ARMA_RNG_ALT) + { + // NOTE: old method to avoid regressions in user code that assumes specific sequence + + uword i, j; + + for(i=0, j=1; j < N; i+=2, j+=2) { arma_rng_alt::randn_dual_val( mem[i], mem[j] ); } + + if(i < N) { mem[i] = eT( arma_rng_alt::randn_val() ); } + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::normal_distribution<double> local_n_distr; + + 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 + { + if(N == uword(1)) { mem[0] = eT( arma_rng_cxx03::randn_val() ); return; } + + typedef typename std::mt19937_64::result_type local_seed_type; + + std::mt19937_64 local_engine; + std::normal_distribution<double> local_n_distr; + + local_engine.seed( local_seed_type(std::rand()) ); + + for(uword i=0; i < N; ++i) { mem[i] = eT( local_n_distr(local_engine) ); } + } + #endif + } + + + inline + static + void + fill(eT* mem, const uword N, const double mu, const double sd) + { + #if defined(ARMA_RNG_ALT) + { + // NOTE: old method to avoid regressions in user code that assumes specific sequence + + uword i, j; + + for(i=0, j=1; j < N; i+=2, j+=2) + { + eT val_i = eT(0); + eT val_j = eT(0); + + arma_rng_alt::randn_dual_val( val_i, val_j ); + + mem[i] = (val_i * sd) + mu; + mem[j] = (val_j * sd) + mu; + } + + if(i < N) + { + const eT val_i = eT( arma_rng_alt::randn_val() ); + + mem[i] = (val_i * sd) + mu; + } + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::normal_distribution<double> local_n_distr(mu, sd); + + 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 + { + if(N == uword(1)) + { + const eT val = eT( arma_rng_cxx03::randn_val() ); + + mem[0] = (val * sd) + mu; + + return; + } + + typedef typename std::mt19937_64::result_type local_seed_type; + + std::mt19937_64 local_engine; + std::normal_distribution<double> local_n_distr(mu, sd); + + local_engine.seed( local_seed_type(std::rand()) ); + + for(uword i=0; i < N; ++i) { mem[i] = eT( local_n_distr(local_engine) ); } + } + #endif + } + }; + + + +template<typename T> +struct arma_rng::randn< std::complex<T> > + { + inline + operator std::complex<T> () const + { + #if defined(_MSC_VER) + // attempt at workaround for MSVC bug + // does MS even test their so-called compilers before release? + T a; + T b; + #else + T a(0); + T b(0); + #endif + + arma_rng::randn<T>::dual_val(a, b); + + return std::complex<T>(a, b); + } + + + inline + static + void + dual_val(std::complex<T>& out1, std::complex<T>& out2) + { + #if defined(_MSC_VER) + T a; + T b; + #else + T a(0); + T b(0); + #endif + + arma_rng::randn<T>::dual_val(a,b); + out1 = std::complex<T>(a,b); + + arma_rng::randn<T>::dual_val(a,b); + out2 = std::complex<T>(a,b); + } + + + inline + static + void + fill(std::complex<T>* mem, const uword N) + { + #if defined(ARMA_RNG_ALT) + { + for(uword i=0; i < N; ++i) { mem[i] = std::complex<T>( arma_rng::randn< std::complex<T> >() ); } + } + #elif defined(ARMA_USE_CXX11_RNG) + { + std::normal_distribution<double> 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(producer) ); + const T b = T( local_n_distr(producer) ); + + mem[i] = std::complex<T>(a,b); + } + + arma_rng::unlock_producer(); + } + #else + { + if(N == uword(1)) + { + T a = T(0); + T b = T(0); + + arma_rng_cxx03::randn_dual_val(a,b); + + mem[0] = std::complex<T>(a,b); + + return; + } + + typedef typename std::mt19937_64::result_type local_seed_type; + + std::mt19937_64 local_engine; + std::normal_distribution<double> local_n_distr; + + local_engine.seed( local_seed_type(std::rand()) ); + + for(uword i=0; i < N; ++i) + { + const T a = T( local_n_distr(local_engine) ); + const T b = T( local_n_distr(local_engine) ); + + mem[i] = std::complex<T>(a,b); + } + } + #endif + } + + + inline + static + void + fill(std::complex<T>* mem, const uword N, const double mu, const double sd) + { + arma_rng::randn< std::complex<T> >::fill(mem, N); + + if( (mu == double(0)) && (sd == double(1)) ) { return; } + + for(uword i=0; i<N; ++i) + { + const std::complex<T>& val = mem[i]; + + mem[i] = std::complex<T>( ((val.real() * sd) + mu), ((val.imag() * sd) + mu) ); + } + } + }; + + + +// + + + +template<typename eT> +struct arma_rng::randg + { + inline + static + void + fill(eT* mem, const uword N, const double a, const double b) + { + #if defined(ARMA_USE_CXX11_RNG) + { + std::gamma_distribution<double> local_g_distr(a,b); + + std::mt19937_64& producer = arma_rng::get_producer(); + + arma_rng::lock_producer(); + + for(uword i=0; i<N; ++i) { mem[i] = eT(local_g_distr(producer)); } + + arma_rng::unlock_producer(); + } + #else + { + typedef typename std::mt19937_64::result_type local_seed_type; + + std::mt19937_64 local_engine; + std::gamma_distribution<double> local_g_distr(a,b); + + local_engine.seed( local_seed_type(arma_rng::randi<local_seed_type>()) ); + + for(uword i=0; i<N; ++i) { mem[i] = eT(local_g_distr(local_engine)); } + } + #endif + } + }; + + + +//! @} |