alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
PhiloxSingle.hpp
Go to the documentation of this file.
1/* Copyright 2022 Jiri Vyskocil, Rene Widera, Bernhard Manfred Gruber
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5#pragma once
6
9
10#include <utility>
11
13{
14
15
16 /** Philox engine generating a single number
17 *
18 * This engine's operator() will return a single number. Since the result is the same size as the counter,
19 * and so it contains more than one number, it has to be stored between individual invocations of
20 * operator(). Additionally a pointer has to be stored indicating which part of the result array is to be
21 * returned next.
22 *
23 * @tparam TParams Basic parameters for the Philox algorithm
24 */
25 template<typename TParams>
26 class PhiloxSingle : public PhiloxBaseCommon<TParams, PhiloxSingle<TParams>>
27 {
28 public:
30
31 /// Counter type
32 using Counter = typename Base::Counter;
33 /// Key type
34 using Key = typename Base::Key;
36
37
38 protected:
39 /** Advance internal counter to the next value
40 *
41 * Advances the full internal counter array, resets the position pointer and stores the intermediate
42 * result to be recalled when the user requests a number.
43 */
44 constexpr void advanceState()
45 {
46 this->advanceCounter(this->state.counter);
47 this->state.result = this->nRounds(this->state.counter, this->state.key);
48 this->state.position = 0;
49 }
50
51 /** Get the next random number and advance internal state
52 *
53 * The intermediate result stores N = TParams::counterSize numbers. Check if we've already given out
54 * all of them. If so, generate a new intermediate result (this also resets the pointer to the position
55 * of the actual number). Finally, we return the actual number.
56 *
57 * @return The next random number
58 */
59 constexpr auto nextNumber()
60 {
61 // Element zero will always contain the next valid random number.
62 auto result = this->state.result[0];
63 ++this->state.position;
64 if(this->state.position == TParams::counterSize)
65 {
67 }
68 else
69 {
70 /* Shift state results to allow hard coded access to element zero.
71 * This will avoid high register usage on NVIDIA devices.
72 * @todo Check if this shifting of the result vector is decreasing CPU performance.
73 * If so this optimization for GPUs (mostly NVIDIA/AMD) should be made optional.
74 */
75 this->state.result[0] = this->state.result[1];
76 this->state.result[1] = this->state.result[2];
77 this->state.result[2] = this->state.result[3];
78 }
79
80 return result;
81 }
82
83 /// Skips the next \a offset numbers
84 constexpr void skip(uint64_t offset)
85 {
86 static_assert(TParams::counterSize == 4, "Only counterSize is supported.");
87 this->state.position = static_cast<decltype(this->state.position)>(this->state.position + (offset & 3));
88 offset += this->state.position < 4 ? 0 : 4;
89 this->state.position -= this->state.position < 4 ? 0 : 4u;
90 for(auto numShifts = this->state.position; numShifts > 0; --numShifts)
91 {
92 // Shift state results to allow hard coded access to element zero.
93 // This will avoid high register usage on NVIDIA devices.
94 this->state.result[0] = this->state.result[1];
95 this->state.result[1] = this->state.result[2];
96 this->state.result[2] = this->state.result[3];
97 }
98 this->skip4(offset / 4);
99 }
100
101 public:
102 /** Construct a new Philox engine with single-value output
103 *
104 * @param seed Set the Philox generator key
105 * @param subsequence Select a subsequence of size 2^64
106 * @param offset Skip \a offset numbers form the start of the subsequence
107 */
108 constexpr PhiloxSingle(uint64_t seed = 0, uint64_t subsequence = 0, uint64_t offset = 0)
109 : Base(State{{0, 0, 0, 0}, {low32Bits(seed), high32Bits(seed)}, {0, 0, 0, 0}, 0u})
110 {
111 this->skipSubsequence(subsequence);
112 skip(offset);
113 advanceState();
114 }
115
116 /** Get the next random number
117 *
118 * @return The next random number
119 */
120 constexpr auto operator()()
121 {
122 return nextNumber();
123 }
124 };
125} // namespace alpaka::rand::engine::internal
typename PhiloxStateless< T_Params >::Counter Counter
typename PhiloxStateless< T_Params >::Key Key
constexpr void skip(uint64_t offset)
Skips the next offset numbers.
constexpr PhiloxSingle(uint64_t seed=0, uint64_t subsequence=0, uint64_t offset=0)
Construct a new Philox engine with single-value output.
constexpr auto nextNumber()
Get the next random number and advance internal state.
constexpr void advanceState()
Advance internal counter to the next value.
constexpr auto operator()()
Get the next random number.
PhiloxBaseCommon< EngineParams, PhiloxSingle< EngineParams > > Base
PhiloxState< Counter, Key, PhiloxSingle< EngineParams > > State
static constexpr auto nRounds(Counter const &counter_in, Key const &key_in) -> Counter
Performs N rounds of the Philox shuffle.
constexpr auto low32Bits(std::uint64_t const x) -> std::uint32_t
Get low 32 bits of a 64-bit number.
constexpr auto high32Bits(std::uint64_t const x) -> std::uint32_t
Get high 32 bits of a 64-bit number.