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-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 
38 #ifdef VSMC_MSVC
39 #include <intrin.h>
40 #endif
41 
42 #define VSMC_DEFINE_RNG_PHILOX_WELY_CONSTANT(T, I, val) \
43  template <> \
44  class PhiloxWeylConstant<T, I> : public std::integral_constant<T, val> \
45  { \
46  }; // class PhiloxWeylConstant
47 
48 #define VSMC_DEFINE_RNG_PHILOX_ROUND_CONSTANT(T, K, I, val) \
49  template <> \
50  class PhiloxRoundConstant<T, K, I> \
51  : public std::integral_constant<T, val> \
52  { \
53  }; // PhiloxRoundConstant
54 
57 #ifndef VSMC_RNG_PHILOX_ROUNDS
58 #define VSMC_RNG_PHILOX_ROUNDS 10
59 #endif
60 
63 #ifndef VSMC_RNG_PHILOX_VECTOR_LENGTH
64 #define VSMC_RNG_PHILOX_VECTOR_LENGTH 4
65 #endif
66 
67 namespace vsmc
68 {
69 
70 namespace internal
71 {
72 
73 template <typename, std::size_t>
75 
78 
80  std::uint64_t, 0, UINT64_C(0x9E3779B97F4A7C15))
82  std::uint64_t, 1, UINT64_C(0xBB67AE8584CAA73B))
83 
84 template <typename, std::size_t, std::size_t>
86 
88  std::uint32_t, 2, 0, UINT32_C(0xD256D193))
89 
91  std::uint32_t, 4, 0, UINT32_C(0xD2511F53))
93  std::uint32_t, 4, 1, UINT32_C(0xCD9E8D57))
94 
96  std::uint64_t, 2, 0, UINT64_C(0xD2B74407B1CE6E93))
97 
99  std::uint64_t, 4, 0, UINT64_C(0xD2E7470EE14C6C93))
101  std::uint64_t, 4, 1, UINT64_C(0xCA5A826395121157))
102 
103 template <std::size_t K, std::size_t I>
104 inline void philox_hilo(std::uint32_t b, std::uint32_t &hi, std::uint32_t &lo)
105 {
106  std::uint64_t prod = static_cast<std::uint64_t>(b) *
107  static_cast<std::uint64_t>(
109  hi = static_cast<std::uint32_t>(prod >> 32);
110  lo = static_cast<std::uint32_t>(prod);
111 }
112 
113 #if VSMC_HAS_INT128
114 
115 template <std::size_t K, std::size_t I>
116 inline void philox_hilo(std::uint64_t b, std::uint64_t &hi, std::uint64_t &lo)
117 {
118  unsigned VSMC_INT128 prod =
119  static_cast<unsigned VSMC_INT128>(b) *
120  static_cast<unsigned VSMC_INT128>(
122  hi = static_cast<std::uint64_t>(prod >> 64);
123  lo = static_cast<std::uint64_t>(prod);
124 }
125 
126 #elif defined(VSMC_MSVC) // VSMC_HAS_INT128
127 
128 template <std::size_t K, std::size_t I>
129 inline void philox_hilo(std::uint64_t b, std::uint64_t &hi, std::uint64_t &lo)
130 {
132 }
133 
134 #else // VSMC_HAS_INT128
135 
136 template <std::size_t K, std::size_t I>
138 {
140  const unsigned whalf = 32;
141  const std::uint64_t lomask = (static_cast<std::uint64_t>(1) << whalf) - 1;
142 
143  lo = static_cast<std::uint64_t>(a * b);
144 
145  const std::uint64_t ahi = a >> whalf;
146  const std::uint64_t alo = a & lomask;
147  const std::uint64_t bhi = b >> whalf;
148  const std::uint64_t blo = b & lomask;
149 
150  const std::uint64_t ahbl = ahi * blo;
151  const std::uint64_t albh = alo * bhi;
152 
153  const std::uint64_t ahbl_albh = ((ahbl & lomask) + (albh & lomask));
154 
155  hi = ahi * bhi + (ahbl >> whalf) + (albh >> whalf);
156  hi += ahbl_albh >> whalf;
157  hi += ((lo >> whalf) < (ahbl_albh & lomask));
158 }
159 
160 #endif // VSMC_HAS_INT128
161 
162 template <typename T, std::size_t K, std::size_t N, bool = (N > 1)>
164 {
165  public:
166  static void eval(std::array<T, K / 2> &) {}
167 }; // class PhiloxBumpKey
168 
169 template <typename T, std::size_t N>
170 class PhiloxBumpKey<T, 2, N, true>
171 {
172  public:
173  static void eval(std::array<T, 1> &par)
174  {
175  std::get<0>(par) += PhiloxWeylConstant<T, 0>::value;
176  }
177 }; // class PhiloxBumpKey
178 
179 template <typename T, std::size_t N>
180 class PhiloxBumpKey<T, 4, N, true>
181 {
182  public:
183  static void eval(std::array<T, 2> &par)
184  {
185  std::get<0>(par) += PhiloxWeylConstant<T, 0>::value;
186  std::get<1>(par) += PhiloxWeylConstant<T, 1>::value;
187  }
188 }; // class PhiloxBumpKey
189 
190 template <typename T, std::size_t K, std::size_t N, bool = (N > 0)>
192 {
193  public:
194  static void eval(std::array<T, K> &, const std::array<T, K / 2> &) {}
195 }; // class PhiloxRound
196 
197 template <typename T, std::size_t N>
198 class PhiloxRound<T, 2, N, true>
199 {
200  public:
201  static void eval(std::array<T, 2> &state, const std::array<T, 1> &par)
202  {
203  T hi = 0;
204  T lo = 0;
205  philox_hilo<2, 0>(std::get<0>(state), hi, lo);
206  hi ^= std::get<0>(par);
207  std::get<0>(state) = hi ^ std::get<1>(state);
208  std::get<1>(state) = lo;
209  }
210 }; // class PhiloxRound
211 
212 template <typename T, std::size_t N>
213 class PhiloxRound<T, 4, N, true>
214 {
215  public:
216  static void eval(std::array<T, 4> &state, const std::array<T, 2> &par)
217  {
218  T hi0 = 0;
219  T lo1 = 0;
220  T hi2 = 0;
221  T lo3 = 0;
222  philox_hilo<4, 1>(std::get<2>(state), hi0, lo1);
223  philox_hilo<4, 0>(std::get<0>(state), hi2, lo3);
224 
225  hi0 ^= std::get<0>(par);
226  hi2 ^= std::get<1>(par);
227  std::get<0>(state) = hi0 ^ std::get<1>(state);
228  std::get<1>(state) = lo1;
229  std::get<2>(state) = hi2 ^ std::get<3>(state);
230  std::get<3>(state) = lo3;
231  }
232 }; // class PhiloxRound
233 
234 } // namespace vsmc::internal
235 
238 template <typename ResultType, std::size_t K = VSMC_RNG_PHILOX_VECTOR_LENGTH,
239  std::size_t Rounds = VSMC_RNG_PHILOX_ROUNDS>
241 {
242  static_assert(std::is_unsigned<ResultType>::value,
243  "**PhiloxGenerator** USED WITH ResultType OTHER THAN UNSIGNED INTEGER "
244  "TYPES");
245 
246  static_assert(sizeof(ResultType) == sizeof(std::uint32_t) ||
247  sizeof(ResultType) == sizeof(std::uint64_t),
248  "**PhiloxGenerator** USED WITH ResultType OF SIZE OTHER THAN 32 OR 64 "
249  "BITS");
250 
251  static_assert(
252  K == 2 || K == 4, "**PhiloxGenerator** USED WITH K OTHER THAN 2 OR 4");
253 
254  public:
255  using result_type = ResultType;
256  using ctr_type = std::array<ResultType, K>;
257  using key_type = std::array<ResultType, K / 2>;
258 
259  static constexpr std::size_t size() { return K; }
260 
261  void reset(const key_type &) {}
262 
263  void operator()(ctr_type &ctr, const key_type &key, ctr_type &buffer) const
264  {
265  increment(ctr);
266  buffer = ctr;
267  key_type par = key;
268  generate<0>(buffer, par, std::true_type());
269  }
270 
271  void operator()(ctr_type &ctr, const key_type &key, std::size_t n,
272  ctr_type *buffer) const
273  {
274  increment(ctr, n, buffer);
275  for (std::size_t i = 0; i != n; ++i) {
276  key_type par = key;
277  generate<0>(buffer[i], par, std::true_type());
278  }
279  }
280 
281  private:
282  template <std::size_t>
283  void generate(ctr_type &, key_type &, std::false_type) const
284  {
285  }
286 
287  template <std::size_t N>
288  void generate(ctr_type &state, key_type &par, std::true_type) const
289  {
292  generate<N + 1>(
293  state, par, std::integral_constant<bool, (N < Rounds)>());
294  }
295 }; // class PhiloxGenerator
296 
299 template <typename ResultType, std::size_t K = VSMC_RNG_PHILOX_VECTOR_LENGTH,
300  std::size_t Rounds = VSMC_RNG_PHILOX_ROUNDS>
302 
306 
310 
314 
318 
322 
326 
327 } // namespace vsmc
328 
329 #endif // VSMC_RNG_PHILOX_HPP
#define UINT64_C(x)
Definition: opencl.h:42
Definition: monitor.hpp:49
#define VSMC_DEFINE_RNG_PHILOX_ROUND_CONSTANT(T, K, I, val)
Definition: philox.hpp:48
static void eval(std::array< T, 4 > &state, const std::array< T, 2 > &par)
Definition: philox.hpp:216
static void eval(std::array< T, 2 > &state, const std::array< T, 1 > &par)
Definition: philox.hpp:201
static constexpr std::size_t size()
Definition: philox.hpp:259
uint uint32_t
Definition: opencl.h:39
void increment(std::array< T, K > &ctr)
Increment a counter by one.
Definition: counter.hpp:62
static void eval(std::array< T, K > &, const std::array< T, K/2 > &)
Definition: philox.hpp:194
ulong uint64_t
Definition: opencl.h:40
STL namespace.
Counter based RNG engine.
Definition: counter.hpp:289
void reset(const key_type &)
Definition: philox.hpp:261
ResultType result_type
Definition: philox.hpp:255
void philox_hilo(std::uint32_t b, std::uint32_t &hi, std::uint32_t &lo)
Definition: philox.hpp:104
#define VSMC_RNG_PHILOX_VECTOR_LENGTH
PhiloxGenerator default vector length.
Definition: philox.hpp:64
static void eval(std::array< T, 2 > &par)
Definition: philox.hpp:183
static void eval(std::array< T, 1 > &par)
Definition: philox.hpp:173
Philox RNG generator.
Definition: philox.hpp:240
#define VSMC_RNG_PHILOX_ROUNDS
PhiloxGenerator default rounds.
Definition: philox.hpp:58
#define VSMC_DEFINE_RNG_PHILOX_WELY_CONSTANT(T, I, val)
Definition: philox.hpp:42
void operator()(ctr_type &ctr, const key_type &key, ctr_type &buffer) const
Definition: philox.hpp:263
std::array< ResultType, K > ctr_type
Definition: philox.hpp:256
#define UINT32_C(x)
Definition: opencl.h:41
std::array< ResultType, K/2 > key_type
Definition: philox.hpp:257
static void eval(std::array< T, K/2 > &)
Definition: philox.hpp:166
void operator()(ctr_type &ctr, const key_type &key, std::size_t n, ctr_type *buffer) const
Definition: philox.hpp:271