Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-14 08:50:58

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file corecel/random/engine/CachedRngEngine.hh
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  * Store several PRNG engine results and return them.
0021  */
0022 template<class Engine, size_type N>
0023 class CachedRngEngine
0024 {
0025     static_assert(N > 0);
0026 
0027   public:
0028     //!@{
0029     //! \name Type aliases
0030     using result_type = typename Engine::result_type;
0031     //!@}
0032 
0033   public:
0034     //! Lowest value potentially generated
0035     static CELER_CONSTEXPR_FUNCTION result_type min() { return Engine::min(); }
0036     //! Highest value potentially generated
0037     static CELER_CONSTEXPR_FUNCTION result_type max() { return Engine::max(); }
0038 
0039     // Save values on construction
0040     inline CELER_FUNCTION CachedRngEngine(Engine& e);
0041 
0042     // Return the next pseudorandom number in the sequence
0043     inline CELER_FUNCTION result_type operator()();
0044 
0045     //! Get the total number of stored samples
0046     static CELER_CONSTEXPR_FUNCTION size_type size() { return N; }
0047 
0048     //! Get the number of remaining samples
0049     CELER_CONSTEXPR_FUNCTION size_type remaining() const { return N - next_; }
0050 
0051   private:
0052     /// DATA ///
0053 
0054     Array<result_type, N> stored_;
0055     size_type next_{0};
0056 };
0057 
0058 //---------------------------------------------------------------------------//
0059 // FREE FUNCTIONS
0060 //---------------------------------------------------------------------------//
0061 /*!
0062  * Return an RNG with the given number of calls cached.
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  * Return an RNG with enough space to return Count of type T.
0073  */
0074 template<class T, size_type Count, class Engine>
0075 inline CELER_FUNCTION auto cache_rng_values(Engine& e)
0076 {
0077     // Account for the fact that some implementations use 64-bit integers for
0078     // RNGs that have return 32 bits of entropy
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 // INLINE DEFINITIONS
0093 //---------------------------------------------------------------------------//
0094 /*!
0095  * Save values on construction.
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  * Return the next pseudorandom number in the sequence.
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 // SPECIALIZATIONS
0119 //---------------------------------------------------------------------------//
0120 /*!
0121  * Specialization of GenerateCanonical for cached engine.
0122  */
0123 template<class Engine, size_type Bytes, class RealType>
0124 struct GenerateCanonical<CachedRngEngine<Engine, Bytes>, RealType>
0125 {
0126     //!@{
0127     //! \name Type aliases
0128     using real_type = RealType;
0129     using result_type = RealType;
0130     using argument_type = CachedRngEngine<Engine, Bytes>;
0131     //!@}
0132 
0133     // Decide what policy to use
0134     static constexpr auto policy = GenerateCanonical<Engine>::policy;
0135 
0136     //! Sample a random number on [0, 1)
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 }  // namespace celeritas