vSMC
vSMC: 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,2014, 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 
37 #ifdef VSMC_MSVC
38 #include <intrin.h>
39 #endif
40 
41 #define VSMC_STATIC_ASSERT_RNG_PHILOX_RESULT_TYPE(ResultType) \
42  VSMC_STATIC_ASSERT( \
43  (cxx11::is_same<ResultType, uint32_t>::value || \
44  cxx11::is_same<ResultType, uint64_t>::value), \
45  USE_PhiloxEngine_WITH_INTEGER_TYPE_OTHER_THAN_uint32_t_OR_uint64_t)
46 
47 #define VSMC_STATIC_ASSERT_RNG_PHILOX_SIZE(K) \
48  VSMC_STATIC_ASSERT((K == 2 || K == 4), \
49  USE_PhiloxEngine_WITH_SIZE_OTHER_THAN_2_OR_4)
50 
51 #define VSMC_STATIC_ASSERT_RNG_PHILOX \
52  VSMC_STATIC_ASSERT_RNG_PHILOX_RESULT_TYPE(ResultType); \
53  VSMC_STATIC_ASSERT_RNG_PHILOX_SIZE(K);
54 
55 #define VSMC_DEFINE_RNG_PHILOX_WELY_CONSTANT(T, I, val) \
56  template <> struct PhiloxWeylConstantValue < T, I > : \
57  public cxx11::integral_constant< T, val > {};
58 
59 #define VSMC_DEFINE_RNG_PHILOX_ROUND_CONSTANT(T, K, I, val) \
60  template <> struct PhiloxRoundConstantValue < T, K, I > : \
61  public cxx11::integral_constant< T, val > {};
62 
65 #ifndef VSMC_RNG_PHILOX_ROUNDS
66 #define VSMC_RNG_PHILOX_ROUNDS 10
67 #endif
68 
69 namespace vsmc {
70 
71 namespace traits {
72 
73 namespace internal {
74 
75 template <typename, std::size_t> struct PhiloxWeylConstantValue;
76 
78  UINT32_C(0x9E3779B9))
80  UINT32_C(0xBB67AE85))
81 
83  UINT64_C(0x9E3779B97F4A7C15))
85  UINT64_C(0xBB67AE8584CAA73B))
86 
87 template <typename, std::size_t, std::size_t> struct PhiloxRoundConstantValue;
88 
90  UINT32_C(0xd256d193))
91 
93  UINT32_C(0xD2511F53))
95  UINT32_C(0xCD9E8D57))
96 
98  UINT64_C(0xD2B74407B1CE6E93))
99 
101  UINT64_C(0xD2E7470EE14C6C93))
103  UINT64_C(0xCA5A826395121157))
104 
105 } // namespace vsmc::traits::internal
106 
116 template <typename ResultType, std::size_t I>
118  public internal::PhiloxWeylConstantValue<ResultType, I> {};
119 
129 template <typename ResultType, std::size_t K, std::size_t I>
131  public internal::PhiloxRoundConstantValue<ResultType, K, I> {};
132 
133 } // namespace vsmc::traits
134 
135 namespace internal {
136 
137 template <typename ResultType, std::size_t K, std::size_t N, bool = (N > 1)>
138 struct PhiloxBumpKey {static void eval (Array<ResultType, K / 2> &) {}};
139 
140 template <typename ResultType, std::size_t N>
141 struct PhiloxBumpKey<ResultType, 2, N, true>
142 {
143  static void eval (Array<ResultType, 1> &par)
144  {
145  par[Position<0>()] +=
147  }
148 }; // struct PhiloxBumpKey
149 
150 template <typename ResultType, std::size_t N>
151 struct PhiloxBumpKey<ResultType, 4, N, true>
152 {
153  static void eval (Array<ResultType, 2> &par)
154  {
155  par[Position<0>()] +=
157  par[Position<1>()] +=
159  }
160 }; // struct PhiloxBumpKey
161 
162 template <std::size_t K, std::size_t I>
163 inline void philox_hilo (uint32_t b, uint32_t &hi, uint32_t &lo)
164 {
165  uint64_t prod =
166  static_cast<uint64_t>(b) *
167  static_cast<uint64_t>(
169  hi = static_cast<uint32_t>(prod >> 32);
170  lo = static_cast<uint32_t>(prod);
171 }
172 
173 #if VSMC_HAS_INT128
174 
175 template <std::size_t K, std::size_t I>
176 inline void philox_hilo (uint64_t b, uint64_t &hi, uint64_t &lo)
177 {
178  unsigned VSMC_INT128 prod =
179  static_cast<unsigned VSMC_INT128>(b) *
180  static_cast<unsigned VSMC_INT128>(
182  hi = static_cast<uint64_t>(prod >> 64);
183  lo = static_cast<uint64_t>(prod);
184 }
185 
186 #elif defined(VSMC_MSVC) // VSMC_HAS_INT128
187 
188 template <std::size_t K, std::size_t I>
189 inline void philox_hilo (uint64_t b, uint64_t &hi, uint64_t &lo)
190 {
192  &hi);
193 }
194 
195 #else // VSMC_HAS_INT128
196 
197 template <std::size_t K, std::size_t I>
198 inline void philox_hilo (uint64_t b, uint64_t &hi, uint64_t &lo)
199 {
200  const uint64_t a =
201  traits::PhiloxRoundConstantTrait<uint64_t, K, I>::value;
202  const unsigned whalf = 32;
203  const uint64_t lomask = (static_cast<uint64_t>(1) << whalf) - 1;
204 
205  lo = static_cast<uint64_t>(a * b);
206 
207  const uint64_t ahi = a >> whalf;
208  const uint64_t alo = a & lomask;
209  const uint64_t bhi = b >> whalf;
210  const uint64_t blo = b & lomask;
211 
212  const uint64_t ahbl = ahi * blo;
213  const uint64_t albh = alo * bhi;
214 
215  const uint64_t ahbl_albh = ((ahbl & lomask) + (albh & lomask));
216 
217  hi = ahi * bhi + (ahbl >> whalf) + (albh >> whalf);
218  hi += ahbl_albh >> whalf;
219  hi += ((lo >> whalf) < (ahbl_albh & lomask));
220 }
221 
222 #endif // VSMC_HAS_INT128
223 
224 template <typename ResultType, std::size_t K, std::size_t N, bool = (N > 0)>
226 {
227  static void eval (Array<ResultType, K> &,
228  const Array<ResultType, K / 2> &) {}
229 }; // struct PhiloxRound
230 
231 template <typename ResultType, std::size_t N>
232 struct PhiloxRound<ResultType, 2, N, true>
233 {
234  static void eval (Array<ResultType, 2> &state,
235  const Array<ResultType, 1> &par)
236  {
237  ResultType hi = 0;
238  ResultType lo = 0;
239  philox_hilo<2, 0>(state[Position<0>()], hi, lo);
240  state[Position<0>()] = hi^(par[Position<0>()]^state[Position<1>()]);
241  state[Position<1>()] = lo;
242  }
243 }; // struct PhiloxRound
244 
245 template <typename ResultType, std::size_t N>
246 struct PhiloxRound<ResultType, 4, N, true>
247 {
248  static void eval (Array<ResultType, 4> &state,
249  const Array<ResultType, 2> &par)
250  {
251  ResultType hi0 = 0;
252  ResultType lo1 = 0;
253  ResultType hi2 = 0;
254  ResultType lo3 = 0;
255  philox_hilo<4, 1>(state[Position<2>()], hi0, lo1);
256  philox_hilo<4, 0>(state[Position<0>()], hi2, lo3);
257 
258  hi0 ^= par[Position<0>()];
259  hi2 ^= par[Position<1>()];
260  state[Position<0>()] = hi0^state[Position<1>()];
261  state[Position<1>()] = lo1;
262  state[Position<2>()] = hi2^state[Position<3>()];
263  state[Position<3>()] = lo3;
264  }
265 }; // struct PhiloxRound
266 
267 } // namespace vsmc::internal
268 
305 template <typename ResultType, std::size_t K,
306  std::size_t Rounds = VSMC_RNG_PHILOX_ROUNDS>
308 {
309  public :
310 
311  typedef ResultType result_type;
314  typedef Array<ResultType, K / 2> key_type;
315 
316  private :
317 
318  typedef Counter<ctr_type> counter;
319 
320  public :
321 
322  explicit PhiloxEngine (result_type s = 0) : index_(K)
323  {
325  seed(s);
326  }
327 
328  template <typename SeedSeq>
329  explicit PhiloxEngine (SeedSeq &seq,
330  typename cxx11::enable_if<internal::is_seed_seq<SeedSeq,
332  >::value>::type * = VSMC_NULLPTR) : index_(K)
333  {
335  seed(seq);
336  }
337 
338  PhiloxEngine (const key_type &k) : index_(K)
339  {
341  seed(k);
342  }
343 
344  void seed (result_type s)
345  {
346  counter::reset(ctr_);
347  key_.fill(0);
348  key_.front() = s;
349  index_ = K;
350  }
351 
352  template <typename SeedSeq>
353  void seed (SeedSeq &seq,
354  typename cxx11::enable_if<internal::is_seed_seq<SeedSeq,
356  >::value>::type * = VSMC_NULLPTR)
357  {
358  counter::reset(ctr_);
359  seq.generate(key_.begin(), key_.end());
360  index_ = K;
361  }
362 
363  void seed (const key_type &k)
364  {
365  counter::reset(ctr_);
366  key_ = k;
367  index_ = K;
368  }
369 
370  ctr_type ctr () const {return ctr_;}
371 
372  key_type key () const {return key_;}
373 
374  void ctr (const ctr_type &c)
375  {
376  counter::set(ctr_, c);
377  index_ = K;
378  }
379 
380  void key (const key_type &k)
381  {
382  key_ = k;
383  index_ = K;
384  }
385 
386  result_type operator() ()
387  {
388  if (index_ == K) {
389  counter::increment(ctr_);
390  generate_buffer(ctr_, buffer_);
391  index_ = 0;
392  }
393 
394  return buffer_[index_++];
395  }
396 
399  buffer_type operator() (const ctr_type &c) const
400  {
401  buffer_type buf;
402  generate_buffer(c, buf);
403 
404  return buf;
405  }
406 
409  void operator() (const ctr_type &c, buffer_type &buf) const
410  {generate_buffer(c, buf);}
411 
412  void discard (result_type nskip)
413  {
414  std::size_t n = static_cast<std::size_t>(nskip);
415  if (index_ + n <= K) {
416  index_ += n;
417  return;
418  }
419 
420  n -= K - index_;
421  if (n <= K) {
422  index_ = K;
423  operator()();
424  index_ = n;
425  return;
426  }
427 
428  counter::increment(ctr_, static_cast<result_type>(n / K));
429  index_ = K;
430  operator()();
431  index_ = n % K;
432  }
433 
434  static VSMC_CONSTEXPR const result_type _Min = 0;
435  static VSMC_CONSTEXPR const result_type _Max = static_cast<result_type>(
436  ~(static_cast<result_type>(0)));
437 
438  static VSMC_CONSTEXPR result_type min VSMC_MNE () {return _Min;}
439  static VSMC_CONSTEXPR result_type max VSMC_MNE () {return _Max;}
440 
441  friend inline bool operator== (
444  {
445  return
446  eng1.index_ == eng2.index_ &&
447  eng1.ctr_ == eng2.ctr_ &&
448  eng1.key_ == eng2.key_;
449  }
450 
451  friend inline bool operator!= (
454  {return !(eng1 == eng2);}
455 
456  template <typename CharT, typename Traits>
457  friend inline std::basic_ostream<CharT, Traits> &operator<< (
458  std::basic_ostream<CharT, Traits> &os,
460  {
461  if (!os.good())
462  return os;
463 
464  os << eng.ctr_ << ' ';
465  os << eng.key_ << ' ';
466  os << eng.buffer_ << ' ';
467  os << eng.index_;
468 
469  return os;
470  }
471 
472  template <typename CharT, typename Traits>
473  friend inline std::basic_istream<CharT, Traits> &operator>> (
474  std::basic_istream<CharT, Traits> &is,
476  {
477  if (!is.good())
478  return is;
479 
481  is >> std::ws >> eng_tmp.buffer_;
482  is >> std::ws >> eng_tmp.ctr_;
483  is >> std::ws >> eng_tmp.key_;
484  is >> std::ws >> eng_tmp.index_;
485 
486  if (is.good()) {
487 #if VSMC_HAS_CXX11_RVALUE_REFERENCES
488  eng = cxx11::move(eng_tmp);
489 #else
490  eng = eng_tmp;
491 #endif
492  }
493 
494  return is;
495  }
496 
497  private :
498 
499  ctr_type ctr_;
500  key_type key_;
501  buffer_type buffer_;
502  std::size_t index_;
503 
504  void generate_buffer (const ctr_type c, buffer_type &buf) const
505  {
506  buf = c;
507  key_type par = key_;
508  generate_buffer<0>(buf, par, cxx11::true_type());
509  }
510 
511  template <std::size_t>
512  void generate_buffer (buffer_type &, key_type &,
513  cxx11::false_type) const {}
514 
515  template <std::size_t N>
516  void generate_buffer (buffer_type &buf, key_type &par,
517  cxx11::true_type) const
518  {
521  generate_buffer<N + 1>(buf, par,
522  cxx11::integral_constant<bool, N < Rounds>());
523  }
524 }; // class PhiloxEngine
525 
529 
533 
537 
541 
544 typedef Philox4x32 Philox;
545 
548 typedef Philox4x64 Philox_64;
549 
550 } // namespace vsmc
551 
552 #endif // VSMC_RNG_PHILOX_HPP
Definition: adapter.hpp:37
static void eval(Array< ResultType, K/2 > &)
Definition: philox.hpp:138
void discard(result_type nskip)
Definition: philox.hpp:412
#define VSMC_CONSTEXPR
constexpr
Definition: defines.hpp:55
PhiloxEngine< uint32_t, 2 > Philox2x32
Philox2x32 RNG engine reimplemented.
Definition: philox.hpp:528
PhiloxEngine< uint32_t, 4 > Philox4x32
Philox4x32 RNG engine reimplemented.
Definition: philox.hpp:532
PhiloxEngine(const key_type &k)
Definition: philox.hpp:338
static void eval(Array< ResultType, K > &, const Array< ResultType, K/2 > &)
Definition: philox.hpp:227
STL namespace.
Array< ResultType, K > ctr_type
Definition: philox.hpp:313
PhiloxEngine(SeedSeq &seq, typename cxx11::enable_if< internal::is_seed_seq< SeedSeq, result_type, key_type, PhiloxEngine< ResultType, K, Rounds > >::value >::type *=nullptr)
Definition: philox.hpp:329
PhiloxEngine< uint64_t, 2 > Philox2x64
Philox2x64 RNG engine reimplemented.
Definition: philox.hpp:536
integral_constant< bool, false > false_type
Function template argument used for position.
Definition: defines.hpp:126
void seed(SeedSeq &seq, typename cxx11::enable_if< internal::is_seed_seq< SeedSeq, result_type, key_type, PhiloxEngine< ResultType, K, Rounds > >::value >::type *=nullptr)
Definition: philox.hpp:353
PhiloxEngine(result_type s=0)
Definition: philox.hpp:322
static void eval(Array< ResultType, 1 > &par)
Definition: philox.hpp:143
#define VSMC_DEFINE_RNG_PHILOX_WELY_CONSTANT(T, I, val)
Definition: philox.hpp:55
#define VSMC_MNE
Avoid MSVC stupid behavior: MNE = Macro No Expansion.
Definition: defines.hpp:38
Array< ResultType, K/2 > key_type
Definition: philox.hpp:314
void key(const key_type &k)
Definition: philox.hpp:380
#define VSMC_RNG_PHILOX_ROUNDS
PhiloxEngine default rounds.
Definition: philox.hpp:66
key_type key() const
Definition: philox.hpp:372
remove_reference< T >::type && move(T &&t) noexcept
ctr_type ctr() const
Definition: philox.hpp:370
std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const Sampler< T > &sampler)
Definition: sampler.hpp:884
void philox_hilo(uint64_t b, uint64_t &hi, uint64_t &lo)
Definition: philox.hpp:176
Traits of PhiloxEngine constants for bumping the key (Weyl sequence)
Definition: philox.hpp:117
Philox4x32 Philox
The default 32-bits Philox engine.
Definition: philox.hpp:544
static void eval(Array< ResultType, 2 > &state, const Array< ResultType, 1 > &par)
Definition: philox.hpp:234
void ctr(const ctr_type &c)
Definition: philox.hpp:374
void seed(const key_type &k)
Definition: philox.hpp:363
#define VSMC_NULLPTR
nullptr
Definition: defines.hpp:79
static void eval(Array< ResultType, 4 > &state, const Array< ResultType, 2 > &par)
Definition: philox.hpp:248
integral_constant< bool, true > true_type
Philox4x64 Philox_64
The default 64-bits Philox engine.
Definition: philox.hpp:548
ResultType result_type
Definition: philox.hpp:311
#define VSMC_DEFINE_RNG_PHILOX_ROUND_CONSTANT(T, K, I, val)
Definition: philox.hpp:59
Traits of PhiloxEngine constants for rounding.
Definition: philox.hpp:130
PhiloxEngine< uint64_t, 4 > Philox4x64
Philox4x64 RNG engine reimplemented.
Definition: philox.hpp:540
static void eval(Array< ResultType, 2 > &par)
Definition: philox.hpp:153
void seed(result_type s)
Definition: philox.hpp:344
Array< ResultType, K > buffer_type
Definition: philox.hpp:312
Philox RNG engine reimplemented.
Definition: philox.hpp:307
#define VSMC_STATIC_ASSERT_RNG_PHILOX
Definition: philox.hpp:51