File indexing completed on 2026-09-24 08:38:55
0001 #pragma once
0002
0003 #include <algorithm>
0004 #include <concepts>
0005 #include <cstdint>
0006 #include <functional>
0007 #include <mutex>
0008 #include <random>
0009
0010 #include <algorithms/detail/random.h>
0011 #include <algorithms/logger.h>
0012 #include <algorithms/service.h>
0013
0014 namespace algorithms {
0015
0016
0017
0018
0019
0020
0021
0022
0023 using RandomEngineCB = detail::CachedBitGenerator::GenFunc;
0024
0025
0026
0027 class Generator {
0028 public:
0029 Generator(const RandomEngineCB& gen, const size_t cache_size) : m_gen{gen, cache_size} {}
0030
0031 template <std::integral Int = int> Int uniform_int(const Int min = Int{0}, const Int max = Int{1}) const {
0032 std::uniform_int_distribution<Int> d{min, max};
0033 std::lock_guard<std::mutex> lock{m_mutex};
0034 return d(m_gen);
0035 }
0036 template <std::floating_point Float = double> Float uniform_double(const Float min = Float{0}, const Float max = Float{1}) const {
0037 std::uniform_real_distribution<Float> d{min, max};
0038 std::lock_guard<std::mutex> lock{m_mutex};
0039 return d(m_gen);
0040 }
0041 template <std::integral Int = int> Int poisson(const Int mean = Int{1}) const {
0042 std::poisson_distribution<Int> d{mean};
0043 std::lock_guard<std::mutex> lock{m_mutex};
0044 return d(m_gen);
0045 }
0046 template <std::floating_point Float = double> Float exponential(const Float lambda = Float{1}) const {
0047 std::exponential_distribution<Float> d{lambda};
0048 std::lock_guard<std::mutex> lock{m_mutex};
0049 return d(m_gen);
0050 }
0051 template <std::floating_point Float = double> Float gaussian(const Float mu = Float{0}, const Float sigma = Float{1}) const {
0052 std::normal_distribution<Float> d{mu, sigma};
0053 std::lock_guard<std::mutex> lock{m_mutex};
0054 return d(m_gen);
0055 }
0056
0057 private:
0058 mutable detail::CachedBitGenerator m_gen;
0059 mutable std::mutex m_mutex;
0060 };
0061
0062
0063
0064
0065
0066 class RandomSvc : public LoggedService<RandomSvc> {
0067 public:
0068 using value_type = detail::CachedBitGenerator::result_type;
0069
0070 Generator generator() { return {m_gen, m_cache_size}; }
0071
0072 #if 0
0073 void init();
0074 void init(const RandomEngineCB& gen);
0075 #endif
0076 void init() {
0077 if (m_seed.hasValue()) {
0078 info() << "Custom random seed requested: " << m_seed << endmsg;
0079 m_gen = createEngine(m_seed);
0080 }
0081 }
0082 void init(const RandomEngineCB& gen) {
0083 info() << "Loading external generator function." << endmsg;
0084 m_gen = gen;
0085 if (m_seed.hasValue()) {
0086 warning() << "Custom random seed request ignored when using external generator function"
0087 << endmsg;
0088 }
0089 }
0090
0091 #if 0
0092 private:
0093 RandomEngineCB createEngine(const size_t seed = 1);
0094 #endif
0095 RandomEngineCB createEngine(const size_t seed = 1) {
0096 return [=](const size_t size) {
0097 static std::mutex m;
0098 static std::mt19937_64 gen{seed};
0099 std::lock_guard<std::mutex> lock{m};
0100 std::vector<value_type> ret(size);
0101 std::generate(ret.begin(), ret.end(), gen);
0102 return ret;
0103 };
0104 }
0105
0106
0107 private:
0108 RandomEngineCB m_gen{createEngine()};
0109 Property<size_t> m_seed{this, "seed", "Random seed for the internal random engine"};
0110 Property<size_t> m_cache_size{this, "cacheSize", 1024, "Cache size for each generator instance"};
0111 std::mutex m_mutex;
0112
0113 ALGORITHMS_DEFINE_LOGGED_SERVICE(RandomSvc)
0114 };
0115
0116 }