Program Listing for File Random.cpp
↰ Return to documentation for file (src/Random.cpp
)
// Random.cpp is based on Random.h
// Mersenne Twister random number generator -- a C++ class Random
// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com
// The Mersenne Twister is an algorithm for generating random numbers. It
// was designed with consideration of the flaws in various other generators.
// The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
// are far greater. The generator is also fast; it avoids multiplication and
// division, and it benefits from caches and pipelines. For more information
// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
// Reference
// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
// Copyright (C) 2000 - 2003, Richard J. Wagner
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. The names of its contributors may not be used to endorse or promote
// products derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// The original code included the following notice:
//
// When you use this, send an email to: matumoto@math.keio.ac.jp
// with an appropriate reference to your work.
//
// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu
// when you write.
// Parts of this file are modified beginning in 29.10.09 for adaption in PXL.
// Parts of this file are modified beginning in 10.02.12 for adaption in CRPropa.
#include "crpropa/Random.h"
#include "crpropa/base64.h"
#include <cstdio>
namespace crpropa {
Random::Random(const uint32_t& oneSeed) {
seed(oneSeed);
}
Random::Random(uint32_t * const bigSeed, const uint32_t seedLength) {
seed(bigSeed, seedLength);
}
Random::Random() {
seed();
}
double Random::rand() {
return double(randInt()) * (1.0 / 4294967295.0);
}
double Random::rand(const double& n) {
return rand() * n;
}
double Random::randExc() {
return double(randInt()) * (1.0 / 4294967296.0);
}
double Random::randExc(const double& n) {
return randExc() * n;
}
double Random::randDblExc() {
return (double(randInt()) + 0.5) * (1.0 / 4294967296.0);
}
double Random::randDblExc(const double& n) {
return randDblExc() * n;
}
double Random::rand53() {
uint32_t a = randInt() >> 5, b = randInt() >> 6;
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); // by Isaku Wada
}
// Return a real number from a normal (Gaussian) distribution with given
// mean and variance by Box-Muller method
double Random::randNorm(const double& mean, const double& variance) {
double r = sqrt(-2.0 * log(1.0 - randDblExc())) * variance;
double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
return mean + r * cos(phi);
}
double Random::randUniform(double min, double max) {
return min + (max - min) * rand();
}
double Random::randRayleigh(double sigma) {
return sigma * sqrt(-2.0 * log(1 - rand()));
}
double Random::randFisher(double kappa) {
return acos(1. + 1. / kappa * log(1 - rand() * (1 - exp(-2 * kappa))));
}
size_t Random::randBin(const std::vector<float> &cdf) {
std::vector<float>::const_iterator it = std::lower_bound(cdf.begin(),
cdf.end(), rand() * cdf.back());
return it - cdf.begin();
}
size_t Random::randBin(const std::vector<double> &cdf) {
std::vector<double>::const_iterator it = std::lower_bound(cdf.begin(),
cdf.end(), rand() * cdf.back());
return it - cdf.begin();
}
Vector3d Random::randVector() {
double z = randUniform(-1.0, 1.0);
double t = randUniform(-1.0 * M_PI, M_PI);
double r = sqrt(1 - z * z);
return Vector3d(r * cos(t), r * sin(t), z);
}
Vector3d Random::randVectorAroundMean(const Vector3d &meanDirection,
double angle) {
Vector3d axis = meanDirection.cross(randVector());
Vector3d v = meanDirection;
return v.getRotated(axis, angle);
}
Vector3d Random::randFisherVector(const Vector3d &meanDirection, double kappa) {
return randVectorAroundMean(meanDirection, randFisher(kappa));
}
Vector3d Random::randConeVector(const Vector3d &meanDirection, double angularRadius) {
const double theta = acos(randUniform(1, cos(angularRadius)));
return randVectorAroundMean(meanDirection, theta);
}
Vector3d Random::randVectorLamberts() {
// random vector following Lamberts cosine law (https://en.wikipedia.org/wiki/Lambert%27s_cosine_law)
// for a surface element with normal vector pointing in positive z-axis (0, 0, 1)
double phi = randUniform(-1.0 * M_PI, M_PI);
double theta = M_PI / 2.0 - acos(sqrt(randUniform(0, 1)));
return Vector3d(cos(phi) * cos(theta), sin(phi) * cos(theta), sin(theta));
}
Vector3d Random::randVectorLamberts(const Vector3d &normalVector) {
// random vector following Lamberts cosine law for a surface element described by normalVector
Vector3d vLambertz = randVectorLamberts();
// find rotation axis that rotates the z-axis to the normalVector of the surface element
Vector3d axis = normalVector.cross(Vector3d(0, 0, 1));
if (axis.getR() < std::numeric_limits<double>::epsilon()) {
axis = Vector3d(0, 0, 1);
}
double angle = normalVector.getAngleTo(Vector3d(0, 0, 1));
// rotate the random Lamberts vector from z-axis to respective surface element
return vLambertz.getRotated(axis / axis.getR(), -angle);
}
Vector3d Random::randomInterpolatedPosition(const Vector3d &a, const Vector3d &b) {
return a + rand() * (b - a);
}
double Random::randPowerLaw(double index, double min, double max) {
if ((min < 0) || (max < min)) {
throw std::runtime_error(
"Power law distribution only possible for 0 <= min <= max");
}
//check for index -1!
if ((std::abs(index + 1.0)) < std::numeric_limits<double>::epsilon()) {
double part1 = log(max);
double part2 = log(min);
return exp((part1 - part2) * rand() + part2);
} else {
double part1 = pow(max, index + 1);
double part2 = pow(min, index + 1);
double ex = 1 / (index + 1);
return pow((part1 - part2) * rand() + part2, ex);
}
}
double Random::randBrokenPowerLaw(double index1, double index2,
double breakpoint, double min, double max) {
if ((min <= 0) || (max < min)) {
throw std::runtime_error(
"Power law distribution only possible for 0 < min <= max");
}
if (min >= breakpoint) {
return this->randPowerLaw(index2, min, max);
} else if (max <= breakpoint) {
return this->randPowerLaw(index2, min, max);
} else {
double intPL1;
// check if index1 = -1
if ((std::abs(index1 + 1.0)) < std::numeric_limits<double>::epsilon()) {
intPL1 = log(breakpoint / min);
} else {
intPL1 = (pow(breakpoint, index1 + 1) - pow(min, index1 + 1))
/ (index1 + 1);
}
double intPL2;
// check if index2 = -1
if ((std::abs(index2 + 1.0)) < std::numeric_limits<double>::epsilon()) {
intPL2 = log(max / breakpoint) * pow(breakpoint, index1 - index2);
} else {
intPL2 = (pow(max, index2 + 1) - pow(breakpoint, index2 + 1))
* pow(breakpoint, index1 - index2) / (index2 + 1);
}
if (rand() > intPL1 / (intPL1 + intPL2))
return randPowerLaw(index2, breakpoint, max);
else
return randPowerLaw(index1, min, breakpoint);
}
}
double Random::randExponential() {
double dum;
do {
dum = rand();
} while (dum < std::numeric_limits<double>::epsilon());
return -1.0 * log(dum);
}
uint32_t Random::randInt() {
if (left == 0)
reload();
--left;
uint32_t s1;
s1 = *pNext++;
s1 ^= (s1 >> 11);
s1 ^= (s1 << 7) & 0x9d2c5680UL;
s1 ^= (s1 << 15) & 0xefc60000UL;
return (s1 ^ (s1 >> 18));
}
uint32_t Random::randInt(const uint32_t& n) {
// Find which bits are used in n
// Optimized by Magnus Jonsson (magnus@smartelectronix.com)
uint32_t used = n;
used |= used >> 1;
used |= used >> 2;
used |= used >> 4;
used |= used >> 8;
used |= used >> 16;
// Draw numbers until one is found in [0,n]
uint32_t i;
do
i = randInt() & used; // toss unused bits to shorten search
while (i > n);
return i;
}
uint64_t Random::randInt64()
{
int64_t a = randInt();
int64_t b = randInt();
return (b + a << 32);
}
uint64_t Random::randInt64(const uint64_t &n)
{
uint64_t used = n;
used |= used >> 1;
used |= used >> 2;
used |= used >> 4;
used |= used >> 8;
used |= used >> 16;
used |= used >> 32;
// Draw numbers until one is found in [0,n]
uint64_t i;
do
i = randInt64() & used; // toss unused bits to shorten search
while (i > n);
return i;
}
void Random::seed(const uint32_t oneSeed) {
initial_seed.resize(1);
initial_seed[0] = oneSeed;
initialize(oneSeed);
reload();
}
void Random::seed(uint32_t * const bigSeed, const uint32_t seedLength) {
initial_seed.resize(seedLength);
for (size_t i =0; i< seedLength; i++)
{
initial_seed[i] = bigSeed[i];
}
initialize(19650218UL);
int i = 1;
uint32_t j = 0;
int k = (N > seedLength ? N : seedLength);
for (; k; --k) {
state[i] = state[i]
^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL);
state[i] += (bigSeed[j] & 0xffffffffUL) + j;
state[i] &= 0xffffffffUL;
++i;
++j;
if (i >= N) {
state[0] = state[N - 1];
i = 1;
}
if (j >= seedLength)
j = 0;
}
for (k = N - 1; k; --k) {
state[i] = state[i]
^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL);
state[i] -= i;
state[i] &= 0xffffffffUL;
++i;
if (i >= N) {
state[0] = state[N - 1];
i = 1;
}
}
state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
reload();
}
void Random::seed() {
// First try getting an array from /dev/urandom
FILE* urandom = std::fopen("/dev/urandom", "rb");
if (urandom) {
uint32_t bigSeed[N];
uint32_t *s = bigSeed;
int i = N;
bool success = true;
while (success && i--)
success = std::fread(s++, sizeof(uint32_t), 1, urandom) != 0;
std::fclose(urandom);
if (success) {
seed(bigSeed, N);
return;
}
}
// Was not successful, so use time() and clock() instead
seed(hash(time(NULL), clock()));
}
void Random::initialize(const uint32_t seed) {
uint32_t *s = state;
uint32_t *r = state;
int i = 1;
*s++ = seed & 0xffffffffUL;
for (; i < N; ++i) {
*s++ = (1812433253UL * (*r ^ (*r >> 30)) + i) & 0xffffffffUL;
r++;
}
}
void Random::reload() {
uint32_t *p = state;
int i;
for (i = N - M; i--; ++p)
*p = twist(p[M], p[0], p[1]);
for (i = M; --i; ++p)
*p = twist(p[M - N], p[0], p[1]);
*p = twist(p[M - N], p[0], state[0]);
left = N, pNext = state;
}
uint32_t Random::hash(time_t t, clock_t c) {
static uint32_t differ = 0; // guarantee time-based seeds will change
uint32_t h1 = 0;
unsigned char *p = (unsigned char *) &t;
for (size_t i = 0; i < sizeof(t); ++i) {
h1 *= std::numeric_limits<unsigned char>::max() + 2U;
h1 += p[i];
}
uint32_t h2 = 0;
p = (unsigned char *) &c;
for (size_t j = 0; j < sizeof(c); ++j) {
h2 *= std::numeric_limits<unsigned char>::max() + 2U;
h2 += p[j];
}
return (h1 + differ++) ^ h2;
}
void Random::save(uint32_t* saveArray) const {
uint32_t *sa = saveArray;
const uint32_t *s = state;
int i = N;
for (; i--; *sa++ = *s++) {
}
*sa = left;
}
const std::vector<uint32_t> &Random::getSeed() const
{
return initial_seed;
}
void Random::load(uint32_t * const loadArray) {
uint32_t *s = state;
uint32_t *la = loadArray;
int i = N;
for (; i--; *s++ = *la++) {
}
left = *la;
pNext = &state[N - left];
}
std::ostream& operator<<(std::ostream& os, const Random& mtrand) {
const uint32_t *s = mtrand.state;
int i = mtrand.N;
for (; i--; os << *s++ << "\t") {
}
return os << mtrand.left;
}
std::istream& operator>>(std::istream& is, Random& mtrand) {
uint32_t *s = mtrand.state;
int i = mtrand.N;
for (; i--; is >> *s++) {
}
is >> mtrand.left;
mtrand.pNext = &mtrand.state[mtrand.N - mtrand.left];
return is;
}
#ifdef _OPENMP
#include <omp.h>
#include <stdexcept>
// see http://stackoverflow.com/questions/8051108/using-the-openmp-threadprivate-directive-on-static-instances-of-c-stl-types
const static int MAX_THREAD = 256;
struct RANDOM_TLS_ITEM {
Random r;
char padding[(sizeof(Random) / 64 + 1) * 64 - sizeof(Random)];
};
#ifdef _MSC_VER
__declspec(align(64)) static RANDOM_TLS_ITEM _tls[MAX_THREAD];
#else
__attribute__ ((aligned(64))) static RANDOM_TLS_ITEM _tls[MAX_THREAD];
#endif
Random &Random::instance() {
int i = omp_get_thread_num();
if (i >= MAX_THREAD)
throw std::runtime_error("crpropa::Random: more than MAX_THREAD threads!");
return _tls[i].r;
}
void Random::seedThreads(const uint32_t oneSeed) {
for(size_t i = 0; i < MAX_THREAD; ++i)
_tls[i].r.seed(oneSeed + i);
}
std::vector< std::vector<uint32_t> > Random::getSeedThreads()
{
std::vector< std::vector<uint32_t> > seeds;
for(size_t i = 0; i < omp_get_num_threads(); ++i)
seeds.push_back(_tls[i].r.getSeed() );
return seeds;
}
#else
static Random _random;
Random &Random::instance() {
return _random;
}
void Random::seedThreads(const uint32_t oneSeed) {
_random.seed(oneSeed);
}
std::vector< std::vector<uint32_t> > Random::getSeedThreads()
{
std::vector< std::vector<uint32_t> > seeds;
seeds.push_back(_random.getSeed() );
return seeds;
}
#endif
const std::string Random::getSeed_base64() const
{
return Base64::encode((unsigned char*) &initial_seed[0], sizeof(initial_seed[0]) * initial_seed.size() / sizeof(unsigned char));
}
void Random::seed(const std::string &b64Seed)
{
std::string decoded_data = Base64::decode(b64Seed);
size_t seedSize = decoded_data.size() * sizeof(decoded_data[0]) / sizeof(uint32_t);
seed((uint32_t*)decoded_data.c_str(), seedSize );
}
} // namespace crpropa