cMHN 1.2
C++ library for learning MHNs with pRC
Loading...
Searching...
No Matches
threefry.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-2-Clause
2
3// References:
4// Authors: John K. Salmon, Mark A. Moraes, Ron O. Dror, David E. Shaw
5// Title: Parallel Random Numbers: As Easy as 1, 2, 3
6// Year: 2011
7// URL: https://doi.org/10.1145/2063384.2063405
8
9#ifndef pRC_CORE_RANDOM_ENGINES_THREEFRY_H
10#define pRC_CORE_RANDOM_ENGINES_THREEFRY_H
11
17
18namespace pRC
19{
20 template<Size Rounds, class U = Seed>
21 class Threefry : public RandomEngine<Threefry<Rounds, U>>
22 {
23 public:
24 using Type = U;
25
26 static constexpr auto min()
27 {
28 return NumericLimits<U>::min();
29 }
30
31 static constexpr auto max()
32 {
33 return NumericLimits<U>::max();
34 }
35
36 static constexpr auto samplesPerBlock()
37 {
38 return 32 / sizeof(U);
39 }
40
41 public:
42 ~Threefry() = default;
43 constexpr Threefry(Threefry &&) = default;
44 constexpr Threefry &operator=(Threefry const &) & = default;
45 constexpr Threefry &operator=(Threefry &&) & = default;
46 constexpr Threefry(Threefry const &) = default;
47
49 {
50 seed();
51 }
52
53 template<Size S>
55 {
56 seed(seq);
57 }
58
59 constexpr void seed()
60 {
61 seed(SeedSequence<0>().generate<8>());
62 }
63
64 template<Size S>
65 constexpr void seed(SeedSequence<S> const &seq)
66 {
67 seed(seq.template generate<8>());
68 }
69
70 constexpr U operator()()
71 {
72 ++mChunkCounter;
73 mChunkCounter %= samplesPerBlock();
74
75 if(mChunkCounter == 0)
76 {
77 incrementCounter();
78 encryptCounter();
79 }
80
81 return reinterpret_cast<U const *>(mCipher.data())[mChunkCounter];
82 }
83
84 constexpr void discard(std::uint64_t z)
85 {
86 if(z < samplesPerBlock() - mChunkCounter)
87 {
88 mChunkCounter += z;
89 return;
90 }
91
92 z -= samplesPerBlock() - mChunkCounter;
93 mChunkCounter = z % samplesPerBlock();
94
95 z -= mChunkCounter;
96 z /= samplesPerBlock();
97
98 incrementCounter(++z);
99 encryptCounter();
100 }
101
102 constexpr void advance(std::uint64_t const z)
103 {
104 if(z > NumericLimits<std::uint64_t>::max() - mCounter[1])
105 {
106 ++mCounter[2];
107 if(mCounter[2] == 0)
108 {
109 ++mCounter[3];
110 }
111 }
112 mCounter[1] += z;
113
114 encryptCounter();
115 }
116
117 constexpr auto operator==(const Threefry &rhs)
118 {
119 if(mChunkCounter != rhs.mChunkCounter)
120 {
121 return false;
122 }
123
124 for(Index i = 0; i < 4U; ++i)
125 {
126 if(mCounter[i] != rhs.mCounter[i])
127 {
128 return false;
129 }
130 if(mKey[i] != rhs.mKey[i])
131 {
132 return false;
133 }
134 if(mCipher[i] != rhs.mCipher[i])
135 {
136 return false;
137 }
138 }
139 return true;
140 }
141
142 constexpr auto operator!=(const Threefry &rhs)
143 {
144 return !(*this == rhs);
145 }
146
147 private:
148 constexpr void seed(StackArray<Seed, 8> const &seq)
149 {
150 for(Index i = 0; i < 4U; ++i)
151 {
152 mKey[i] = (static_cast<std::uint64_t>(seq[2 * i]) << 32) |
153 seq[2 * i + 1];
154 }
155 mKey[4] =
156 0x1BD11BDAA9FC1A22 ^ mKey[0] ^ mKey[1] ^ mKey[2] ^ mKey[3];
157
158 resetCounter();
159 encryptCounter();
160 }
161
162 constexpr void resetCounter()
163 {
164 for(Index i = 0; i < 4U; ++i)
165 {
166 mCounter[i] = 0;
167 }
168 mChunkCounter = 0;
169 }
170
171 constexpr void incrementCounter()
172 {
173 ++mCounter[0];
174 if(mCounter[0] != 0)
175 {
176 return;
177 }
178
179 ++mCounter[1];
180 if(mCounter[1] != 0)
181 {
182 return;
183 }
184
185 ++mCounter[2];
186 if(mCounter[2] != 0)
187 {
188 return;
189 }
190
191 ++mCounter[3];
192 }
193
194 constexpr void incrementCounter(std::uint64_t const z)
195 {
196 if(z > NumericLimits<std::uint64_t>::max() - mCounter[0])
197 {
198 ++mCounter[1];
199 if(mCounter[1] == 0)
200 {
201 ++mCounter[2];
202 if(mCounter[2] == 0)
203 {
204 ++mCounter[3];
205 }
206 }
207 }
208 mCounter[0] += z;
209 }
210
211 constexpr void encryptCounter()
212 {
213 auto const mix = [](auto &x, auto &y, std::uint8_t const bits)
214 {
215 x += y;
216 y = bitRotateLeft(y, bits);
217 y ^= x;
218 };
219
220 auto const add = [](auto &cipher, auto const &key,
221 auto const offset, auto const cycle)
222 {
223 range<4>(
224 [&cipher, &key, &offset](auto const i)
225 {
226 cipher[i] += key[(offset + i) % 5];
227 });
228
229 cipher[3] += cycle;
230 };
231
232 range<4>(
233 [this](auto const i)
234 {
235 mCipher[i] = mCounter[i];
236 });
237
238 range<4>(
239 [this](auto const i)
240 {
241 mCipher[i] += mKey[i];
242 });
243
244 Size cycle = 0;
245
247 [this, &mix, &add, &cycle](auto const i)
248 {
249 if(i % 8 == 0)
250 {
251 mix(mCipher[0], mCipher[1], 14U);
252 mix(mCipher[2], mCipher[3], 16U);
253 }
254
255 if(i % 8 == 1)
256 {
257 mix(mCipher[0], mCipher[3], 52U);
258 mix(mCipher[2], mCipher[1], 57U);
259 }
260
261 if(i % 8 == 2)
262 {
263 mix(mCipher[0], mCipher[1], 23U);
264 mix(mCipher[2], mCipher[3], 40U);
265 }
266
267 if(i % 8 == 3)
268 {
269 mix(mCipher[0], mCipher[3], 5U);
270 mix(mCipher[2], mCipher[1], 37U);
271 add(mCipher, mKey, (i + 1) / 4, ++cycle);
272 }
273
274 if(i % 8 == 4)
275 {
276 mix(mCipher[0], mCipher[1], 25U);
277 mix(mCipher[2], mCipher[3], 33U);
278 }
279
280 if(i % 8 == 5)
281 {
282 mix(mCipher[0], mCipher[3], 46U);
283 mix(mCipher[2], mCipher[1], 12U);
284 }
285
286 if(i % 8 == 6)
287 {
288 mix(mCipher[0], mCipher[1], 58U);
289 mix(mCipher[2], mCipher[3], 22U);
290 }
291
292 if(i % 8 == 7)
293 {
294 mix(mCipher[0], mCipher[3], 32U);
295 mix(mCipher[2], mCipher[1], 32U);
296 add(mCipher, mKey, (i + 1) / 4, ++cycle);
297 }
298 });
299 }
300
301 private:
305 std::uint8_t mChunkCounter;
306 };
307}
308#endif // pRC_CORE_RANDOM_ENGINES_THREEFRY_H
Definition declarations.hpp:12
Definition engine.hpp:13
Definition seq.hpp:13
Definition threefry.hpp:22
constexpr void discard(std::uint64_t z)
Definition threefry.hpp:84
constexpr auto operator!=(const Threefry &rhs)
Definition threefry.hpp:142
constexpr Threefry & operator=(Threefry const &) &=default
constexpr Threefry & operator=(Threefry &&) &=default
constexpr Threefry(Threefry &&)=default
static constexpr auto max()
Definition threefry.hpp:31
constexpr void seed()
Definition threefry.hpp:59
constexpr void seed(SeedSequence< S > const &seq)
Definition threefry.hpp:65
Threefry(SeedSequence< S > const &seq)
Definition threefry.hpp:54
~Threefry()=default
constexpr auto operator==(const Threefry &rhs)
Definition threefry.hpp:117
static constexpr auto min()
Definition threefry.hpp:26
U Type
Definition threefry.hpp:24
constexpr Threefry(Threefry const &)=default
static constexpr auto samplesPerBlock()
Definition threefry.hpp:36
constexpr void advance(std::uint64_t const z)
Definition threefry.hpp:102
Threefry()
Definition threefry.hpp:48
constexpr U operator()()
Definition threefry.hpp:70
int i
Definition gmock-matchers-comparisons_test.cc:603
Uncopyable z
Definition gmock-matchers-containers_test.cc:378
const double y
Definition gmock-matchers-containers_test.cc:377
int x
Definition gmock-matchers-containers_test.cc:376
Definition cholesky.hpp:10
Size Index
Definition basics.hpp:32
std::size_t Size
Definition basics.hpp:31
static constexpr auto bitRotateLeft(TA const value, TB count)
Definition bit_rotate_left.hpp:12
CommonArray< Allocation::Stack, T, Ns... > StackArray
Definition declarations.hpp:15
static constexpr auto range(F &&f, Xs &&...args)
Definition range.hpp:18
Definition limits.hpp:13