Monte Carlo Integration Library 1.0
High-performance Monte Carlo methods for numerical integration and optimization
rng_factory.cpp
Go to the documentation of this file.
1
13#include "rng_factory.hpp"
14#include "rng_global.hpp"
15
16#ifdef _OPENMP
17 #include <omp.h>
18#endif
19
20#include <iterator> // std::begin/std::end
21
22namespace mc {
23
24namespace rng {
25
26namespace detail {
27
28// splitmix64 mixer (Vigna), used here as a high-quality mixing function
29inline std::uint64_t splitmix64_mix(std::uint64_t x) {
30 x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;
31 x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;
32 x = x ^ (x >> 31);
33 return x;
34}
35
36inline std::uint64_t combine_seeds(std::uint64_t base_seed,
37 std::uint64_t stream_id,
38 std::uint64_t thread_id)
39{
40 constexpr std::uint64_t GOLDEN = 0x9e3779b97f4a7c15ULL;
41
42 std::uint64_t combined = base_seed;
43 combined ^= splitmix64_mix(stream_id + GOLDEN);
44 combined ^= splitmix64_mix((thread_id << 1) + 1ULL);
45
46 return splitmix64_mix(combined);
47}
48
55inline std::mt19937 create_mt19937(std::uint64_t seed) {
56 std::uint32_t data[8];
57
58 std::uint64_t x = seed;
59 for (int i = 0; i < 8; ++i) {
60 x = splitmix64_mix(x + 0x9e3779b97f4a7c15ULL);
61 data[i] = static_cast<std::uint32_t>(x & 0xFFFFFFFFULL);
62 }
63
64 std::seed_seq seq(std::begin(data), std::end(data));
65 return std::mt19937(seq);
66}
67
68} // detail namespace
69
70std::mt19937 make_engine(std::uint64_t stream_id) {
71 const std::uint64_t base = static_cast<std::uint64_t>(get_global_seed());
72 const std::uint64_t mixed = mc::rng::detail::combine_seeds(base, stream_id, 0ULL);
74}
75
76std::mt19937 make_thread_engine(std::uint64_t stream_id) {
77 const std::uint64_t base = static_cast<std::uint64_t>(get_global_seed());
78
79 std::uint64_t tid = 0ULL;
80#ifdef _OPENMP
81 tid = static_cast<std::uint64_t>(omp_get_thread_num());
82#endif
83
84 const std::uint64_t mixed = mc::rng::detail::combine_seeds(base, stream_id, tid);
86}
87
88std::mt19937 make_engine_with_seed(std::optional<std::uint32_t> base_seed,
89 std::uint64_t stream_id)
90{
91 const std::uint64_t base = base_seed.has_value()
92 ? static_cast<std::uint64_t>(*base_seed)
93 : static_cast<std::uint64_t>(get_global_seed());
94
95 const std::uint64_t mixed = mc::rng::detail::combine_seeds(base, stream_id, 0ULL);
97}
98
99} // namespace rng
100} // namespace mc
std::uint64_t combine_seeds(std::uint64_t base_seed, std::uint64_t stream_id, std::uint64_t thread_id)
std::mt19937 create_mt19937(std::uint64_t seed)
Create mt19937 from a 64-bit seed.
std::uint64_t splitmix64_mix(std::uint64_t x)
std::mt19937 make_thread_engine(std::uint64_t stream_id)
Create a deterministic RNG engine for the current thread (OpenMP if available)
std::mt19937 make_engine_with_seed(std::optional< std::uint32_t > base_seed, std::uint64_t stream_id)
Create a deterministic RNG engine with explicit seed override (optional)
std::mt19937 make_engine(std::uint64_t stream_id)
Create a deterministic RNG engine for a specific stream.
std::uint32_t get_global_seed()
Get the current global seed.
Factory for creating deterministic, independent RNG engines.