Bastian M. Wojek 55071fb754 Updated the built-in version of the cuba library to version 2.1 within the BMWlibs.
Also the cuba-compiler-check for gcc-versions containing a certain bug (4.2, 4.4.3) has been adopted.
This still needs to be tested on systems having such a gcc.

If this new version of the built-in library should be installed,
first make sure that the old version is completely deinstalled (including headers, pkg-config-files, etc.).
2011-01-27 13:46:51 +00:00

366 lines
10 KiB
C

/*
Random.c
quasi- and pseudo-random-number generation
last modified 8 Jun 10 th
*/
/***************************************************************************
* Copyright (C) 2004-2010 by Thomas Hahn *
* hahn@feynarts.de *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
/*
PART 1: Sobol quasi-random-number generator
adapted from ACM TOMS algorithm 659
*/
static void SobolGet(This *t, real *x)
{
number seq = t->rng.sobol.seq++;
count zerobit = 0, dim;
while( seq & 1 ) {
++zerobit;
seq >>= 1;
}
for( dim = 0; dim < t->ndim; ++dim ) {
t->rng.sobol.prev[dim] ^= t->rng.sobol.v[dim][zerobit];
x[dim] = t->rng.sobol.prev[dim]*t->rng.sobol.norm;
}
}
static void SobolSkip(This *t, number n)
{
while( n-- ) {
number seq = t->rng.sobol.seq++;
count zerobit = 0, dim;
while( seq & 1 ) {
++zerobit;
seq >>= 1;
}
for( dim = 0; dim < t->ndim; ++dim )
t->rng.sobol.prev[dim] ^= t->rng.sobol.v[dim][zerobit];
}
}
static inline void SobolIni(This *t)
{
static number ini[9*40] = {
3, 1, 0, 0, 0, 0, 0, 0, 0,
7, 1, 1, 0, 0, 0, 0, 0, 0,
11, 1, 3, 7, 0, 0, 0, 0, 0,
13, 1, 1, 5, 0, 0, 0, 0, 0,
19, 1, 3, 1, 1, 0, 0, 0, 0,
25, 1, 1, 3, 7, 0, 0, 0, 0,
37, 1, 3, 3, 9, 9, 0, 0, 0,
59, 1, 3, 7, 13, 3, 0, 0, 0,
47, 1, 1, 5, 11, 27, 0, 0, 0,
61, 1, 3, 5, 1, 15, 0, 0, 0,
55, 1, 1, 7, 3, 29, 0, 0, 0,
41, 1, 3, 7, 7, 21, 0, 0, 0,
67, 1, 1, 1, 9, 23, 37, 0, 0,
97, 1, 3, 3, 5, 19, 33, 0, 0,
91, 1, 1, 3, 13, 11, 7, 0, 0,
109, 1, 1, 7, 13, 25, 5, 0, 0,
103, 1, 3, 5, 11, 7, 11, 0, 0,
115, 1, 1, 1, 3, 13, 39, 0, 0,
131, 1, 3, 1, 15, 17, 63, 13, 0,
193, 1, 1, 5, 5, 1, 27, 33, 0,
137, 1, 3, 3, 3, 25, 17, 115, 0,
145, 1, 1, 3, 15, 29, 15, 41, 0,
143, 1, 3, 1, 7, 3, 23, 79, 0,
241, 1, 3, 7, 9, 31, 29, 17, 0,
157, 1, 1, 5, 13, 11, 3, 29, 0,
185, 1, 3, 1, 9, 5, 21, 119, 0,
167, 1, 1, 3, 1, 23, 13, 75, 0,
229, 1, 3, 3, 11, 27, 31, 73, 0,
171, 1, 1, 7, 7, 19, 25, 105, 0,
213, 1, 3, 5, 5, 21, 9, 7, 0,
191, 1, 1, 1, 15, 5, 49, 59, 0,
253, 1, 1, 1, 1, 1, 33, 65, 0,
203, 1, 3, 5, 15, 17, 19, 21, 0,
211, 1, 1, 7, 11, 13, 29, 3, 0,
239, 1, 3, 7, 5, 7, 11, 113, 0,
247, 1, 1, 5, 3, 15, 19, 61, 0,
285, 1, 3, 1, 1, 9, 27, 89, 7,
369, 1, 1, 3, 7, 31, 15, 45, 23,
299, 1, 3, 3, 9, 9, 25, 107, 39 };
count dim, bit, nbits;
number max, *pini = ini;
cnumber nmax = 2*t->maxeval;
for( nbits = 0, max = 1; max <= nmax; max <<= 1 ) ++nbits;
t->rng.sobol.norm = 1./max;
for( bit = 0; bit < nbits; ++bit )
t->rng.sobol.v[0][bit] = (max >>= 1);
for( dim = 1; dim < t->ndim; ++dim ) {
number *pv = t->rng.sobol.v[dim], *pvv = pv;
number powers = *pini++, j;
int inibits = -1, bit;
for( j = powers; j; j >>= 1 ) ++inibits;
memcpy(pv, pini, inibits*sizeof(*pini));
pini += 8;
for( bit = inibits; bit < nbits; ++bit ) {
number newv = *pvv, j = powers;
int b;
for( b = 0; b < inibits; ++b ) {
if( j & 1 ) newv ^= pvv[b] << (inibits - b);
j >>= 1;
}
pvv[inibits] = newv;
++pvv;
}
for( bit = 0; bit < nbits - 1; ++bit )
pv[bit] <<= nbits - bit - 1;
}
t->rng.sobol.seq = 0;
VecClear(t->rng.sobol.prev);
t->rng.getrandom = SobolGet;
t->rng.skiprandom = SobolSkip;
}
/*
PART 2: Mersenne Twister pseudo-random-number generator
adapted from T. Nishimura's and M. Matsumoto's C code at
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
*/
/* 32 or 53 random bits */
#define RANDOM_BITS 32
static inline state_t Twist(state_t a, state_t b)
{
state_t mixbits = (a & 0x80000000) | (b & 0x7fffffff);
state_t matrixA = (-(b & 1)) & 0x9908b0df;
return (mixbits >> 1) ^ matrixA;
}
static inline void MersenneReload(state_t *state)
{
state_t *s = state;
int j;
for( j = MERSENNE_N - MERSENNE_M + 1; --j; ++s )
*s = s[MERSENNE_M] ^ Twist(s[0], s[1]);
for( j = MERSENNE_M; --j; ++s )
*s = s[MERSENNE_M - MERSENNE_N] ^ Twist(s[0], s[1]);
*s = s[MERSENNE_M - MERSENNE_N] ^ Twist(s[0], state[0]);
}
static inline state_t MersenneInt(state_t s)
{
s ^= s >> 11;
s ^= (s << 7) & 0x9d2c5680;
s ^= (s << 15) & 0xefc60000;
return s ^ (s >> 18);
}
static void MersenneGet(This *t, real *x)
{
count next = t->rng.mersenne.next, dim;
for( dim = 0; dim < t->ndim; ++dim ) {
#if RANDOM_BITS == 53
state_t a, b;
#endif
if( next >= MERSENNE_N ) {
MersenneReload(t->rng.mersenne.state);
next = 0;
}
#if RANDOM_BITS == 53
a = MersenneInt(t->rng.mersenne.state[next++]) >> 5;
b = MersenneInt(t->rng.mersenne.state[next++]) >> 6;
x[dim] = (67108864.*a + b)/9007199254740992.;
#else
x[dim] = MersenneInt(t->rng.mersenne.state[next++])/4294967296.;
#endif
}
t->rng.mersenne.next = next;
}
static void MersenneSkip(This *t, number n)
{
#if RANDOM_BITS == 53
n = 2*n*t->ndim + t->rng.mersenne.next;
#else
n = n*t->ndim + t->rng.mersenne.next;
#endif
t->rng.mersenne.next = n % MERSENNE_N;
n /= MERSENNE_N;
while( n-- ) MersenneReload(t->rng.mersenne.state);
}
static inline void MersenneIni(This *t)
{
state_t seed = t->seed;
state_t *next = t->rng.mersenne.state;
count j;
for( j = 1; j <= MERSENNE_N; ++j ) {
*next++ = seed;
seed = 0x6c078965*(seed ^ (seed >> 30)) + j;
/* see Knuth TAOCP Vol 2, 3rd Ed, p. 106 for multiplier */
}
MersenneReload(t->rng.mersenne.state);
t->rng.mersenne.next = 0;
t->rng.getrandom = MersenneGet;
t->rng.skiprandom = MersenneSkip;
}
/*
PART 3: Ranlux subtract-and-borrow random-number generator
proposed by Marsaglia and Zaman, implemented by F. James with
the name RCARRY in 1991, and later improved by Martin Luescher
in 1993 to produce "Luxury Pseudorandom Numbers".
Adapted from the CERNlib Fortran 77 code by F. James, 1993.
The available luxury levels are:
level 0 (p = 24): equivalent to the original RCARRY of Marsaglia
and Zaman, very long period, but fails many tests.
level 1 (p = 48): considerable improvement in quality over level 0,
now passes the gap test, but still fails spectral test.
level 2 (p = 97): passes all known tests, but theoretically still
defective.
level 3 (p = 223): DEFAULT VALUE. Any theoretically possible
correlations have very small chance of being observed.
level 4 (p = 389): highest possible luxury, all 24 bits chaotic.
*/
static inline int RanluxInt(This *t, count n)
{
int s = 0;
while( n-- ) {
s = t->rng.ranlux.state[t->rng.ranlux.j24] -
t->rng.ranlux.state[t->rng.ranlux.i24] + t->rng.ranlux.carry;
s += (t->rng.ranlux.carry = NegQ(s)) & (1 << 24);
t->rng.ranlux.state[t->rng.ranlux.i24] = s;
--t->rng.ranlux.i24;
t->rng.ranlux.i24 += NegQ(t->rng.ranlux.i24) & 24;
--t->rng.ranlux.j24;
t->rng.ranlux.j24 += NegQ(t->rng.ranlux.j24) & 24;
}
return s;
}
static void RanluxGet(This *t, real *x)
{
/* The Generator proper: "Subtract-with-borrow",
as proposed by Marsaglia and Zaman, FSU, March 1989 */
count dim;
for( dim = 0; dim < t->ndim; ++dim ) {
cint nskip = (--t->rng.ranlux.n24 >= 0) ? 0 :
(t->rng.ranlux.n24 = 24, t->rng.ranlux.nskip);
cint s = RanluxInt(t, 1 + nskip);
x[dim] = s*0x1p-24;
/* small numbers (with less than 12 significant bits) are "padded" */
if( s < (1 << 12) )
x[dim] += t->rng.ranlux.state[t->rng.ranlux.j24]*0x1p-48;
}
}
static void RanluxSkip(This *t, cnumber n)
{
RanluxInt(t, n + t->rng.ranlux.nskip*(n/24));
t->rng.ranlux.n24 = 24 - n % 24;
}
static inline void RanluxIni(This *t)
{
cint skip[] = {24, 48, 97, 223, 389,
223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
223, 223, 223, 223, 223, 223, 223, 223, 223, 223};
state_t seed = t->seed;
state_t level = RNG;
count i;
if( level < sizeof skip ) level = skip[level];
t->rng.ranlux.nskip = level - 24;
t->rng.ranlux.i24 = 23;
t->rng.ranlux.j24 = 9;
t->rng.ranlux.n24 = 24;
for( i = 0; i < 24; ++i ) {
cint k = seed/53668;
seed = 40014*(seed - k*53668) - k*12211;
seed += NegQ(seed) & 2147483563;
t->rng.ranlux.state[i] = seed & ((1 << 24) - 1);
}
t->rng.ranlux.carry = ~TrueQ(t->rng.ranlux.state[23]) & (1 << 24);
t->rng.getrandom = RanluxGet;
t->rng.skiprandom = RanluxSkip;
}
/*
PART 4: User routines:
- IniRandom sets up the random-number generator to produce a
sequence of at least n ndim-dimensional random vectors.
- GetRandom retrieves one random vector.
- SkipRandom skips over n random vectors.
*/
static inline void IniRandom(This *t)
{
if( t->seed == 0 ) SobolIni(t);
else if( RNG == 0 ) MersenneIni(t);
else RanluxIni(t);
}