Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-30 07:53:48

0001 #pragma once
0002 
0003 #include <algorithm>
0004 #include <cstdint>
0005 #include <functional>
0006 #include <mutex>
0007 #include <random>
0008 
0009 #include <algorithms/detail/random.h>
0010 #include <algorithms/logger.h>
0011 #include <algorithms/service.h>
0012 
0013 namespace algorithms {
0014 
0015 // Random Engine callback function:
0016 //   - Signature: std::function<std::vector<value_type>(size_t N)> --> generates a vector
0017 //     of N numbers
0018 //   - RandomEngineCB is required to return N random numbers between 0 and
0019 //     std::numeric_limits<uint_fast64_t>::max()
0020 //   - RandomEngineCB is responsible to deal with possible simultaneous access by multiple
0021 //     Generator instances (required to be thread-safe).
0022 using RandomEngineCB = detail::CachedBitGenerator::GenFunc;
0023 
0024 // thread-safe generator front-end. Requires that the underlying random engine used by
0025 // the RandomSvc is thread-safe.
0026 class Generator {
0027 public:
0028   Generator(const RandomEngineCB& gen, const size_t cache_size) : m_gen{gen, cache_size} {}
0029 
0030   template <class Int = int> Int uniform_int(const Int min, const Int max) const {
0031     std::uniform_int_distribution<Int> d{min, max};
0032     std::lock_guard<std::mutex> lock{m_mutex};
0033     return d(m_gen);
0034   }
0035   template <class Float = double> Float uniform_double(const Float min, const Float max) const {
0036     std::uniform_real_distribution<Float> d{min, max};
0037     std::lock_guard<std::mutex> lock{m_mutex};
0038     return d(m_gen);
0039   }
0040   template <class Int = int> Int poisson(const Int mean) const {
0041     std::poisson_distribution<Int> d{mean};
0042     std::lock_guard<std::mutex> lock{m_mutex};
0043     return d(m_gen);
0044   }
0045   template <class Float = double> Float exponential(const Float lambda) const {
0046     std::exponential_distribution<Float> d{lambda};
0047     std::lock_guard<std::mutex> lock{m_mutex};
0048     return d(m_gen);
0049   }
0050   template <class Float = double> Float gaussian(const Float mu, const Float sigma) const {
0051     std::normal_distribution<Float> d{mu, sigma};
0052     std::lock_guard<std::mutex> lock{m_mutex};
0053     return d(m_gen);
0054   }
0055 
0056 private:
0057   mutable detail::CachedBitGenerator m_gen;
0058   mutable std::mutex m_mutex;
0059 };
0060 
0061 // Random service that creates multiple Generators that are linked to a single random
0062 // engine. The Generators are safe to be used in parallel as long as the Engine itself is
0063 // thread-safe (this is a hard requirement for MT). The Generators avoid unnecesary locking
0064 // by running off a auto-refreshing cached random sequence.
0065 class RandomSvc : public LoggedService<RandomSvc> {
0066 public:
0067   using value_type = detail::CachedBitGenerator::result_type;
0068 
0069   Generator generator() { return {m_gen, m_cache_size}; }
0070 // FIXME fix the CMake setup so these are properly found in Gaudi
0071 #if 0 
0072   void init();
0073   void init(const RandomEngineCB& gen);
0074 #endif
0075   void init() {
0076     if (m_seed.hasValue()) {
0077       info() << "Custom random seed requested: " << m_seed << endmsg;
0078       m_gen = createEngine(m_seed);
0079     }
0080   }
0081   void init(const RandomEngineCB& gen) {
0082     info() << "Loading external generator function." << endmsg;
0083     m_gen = gen;
0084     if (m_seed.hasValue()) {
0085       warning() << "Custom random seed request ignored when using external generator function"
0086                 << endmsg;
0087     }
0088   }
0089 
0090 #if 0
0091 private:
0092   RandomEngineCB createEngine(const size_t seed = 1);
0093 #endif
0094   RandomEngineCB createEngine(const size_t seed = 1) {
0095     return [=](const size_t size) {
0096       static std::mutex m;
0097       static std::mt19937_64 gen{seed};
0098       std::lock_guard<std::mutex> lock{m};
0099       std::vector<value_type> ret(size);
0100       std::generate(ret.begin(), ret.end(), gen);
0101       return ret;
0102     };
0103   }
0104   // end of FIXME
0105 
0106 private:
0107   RandomEngineCB m_gen{createEngine()};
0108   Property<size_t> m_seed{this, "seed", "Random seed for the internal random engine"};
0109   Property<size_t> m_cache_size{this, "cacheSize", 1024, "Cache size for each generator instance"};
0110   std::mutex m_mutex;
0111 
0112   ALGORITHMS_DEFINE_LOGGED_SERVICE(RandomSvc)
0113 };
0114 
0115 } // namespace algorithms