OpenRAND  0.9
OpenRAND: A C++ Library for Reproducible Random Number Generation in Parallel Computing Environments
philox.h
1 // @HEADER
2 // *******************************************************************************
3 // OpenRAND *
4 // A Performance Portable, Reproducible Random Number Generation Library *
5 // *
6 // Copyright (c) 2023, Michigan State University *
7 // *
8 // Permission is hereby granted, free of charge, to any person obtaining a copy *
9 // of this software and associated documentation files (the "Software"), to deal *
10 // in the Software without restriction, including without limitation the rights *
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
12 // copies of the Software, and to permit persons to whom the Software is *
13 // furnished to do so, subject to the following conditions: *
14 // *
15 // The above copyright notice and this permission notice shall be included in *
16 // all copies or substantial portions of the Software. *
17 // *
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *
24 // SOFTWARE. *
25 //********************************************************************************
26 // @HEADER
27 
28 #ifndef OPENRAND_Philox_H_
29 #define OPENRAND_Philox_H_
30 
31 #include <openrand/base_state.h>
32 
33 #include <array>
34 #include <cstdint>
35 #include <iostream>
36 #include <limits>
37 
38 #define PHILOX_W0 0x9E3779B9
39 #define PHILOX_W1 0xBB67AE85
40 #define PHILOX_M0 0xD2511F53
41 #define PHILOX_M1 0xCD9E8D57
42 
43 namespace openrand {
44 
51 class Philox : public BaseRNG<Philox> {
52  public:
64  OPENRAND_DEVICE Philox(uint64_t seed, uint32_t ctr,
65  uint32_t global_seed = openrand::DEFAULT_GLOBAL_SEED,
66  uint32_t ctr1 = 0x12345)
67  : seed_hi((uint32_t)(seed >> 32)),
68  seed_lo((uint32_t)(seed & 0xFFFFFFFF)),
69  ctr0(ctr),
70  ctr1(ctr1),
71  ctr2(global_seed) {
72  }
73 
74  template <typename T = uint32_t>
75  OPENRAND_DEVICE T draw() {
76  generate();
77 
78  static_assert(std::is_same_v<T, uint32_t> || std::is_same_v<T, uint64_t>);
79  if constexpr (std::is_same_v<T, uint32_t>) return _out[0];
80 
81  // Not wrapping this block in else{} would lead to compiler warning
82  else {
83  uint64_t res = (static_cast<uint64_t>(_out[0]) << 32) |
84  static_cast<uint64_t>(_out[1]);
85  return static_cast<uint64_t>(res);
86  }
87  }
88 
89  openrand::uint4 draw_int4() {
90  generate();
91  return openrand::uint4{_out[0], _out[1], _out[2], _out[3]};
92  }
93 
94  openrand::float4 draw_float4() {
95  generate();
96  return openrand::float4{
97  u01<float, uint32_t>(_out[0]), u01<float, uint32_t>(_out[1]),
98  u01<float, uint32_t>(_out[2]), u01<float, uint32_t>(_out[3])};
99  }
100 
101  private:
102  OPENRAND_DEVICE void generate() {
103  uint32_t key[2] = {seed_hi, seed_lo};
113  _out[0] = ctr0;
114  _out[1] = ctr1;
115  _out[2] = ctr2;
116  _out[3] = _ctr;
117 
118  for (int r = 0; r < 10; r++) {
119  if (r > 0) {
120  key[0] += PHILOX_W0;
121  key[1] += PHILOX_W1;
122  }
123  round(key, _out);
124  }
125  _ctr++;
126  }
127 
128  inline OPENRAND_DEVICE uint32_t mulhilo(uint32_t L, uint32_t R,
129  uint32_t *hip) {
130  uint64_t product = static_cast<uint64_t>(L) * static_cast<uint64_t>(R);
131  *hip = static_cast<uint32_t>(product >> 32);
132  return static_cast<uint32_t>(product);
133  }
134 
135  inline OPENRAND_DEVICE void round(const uint32_t (&key)[2],
136  uint32_t (&ctr)[4]) {
137  uint32_t hi0;
138  uint32_t hi1;
139  uint32_t lo0 = mulhilo(PHILOX_M0, ctr[0], &hi0);
140  uint32_t lo1 = mulhilo(PHILOX_M1, ctr[2], &hi1);
141  ctr[0] = hi1 ^ ctr[1] ^ key[0];
142  ctr[1] = lo1;
143  ctr[2] = hi0 ^ ctr[3] ^ key[1];
144  ctr[3] = lo0;
145  }
146 
147  // User provided seed and counter, constant throughout
148  // the lifetime of the rng object
149  const uint32_t seed_hi, seed_lo;
150  const uint32_t ctr0, ctr1, ctr2;
151  uint32_t _out[4];
152 
153  public:
154  // internal counter to keep track of numbers generated by this instance of rng
155  uint32_t _ctr = 0;
156 }; // class Philox
157 
158 } // namespace openrand
159 
160 #endif // OPENRAND_Philox_H_
Base class for random number generators.
Definition: base_state.h:50
Philox generator.
Definition: philox.h:51
OPENRAND_DEVICE Philox(uint64_t seed, uint32_t ctr, uint32_t global_seed=openrand::DEFAULT_GLOBAL_SEED, uint32_t ctr1=0x12345)
Construct a new Philox generator.
Definition: philox.h:64
Definition: util.h:95