Molassembler  1.0.0
Molecule graph and conformer library
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Jsf.h
Go to the documentation of this file.
1 
8 #ifndef INCLUDE_MOLASSEMBLER_TEMPLE_CONSTEXPR_JSF
9 #define INCLUDE_MOLASSEMBLER_TEMPLE_CONSTEXPR_JSF
10 
11 #include <cstdint>
12 #include <random>
13 #include <array>
14 
15 namespace Scine {
16 namespace Molassembler {
17 namespace Temple {
18 
19 /* Heavily modified from:
20  *
21  * A C++ implementation of a Bob Jenkins Small Fast (Noncryptographic) PRNGs
22  * Based on code published by Bob Jenkins in 2007, adapted for C++
23  *
24  * The MIT License (MIT)
25  *
26  * Copyright (c) 2018 Melissa E. O'Neill
27  *
28  * Permission is hereby granted, free of charge, to any person obtaining a
29  * copy of this software and associated documentation files (the "Software"),
30  * to deal in the Software without restriction, including without limitation
31  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
32  * and/or sell copies of the Software, and to permit persons to whom the
33  * Software is furnished to do so, subject to the following conditions:
34  *
35  * The above copyright notice and this permission notice shall be included in
36  * all copies or substantial portions of the Software.
37  *
38  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
43  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
44  * IN THE SOFTWARE.
45  */
46 
58 template<
59  typename UnsignedType,
60  unsigned p,
61  unsigned q,
62  unsigned r
63 > class JSF {
64 public:
66  using result_type = UnsignedType;
67 
71  static constexpr result_type min() {
72  return 0;
73  }
74 
76  static constexpr result_type max() {
77  return ~result_type(0);
78  }
80 
84  constexpr explicit JSF() = default;
85 
87  constexpr explicit JSF(const std::array<UnsignedType, 4>& input) {
88  static_assert(
89  std::is_unsigned<UnsignedType>::value,
90  "The underlying type of the JSF generator must be unsigned!"
91  );
92 
93  seed_(input);
94  }
95 
97  explicit JSF(std::seed_seq& seedSeq) {
98  seed_(seedSeq);
99  }
100 
102  explicit JSF(int seedInt) {
103  seed(seedInt);
104  }
106 
110  constexpr void seed(const std::array<UnsignedType, 4>& input) {
111  seed_(input);
112  }
113 
115  void seed(std::seed_seq& seedSeq) {
116  seed_(seedSeq);
117  }
118 
120  void seed(int seed) {
121  std::seed_seq seedSeq {{seed}};
122  seed_(seedSeq);
123  }
125 
128 
132  constexpr UnsignedType operator() () {
133  advance_();
134 
135  return d_;
136  }
137 
142  constexpr bool operator == (const JSF& other) const {
143  return (
144  a_ == other.a_
145  && b_ == other.b_
146  && c_ == other.c_
147  && d_ == other.d_
148  );
149  }
150 
152  constexpr bool operator != (const JSF& other) const {
153  return !(*this == other);
154  }
156 
157 private:
160  UnsignedType a_, b_, c_, d_;
162 
165  static constexpr unsigned bits = 8 * sizeof(UnsignedType);
167 
170  static constexpr UnsignedType rotate_(UnsignedType x, unsigned k) {
171  return (x << k) | (x >> (bits - k));
172  }
173 
174  constexpr void advance_() {
175  UnsignedType e = a_ - rotate_(b_, p);
176  a_ = b_ ^ rotate_(c_, q);
177  b_ = c_ + ((r > 0) ? rotate_(d_, r) : d_);
178  c_ = d_ + e;
179  d_ = e + a_;
180  }
181 
182  constexpr void advance_(unsigned N) {
183  for(unsigned i = 0; i < N; ++i) {
184  advance_();
185  }
186  }
187 
188  constexpr void seed_(const std::array<UnsignedType, 4>& state) {
189  a_ = state[0];
190  b_ = state[1];
191  c_ = state[2];
192  d_ = state[3];
193  }
194 
195  void seed_(std::seed_seq& seedSeq) {
196  std::array<UnsignedType, 4> stateArray;
197 
198  seedSeq.generate(
199  std::begin(stateArray),
200  std::end(stateArray)
201  );
202 
203  /* C++17 replace with if constexpr
204  *
205  * You can safely ignore the warning that shift cout >= width of type for
206  * instantiations with uint32_t by clang. In those cases, stateArray is
207  * already adequately filled.
208  */
209  if(std::is_same<UnsignedType, std::uint64_t>::value) {
210  /* seed_seq only generates 32 bit unsigneds, so just combine 8 32-bit
211  * values into 4 64-bit values for the state array
212  */
213  std::array<UnsignedType, 4> topBits;
214 
215  seedSeq.generate(
216  std::begin(topBits),
217  std::end(topBits)
218  );
219 
220  // Shift the topBits values by 32 and XOR them onto stateArray
221  for(unsigned i = 0; i < 4; ++i) {
222  stateArray[i] ^= (topBits[i] << 32);
223  }
224  }
225 
226  seed_(stateArray);
227  }
229 };
230 
232 //
233 // Each size has variations corresponding to different parameter sets.
234 // Each variant will create a distinct (and hopefully statistically
235 // independent) sequence.
236 //
237 // The constants are all those suggested by Bob Jenkins. The n variants
238 // perform only two rotations, the r variants perform three.
239 // 128 state bits, uint32_t output
240 
241 using JSF32na = JSF<uint32_t, 27, 17, 0>;
242 using JSF32nb = JSF<uint32_t, 9, 16, 0>;
243 using JSF32nc = JSF<uint32_t, 9, 24, 0>;
244 using JSF32nd = JSF<uint32_t, 10, 16, 0>;
245 using JSF32ne = JSF<uint32_t, 10, 24, 0>;
246 using JSF32nf = JSF<uint32_t, 11, 16, 0>;
247 using JSF32ng = JSF<uint32_t, 11, 24, 0>;
248 using JSF32nh = JSF<uint32_t, 25, 8, 0>;
249 using JSF32ni = JSF<uint32_t, 25, 16, 0>;
250 using JSF32nj = JSF<uint32_t, 26, 8, 0>;
251 using JSF32nk = JSF<uint32_t, 26, 16, 0>;
252 using JSF32nl = JSF<uint32_t, 26, 17, 0>;
253 using JSF32nm = JSF<uint32_t, 27, 16, 0>;
254 
255 using JSF32ra = JSF<uint32_t, 3, 14, 24>;
256 using JSF32rb = JSF<uint32_t, 3, 25, 15>;
257 using JSF32rc = JSF<uint32_t, 4, 15, 24>;
258 using JSF32rd = JSF<uint32_t, 6, 16, 28>;
259 using JSF32re = JSF<uint32_t, 7, 16, 27>;
260 using JSF32rf = JSF<uint32_t, 8, 14, 3>;
261 using JSF32rg = JSF<uint32_t, 11, 16, 23>;
262 using JSF32rh = JSF<uint32_t, 12, 16, 22>;
263 using JSF32ri = JSF<uint32_t, 12, 17, 23>;
264 using JSF32rj = JSF<uint32_t, 13, 16, 22>;
265 using JSF32rk = JSF<uint32_t, 15, 25, 3>;
266 using JSF32rl = JSF<uint32_t, 16, 9, 3>;
267 using JSF32rm = JSF<uint32_t, 17, 9, 3>;
268 using JSF32rn = JSF<uint32_t, 17, 27, 7>;
269 using JSF32ro = JSF<uint32_t, 19, 7, 3>;
270 using JSF32rp = JSF<uint32_t, 23, 15, 11>;
271 using JSF32rq = JSF<uint32_t, 23, 16, 11>;
272 using JSF32rr = JSF<uint32_t, 23, 17, 11>;
273 using JSF32rs = JSF<uint32_t, 24, 3, 16>;
274 using JSF32rt = JSF<uint32_t, 24, 4, 16>;
275 using JSF32ru = JSF<uint32_t, 25, 14, 3>;
276 using JSF32rv = JSF<uint32_t, 27, 16, 6>;
277 using JSF32rw = JSF<uint32_t, 27, 16, 7>;
278 
279 using JSF32n = JSF32na;
280 using JSF32r = JSF32rq;
281 using JSF32 = JSF32n;
282 
283 // - 256 state bits, uint64_t output
284 
285 using JSF64na = JSF<uint64_t, 39, 11, 0>;
286 using JSF64ra = JSF<uint64_t, 7, 13, 37>;
287 
288 using JSF64n = JSF64na;
289 using JSF64r = JSF64ra;
290 using JSF64 = JSF64r;
291 
293 template<class Engine = JSF32>
294 struct Generator {
295  Engine engine;
296 
297  explicit Generator() {
298 #ifndef NDEBUG
299  engine.seed(272181374);
300 #else
301  std::random_device randomDevice;
302 
303  engine.seed(
304  std::array<typename Engine::result_type, 4> {
305  randomDevice(),
306  randomDevice(),
307  randomDevice(),
308  randomDevice()
309  }
310  );
311 #endif
312  }
313 };
314 
315 } // namespace Temple
316 } // namespace Molassembler
317 } // namespace Scine
318 
319 #endif
JSF(std::seed_seq &seedSeq)
Construct from a seed sequence.
Definition: Jsf.h:97
static constexpr result_type max()
Maximum value of result_type.
Definition: Jsf.h:76
constexpr UnsignedType operator()()
Advance the state and return the current value.
Definition: Jsf.h:132
constexpr bool operator==(const JSF &other) const
Compares the underlying state of two instances.
Definition: Jsf.h:142
constexpr JSF()=default
Default constructor.
JSF(int seedInt)
Construct from a single integer seed value.
Definition: Jsf.h:102
Provides a seeded engine instance.
Definition: Jsf.h:294
void seed(int seed)
Seed the underlying state with a single integer value.
Definition: Jsf.h:120
constexpr JSF(const std::array< UnsignedType, 4 > &input)
Construct from four seed values.
Definition: Jsf.h:87
constexpr void seed(const std::array< UnsignedType, 4 > &input)
Seed the underlying state with four values.
Definition: Jsf.h:110
static constexpr result_type min()
Minimum value of result_type.
Definition: Jsf.h:71
UnsignedType result_type
When used as a functor, this is the return type of operator ()
Definition: Jsf.h:66
General class enabling the construction of a pattern of PRNGs by Bob Jenkins.
Definition: Jsf.h:63
void seed(std::seed_seq &seedSeq)
Seed the underlying state with a seed sequence.
Definition: Jsf.h:115
constexpr bool operator!=(const JSF &other) const
Compares the underlying state of two instances.
Definition: Jsf.h:152