pRC
multi-purpose Tensor Train library for C++
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_THREEFRY_H
10#define pRC_CORE_RANDOM_THREEFRY_H
11
19
20namespace pRC
21{
22 template<Size Rounds, class U>
24 {
25 public:
26 using result_type = U;
27
28 public:
29 static constexpr auto min()
30 {
31 return NumericLimits<U>::min();
32 }
33 static constexpr auto max()
34 {
35 return NumericLimits<U>::max();
36 }
37
38 static constexpr auto samplesPerBlock()
39 {
40 return 32 / sizeof(U);
41 }
42
43 public:
44 ~Threefry() = default;
45 constexpr Threefry(Threefry &&) = default;
46 constexpr Threefry &operator=(Threefry const &) & = default;
47 constexpr Threefry &operator=(Threefry &&) & = default;
48 constexpr Threefry(Threefry const &) = default;
49
51 {
52 seed();
53 }
54
55 template<Size S>
57 {
58 seed(seq);
59 }
60
61 constexpr void seed()
62 {
64 }
65
66 template<Size S>
67 constexpr void seed(SeedSequence<S> const &seq)
68 {
69 seed(seq.template generate<8>());
70 }
71
72 constexpr U operator()()
73 {
74 ++mChunkCounter;
75 mChunkCounter %= samplesPerBlock();
76
77 if(mChunkCounter == 0)
78 {
79 incrementCounter();
80 encryptCounter();
81 }
82
83 return reinterpret_cast<U const *>(mCipher.data())[mChunkCounter];
84 }
85
86 constexpr void discard(std::uint64_t z)
87 {
88 if(z < samplesPerBlock() - mChunkCounter)
89 {
90 mChunkCounter += z;
91 return;
92 }
93
94 z -= samplesPerBlock() - mChunkCounter;
95 mChunkCounter = z % samplesPerBlock();
96
97 z -= mChunkCounter;
98 z /= samplesPerBlock();
99
100 incrementCounter(++z);
101 encryptCounter();
102 }
103
104 constexpr void advance(std::uint64_t const z)
105 {
106 if(z > NumericLimits<std::uint64_t>::max() - mCounter[1])
107 {
108 ++mCounter[2];
109 if(mCounter[2] == 0)
110 {
111 ++mCounter[3];
112 }
113 }
114 mCounter[1] += z;
115
116 encryptCounter();
117 }
118
119 constexpr auto operator==(const Threefry &rhs)
120 {
121 if(mChunkCounter != rhs.mChunkCounter)
122 {
123 return false;
124 }
125
126 for(Index i = 0; i < 4U; ++i)
127 {
128 if(mCounter[i] != rhs.mCounter[i])
129 {
130 return false;
131 }
132 if(mKey[i] != rhs.mKey[i])
133 {
134 return false;
135 }
136 if(mCipher[i] != rhs.mCipher[i])
137 {
138 return false;
139 }
140 }
141 return true;
142 }
143
144 constexpr auto operator!=(const Threefry &rhs)
145 {
146 return !(*this == rhs);
147 }
148
149 private:
150 constexpr void seed(StackArray<Seed, 8> const &seq)
151 {
152 for(Index i = 0; i < 4U; ++i)
153 {
154 mKey[i] = (static_cast<std::uint64_t>(seq[2 * i]) << 32) |
155 seq[2 * i + 1];
156 }
157 mKey[4] =
158 0x1BD11BDAA9FC1A22 ^ mKey[0] ^ mKey[1] ^ mKey[2] ^ mKey[3];
159
160 resetCounter();
161 encryptCounter();
162 }
163
164 constexpr void resetCounter()
165 {
166 for(Index i = 0; i < 4U; ++i)
167 {
168 mCounter[i] = 0;
169 }
170 mChunkCounter = 0;
171 }
172
173 constexpr void incrementCounter()
174 {
175 ++mCounter[0];
176 if(mCounter[0] != 0)
177 {
178 return;
179 }
180
181 ++mCounter[1];
182 if(mCounter[1] != 0)
183 {
184 return;
185 }
186
187 ++mCounter[2];
188 if(mCounter[2] != 0)
189 {
190 return;
191 }
192
193 ++mCounter[3];
194 }
195
196 constexpr void incrementCounter(std::uint64_t const z)
197 {
198 if(z > NumericLimits<std::uint64_t>::max() - mCounter[0])
199 {
200 ++mCounter[1];
201 if(mCounter[1] == 0)
202 {
203 ++mCounter[2];
204 if(mCounter[2] == 0)
205 {
206 ++mCounter[3];
207 }
208 }
209 }
210 mCounter[0] += z;
211 }
212
213 constexpr void encryptCounter()
214 {
215 auto const mix = [](auto &x, auto &y, std::uint8_t const bits)
216 {
217 x += y;
218 y = bitRotateLeft(y, bits);
219 y ^= x;
220 };
221
222 auto const add = [](auto &cipher, auto const &key,
223 auto const offset, auto const cycle)
224 {
225 range<4>(
226 [&cipher, &key, &offset](auto const i)
227 {
228 cipher[i] += key[(offset + i) % 5];
229 });
230
231 cipher[3] += cycle;
232 };
233
234 range<4>(
235 [this](auto const i)
236 {
237 mCipher[i] = mCounter[i];
238 });
239
240 range<4>(
241 [this](auto const i)
242 {
243 mCipher[i] += mKey[i];
244 });
245
246 Size cycle = 0;
247
249 [this, &mix, &add, &cycle](auto const i)
250 {
251 if(i % 8 == 0)
252 {
253 mix(mCipher[0], mCipher[1], 14U);
254 mix(mCipher[2], mCipher[3], 16U);
255 }
256
257 if(i % 8 == 1)
258 {
259 mix(mCipher[0], mCipher[3], 52U);
260 mix(mCipher[2], mCipher[1], 57U);
261 }
262
263 if(i % 8 == 2)
264 {
265 mix(mCipher[0], mCipher[1], 23U);
266 mix(mCipher[2], mCipher[3], 40U);
267 }
268
269 if(i % 8 == 3)
270 {
271 mix(mCipher[0], mCipher[3], 5U);
272 mix(mCipher[2], mCipher[1], 37U);
273 add(mCipher, mKey, (i + 1) / 4, ++cycle);
274 }
275
276 if(i % 8 == 4)
277 {
278 mix(mCipher[0], mCipher[1], 25U);
279 mix(mCipher[2], mCipher[3], 33U);
280 }
281
282 if(i % 8 == 5)
283 {
284 mix(mCipher[0], mCipher[3], 46U);
285 mix(mCipher[2], mCipher[1], 12U);
286 }
287
288 if(i % 8 == 6)
289 {
290 mix(mCipher[0], mCipher[1], 58U);
291 mix(mCipher[2], mCipher[3], 22U);
292 }
293
294 if(i % 8 == 7)
295 {
296 mix(mCipher[0], mCipher[3], 32U);
297 mix(mCipher[2], mCipher[1], 32U);
298 add(mCipher, mKey, (i + 1) / 4, ++cycle);
299 }
300 });
301 }
302
303 private:
307 std::uint8_t mChunkCounter;
308 };
309}
310#endif // pRC_CORE_RANDOM_THREEFRY_H
Definition type_traits.hpp:49
Definition seq.hpp:13
Definition threefry.hpp:24
U result_type
Definition threefry.hpp:26
constexpr void discard(std::uint64_t z)
Definition threefry.hpp:86
constexpr auto operator!=(const Threefry &rhs)
Definition threefry.hpp:144
constexpr Threefry & operator=(Threefry const &) &=default
constexpr Threefry & operator=(Threefry &&) &=default
constexpr Threefry(Threefry &&)=default
static constexpr auto max()
Definition threefry.hpp:33
constexpr void seed()
Definition threefry.hpp:61
constexpr void seed(SeedSequence< S > const &seq)
Definition threefry.hpp:67
Threefry(SeedSequence< S > const &seq)
Definition threefry.hpp:56
~Threefry()=default
constexpr auto operator==(const Threefry &rhs)
Definition threefry.hpp:119
static constexpr auto min()
Definition threefry.hpp:29
constexpr Threefry(Threefry const &)=default
static constexpr auto samplesPerBlock()
Definition threefry.hpp:38
constexpr void advance(std::uint64_t const z)
Definition threefry.hpp:104
Threefry()
Definition threefry.hpp:50
constexpr U operator()()
Definition threefry.hpp:72
Definition cholesky.hpp:18
std::size_t Size
Definition type_traits.hpp:20
static constexpr Conditional< IsSatisfied< C >, RemoveConstReference< X >, X > copy(X &&a)
Definition copy.hpp:13
static constexpr auto bitRotateLeft(TA const value, TB count)
Definition bit_rotate_left.hpp:13
Size Index
Definition type_traits.hpp:21
Definition limits.hpp:13