#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
 

/*********************************************************************/ 
/*      RANDOM NUMBER GENERATOR                                      */ 
/*                                                                   */ 
/*      Wichmann, B. A. & Hill, I. D. (1982)                         */ 
/*      Algorithm AS 183:                                            */ 
/*      An efficient and portable pseudo-random number generator     */ 
/*      Applied Statistics 31 (1982) 188-190                         */ 
/*                                                                   */ 
/*      see also:                                                    */ 
/*              Correction to Algorithm AS 183                       */ 
/*              Applied Statistics 33 (1984) 123                     */ 
/*                                                                   */ 
/*              McLeod, A. I. (1985)                                 */ 
/*              A remark on Algorithm AS 183                         */ 
/*              Applied Statistics 34 (1985),198-200                 */ 
/*-------------------------------------------------------------------*/ 
/* Typical Usage: double RN;                                         */ 
/*                whseed(x,y,z);                                     */ 
/*                RN = whrandom();                                   */ 
/* where                                                             */ 
/* x,y,z : three integers not identically zero                       */ 
/* RN : a random number generated by the function                    */ 
/*********************************************************************/ 

static int ix, iy, iz; 

double whrandom() 
{ 
 extern int ix,iy,iz; 
 double term, rand; 
 double floor(); 

 ix = 171 * (ix % 177) - 2 * (ix/177); 
 iy = 172 * (iy % 176) - 35 * (iy/176); 
 iz = 170 * (iz % 178) - 63 * (iz/178); 

 if (ix < 0) ix = ix + 30269; 
 if (iy < 0) iy = iy + 30307; 
 if (iz < 0) iz = iz + 30323; 

 term = ix/30269.0 + iy/30307.0 + iz/30323.0; 
 rand = term - floor(term); 
 return((rand < 1.0) ? rand : 0.9999999); 
} 

void whseed(x,y,z) 
 int x, y, z; 
{ 
 extern int ix,iy,iz; 

 ix = x; 
 iy = y; 
 iz = z; 
} 

/*********************************************************************/ 
/* This function generated a Gaussian random number using the Box-   */ 
/* Muller algorithm.                                                 */ 
/* Typical Usage: double GRN;                                        */ 
/*                GRN = gaussian();                                  */ 
/* N.B.: The function "whseed()" should be called before calling     */ 
/*       this function                                               */ 
/*********************************************************************/ 
double gaussian() 
{ 
 double r1,r2,r; 

/* Box-Muller algorithm */ 
 r1 = whrandom(); 
 r2 = whrandom(); 
 r = sqrt(-2.0*log(r1))*cos(PI_2*r2); 
 while (fabs(r1)<0.000001) 
 { 
   r1 = whrandom(); 
   r2 = whrandom(); 
   r = sqrt(-2.0*log(r1))*cos(PI_2*r2); 
 } 
 return(r); 
} 

double rnorm(double m,double v)
{
 double r1,r2,r; 

/* Box-Muller algorithm */ 
 r1 = whrandom(); 
 r2 = whrandom(); 
 r = sqrt(-2.0*log(r1))*cos(PI_2*r2); 
 while (fabs(r1)<0.000001) 
 { 
   r1 = whrandom(); 
   r2 = whrandom(); 
   r = sqrt(-2.0*log(r1))*cos(PI_2*r2); 
 } 
 return(m+v*r); 
}

double gammafn(double x) 
{ 
   int i,k,m; 
   double ga,gr,r,z; 

   static double g[] = { 
       1.0, 
       0.5772156649015329, 
      -0.6558780715202538, 
      -0.420026350340952e-1, 
       0.1665386113822915, 
      -0.421977345555443e-1, 
      -0.9621971527877e-2, 
       0.7218943246663e-2, 
      -0.11651675918591e-2, 
      -0.2152416741149e-3, 
       0.1280502823882e-3, 
      -0.201348547807e-4, 
      -0.12504934821e-5, 
       0.1133027232e-5, 
      -0.2056338417e-6, 
       0.6116095e-8, 
       0.50020075e-8, 
      -0.11812746e-8, 
       0.1043427e-9, 
       0.77823e-11, 
      -0.36968e-11, 
       0.51e-12, 
      -0.206e-13, 
      -0.54e-14, 
       0.14e-14}; 

   if (x > 171.0) return 1e308;    // This value is an overflow flag. 
   if (x == (int)x) { 
       if (x > 0.0) { 
           ga = 1.0;               // use factorial 
           for (i=2;i<x;i++) { 
              ga *= i; 
           } 
        } 
        else 
           ga = 1e308; 
    } 
    else { 
       if (fabs(x) > 1.0) { 
           z = fabs(x); 
           m = (int)z; 
           r = 1.0; 
           for (k=1;k<=m;k++) { 
               r *= (z-k); 
           } 
           z -= m; 
       } 
       else 
           z = x; 
       gr = g[24]; 
       for (k=23;k>=0;k--) { 
           gr = gr*z+g[k]; 
       } 
       ga = 1.0/(gr*z); 
       if (fabs(x) > 1.0) { 
           ga *= r; 
           if (x < 0.0) { 
               ga = -M_PI/(x*ga*sin(M_PI*x)); 
           } 
       } 
   } 
   return ga; 
} 
/************************************************************* 
* return n random values from gamma(a,1) when 0<a<1          * 
* external array Y contains the random values                * 
*                                                            * 
* Remember to set the seed before using rand(). Otherwise,   * 
* you will get back the same array every time this is run.   * 
*************************************************************/ 

double gamrnd(double a,double b)
{
	int F;
	double bb,c,d,e,r,x,y,u,v,w,z;

	if (a<0 || b<0)
		exit(1); 

	//srand(time(NULL));
 	whseed(rand(),rand(),rand());

	if (a == 1)
		return -b*log(whrandom());

	if  (a < 1 && a > 0)
	{
		c = 1/a;
		d = 1/(1-a);
		F = 1;
		while (F)
		{
			u = whrandom();
			v = whrandom();
			x = pow(u,c);
			y = pow(v,d);
			if ((x + y) <= 1)
			{
				e = -log(whrandom());
				r = e*x/(x+y);
				F = 0;
			}
		}
		r *= b;
	}
	else if (a > 1)
	{
		
		bb = a - 1;
		c = 3*a - 0.75;
		F = 1;
		while (F) 
		{
			u = whrandom();
			v = whrandom();
			w = u*(1-u);
			y = sqrt(c/w)*(u-0.5);
			x = bb+y;
			if (x >= 0)
			{
				z = 64*w*w*w*v*v;
				if (z <= (1 - 2*y*y/x))
				{
					r = x;
					F = 0;
				}
				else if ( log(z) <= 2*(bb*log(x/bb)-y) )
				{
					r = x;
					F = 0;
				}
			}
		}
		r *= b;
	}
	return r;
}

void dirichletrv(double *a,int n, double *rp)
{
	int i;
	double *X,S;

	X = (double *) calloc(n+1,sizeof(double));

	S = 0;
	for (i=0;i<=n;i++)
	{
		X[i] = gamrnd(a[i],1.0);
		S += X[i];
	}

	for (i=0;i<=n;i++)
		rp[i] = X[i]/S;

	free(X);
}

void swap(int *permuter,double *randarray,int i,int j) 
{ 
        double temp; 
        int tmp; 
         
        temp = *(randarray+i); 
        *(randarray+i) = *(randarray+j); 
        *(randarray+j) = temp; 
        tmp = *(permuter+i); 
        *(permuter+i) = *(permuter+j); 
        *(permuter+j) = tmp; 
} 


void qsort1(int *permuter,double *randarray,int left,int right) 
{ 
        int i,last; 
         
        if (left >= right)    // Do nothing if array contains < 2 elements  
                return; 
         
        // move partition elem to position 0  
        swap(permuter,randarray,left,(left+right)/2); 
        last = left; 
        for(i=left+1;i<=right;i++) 
                if(*(randarray+i) < *(randarray+left)) 
                        swap(permuter,randarray,++last,i); 
        swap(permuter,randarray,left,last); 
        qsort1(permuter,randarray,left,last-1); 
        qsort1(permuter,randarray,last+1,right); 
} 


void rrank(int N,int **data,int aN)
{
	//double *R,*P;
	double *R;
	int i,j,*index;
	int **tdata;

	tdata = (int**) calloc(N,sizeof(int));
	for (i=0;i<N;i++)
	{
		tdata[i] = (int*) calloc((3+2*aN),sizeof(int));
		for (j=0;j<(3+2*aN);j++)
		{
			tdata[i][j] = data[i][j];
		}
		
	}

	R = (double*) calloc(N,sizeof(double));
	//P = (double*) calloc(N,sizeof(double));
	index = (int*) calloc(N,sizeof(int));
	whseed(rand(),rand(),rand()); 
	for (i=0;i<N;i++)
	{
		R[i] = whrandom();
		index[i] = i;
	}
//  rapid rank R
	qsort1(index,R,0,N-1);

	for (i=0;i<N;i++)
	{
		for (j=0;j<(3+2*aN);j++)
		{
			data[i][j] = tdata[index[i]][j];
		}
	}
	
	for (i=0;i<N;i++)
		free(tdata[i]);
	free(tdata);
	free(R);//free(P);
	free(index);
}

void getZn(int N,int **data,int *Zn)
{
	int i;

	Zn[0] = Zn[1] = Zn[2] = Zn[3] = 0;
	for (i=0;i<N;i++)
	{
		if (data[i][0] == 1)
			Zn[0]++;
		if (data[i][0] == 2)
			Zn[1]++;
		if (data[i][0] == 3)
			Zn[2]++;
		if (data[i][0] == 4)
			Zn[3]++;
	}
}

void get_truepar(int aN,int *xM,double ***p,char *file)
{
	int i,j;
	FILE *fid;

	fid = fopen(file,"r");

	for (i=0;i<aN;i++)
	{
		for (j=0;j<xM[i];j++)
			fscanf(fid,"%lf %lf %lf %lf\n",&p[i][0][j],&p[i][1][j],&p[i][2][j],&p[i][3][j]);
	}
	fclose(fid);
}

void get_data(int N,int aN, int **data,char *file)
{
	int i,j;
	FILE *fid;

	fid = fopen(file,"r");

	for (i=0;i<N;i++)
	{
		for (j=0;j<2+aN;j++)
			fscanf(fid,"%ld ",&data[i][j]);
		fscanf(fid,"\n");
	}
	fclose(fid);
}

double Ggenotype (int m, double pA1,double pA2,double pA3,double pA4)
{
	double pG;

	if (m==0)
		pG = pA1*pA3;
	if (m==1)
		pG = pA1*pA4+pA2*pA3;
	if (m==2)
		pG = pA2*pA4;
	return(pG);
}

double mean(int N,double *x,int offset)
{
	int i;
	double sum;

	for (sum=0,i=0;i<N;i++)
		sum += x[offset+i];

	return sum/N;
}