samer@0: /* samer@0: * Pseudorandom generators for SWI Prolog samer@0: * Samer Abdallah (2009) samer@0: * Some samplers adapted from code in Tom Minka's lightspeed Matlab toolbox. samer@0: * Other bits of code culled from SWI Prolog distribution random.c samer@0: * samer@0: * To do: samer@0: * work out lower bound for skew stable distributions samer@0: * stream splitting with jumps samer@0: * reduce blob copying samer@0: * fast discrete distributions samer@0: * ziggurat for normals samer@0: */ samer@0: samer@0: #define _USE_MATH_DEFINES 1 samer@0: samer@0: #include samer@0: #include samer@0: #include "rndutils.h" samer@0: samer@0: #if HAVE_GSL samer@0: #include samer@0: #else samer@0: double gsl_sf_zeta(const double s) { return NAN; } samer@0: double gsl_sf_hzeta(const double s, const double k) { return NAN; } samer@0: #endif samer@0: samer@0: #ifndef M_PI samer@0: #define M_PI 3.14159265358979323846 samer@0: #endif samer@0: samer@0: samer@0: // ----------------------------------------------------- samer@0: samer@0: // Returns a sample from Normal(0,1) samer@0: double Normal(RndState *S) samer@0: { samer@0: double x=S->prev_normal; samer@0: samer@0: if(!isnan(x)) { samer@0: S->prev_normal=NAN; samer@0: } else { samer@0: double y,radius; samer@0: samer@0: /* Generate a random point inside the unit circle */ samer@0: do { samer@0: x = 2*Uniform(S)-1; samer@0: y = 2*Uniform(S)-1; samer@0: radius = (x*x)+(y*y); samer@0: } while((radius >= 1.0) || (radius == 0.0)); samer@0: /* Box-Muller formula */ samer@0: radius = sqrt(-2*log(radius)/radius); samer@0: x *= radius; samer@0: y *= radius; samer@0: S->prev_normal=y; samer@0: } samer@0: return x; samer@0: } samer@0: samer@0: /* Returns a sample from Gamma(a, 1). samer@0: * For Gamma(a,b), scale the result by b. samer@0: */ samer@0: double Gamma(RndState *S, double a) samer@0: { samer@0: /* Algorithm: samer@0: * G. Marsaglia and W.W. Tsang, A simple method for generating gamma samer@0: * variables, ACM Transactions on Mathematical Software, Vol. 26, No. 3, samer@0: * Pages 363-372, September, 2000. samer@0: * http://portal.acm.org/citation.cfm?id=358414 samer@0: */ samer@0: double boost, d, c, v; samer@0: if(a < 1) { samer@0: /* boost using Marsaglia's (1961) method: gam(a) = gam(a+1)*U^(1/a) */ samer@0: boost = exp(log(Uniform(S))/a); samer@0: a++; samer@0: } samer@0: else boost = 1; samer@0: d = a-1.0/3; c = 1.0/sqrt(9*d); samer@0: while(1) { samer@0: double x,u; samer@0: do { samer@0: x = Normal(S); samer@0: v = 1+c*x; samer@0: } while(v <= 0); samer@0: v = v*v*v; samer@0: x = x*x; samer@0: u = Uniform(S); samer@0: if((u < 1-.0331*x*x) || samer@0: (log(u) < 0.5*x + d*(1-v+log(v)))) break; samer@0: } samer@0: return( boost*d*v ); samer@0: } samer@0: samer@0: /* Returns a sample from Dirichlet(n,a) where n is dimensionality */ samer@0: int Dirichlet(RndState *S, long n, double *a, double *x) samer@0: { samer@0: long i; samer@0: double tot=0, z; samer@0: for (i=0; i=v) { samer@0: do { samer@0: k0=k; zk0=zk; samer@0: k=k0+1; zk=zk0-pow(k0,-s); samer@0: } while (zk>=v && zk!=zk0); samer@0: return k0; samer@0: } else { samer@0: do { samer@0: k0=k; zk0=zk; samer@0: k=k0-1; zk=zk0+pow(k,-s); samer@0: } while (zk= 1-DBL_EPSILON) return n; samer@0: if((p > 0.5) && (n < 15)) { samer@0: /* Coin flip method. This takes O(n) time. */ samer@0: int i; samer@0: for(i=0;i=15) { samer@0: double m=floor(lambda*7/8); samer@0: double x=Gamma(S,m); samer@0: samer@0: if (x>lambda) r=Binomial(S,lambda/x,m-1); samer@0: else r=m+Poisson(S,lambda-x); samer@0: } else { samer@0: double p; samer@0: for (p=0, r=-1; p=0; u-=p[++i]); samer@0: return i; samer@0: } samer@0: samer@0: double Uniform(RndState *S0) samer@0: { samer@0: return RngStream_Double(&S0->g,&S0->g); samer@0: } samer@0: samer@0: double Raw(RndState *S0) samer@0: { samer@0: return RngStream_Raw(&S0->g,&S0->g); samer@0: } samer@0: samer@0: void InitRndState(RndState *S) samer@0: { samer@0: RngStream_InitState(&S->g); samer@0: S->prev_normal=NAN; samer@0: } samer@0: samer@0: samer@0: int spawn_gen(RndState *S0, RndState *S1) samer@0: { samer@0: unsigned seeds[6]; samer@0: int i; samer@0: samer@0: for (i=0; i<6; i++) seeds[i]=(unsigned)RngStream_Raw(&S0->g,&S0->g); samer@0: RngStream_SetState(&S1->g,seeds); samer@0: for (i=0; i<3; i++) RngStream_Raw(&S1->g,&S1->g); samer@0: S1->prev_normal=NAN; samer@0: return 1; samer@0: } samer@0: samer@0: int randomise_from(FILE *p, RndState *S) samer@0: { samer@0: unsigned seeds[6]; samer@0: size_t r=fread((void *)seeds,sizeof(unsigned),6,p); samer@0: samer@0: if (r==6) { samer@0: int i; samer@0: if (RngStream_SetState(&S->g,seeds)<0) return 0; samer@0: for (i=0; i<3; i++) RngStream_Raw(&S->g,&S->g); samer@0: S->prev_normal=NAN; samer@0: return 1; samer@0: } else return 0; samer@0: } samer@0: