/****Copyright (c) 1997-2005  Alexandros V. Gerbessiotis.
 **** All rights reserved.
 ****Permission to use, copy, modify, and distribute this software,
 ****and to incorporate it, in whole or in part, into
 ****other software,is hereby granted without fee, provided that
 ****  (1) the above copyright notice and this permission
 ****      notice appear in all copies of the source code, and
 ****      the above copyright notice appear in clearly visible
 ****      form on all supporting documentation and distribution
 ****      media, and
 ****     (2) any redistribution of the software, in original
 ****         or modified form, be without fee and subject to
 ****         these same conditions.
 ****   No guarantee, whatsoever, is offered that the code works as
 ****   advertised or is absent of any, even damaging,
 ****   side-effects. Use this code at your own personal risk.
 ****/

#include "ssrt.h"
#include "setdata.h"
#define MAX_RINT        ((unsigned int)2147483647)
#define MODULO_R        ((double)2147483647.0)
#define MODULO_I        ((unsigned int)2147483647)
#define A_R             ((double)62089911.0)
#define A_I             ((unsigned int)62089911)
#define A_1_R           ((double)241748845.0)
#define A_1_I           ((unsigned int)241748845)
#define MODULO_MAX      ((unsigned int)4294967296)
#define PI 		((double)3.141592654)

static unsigned int local_seed=100;
static unsigned int mcgn, srgn;
static double seed=314159265.0;


/* The following initialization/input-preparation function 
 * WR_i_Benchmark is a 
 * verbatim copy (minus minor adaptations)
 * of code written and copyrighted by
 * D.R.Helman J. JaJa and D.A.Bader 
 * at the University of Maryland, College Park,
 * USA.
 */
void WR_i_Benchmark(int col_size, data *In, int s)
{

int i,j,k,t1,t2;
int MYPROC;
int PROCS;
int MAX_VAL= MAX_RINT;

MYPROC=AIPID(); PROCS=AINPROCS();
t1 = (MAX_VAL/PROCS) + 1;

k=0;

if (MYPROC == 0)
  {for (i=0;i<(PROCS-2);i+=2)
     {t2 = i * t1;
      for (j=1;j<(col_size/PROCS);j++)
        In[k++] = (data)t2 + 1 + (random() % (t1 - 1));
      In[k++] = (data)(t2 += t1);
      for (j=1;j<(col_size/s);j++)
        In[k++] = (data)t2;
      for (j=(col_size/s);j<(col_size/PROCS);j++)
        In[k++] = (data)t2 + 1 + (random() % (t1 - 1));
      In[k++] = (data)t2 + t1;
     } 
   t2 = (PROCS - 2) * t1;
   for (j=1;j<(col_size/PROCS);j++)
     In[k++] = (data)t2 + 1 + (random() % (t1 - 1));
   In[k++] = (data)(t2 += t1);
   for (j=1;j<(col_size/s);j++)
     In[k++] = (data)t2;
   for (j=(col_size/s);j<=(col_size/PROCS);j++)
     In[k++] = (data)t2 + 1 + (random() % (t1 - 1));
  }
else
  {for (i=0;i<PROCS;i+=2)
     {t2 = i * t1;
      for (j=1;j<((col_size/PROCS) + (col_size/s));j++)
        In[k++] = (data)t2 + 1 + (random() % (t1 - 1));
      In[k++] = t2 + t1 + MYPROC;
      for (j=0;j<((col_size/PROCS) - (col_size/s));j++)
        In[k++] = (data)t2 + t1 + 1 + MYPROC + (random() % (t1 - 1 - MYPROC));
     } 
  }

}


int	initialize(data *d,int size,int testid,unsigned int range)
{
 int    (*func_ir[3])()={ get_uniform, get_gauss, get_nas};   
 double 	(*test_func)();
 int    	(*test_ir_func)(unsigned int);
 register int	pid;
 register int	nprocs;
 register int 	gid,bid;
 register int 	i,j,k;

 pid=AIPID();nprocs=AINPROCS();
 if ((testid >99) && (range ==0)) range=2;
 if ((0==range) && (testid <100) && (testid !=3)) range =MAX_RINT;

 switch (testid) {
  case 0:
/* 1 Uncomment 1 if same input is maintained when number of procs increases
       srandom(127);
       	for(i=0;i<(pid*size);i++) {
           k=(random()%range);
        }
       	for(i=0;i<size;i++) {
           d[i]= (data) (random()%range);
        }
   1 */
 	srandom(21+1001*11);
/*
       	for(i=0;i<(pid*size);i++) {
           k=(random());
        }
*/
       	for(i=0;i<size;i++) {
           d[i]= (data) (random() & MODULO_I);
        }
/*
	init_uniform(127); test_ir_func = func_ir[testid]; 
       	for(i=0;i<(pid*size);i++)
           test_ir_func(range);
       	for(i=0;i<size;i++)
           d[i]= (data) test_ir_func(range);
*/
/*
           d[i]= (data) ((random()) % MAX_RINT);
*/
/* 2 Uncomment 2 only to get input similar to Bader et al */
/* 2 Comment it to run _Different input runs_ (initializer in so.c)     
	srandom(21+1001*pid); 
       	for(i=0;i<size;i++)
           d[i]= (data) ((random()) & MAX_RINT);
   2 */
	break;
  case 1:
/*
	init_gauss(127); test_ir_func = func_ir[testid];
        for(i=0;i<pid*size;i++)
           (*test_ir_func)(range);
*/
	srandom(21+101*pid); test_ir_func = func_ir[testid]; 
       	for(i=0;i<size;i++)
           d[i]= (data) test_ir_func(range);
	break;
  case 2:
/*      init_nas(127); test_ir_func=func_ir[testid];
*/
	init_nas(21+101*pid); test_ir_func = func_ir[testid];
       	for(i=0;i<pid*size;i++)
           (*test_ir_func)(range);
        for(i=0;i<size;i++)
           d[i]= (data) test_ir_func(range);
        break;
  case 3:
 	srandom(21+1001*11);
        if (range ==-1) k=size*8;
           else k=range;
        if (range == 0) k=size;
       	for(i=0;i<size;i++) {
           d[i]= (data) (k*(random()/((double)INT_MAX)));
        }
        break;
  case 100:
	init_uniform(21+1001*pid);
       	for(i=0;i<size;i++) {
	   d[i] = (data) ( ((i*nprocs)/size)*FLOOR(MAX_RINT,nprocs)
		       +get_uniform((FLOOR(MAX_RINT,nprocs)-1)));
	}
	break;
  case 101:
	init_uniform(21+1001*pid);
       	for(i=0;i<size;i++) {
	   gid= pid/range;
	   bid= (i*gid)/size;
	   d[i] = (data) ( ((gid*range+bid+nprocs/2) % nprocs)*
		   FLOOR(MAX_RINT,nprocs)+
		   get_uniform((FLOOR(MAX_RINT,nprocs)-1)));
	}
	break;
  case 102:
	init_uniform(21+1001*pid);
       	for(i=0;i<size;i++) {
	   if (pid < (nprocs/2)) {
	      d[i] = (data) ( (2*pid+1)*FLOOR(MAX_RINT,nprocs)+
			 +get_uniform((FLOOR(MAX_RINT,nprocs)-1)));
	   } else {
	      d[i] = (data) ( (pid-nprocs/2)*FLOOR(MAX_RINT,nprocs)+
			 +get_uniform((FLOOR(MAX_RINT,nprocs)-1)));
	   }
	}
	break;
  case 103:
	init_uniform(21+1001*pid);
        for(i=0;i<size;i++) {
	   if (pid != (nprocs-1)) {
              gid= (int) clg((nprocs-pid)*size);
	   } else {
              gid= (int) clg((size-i));
	   }
           d[i] = (data) (range*gid);
        }
	break;
  case 104:
       init_uniform(21+1001*pid);
       WR_i_Benchmark(size, d, (int) (nprocs*log(log(size))));
        break;

  default:
	printf("Input Option = %d\n",testid);
	AIABORT("Input option invalid");
	break;
 }
	return(0);
}


int flg (int x) {
  register int l;
  if (x <= 1) {
    return(0);
  }
  else {
    l = 0;
    while (x>1) {
      x=Div2(x);
      l++;
    }
    return(l);
  }
}

int clg (int x)
{
  register int l;
  if (x <= 1) {
    return(0);
  }
  else {
    x--;l = 1;
    while (x>1) {
      x=Div2(x);
      l++;
    }
    return(l);
  }

}


/* RANDOM NUMBER GENERATORS
   build a set of random number generators. common interface as
   follows
   init_random(int value) : sets local seed to this value
   get_random (int range) : a random number in the range 0..range
 */

void init_5_random(unsigned int value)
{
/* srand48(value); */
     srandom(value);
}

int  get_5_random(unsigned int range)
{
/* return((int)((lrand48()*(double)range)/MODULO_I)); */
/* return((random()*range) & MODULO_I); */
/* Commented out Jul 17,2003
*/
/*
     return((int)((random()*(double)range)/MODULO_I));
*/
     return(random()%range);
}

void init_3_random(unsigned int value)
{
     local_seed=value;   
}

int  get_3_random(unsigned int range)
{
#ifdef T3D
     local_seed=(local_seed*A_I)% MODULO_I;
     return((int)((local_seed*(double)range)/MODULO_I));
/* Change (double) to nothing March 17: 11:00*/
#else
     local_seed=(local_seed*A_I);
     return((int)((local_seed*(double)range)/MODULO_I));
#endif
}

/* Here is the I/O interface */

/* From Jaja et al paper : A uniform RNG using random() */
void            init_uniform(unsigned int value)
{
        	SRANDOM(value);   
}

int             get_uniform(unsigned int range)
{
		return(RANDOM((range)));
}

/* From Jaja et al: Gaussian */
void            init_gauss(unsigned int value)
{
	srandom(value);
}

int            get_gauss(unsigned int range)
{
	register   double   x1=0.0;
        x1  = (double) (random() & MAX_RINT); x1 += (double) (random() & MAX_RINT);
        x1 += (double) (random() & MAX_RINT); x1 += (double) (random() & MAX_RINT);
        x1 = x1/4.0;
	return((int)x1);
}


/* NAS Benchmark random number generator from Jaja description */
void            init_nas(unsigned int  value) 
{
    seed = 314159265.0;
}

int             get_nas(unsigned int range)
{
 register double temp;
 register double t1;

 temp = (seed * 1220703125.0 ); seed =  fmod(temp,70368744177664.0);
 t1 =  seed;
 temp = (seed * 1220703125.0 ); seed =  fmod(temp,70368744177664.0);
 t1 += seed;
 temp = (seed * 1220703125.0 ); seed =  fmod(temp,70368744177664.0);
 t1 +=  seed;
 temp = (seed * 1220703125.0 ); seed =  fmod(temp,70368744177664.0);
/*
 t1 +=  seed; t1 = t1 / 4.0; temp =  t1/134217728.0;
*/
 t1 +=  seed; t1 = t1 / 4.0; temp =  t1/33554432.0;
 return((int) (temp));
}
