File indexing completed on 2025-09-14 08:50:58
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Assert.hh"
0010 #include "corecel/Types.hh"
0011 #include "corecel/cont/Array.hh"
0012 #include "corecel/math/NumericLimits.hh"
0013 #include "corecel/random/distribution/GenerateCanonical.hh"
0014 #include "corecel/random/distribution/detail/GenerateCanonical32.hh"
0015
0016 namespace celeritas
0017 {
0018
0019
0020
0021
0022 template<class Engine, size_type N>
0023 class CachedRngEngine
0024 {
0025 static_assert(N > 0);
0026
0027 public:
0028
0029
0030 using result_type = typename Engine::result_type;
0031
0032
0033 public:
0034
0035 static CELER_CONSTEXPR_FUNCTION result_type min() { return Engine::min(); }
0036
0037 static CELER_CONSTEXPR_FUNCTION result_type max() { return Engine::max(); }
0038
0039
0040 inline CELER_FUNCTION CachedRngEngine(Engine& e);
0041
0042
0043 inline CELER_FUNCTION result_type operator()();
0044
0045
0046 static CELER_CONSTEXPR_FUNCTION size_type size() { return N; }
0047
0048
0049 CELER_CONSTEXPR_FUNCTION size_type remaining() const { return N - next_; }
0050
0051 private:
0052
0053
0054 Array<result_type, N> stored_;
0055 size_type next_{0};
0056 };
0057
0058
0059
0060
0061
0062
0063
0064 template<size_type N, class Engine>
0065 inline CELER_FUNCTION auto cache_rng_count(Engine& e)
0066 {
0067 return CachedRngEngine<Engine, N>{e};
0068 }
0069
0070
0071
0072
0073
0074 template<class T, size_type Count, class Engine>
0075 inline CELER_FUNCTION auto cache_rng_values(Engine& e)
0076 {
0077
0078
0079 using result_type = typename Engine::result_type;
0080 static_assert(sizeof(result_type) == 4 || sizeof(result_type) == 8,
0081 "only implemented for 32- and 64-bit integers");
0082 constexpr size_type bytes_entropy
0083 = sizeof(result_type) == 4 ? 4
0084 : Engine::max() <= numeric_limits<unsigned>::max() ? sizeof(unsigned)
0085 : Engine::max() <= numeric_limits<unsigned long long>::max()
0086 ? sizeof(unsigned long long)
0087 : 0;
0088 return CachedRngEngine<Engine, Count * sizeof(T) / bytes_entropy>{e};
0089 }
0090
0091
0092
0093
0094
0095
0096
0097 template<class Engine, size_type Bytes>
0098 CELER_FUNCTION CachedRngEngine<Engine, Bytes>::CachedRngEngine(Engine& rng)
0099 {
0100 for (result_type& entry : stored_)
0101 {
0102 entry = rng();
0103 }
0104 }
0105
0106
0107
0108
0109
0110 template<class Engine, size_type Bytes>
0111 CELER_FUNCTION auto CachedRngEngine<Engine, Bytes>::operator()() -> result_type
0112 {
0113 CELER_EXPECT(this->remaining() != 0);
0114 return stored_[next_++];
0115 }
0116
0117
0118
0119
0120
0121
0122
0123 template<class Engine, size_type Bytes, class RealType>
0124 struct GenerateCanonical<CachedRngEngine<Engine, Bytes>, RealType>
0125 {
0126
0127
0128 using real_type = RealType;
0129 using result_type = RealType;
0130 using argument_type = CachedRngEngine<Engine, Bytes>;
0131
0132
0133
0134 static constexpr auto policy = GenerateCanonical<Engine>::policy;
0135
0136
0137 CELER_FORCEINLINE_FUNCTION result_type operator()(argument_type& rng)
0138 {
0139 if constexpr (policy == GenerateCanonicalPolicy::builtin32)
0140 {
0141 return detail::GenerateCanonical32<RealType>()(rng);
0142 }
0143 else if constexpr (policy == GenerateCanonicalPolicy::std)
0144 {
0145 #ifndef CELER_DEVICE_SOURCE
0146 using limits_t = std::numeric_limits<result_type>;
0147 return std::generate_canonical<result_type, limits_t::digits>(rng);
0148 #else
0149 CELER_ASSERT_UNREACHABLE();
0150 #endif
0151 }
0152 else
0153 {
0154 CELER_NOT_IMPLEMENTED("Custom sampling for cached RNG engine");
0155 }
0156 }
0157 };
0158
0159
0160 }