algorithms  2.2.0
Framework-independent algorithms for the EIC
Loading...
Searching...
No Matches
random.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <concepts>
5#include <cstdint>
6#include <functional>
7#include <memory>
8#include <mutex>
9#include <random>
10
12#include <algorithms/logger.h>
13#include <algorithms/service.h>
14
15namespace algorithms {
16
17// Random Engine callback function:
18// - Signature: std::function<std::vector<value_type>(size_t N)> --> generates a vector
19// of N numbers
20// - RandomEngineCB is required to return N random numbers between 0 and
21// std::numeric_limits<uint_fast64_t>::max()
22// - RandomEngineCB is responsible to deal with possible simultaneous access by multiple
23// Generator instances (required to be thread-safe).
25
26// thread-safe generator front-end. Requires that the underlying random engine used by
27// the RandomSvc is thread-safe.
28class Generator {
29public:
30 Generator(const RandomEngineCB& gen, const size_t cache_size) : m_gen{gen, cache_size} {}
31
32 template <std::integral Int = int> Int uniform_int(const Int min = Int{0}, const Int max = Int{1}) const {
33 std::uniform_int_distribution<Int> d{min, max};
34 std::lock_guard<std::mutex> lock{m_mutex};
35 return d(m_gen);
36 }
37 template <std::floating_point Float = double> Float uniform_double(const Float min = Float{0}, const Float max = Float{1}) const {
38 std::uniform_real_distribution<Float> d{min, max};
39 std::lock_guard<std::mutex> lock{m_mutex};
40 return d(m_gen);
41 }
42 template <std::integral Int = int> Int poisson(const double mean = 1.) const {
43 std::poisson_distribution<Int> d{mean};
44 std::lock_guard<std::mutex> lock{m_mutex};
45 return d(m_gen);
46 }
47 template <std::floating_point Float = double> Float exponential(const Float lambda = Float{1}) const {
48 std::exponential_distribution<Float> d{lambda};
49 std::lock_guard<std::mutex> lock{m_mutex};
50 return d(m_gen);
51 }
52 template <std::floating_point Float = double> Float gaussian(const Float mu = Float{0}, const Float sigma = Float{1}) const {
53 std::normal_distribution<Float> d{mu, sigma};
54 std::lock_guard<std::mutex> lock{m_mutex};
55 return d(m_gen);
56 }
57
58private:
59 mutable detail::CachedBitGenerator m_gen;
60 mutable std::mutex m_mutex;
61};
62
63// Random service that creates multiple Generators that are linked to a single random
64// engine. The Generators are safe to be used in parallel as long as the Engine itself is
65// thread-safe (this is a hard requirement for MT). The Generators avoid unnecesary locking
66// by running off a auto-refreshing cached random sequence.
67class RandomSvc : public LoggedService<RandomSvc> {
68public:
70
71 Generator generator() { return {m_gen, m_cache_size}; }
72// FIXME fix the CMake setup so these are properly found in Gaudi
73#if 0
74 void init();
75 void init(const RandomEngineCB& gen);
76#endif
77 void init() {
78 if (m_seed.hasValue()) {
79 info() << "Custom random seed requested: " << m_seed << endmsg;
80 m_gen = createEngine(m_seed);
81 }
82 }
83 void init(const RandomEngineCB& gen) {
84 info() << "Loading external generator function." << endmsg;
85 m_gen = gen;
86 if (m_seed.hasValue()) {
87 warning() << "Custom random seed request ignored when using external generator function"
88 << endmsg;
89 }
90 }
91
92#if 0
93private:
94 RandomEngineCB createEngine(const size_t seed = 1);
95#endif
96 RandomEngineCB createEngine(const size_t seed = 1) {
97 // Each engine has its own state, shared by all copies of the callback
98 struct Engine {
99 std::mutex m;
100 std::mt19937_64 gen;
101 };
102 auto engine = std::make_shared<Engine>();
103 engine->gen.seed(seed);
104 return [engine](const size_t size) {
105 std::lock_guard<std::mutex> lock{engine->m};
106 std::vector<value_type> ret(size);
107 // pass the generator by reference, so its state advances
108 std::generate(ret.begin(), ret.end(), std::ref(engine->gen));
109 return ret;
110 };
111 }
112 // end of FIXME
113
114private:
116 Property<size_t> m_seed{this, "seed", "Random seed for the internal random engine"};
117 Property<size_t> m_cache_size{this, "cacheSize", 1024, "Cache size for each generator instance"};
118 std::mutex m_mutex;
119
121};
122
123} // namespace algorithms
Float gaussian(const Float mu=Float{0}, const Float sigma=Float{1}) const
Definition random.h:52
Float exponential(const Float lambda=Float{1}) const
Definition random.h:47
Float uniform_double(const Float min=Float{0}, const Float max=Float{1}) const
Definition random.h:37
Generator(const RandomEngineCB &gen, const size_t cache_size)
Definition random.h:30
Int uniform_int(const Int min=Int{0}, const Int max=Int{1}) const
Definition random.h:32
Int poisson(const double mean=1.) const
Definition random.h:42
LoggedService(std::string_view name)
Definition logger.h:273
static std::ostream & endmsg(std::ostream &os)
Definition logger.h:244
detail::LoggerStream warning() const
Definition logger.h:197
detail::LoggerStream info() const
Definition logger.h:198
Generator generator()
Definition random.h:71
void init(const RandomEngineCB &gen)
Definition random.h:83
detail::CachedBitGenerator::result_type value_type
Definition random.h:69
RandomEngineCB createEngine(const size_t seed=1)
Definition random.h:96
std::function< std::vector< result_type >(size_t)> GenFunc
Definition random.h:21
#define ALGORITHMS_DEFINE_LOGGED_SERVICE(className)
Definition logger.h:278
detail::CachedBitGenerator::GenFunc RandomEngineCB
Definition random.h:24