vSMC  v3.0.0
Scalable Monte Carlo
philox.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/rng/philox.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2016, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef VSMC_RNG_PHILOX_HPP
33 #define VSMC_RNG_PHILOX_HPP
34 
36 #include <vsmc/rng/counter.hpp>
37 #include <vsmc/rng/threefry.hpp>
38 
39 #ifdef VSMC_MSVC
40 #include <intrin.h>
41 #endif
42 
43 #define VSMC_DEFINE_RNG_PHILOX_WEYL_CONSTANT(W, K, val) \
44  template <typename T> \
45  class PhiloxWeylConstant<T, K, W> \
46  : public std::integral_constant<T, UINT##W##_C(val)> \
47  { \
48  }; // PhiloxMulConstant
49 
50 #define VSMC_DEFINE_RNG_PHILOX_MUL_CONSTANT(W, K, I, val) \
51  template <typename T> \
52  class PhiloxMulConstant<T, K, I, W> \
53  : public std::integral_constant<T, UINT##W##_C(val)> \
54  { \
55  }; // PhiloxMulConstant
56 
59 #ifndef VSMC_RNG_PHILOX_ROUNDS
60 #define VSMC_RNG_PHILOX_ROUNDS 10
61 #endif
62 
65 #ifndef VSMC_RNG_PHILOX_VECTOR_LENGTH
66 #define VSMC_RNG_PHILOX_VECTOR_LENGTH 4
67 #endif
68 
69 namespace vsmc
70 {
71 
72 namespace internal
73 {
74 
75 template <typename T, std::size_t, int = std::numeric_limits<T>::digits>
77 
80 
81 VSMC_DEFINE_RNG_PHILOX_WEYL_CONSTANT(64, 0, 0x9E3779B97F4A7C15)
82 VSMC_DEFINE_RNG_PHILOX_WEYL_CONSTANT(64, 1, 0xBB67AE8584CAA73B)
83 
84 template <typename T, std::size_t, std::size_t,
85  int = std::numeric_limits<T>::digits>
87 
89 
92 
93 VSMC_DEFINE_RNG_PHILOX_MUL_CONSTANT(64, 2, 0, 0xD2B74407B1CE6E93)
94 
95 VSMC_DEFINE_RNG_PHILOX_MUL_CONSTANT(64, 4, 0, 0xCA5A826395121157)
96 VSMC_DEFINE_RNG_PHILOX_MUL_CONSTANT(64, 4, 1, 0xD2E7470EE14C6C93)
97 
98 } // namespace internal
99 
102 template <typename T, std::size_t K>
104 {
105  public:
107  template <std::size_t I>
109 
111  template <std::size_t I>
113 }; // class PhiloxConstants
114 
115 namespace internal
116 {
117 
118 template <typename T, int = std::numeric_limits<T>::digits>
120 
121 template <typename T>
122 class PhiloxHiLo<T, 32>
123 {
124  public:
125  static void eval(T a, T b, T &hi, T &lo)
126  {
127  union {
128  std::uint64_t prod;
129  std::array<T, 2> result;
130  } buf;
131 
132  buf.prod =
133  static_cast<std::uint64_t>(a) * static_cast<std::uint64_t>(b);
134 #if VSMC_HAS_X86 // little endian
135  hi = std::get<1>(buf.result);
136  lo = std::get<0>(buf.result);
137 #else // VSMC_HAS_X86
138  hi = static_cast<T>(buf.prod >> 32);
139  lo = static_cast<T>(buf.prod);
140 #endif // VSMC_HAS_X86
141  }
142 }; // class PhiloxHiLo
143 
144 template <typename T>
145 class PhiloxHiLo<T, 64>
146 {
147  public:
148  static void eval(T a, T b, T &hi, T &lo)
149  {
150 #if VSMC_HAS_INT128
151 
152 #ifdef VSMC_GCC
153 #pragma GCC diagnostic push
154 #pragma GCC diagnostic ignored "-Wpedantic"
155 #endif // VSMC_GCC
156  union {
157  unsigned VSMC_INT128 prod;
158  std::array<T, 2> result;
159  } buf;
160 
161  buf.prod = static_cast<unsigned VSMC_INT128>(a) *
162  static_cast<unsigned VSMC_INT128>(b);
163 #ifdef VSMC_GCC
164 #pragma GCC diagnostic pop
165 #endif // VSMC_GCC
166 
167 #if VSMC_HAS_X86 // littel endia
168  hi = std::get<1>(buf.result);
169  lo = std::get<0>(buf.result);
170 #else // VSMC_HAS_X86
171  hi = static_cast<T>(buf.prod >> 64);
172  lo = static_cast<T>(buf.prod);
173 #endif // VSMC_HAS_X86
174 
175 #elif defined(VSMC_MSVC)
176 
177  unsigned __int64 Multiplier =
178  static_cast<unsigned __int64>(multiplier::value);
179  unsigned __int64 Multiplicand = static_cast<unsigned __int64>(b);
180  unsigned __int64 hi_tmp = 0;
181  lo = static_cast<T>(_umul128(Multiplier, Multiplicand, &hi_tmp));
182  hi = static_cast<T>(hi_tmp);
183 
184 #else // VSMC_HAS_INT128
185 
186  const T a = multiplier::value;
187  const T lomask = (static_cast<T>(1) << 32) - 1;
188  const T ahi = a >> 32;
189  const T alo = a & lomask;
190  const T bhi = b >> 32;
191  const T blo = b & lomask;
192  const T ahbl = ahi * blo;
193  const T albh = alo * bhi;
194  const T ahbl_albh = ((ahbl & lomask) + (albh & lomask));
195 
196  lo = a * b;
197  hi = ahi * bhi + (ahbl >> 32) + (albh >> 32);
198  hi += ahbl_albh >> 32;
199  hi += ((lo >> 32) < (ahbl_albh & lomask));
200  std::array<T, 2> hilo = {{lo, hi}};
201 
202  return hilo;
203 
204 #endif // VSMC_HAS_INT128
205  }
206 }; // class PhiloxHiLo
207 
208 template <typename T, std::size_t K, std::size_t N, typename Constants,
209  bool = (N > 1)>
211 {
212  public:
213  static void eval(std::array<T, K / 2> &) {}
214 }; // class PhiloxBumpKey
215 
216 template <typename T, std::size_t N, typename Constants>
217 class PhiloxBumpKey<T, 2, N, Constants, true>
218 {
219  template <std::size_t I>
220  using weyl = typename Constants::template weyl<I>;
221 
222  public:
223  static void eval(std::array<T, 1> &par)
224  {
225  std::get<0>(par) += weyl<0>::value;
226  }
227 }; // class PhiloxBumpKey
228 
229 template <typename T, std::size_t N, typename Constants>
230 class PhiloxBumpKey<T, 4, N, Constants, true>
231 {
232  template <std::size_t I>
233  using weyl = typename Constants::template weyl<I>;
234 
235  public:
236  static void eval(std::array<T, 2> &par)
237  {
238  std::get<0>(par) += weyl<0>::value;
239  std::get<1>(par) += weyl<1>::value;
240  }
241 }; // class PhiloxBumpKey
242 
243 template <typename T, std::size_t K, typename Constants>
245 {
246  public:
247  template <std::size_t Rp1>
248  static void eval(const std::array<T, K / 2> &key,
249  std::array<std::array<T, K / 2>, Rp1> &par)
250  {
251  std::get<0>(par) = key;
252  eval<1>(par, std::integral_constant<bool, 1 < Rp1>());
253  }
254 
255  private:
256  template <std::size_t, std::size_t Rp1>
257  static void eval(std::array<std::array<T, K / 2>, Rp1> &, std::false_type)
258  {
259  }
260 
261  template <std::size_t N, std::size_t Rp1>
262  static void eval(
263  std::array<std::array<T, K / 2>, Rp1> &par, std::true_type)
264  {
265  std::get<N>(par) = std::get<N - 1>(par);
266  PhiloxBumpKey<T, K, N, Constants>::eval(std::get<N>(par));
267  eval<N + 1>(par, std::integral_constant<bool, N + 1 < Rp1>());
268  }
269 }; // class PhiloxInitPar
270 
271 template <typename T, std::size_t K, std::size_t N, typename, bool = (N > 0)>
273 {
274  public:
275  template <std::size_t Rp1>
276  static void eval(
277  std::array<T, K> &, const std::array<std::array<T, K / 2>, Rp1> &)
278  {
279  }
280 }; // class PhiloxSBox
281 
282 template <typename T, std::size_t K, std::size_t N, typename Constants>
283 class PhiloxSBox<T, K, N, Constants, true>
284 {
285  public:
286  template <std::size_t Rp1>
287  static void eval(std::array<T, K> &state,
288  const std::array<std::array<T, K / 2>, Rp1> &par)
289  {
290  eval<0>(state, par, std::integral_constant<bool, 1 < K>());
291  }
292 
293  private:
294  template <std::size_t I>
295  using multiplier = typename Constants::template multiplier<I>;
296 
297  template <std::size_t, std::size_t Rp1>
298  static void eval(std::array<T, K> &,
299  const std::array<std::array<T, K / 2>, Rp1> &, std::false_type)
300  {
301  }
302 
303  template <std::size_t I, std::size_t Rp1>
304  static void eval(std::array<T, K> &state,
305  const std::array<std::array<T, K / 2>, Rp1> &par, std::true_type)
306  {
307  T x = std::get<I + 1>(state) ^ std::get<I / 2>(std::get<N>(par));
308  PhiloxHiLo<T>::eval(std::get<I>(state), multiplier<I / 2>::value,
309  std::get<I>(state), std::get<I + 1>(state));
310  std::get<I>(state) ^= x;
311  eval<I + 2>(state, par, std::integral_constant<bool, I + 3 < K>());
312  }
313 }; // class PhiloxSBox
314 
315 template <typename T, std::size_t K, std::size_t N, bool = (N > 0)>
317 {
318  public:
319  static void eval(std::array<T, K> &) {}
320 }; // class PhiloxPBox
321 
322 template <typename T, std::size_t K, std::size_t N>
323 class PhiloxPBox<T, K, N, true>
324 {
325  public:
326  static void eval(std::array<T, K> &state)
327  {
328  std::array<T, K> tmp;
329  eval<0>(state, tmp, std::integral_constant<bool, 0 < K>());
330  std::memcpy(state.data(), tmp.data(), sizeof(T) * K);
331  }
332 
333  private:
334  template <std::size_t>
335  static void eval(
336  const std::array<T, K> &, std::array<T, K> &, std::false_type)
337  {
338  }
339 
340  template <std::size_t I>
341  static void eval(
342  const std::array<T, K> &state, std::array<T, K> &tmp, std::true_type)
343  {
344  static constexpr std::size_t J =
345  K - ThreefryPermuteConstant<K, K - I - 1>::value - 1;
346 
347  std::get<I>(tmp) = std::get<J>(state);
348  eval<I + 1>(state, tmp, std::integral_constant<bool, I + 1 < K>());
349  }
350 }; // class PhiloxPBox
351 
352 template <typename T, std::size_t N>
353 class PhiloxPBox<T, 2, N, true>
354 {
355  public:
356  static void eval(std::array<T, 2> &) {}
357 }; // class PhiloxPBox
358 
359 template <typename T, std::size_t N>
360 class PhiloxPBox<T, 4, N, true>
361 {
362  public:
363  static void eval(std::array<T, 4> &state)
364  {
365  std::swap(std::get<0>(state), std::get<2>(state));
366  }
367 }; // class PhiloxPBox
368 
369 template <typename T, std::size_t N>
370 class PhiloxPBox<T, 8, N, true>
371 {
372  public:
373  static void eval(std::array<T, 8> &state)
374  {
375  std::swap(std::get<0>(state), std::get<4>(state));
376  T x = std::get<7>(state);
377  std::get<7>(state) = std::get<5>(state);
378  std::get<5>(state) = std::get<3>(state);
379  std::get<3>(state) = std::get<1>(state);
380  std::get<1>(state) = x;
381  }
382 }; // class PhiloxPBox
383 
384 } // namespace vsmc::internal
385 
399 template <typename T, std::size_t K = VSMC_RNG_PHILOX_VECTOR_LENGTH,
400  std::size_t Rounds = VSMC_RNG_PHILOX_ROUNDS,
401  typename Constants = PhiloxConstants<T, K>>
403 {
404  static_assert(std::is_unsigned<T>::value,
405  "**PhiloxGenerator** USED WITH T OTHER THAN UNSIGNED INTEGER TYPES");
406 
407  static_assert(K != 0 && K % 2 == 0,
408  "**PhiloxGenerator** USED WITH K OTHER THAN MULTIPLES OF 2");
409 
410  static_assert(
411  Rounds != 0, "**PhiloxGenerator** USED WITH ROUNDS EQUAL TO ZERO");
412 
413  public:
414  using ctr_type = std::array<T, K>;
415  using key_type = std::array<T, K / 2>;
416 
417  static constexpr std::size_t size() { return sizeof(T) * K; }
418 
419  void reset(const key_type &key) { key_ = key; }
420 
421  template <typename ResultType>
422  void operator()(ctr_type &ctr,
423  std::array<ResultType, size() / sizeof(ResultType)> &buffer) const
424  {
425  union {
426  std::array<T, K> state;
427  ctr_type ctr;
428  std::array<ResultType, size() / sizeof(ResultType)> result;
429  } buf;
430 
431  std::array<key_type, Rounds + 1> par;
433 
434  increment(ctr);
435  buf.ctr = ctr;
436  generate<0>(buf.state, par, std::true_type());
437  buffer = buf.result;
438  }
439 
440  template <typename ResultType>
441  void operator()(ctr_type &ctr, std::size_t n,
442  std::array<ResultType, size() / sizeof(ResultType)> *buffer) const
443  {
444  union {
445  std::array<T, K> state;
446  ctr_type ctr;
447  std::array<ResultType, size() / sizeof(ResultType)> result;
448  } buf;
449 
450  std::array<key_type, Rounds + 1> par;
452 
453  for (std::size_t i = 0; i != n; ++i) {
454  increment(ctr);
455  buf.ctr = ctr;
456  generate<0>(buf.state, par, std::true_type());
457  buffer[i] = buf.result;
458  }
459  }
460 
461  friend bool operator==(const PhiloxGenerator<T, K, Rounds> &gen1,
462  const PhiloxGenerator<T, K, Rounds> &gen2)
463  {
464  return gen1.key_ == gen2.key_;
465  }
466 
467  friend bool operator!=(const PhiloxGenerator<T, K, Rounds> &gen1,
468  const PhiloxGenerator<T, K, Rounds> &gen2)
469  {
470  return !(gen1 == gen2);
471  }
472 
473  template <typename CharT, typename Traits>
474  friend std::basic_ostream<CharT, Traits> &operator<<(
475  std::basic_ostream<CharT, Traits> &os,
477  {
478  if (!os)
479  return os;
480 
481  os << gen.key_;
482 
483  return os;
484  }
485 
486  template <typename CharT, typename Traits>
487  friend std::basic_istream<CharT, Traits> &operator>>(
488  std::basic_istream<CharT, Traits> &is,
490  {
491  if (!is)
492  return is;
493 
494  key_type key = {{0}};
495  is >> std::ws >> key;
496 
497  if (is)
498  gen.key_ = std::move(key);
499 
500  return is;
501  }
502 
503  private:
504  key_type key_;
505 
506  template <std::size_t>
507  void generate(std::array<T, K> &, std::array<key_type, Rounds + 1> &,
508  std::false_type) const
509  {
510  }
511 
512  template <std::size_t N>
513  void generate(std::array<T, K> &state,
514  std::array<key_type, Rounds + 1> &par, std::true_type) const
515  {
518  generate<N + 1>(
519  state, par, std::integral_constant<bool, (N < Rounds)>());
520  }
521 }; // class PhiloxGenerator
522 
525 template <typename ResultType, typename T = ResultType,
526  std::size_t K = VSMC_RNG_PHILOX_VECTOR_LENGTH,
527  std::size_t Rounds = VSMC_RNG_PHILOX_ROUNDS,
528  typename Constants = PhiloxConstants<T, K>>
529 using PhiloxEngine =
531 
534 template <typename ResultType>
536 
539 template <typename ResultType>
541 
544 template <typename ResultType>
546 
549 template <typename ResultType>
551 
555 
559 
563 
567 
571 
575 
579 
583 
587 
591 
592 } // namespace vsmc
593 
594 #endif // VSMC_RNG_PHILOX_HPP
Definition: monitor.hpp:48
void operator()(ctr_type &ctr, std::array< ResultType, size()/sizeof(ResultType)> &buffer) const
Definition: philox.hpp:422
friend bool operator!=(const PhiloxGenerator< T, K, Rounds > &gen1, const PhiloxGenerator< T, K, Rounds > &gen2)
Definition: philox.hpp:467
static void eval(T a, T b, T &hi, T &lo)
Definition: philox.hpp:148
static void eval(std::array< T, 2 > &)
Definition: philox.hpp:356
static void eval(T a, T b, T &hi, T &lo)
Definition: philox.hpp:125
void increment(std::array< T, K > &ctr)
Increment a counter by one.
Definition: counter.hpp:62
static void eval(const std::array< T, K/2 > &key, std::array< std::array< T, K/2 >, Rp1 > &par)
Definition: philox.hpp:248
ulong uint64_t
Definition: opencl.h:42
STL namespace.
Counter based RNG engine.
Definition: counter.hpp:187
static void eval(std::array< T, K > &, const std::array< std::array< T, K/2 >, Rp1 > &)
Definition: philox.hpp:276
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, PhiloxGenerator< T, K, Rounds > &gen)
Definition: philox.hpp:487
#define VSMC_DEFINE_RNG_PHILOX_MUL_CONSTANT(W, K, I, val)
Definition: philox.hpp:50
#define VSMC_RNG_PHILOX_VECTOR_LENGTH
PhiloxGenerator default vector length.
Definition: philox.hpp:66
static void eval(std::array< T, K > &state)
Definition: philox.hpp:326
friend bool operator==(const PhiloxGenerator< T, K, Rounds > &gen1, const PhiloxGenerator< T, K, Rounds > &gen2)
Definition: philox.hpp:461
static void eval(std::array< T, 8 > &state)
Definition: philox.hpp:373
static void eval(std::array< T, K/2 > &)
Definition: philox.hpp:213
Philox RNG generator.
Definition: philox.hpp:402
static void eval(std::array< T, K > &)
Definition: philox.hpp:319
std::array< T, K > ctr_type
Definition: philox.hpp:414
#define VSMC_RNG_PHILOX_ROUNDS
PhiloxGenerator default rounds.
Definition: philox.hpp:60
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const PhiloxGenerator< T, K, Rounds > &gen)
Definition: philox.hpp:474
#define VSMC_DEFINE_RNG_PHILOX_WEYL_CONSTANT(W, K, val)
Definition: philox.hpp:43
static void eval(std::array< T, 4 > &state)
Definition: philox.hpp:363
static void eval(std::array< T, 1 > &par)
Definition: philox.hpp:223
void reset(const key_type &key)
Definition: philox.hpp:419
Default Philox constants.
Definition: philox.hpp:103
void operator()(ctr_type &ctr, std::size_t n, std::array< ResultType, size()/sizeof(ResultType)> *buffer) const
Definition: philox.hpp:441
static constexpr std::size_t size()
Definition: philox.hpp:417
std::array< T, K/2 > key_type
Definition: philox.hpp:415
static void eval(std::array< T, 2 > &par)
Definition: philox.hpp:236
void swap(StateMatrixBase< Layout, Dim, T > &state1, StateMatrixBase< Layout, Dim, T > &state2) noexcept
Swap two StateMatrixBase objects.
static void eval(std::array< T, K > &state, const std::array< std::array< T, K/2 >, Rp1 > &par)
Definition: philox.hpp:287