Allolib  1.0
C++ Components For Interactive Multimedia
al_Random.hpp
1 #ifndef INCLUDE_AL_UTIL_MATH_RANDOM_HPP
2 #define INCLUDE_AL_UTIL_MATH_RANDOM_HPP
3 
4 /* Allocore --
5  Multimedia / virtual environment application class library
6 
7  Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
8  Copyright (C) 2012. The Regents of the University of California.
9  All rights reserved.
10 
11  Redistribution and use in source and binary forms, with or without
12  modification, are permitted provided that the following conditions are met:
13 
14  Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16 
17  Redistributions in binary form must reproduce the above copyright
18  notice, this list of conditions and the following disclaimer in the
19  documentation and/or other materials provided with the distribution.
20 
21  Neither the name of the University of California nor the names of its
22  contributors may be used to endorse or promote products derived from
23  this software without specific prior written permission.
24 
25  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  POSSIBILITY OF SUCH DAMAGE.
36 
37 
38  File description:
39  Various flavors of pseudo-random number generators and distributions
40 
41  File author(s):
42  Lance Putnam, 2006, putnam.lance@gmail.com
43 */
44 
45 #include "al/math/al_StdRandom.hpp"
46 
47 /* req'd for int to float conversion */
48 #include <time.h> /* req'd for time() */
49 
50 #include <cmath>
51 #include <random>
52 
53 #include "al/math/al_Constants.hpp"
54 #include "al/types/al_Conversion.hpp"
55 
56 namespace al {
57 
59 namespace rnd {
60 
61 class LinCon;
62 class MulLinCon;
63 class Tausworthe;
64 template <class RNG>
65 class Random;
66 
68 inline static uint32_t seed() {
69  static uint32_t val = time(NULL);
70  return val = val * 1664525UL + 1013904223UL;
71 }
72 
76 template <class RNG = al::rnd::Tausworthe>
77 class Random {
78  public:
80  Random() {}
81 
83  Random(uint32_t seed) : mRNG(seed) {}
84 
86  Random& seed(uint32_t v) {
87  mRNG.seed(v);
88  return *this;
89  }
90 
92  RNG& rng() { return mRNG; }
93 
95  float uniform() { return al::uintToUnit<float>(mRNG()); }
96 
98  template <class T>
99  T uniform(const T& hi) {
100  return hi * uniform();
101  }
102 
104  template <class T>
105  T uniform(const T& hi, const T& lo) {
106  return T((hi - lo) * uniform()) + lo;
107  }
108 
110  float uniformS() { return al::uintToUnitS<float>(mRNG()); }
111 
113  template <class T>
114  T uniformS(const T& lim) {
115  return lim * uniformS();
116  }
117 
119 
123  template <int N, class T>
124  void ball(T* point);
125 
127  template <template <int, class> class VecType, int N, class T>
128  void ball(VecType<N, T>& point) {
129  ball<N>(&point[0]);
130  }
131 
133  template <class VecType>
134  VecType ball() {
135  VecType v;
136  ball(v);
137  return v;
138  }
139 
141  float normal() {
142  float r;
143  normal(r, r);
144  return r;
145  }
146 
148  template <class T>
149  void normal(T& y1, T& y2);
150 
152  float triangle();
153 
155  template <class T>
156  T triangle(const T& hi) {
157  return hi * triangle();
158  }
159 
161  float sign(float x = 1.f);
162 
164  bool prob() { return mRNG() & 0x80000000; }
165 
167  bool prob(float p) { return uniform() < p; }
168 
170  template <class T>
171  void shuffle(T* arr, uint32_t len);
172 
173  // DEPRECATED:
174  float gaussian() { return normal(); }
175  template <class T>
176  void gaussian(T& y1, T& y2) {
177  normal(y1, y2);
178  }
179 
180  protected:
181  RNG mRNG;
182 };
183 
185 
195 class LinCon {
196  public:
198  LinCon() {
199  seed(al::rnd::seed());
200  type(0);
201  }
202 
204  LinCon(uint32_t seed) : mVal(seed) { type(0); }
205 
207  uint32_t operator()() { return mVal = mVal * mMul + mAdd; }
208 
210  void seed(uint32_t v) { mVal = v; }
211 
213 
216  void type(int v) {
217  switch (v) {
218  default:
219  case 0:
220  mMul = 1664525;
221  mAdd = 1013904223;
222  break;
223  case 1:
224  mMul = 2147001325;
225  mAdd = 715136305;
226  break;
227  }
228  }
229 
230  private:
231  uint32_t mVal;
232  uint32_t mMul, mAdd;
233 };
234 
236 
244 class MulLinCon {
245  public:
248  seed(al::rnd::seed());
249  type(0);
250  }
251 
253  MulLinCon(uint32_t seed) : mVal(seed) { type(0); }
254 
256  uint32_t operator()() { return mVal *= mMul; }
257 
259  void seed(uint32_t v) { mVal = v; }
260 
262 
267  void type(int v) {
268  switch (v) {
269  default:
270  mMul = 2891336453UL;
271  break; // L'Ecuyer M8
272  case 1:
273  mMul = 29943829UL;
274  break; // L'Ecuyer M16
275  case 2:
276  mMul = 32310901UL;
277  break; // L'Ecuyer M32
278  case 3:
279  mMul = 69069UL;
280  break; // Super-duper
281  }
282  }
283 
284  private:
285  uint32_t mVal;
286  uint32_t mMul;
287 };
288 
290 
299 class Tausworthe {
300  public:
302  Tausworthe();
303 
305  Tausworthe(uint32_t seed);
306 
308  uint32_t operator()();
309 
311  void seed(uint32_t v);
312 
314  void seed(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4);
315 
316  private:
317  uint32_t s1, s2, s3, s4;
318  void iterate();
319 };
320 
321 // Implementation_______________________________________________________________
322 
323 inline Tausworthe::Tausworthe() { seed(al::rnd::seed()); }
324 inline Tausworthe::Tausworthe(uint32_t sd) { seed(sd); }
325 
326 inline uint32_t Tausworthe::operator()() {
327  iterate();
328  return s1 ^ s2 ^ s3 ^ s4;
329 }
330 
331 inline void Tausworthe::seed(uint32_t v) {
332  al::rnd::LinCon g(v);
333  g();
334  seed(g(), g(), g(), g());
335 }
336 
337 inline void Tausworthe::seed(uint32_t v1, uint32_t v2, uint32_t v3,
338  uint32_t v4) {
339  // printf("%u %u %u %u\n", v1, v2, v3, v4);
340  v1& 0xffffffe ? s1 = v1 : s1 = ~v1;
341  v2& 0xffffff8 ? s2 = v2 : s2 = ~v2;
342  v3& 0xffffff0 ? s3 = v3 : s3 = ~v3;
343  v4& 0xfffff80 ? s4 = v4 : s4 = ~v4;
344 }
345 
346 inline void Tausworthe::iterate() {
347  s1 = ((s1 & 0xfffffffe) << 18) ^ (((s1 << 6) ^ s1) >> 13);
348  s2 = ((s2 & 0xfffffff8) << 2) ^ (((s2 << 2) ^ s2) >> 27);
349  s3 = ((s3 & 0xfffffff0) << 7) ^ (((s3 << 13) ^ s3) >> 21);
350  s4 = ((s4 & 0xffffff80) << 13) ^ (((s4 << 3) ^ s4) >> 12);
351 }
352 
353 template <class RNG>
354 template <int N, class T>
355 void Random<RNG>::ball(T* point) {
356  T w;
357  do {
358  w = T(0);
359  for (int i = 0; i < N; ++i) {
360  float v = uniformS();
361  point[i] = v;
362  w += v * v;
363  }
364  } while (w >= T(1)); // if on or outside unit ball, try again
365 }
366 
367 // Box-Muller transform
368 // Box, G. and Muller, M. A note on the generation of normal deviates.
369 // Ann. Math. Slat. 28, (1958).
370 //
371 // http://en.wikipedia.org/wiki/Box-Muller_transform
372 template <class RNG>
373 template <class T>
374 void Random<RNG>::normal(T& y1, T& y2) {
375  float x1, x2, w;
376 
377  // Search for point within unit circle using sample-reject.
378  // This will pass with probability pi/4 = ~0.785.
379  do {
380  x1 = uniformS();
381  x2 = uniformS();
382  w = x1 * x1 + x2 * x2;
383  } while (w >= 1.f);
384 
385  // perform inverse Gaussian function mapping
386  w = std::sqrt((-2.f * std::log(w)) / w);
387  y1 = T(x1 * w);
388  y2 = T(x2 * w);
389 }
390 
391 template <class RNG>
392 inline float Random<RNG>::triangle() {
393  union {
394  float f;
395  uint32_t i;
396  } u, v;
397  u.i = 0x3f800000 | (mRNG() >> 9); // float in [1,2)
398  v.i = 0x3f800000 | (mRNG() >> 9); // float in [1,2)
399  return u.f - v.f;
400 }
401 
402 template <class RNG>
403 inline float Random<RNG>::sign(float x) {
404  union {
405  float f;
406  uint32_t i;
407  } u = {x};
408  u.i |= mRNG() & 0x80000000;
409  return u.f;
410 }
411 
412 // Fisher-Yates shuffle
413 template <class RNG>
414 template <class T>
415 void Random<RNG>::shuffle(T* arr, uint32_t len) {
416  for (uint32_t i = len - 1; i > 0; --i) {
417  uint32_t j = uniform(i + 1);
418  T t = arr[i];
419  arr[i] = arr[j];
420  arr[j] = t;
421  }
422 }
423 
424 } // namespace rnd
425 
426 // for using std random class with al_Random interface
427 
428 class StdRnd {
429  public:
430  rand_uniformf mUniformf;
431  rand_uniformi mUniformi;
432 
433  StdRnd() : mUniformf{} {}
434  StdRnd(unsigned int seed) : mUniformf{seed}, mUniformi{seed} {}
435 
436  // [0, 1)
437  float operator()() { return mUniformf(); }
438  float operator()(float hi) { return mUniformf(0, hi); }
439  float operator()(float lo, float hi) { return mUniformf(lo, hi); }
440 
441  void seed(unsigned int s) { mUniformf.seed(s); }
442 
443  int randi(int hi) { return mUniformi(0, hi); }
444  int randi(int lo, int hi) { return mUniformi(lo, hi); }
445 
446  void seedi(unsigned int s) { mUniformi.seed(s); }
447 };
448 
450 
451 namespace rnd {
452 
453 template <>
454 inline float StdRandom::uniform() {
455  return mRNG();
456 }
457 
458 template <>
459 template <typename T>
460 inline T StdRandom::uniform(T const& hi) {
461  return static_cast<T>(mRNG(float(hi)));
462 }
463 
464 template <>
465 template <typename T>
466 inline T StdRandom::uniform(T const& hi, T const& lo) {
467  return static_cast<T>(mRNG(float(lo), float(hi)));
468 }
469 
470 template <>
471 inline float StdRandom::uniformS() {
472  return mRNG(-1.0f, 1.0f);
473 }
474 
475 template <>
476 template <typename T>
477 inline T StdRandom::uniformS(T const& lim) {
478  return static_cast<T>(mRNG(float(-lim), float(lim)));
479 }
480 
481 template <>
482 inline float StdRandom::triangle() {
483  return 0.5f * (uniformS() + uniformS());
484 }
485 
486 template <>
487 inline float StdRandom::sign(float x) {
488  static float arr[2] = {-1.0f, 1.0f};
489  return x * arr[mRNG.randi(0, 1)];
490 }
491 
492 template <>
493 template <class T>
494 inline void StdRandom::shuffle(T* arr, uint32_t len) {
495  for (uint32_t i = len - 1; i > 0; i -= 1) {
496  uint32_t j = mRNG.randi(i + 1);
497  T t = arr[i];
498  arr[i] = arr[j];
499  arr[j] = t;
500  }
501 }
502 
503 } // namespace rnd
504 
505 } // namespace al
506 
507 #endif
Linear congruential uniform pseudo-random number generator.
Definition: al_Random.hpp:195
uint32_t operator()()
Generate next uniform random integer in [0, 2^32)
Definition: al_Random.hpp:207
LinCon()
Default constructor uses a randomly generated seed.
Definition: al_Random.hpp:198
void seed(uint32_t v)
Set seed.
Definition: al_Random.hpp:210
void type(int v)
Change the type of equation used.
Definition: al_Random.hpp:216
LinCon(uint32_t seed)
Definition: al_Random.hpp:204
Multiplicative linear congruential uniform pseudo-random number generator.
Definition: al_Random.hpp:244
uint32_t operator()()
Generate next uniform random integer in [0, 2^32)
Definition: al_Random.hpp:256
void seed(uint32_t v)
Set seed.
Definition: al_Random.hpp:259
void type(int v)
Change the type of equation used.
Definition: al_Random.hpp:267
MulLinCon()
Default constructor uses a randomly generated seed.
Definition: al_Random.hpp:247
MulLinCon(uint32_t seed)
Definition: al_Random.hpp:253
float normal()
Returns standard normal variate.
Definition: al_Random.hpp:141
Random & seed(uint32_t v)
Set seed.
Definition: al_Random.hpp:86
Random(uint32_t seed)
Definition: al_Random.hpp:83
bool prob()
Returns true with a probability of 0.5.
Definition: al_Random.hpp:164
float triangle()
Returns triangle distribution variate, in (-1,1)
Definition: al_Random.hpp:392
RNG & rng()
Get underlying random number generator.
Definition: al_Random.hpp:92
void ball(VecType< N, T > &point)
Returns point within a unit ball.
Definition: al_Random.hpp:128
VecType ball()
Returns point within a unit ball.
Definition: al_Random.hpp:134
T uniform(const T &hi)
Returns uniform random in [0, hi)
Definition: al_Random.hpp:99
T uniform(const T &hi, const T &lo)
Returns uniform random in [lo, hi)
Definition: al_Random.hpp:105
float uniformS()
Returns uniform random in [-1, 1)
Definition: al_Random.hpp:110
float sign(float x=1.f)
Returns argument with sign randomly flipped.
Definition: al_Random.hpp:403
void shuffle(T *arr, uint32_t len)
Randomly shuffles elements in array.
Definition: al_Random.hpp:415
T uniformS(const T &lim)
Returns uniform random in [-lim, lim)
Definition: al_Random.hpp:114
float uniform()
Returns uniform random in [0, 1)
Definition: al_Random.hpp:95
Random()
Default constructor uses a randomly generated seed.
Definition: al_Random.hpp:80
T triangle(const T &hi)
Returns triangle distribution variate, in (-hi,hi)
Definition: al_Random.hpp:156
bool prob(float p)
Returns true with a probability of p.
Definition: al_Random.hpp:167
Combined Tausworthe uniform pseudo-random number generator.
Definition: al_Random.hpp:299
Tausworthe()
Default constructor uses a randomly generated seed.
Definition: al_Random.hpp:323
void seed(uint32_t v)
Set seed.
Definition: al_Random.hpp:331
uint32_t operator()()
Generate next uniform random integer in [0, 2^32)
Definition: al_Random.hpp:326
float uniformS()
Returns signed uniform random in (-1, 1)
float uniform()
Returns uniform random in [0, 1)
Definition: al_App.hpp:23