https://github.com/LiisaLoog/SpaceTime-Framework
Raw File
Tip revision: 4a56fa7f823b597dc904a666ddd9841841fd26b1 authored by LiisaLoog on 22 October 2017, 20:03:22 UTC
Update README.md
Tip revision: 4a56fa7
MersenneTwist.cpp
//---------------------------------------------------------------------------
#include <math.h>
#include <algorithm>
#include <stdio.h>

typedef unsigned int uint;

#include <assert.h>
#include "MersenneTwist.h"

//---------------------------------------------------------------------------
// uint must be an unsigned integer type capable of holding at least 32
// bits; exactly 32 should be fastest, but 64 is better on an Alpha with
// GCC at -O3 optimization so try your options and see what's best for you
//---------------------------------------------------------------------------
#define M              (397)                 // a period parameter
#define K              (0x9908B0DFU)         // a magic constant
#define hiBit(u)       ((u) & 0x80000000U)   // mask all but highest   bit of u
#define loBit(u)       ((u) & 0x00000001U)   // mask all but lowest    bit of u
#define loBits(u)      ((u) & 0x7FFFFFFFU)   // mask     the highest   bit of u
#define mixBits(u, v)  (hiBit(u)|loBits(v))  // move hi bit of u to hi bit of v

uint    MT::state[N+1];     // state vector + 1 extra to not violate ANSI C
uint   *MT::next;           // next random value is computed from here
int     MT::left = -1;      // can *next++ this many times before reloading


const double MT::pi = 3.14159265358979323846264338328;

//---------------------------------------------------------------------------
double MT::normOld  = 0;
int    MT::nNormOld = 0;

//---------------------------------------------------------------------------

void MT::SaveState(FILE *f)
{
#define SAVE(a) fwrite(&a, sizeof(a), 1, f);
	require(f != NULL);
	fwrite(&state[0], sizeof(uint), N+1, f);
	int k = next - state;
	SAVE(k);
	SAVE(left);
	SAVE(normOld);
	SAVE(nNormOld);
#undef SAVE
}

void MT::LoadState(FILE *f)
{
#define LOAD(a) require(fread(&a, sizeof(a), 1, f) == 1);
	require(f != NULL);
	require(fread(&state[0], sizeof(uint), N+1, f) == N+1);
	int k; LOAD(k); next = state + k;
	LOAD(left);
	LOAD(normOld);
	LOAD(nNormOld);
#undef LOAD
}

//---------------------------------------------------------------------------
void MT::Seed(uint seed)
{
	// We initialize state[0..(N-1)] via the generator
	//
	//   x_new = (69069 * x_old) mod 2^32
	//
	// from Line 15 of Table 1, p. 106, Sec. 3.3.4 of Knuth's
	// _The Art of Computer Programming_, Volume 2, 3rd ed.
	//
	// Notes (SJC): I do not know what the initial state requirements
	// of the Mersenne Twister are, but it seems this seeding generator
	// could be better.  It achieves the maximum period for its modulus
	// (2^30) iff x_initial is odd (p. 20-21, Sec. 3.2.1.2, Knuth); if
	// x_initial can be even, you have sequences like 0, 0, 0, ...;
	// 2^31, 2^31, 2^31, ...; 2^30, 2^30, 2^30, ...; 2^29, 2^29 + 2^31,
	// 2^29, 2^29 + 2^31, ..., etc. so I force seed to be odd below.
	//
	// Even if x_initial is odd, if x_initial is 1 mod 4 then
	//
	//   the          lowest bit of x is always 1,
	//   the  next-to-lowest bit of x is always 0,
	//   the 2nd-from-lowest bit of x alternates      ... 0 1 0 1 0 1 0 1 ... ,
	//   the 3rd-from-lowest bit of x 4-cycles        ... 0 1 1 0 0 1 1 0 ... ,
	//   the 4th-from-lowest bit of x has the 8-cycle ... 0 0 0 1 1 1 1 0 ... ,
	//    ...
	//
	// and if x_initial is 3 mod 4 then
	//
	//   the          lowest bit of x is always 1,
	//   the  next-to-lowest bit of x is always 1,
	//   the 2nd-from-lowest bit of x alternates      ... 0 1 0 1 0 1 0 1 ... ,
	//   the 3rd-from-lowest bit of x 4-cycles        ... 0 0 1 1 0 0 1 1 ... ,
	//   the 4th-from-lowest bit of x has the 8-cycle ... 0 0 1 1 1 1 0 0 ... ,
	//    ...
	//
	// The generator's potency (min. s>=0 with (69069-1)^s = 0 mod 2^32) is
	// 16, which seems to be alright by p. 25, Sec. 3.2.1.3 of Knuth.  It
	// also does well in the dimension 2..5 spectral tests, but it could be
	// better in dimension 6 (Line 15, Table 1, p. 106, Sec. 3.3.4, Knuth).
	//
	// Note that the random number user does not see the values generated
	// here directly since reloadMT() will always munge them first, so maybe
	// none of all of this matters.  In fact, the seed values made here could
	// even be extra-special desirable if the Mersenne Twister theory says
	// so-- that's why the only change I made is to restrict to odd seeds.

	register uint x = (seed | 1U) & 0xFFFFFFFFU, *s = state;
	register int    j;

	for(left=0, *s++=x, j=N; --j;	) *s++ = (x*=69069U) & 0xFFFFFFFFU;
}

//---------------------------------------------------------------------------
uint MT::Reload()
{
	register uint *p0=state, *p2=state+2, *pM=state+M, s0, s1;
	register int    j;

	if(left < -1) MT::Seed(4357U);

	left=N-1, next=state+1;

	for(s0=state[0], s1=state[1], j=N-M+1; --j; s0=s1, s1=*p2++)
		*p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);

	for(pM=state, j=M; --j; s0=s1, s1=*p2++)
		*p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);

	s1=state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
	s1 ^= (s1 >> 11);
	s1 ^= (s1 <<  7) & 0x9D2C5680U;
	s1 ^= (s1 << 15) & 0xEFC60000U;
	return(s1 ^ (s1 >> 18));
}

//---------------------------------------------------------------------------
//	uint MT::Poisson(double lambda)
//	{
//		static const double PiFactor = 3.1415926535897932384626433832795028842/4294967296.0;
//		double g = exp(-lambda), t = 1;
//		int    n = -1;
//
//		if (lambda < 12.0) {
//			do {
//				++n;
//				t *= Uni();
//			} while (t > g);
//		} else {
//			double sq = sqrt(2.0 * lambda);
//			double alxm = log(lambda);
//			g = lambda * alxm - LnGamma(lambda + 1);
//
//			// sample until not rejected
//			double y,z;
//			do {
//				do {
//					// y is deviate from Lorentzian
//					y = tan(PiFactor * Rand());
//					// comparison function
//					z = sq * y + lambda;
//				} while (z < 0.0);
//				z = floor(z); // convert to integer
//				t = 0.9 * (1 + y*y) * exp(z*alxm - LnGamma(z + 1) - g);
//			} while (Uni() > t);
//			// set n to accepted value
//			n = (uint)z;
//		}
//
//		return n;
//	}


//---------------------------------------------------------------------------

int MT::Binomial(const int n, const double &pp) 
{
// 	const double p = (pp <= 0.5 ? pp : 1.0 - pp); // The binomial distribution is invariant under changing pp to 1-pp, 
// 												// if we also change the answer to n minus it self; weŐll remember to 
// 												// do this below. 
// 	
// 	int bnl = 0; 
// 	for(int j = 0; j < n; j++) if( Uni() < p) ++bnl;
// 	
// 	if( p != pp ) bnl = n - bnl; // Remember to undo the symmetry transformation.	
// 	return bnl; 

#define PI 3.1415926535897932385 
// Returns as a floating-point number an integer value that is a 
//	random deviate drawn from a binomial distribution of n trials 
// each of probability pp, using Uni() as a source of uniform 
	// random deviates. 
	int j, bnl; 
	static int nold = -1; 
	static double pold = (-1.0), pc, plog, pclog, en, oldg; 
	const double p = (pp <= 0.5 ? pp : 1.0 - pp); // The binomial distribution is invariant under changing pp to 1-pp, 
												// if we also change the answer to n minus it self; weŐll remember to 
												// do this below. 
	const double am = n*p; // This is the mean of the deviate to be produced. 
	if ( n < 25 ) { // Use the direct method while n is not too large. This can require up to 25 calls to ran1.
		bnl = 0; 
		for(int j = 1; j <= n; j++) if( Uni() < p) ++bnl; 
	} else if (am < 1.0) { // If fewer than one event is expected out of 25 or more trials, 
								  // then the distribution is quite accurately Poisson. Use direct Poisson method. 
		const double g = exp(-am); 
		double t = 1.0;
		for(j = 0; j <= n; j++) { 
			t *= Uni(); 
			if(t < g) break; 
		} 
		bnl = (j <= n ? j : n); 
		
	} else { // Use the rejection method.
		
		if(n != nold) { // If n has changed, then compute useful quantities.
			en = n; oldg = LnGamma(en+1.0); nold = n; 
		}
		
		if(p != pold){ // If p has changed, then compute useful quantities.
			pc = 1.0 - p; plog = log(p); pclog = log(pc); pold = p; 
		} 
		
		const double sq = sqrt(2.0*am*pc); // The following code should by now seem familiar: rejection method with a Lorentzian comparison function. 
		double t, y, em;
		do { 
			do { 
				const double angle = PI*Uni(); 
				y = tan(angle); 
				em = sq*y + am; 
			} while(em < 0.0 || em >= (en + 1.0));  // Reject. 
			
			em = floor(em); // Trick for integer-valued distribution. 
			t = 1.2 * sq * (1.0 + y*y) * exp(oldg - LnGamma(em + 1.0) - LnGamma(en - em + 1.0) + em*plog + (en - em)*pclog); 
			
		} while( Uni() > t); // Reject. This happens about 1.5 times per deviate, on average.
		
		bnl = (int)em; 
	} 
	
	if( p != pp ) bnl = n - bnl; // Remember to undo the symmetry transformation.
	
	return bnl; 
}

//---------------------------------------------------------------------------

static double ProbKS(double x)
{
	double a2,fac=2.0, sum=0.0, term, termbf=0.0;

	a2 = -2.0 * x * x;
	for (int j=1; j <=100; j++) {
		term = exp(a2 * (j * j));
		sum += fac * term;
		if (term <= 1.0e-10 * sum) return sum;
		fac    = -fac;
		termbf = term;
	}
	return 1.0;
}


double MT::KolmogorovSmirnovTest(int n, int data[], double scale)
{
	double d = 0, dt, en, ff, fn, fo =0;

	std::sort(data, data + n);
	
	en = 1./(double)n;
	for (int j=0; j < n; j++) {
		fn = j*en; ff = data[j]*scale;
		dt = fabs(fo-ff);
		{ 
			double yy = fabs(fn-ff);
			if (yy > dt) dt = yy;
		}
		if (dt > d) d = dt;
		fo = fn;
	}

	return ProbKS((sqrt(n) + 0.12 + 0.11 * sqrt(en)) * d);
}

//---------------------------------------------------------------------------
back to top