/**********************************************************
** Binomial Tree calculations for option pricing (main())
**Copyright (c) 2001   Alexandros V. Gerbessiotis
**
**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  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 is offered that the code works as
**advertised or is absent of any, even damaging,
**side-effects; use this code on your own personal risk
**/

/*  Main file for matrix inverse under the wrapped mapping
 *  distribution.
 *
 */
#include <stdio.h>
#include <sys/utsname.h>
#include <unistd.h>
#include "bt.h"
#include "aimpi.h"

#define PRINTMAT(X)   bspfold((void (*)(void *,void *,void *)) foldmin,(char *)&t1,(char *)&t3,sizeof(double)); bspfold((void (*)(void *,void *,void *)) foldmax,(char *)&t1,(char *)&t4,sizeof(double)); 



void check_if_null(void *x,char *s,char *t)
{
  if (NULL == x) {
     printf("%s:: Null pointer error (%s)\n",s,t);
     AIABORT("check_if_null");
  }
}

void check_if_valid(int x,int y, char *s,char *t)
{
 if (x != y) {
  printf("%s:: Intparameter %d should be = to %d (%s)\n",
         s,x,y,t);
   AIABORT("check_if_valid");
 }
}


/* Broadcasting to communicate command line args */
void bspbroad(int fromp, char *from, char *to, int size)
{
 int pid;
 int nprocs;
 int i;

 pid=AIPID(); /* processor id */
 nprocs=AINPROCS(); /* number of processors */
 AIREGISTER(to,size);
 AISYNC();
 for (i = 0; i < nprocs;i++) {
   if (pid==fromp)
        AIHPPUT(i,from,to,0,size);
 }
 AISYNC();
}

/* operators for bspfold */

void foldmax(double *z, double *x, double *y)
{
  *z=(((*x)>=(*y))?(*x):(*y));
}

void foldmin(double *z, double *x, double *y)
{
  *z=(((*x)<(*y))?(*x):(*y));
}


/* Folding operation for timing purposes */
void bspfold(
          void (*operator)(void *,void*,void*),
          char *from,char *to,int size)
{
 int  pid; 
 int  nprocs; 
 int  i;
 char *list;
 int  lsize;

 pid=AIPID(); 
 nprocs=AINPROCS(); 
 if (1==nprocs)  /* if local, copy */
    
    memcpy(to,from,size*sizeof(char));
 else {  /* if global, allocate O(p) memory per proc */
    lsize = nprocs*size; 
    list=(char *) malloc(lsize*sizeof(char));
    check_if_null(list,"bspfold","list");
    AIREGISTER(list,lsize);
    AISYNC();
 }
 /* each proc sends its from to every other proc */
 for (i = 0; i < nprocs;i++) {  
   AIHPPUT(i,from,list,pid*size,size);
 }
 AISYNC();
 /* apply operator to local list */
 for (i = 0; i < nprocs-1;i++) {
  operator(to,(list+i*size),(list+(i+1)*size));
  memcpy((list+(i+1)*size),to,size);
 }
    /* free memory and deregister */
 
    AIDEREGISTER(list);
    free((void *)list);
}

/* MAIN function */

int	main(int argc, char *argv[])
{
 int 	i,j,k,n,nprocs,runs,debug,pid,option;
 double t3,t4,t1,a,b,c;
 char hostname[512];
 double K, S,r,u,d;
 int    T,N,blocksize;
 double result,sigma;
 double rst, rc;


 AIBEGIN(AINPROCS());
 pid = AIPID(); nprocs = AINPROCS();

 gethostname(hostname,sizeof(hostname));
 /* Show hostnames of processors; */
#undef SANITY_CHECK
#ifdef SANITY_CHECK
 for(i=0;i<nprocs;i++) {
   if (i==pid) {
      printf("Processor %d of %d [%s]\n",pid,nprocs,hostname);
      fflush(stdout);
   }
 }
#endif
 AIBARRIER();

  /* Command line processing */
 n=8;debug=0;runs=1; 
 if (0 == pid ){
   if (3 != argc){
    printf("Usage: %s blocksize horizon \n\
            Integer blocksize-1 must divide integer horizon", 
           argv[0]);
     fflush(stdout);
     AIABORT("exit");
   } 
   else {
    blocksize=atoi(argv[1]);
    scanf("%lf",&K);
    scanf("%d",&T);
    scanf("%lf",&S);
    scanf("%lf",&r);
    scanf("%d",&N);
    scanf("%lf",&sigma);
    N= atoi(argv[2]);
   }
 }

   /* Parallel Command line processing */
   AIREGISTER(&K,sizeof(double));
   AISYNC();
      bspbroad(0,(void *)&K ,(void *)&K ,sizeof(double));
   AISYNC();
   AIDEREGISTER(&K );

   AIREGISTER(&T,sizeof(int   ));
   AISYNC();
      bspbroad(0,(void *)&T ,(void *)&T ,sizeof(int   ));
   AISYNC();
   AIDEREGISTER(&T );

   AIREGISTER(&blocksize,sizeof(int   ));
   AISYNC();
      bspbroad(0,(void *)&blocksize ,(void *)&blocksize ,sizeof(int   ));
   AISYNC();
   AIDEREGISTER(&blocksize );

   AIREGISTER(&S,sizeof(double));
   AISYNC();
      bspbroad(0,(void *)&S ,(void *)&S ,sizeof(double));
   AISYNC();
   AIDEREGISTER(&S );

   AIREGISTER(&r,sizeof(double));
   AISYNC();
      bspbroad(0,(void *)&r ,(void *)&r ,sizeof(double));
   AISYNC();
   AIDEREGISTER(&r );

   AIREGISTER(&sigma,sizeof(double));
   AISYNC();
      bspbroad(0,(void *)&sigma ,(void *)&sigma ,sizeof(double));
   AISYNC();
   AIDEREGISTER(&sigma );


   AIREGISTER(&N,sizeof(int   ));
   AISYNC();
      bspbroad(0,(void *)&N ,(void *)&N ,sizeof(int   ));
   AISYNC();
   AIDEREGISTER(&N );

   if ((nprocs-1)==pid) {
     fprintf(stdout, "proc=%d ::K=%f T=%d S=%f r=%f N=%d, sigma=%f b=%d\n", pid,K,T,S,r,N,sigma,blocksize); 
     fflush(stdout);
   }

   
   t1=0.0;
   for(k=0;k<runs;k++) {

     AIBARRIER();
     t3=AITIME();
        bt(K,T,S,r,N,sigma,blocksize,&rst,&rc);
     AIBARRIER();
     t4=AITIME();
     t1 += (t4-t3);
     PRINTMAT(EuroCall);

     if (0 == pid) {
        printf("OptionPrice= %18.8f (rst=%f)\n",rc,rst);
        printf("RunningTime= %8.5f-%8.5f secs (p=%d,L=%5.1f,g=%5.3f)\n",(t3),(t4),AINPROCS(),AIL(),AIG());
     }
   }

 AIEND();  
}

