/*  This program is documented inside node.c and is not as recent or as powerful
    as node.c, and does not do expectations.                                  */
#include <stdio.h>
#include <math.h>
#include <sys/time.h>
/*.proc files #include at end*/

#define TRUE 1
#define FALSE 0
#define EMPTY (-1)
#define LEVELS 20
#define DLEVELS 10
#define DRND 0.1
#define DALPHA 0.9524
#define MAXNODES 8000


struct   pi {  
  float  Jmin;
  float  denom[2][2][8];
  float  prob;
  float  value[8];
  short  Opti;
  short  Optj;
  short  optflag;
  short  age;
  float  cube;

  int    child[2][2][8],         
         left,                    
         right,
         parent;
};

typedef struct pi *list;

short levels=LEVELS,
      ivalue,
      jvalue,
      constrain=FALSE;

int   nnod[LEVELS+1],
      stop[LEVELS+1];

long int next=1;
 
float alpha=DALPHA,
      rnd=DRND;

FILE  *fsens,
      *fdata,
      *fyear;

list  node[MAXNODES];

main() {
  void  make_sens(),                    get_constants(),
	sort_Jmin(),                    determine_optimum(),
	init_to_zero(),                 pick_mtrx(),
	set_p_mtrx(),                   init_Jmin(),
	open_files(),                   set_cu_mtrx(),
	print_tree(),                   set_ca_mtrx(),
	set_cx_mtrx(),                  unalloc(),
	set_q_mtrx(),                   write_pi(),                   
        graph_year(),                   graph_data(),
        get_pi_val(),                   close_files(),
        expand_tree(),                  data_head(),
        clock(),                        alloc(),
        init_tree(),                    make_fortyeight();
       

  float assign_value(),
        round(),
        p[20][8][8], 
        q[2][8][8], 
        ca[2][8], 
        cu[8], 
        cx[2][7];

  int   rndmax(),
        insert_node(),
        pchoice, 
        qchoice,
        start[LEVELS+1];

  short z, time[3];

  init_to_zero(p, 20);
  init_to_zero(q, 2);

  pick_mtrx(&pchoice, &qchoice);
  get_constants(&rnd, &alpha, &levels);

  set_p_mtrx(p, pchoice);
  set_q_mtrx(q, qchoice);
  set_ca_mtrx(ca);
  set_cu_mtrx(cu);
  set_cx_mtrx(cx);

  init_tree(start);
  clock(time);

  for(z=0;z<levels;z++) 
    expand_tree(start, p, q, z);

  init_Jmin(start[levels],stop[levels]);
  determine_optimum(start, ca, cu, cx, p, qchoice);  
  sort_Jmin();
  
  open_files();
  data_head(alpha, rnd, pchoice, qchoice, time, start);
  graph_year(pchoice, qchoice);
  for(z=0;z<levels;z++) {
    make_sens (start[0], z, pchoice, qchoice);
    print_tree (start,z);
  }
  close_files();
  printf("\nRun Time: %d:%02d:%02d",time[0],time[1],time[2]);
  printf("                                         Jmin:%f.\n\n",
          node[start[0]]->Jmin);
}
/****************************************************************************/
void expand_tree(start, p, q, z)    
int start[];                  
float p[][8][8], q[][8][8]; 
short z; {
  int temp;

  printf("Level %2d", z+1);
  nnod[z]=0;
  temp=start[z];
  while(temp<stop[z]) {
    make_fortyeight(temp, start, p, q, z);     
    temp++;
  }
  stop[z+1]=next;
  printf("          nodes:%d\n",nnod[z]);
}
/***************************************************************************/
void make_fortyeight(dad,start, p, q, z) 
int start[],dad;
float p[][8][8], q[][8][8];
short z; { 
  short i, j, k, l, m, n, combined;
  float total, dummy, dummy2;
  int kid;

  for(i=0;i<2;i++) 
    for(j=0;j<2;j++)  
      for(l=0;l<8;l++){
        kid=next;
	dummy2=0.0;
        for(m=0;m<8;m++) {
          dummy=0.0;
          for(n=0;n<8;n++) {
          dummy=dummy +(p[(node[dad]->age)*(1-i)][n][m]*(node[dad]->value[n]));
          }
          dummy2=dummy2+(q[j][m][l]*dummy);
        }
        total=0.0;
        for(k=0;k<8;k++) {
          node[kid]->value[k]=assign_value(dad, p[(node[dad]->age)*(1-i)], k, q[j][k][l],dummy2);
          total+=node[kid]->value[k];
        }
        if(total==0.0) {
          node[dad]->denom[i][j][l]=0.0;
          node[dad]->child[i][j][l]=EMPTY;
        }
        else{
          node[dad]->child[i][j][l]=kid;
          node[kid]->cube=round(node[kid]->value,rnd);
          node[dad]->denom[i][j][l]=dummy2;
          node[kid]->age=(node[dad]->age)*(1-i)+1;
          combined=FALSE;
          if(start[z+1]==EMPTY)
            start[z+1]=kid;
          else 
            combined=insert_node(dad,start[z+1],i,j,l);
          if(!combined) {
            node[kid]->left=EMPTY;
            node[kid]->right=EMPTY;
            node[kid]->optflag=FALSE;
            node[kid]->parent=dad;
            node[kid]->prob=node[dad]->denom[i][j][l]*node[dad]->prob;
            nnod[z]++;
            next++;
          }
        printf("");
        }
      }
}
/*****************************************************************************/
int insert_node(dad,slot,i,j,l) 
int slot,dad;
short i,j,l; {
  list temp,kid;

  kid=node[node[dad]->child[i][j][l]];

  while(TRUE) {
    temp=node[slot];
    if(temp->cube==kid->cube) {
        node[dad]->child[i][j][l]=slot;
        return(TRUE);
    }
    else {
      if(kid->cube<temp->cube) {
        if(temp->left==EMPTY) {
          temp->left=node[dad]->child[i][j][l];
          return(FALSE);
        }
        slot=temp->left;
      }
      else {
        if(temp->right==EMPTY) {
           temp->right=node[dad]->child[i][j][l];
           return(FALSE);
        }
        slot=temp->right;
      }
    }
  }
}
/*****************************************************************************/
float assign_value(slot, p, k, q, dummy2)
int slot;
short k;      
float p[][8], q,dummy2; {
  float dummy1=0.0;
  short n;

  if(dummy2==0.0)
    return(0.0);
  for(n=0;n<8;n++)
    dummy1+=(p[n][k]*(node[slot]->value[n]));
  return(q*dummy1/dummy2);
} 
/*****************************************************************************/
void init_Jmin(start,stop) 
int start; {                            
  int temp;

  temp=start;
  while(temp<(stop+1)) {
    node[temp]->Jmin=0.0;
    temp++;
  }
}
/*****************************************************************************/
void determine_optimum(start, ca, cu, cx, p,qchoice) 
int start[]; 
int qchoice;                          
float ca[][8], cu[], cx[2][7], p[][8][8]; {
  int temp;
  float cofm, cofu, cofa, future;
  short z;
  int i, j, l, m, k;

  for(z=levels-1;z>(-1);z--) {
    temp=start[z];
    while(temp<stop[z]) {
      node[temp]->Jmin=10000000.0;
      for(i=0;i<2;i++) {
	cofa=cofu=0.0;
	for(k=0;k<8;k++) {
	  cofa+=(node[temp]->value[k]*ca[i][k]);
	  for(m=0;m<8;m++) 
	   cofu+=(node[temp]->value[k]*p[(node[temp]->age)*(1-i)][k][m]*cu[m]);
	} 
	cofu*=alpha;
	for(j=0;j<2;j++) {
	  cofm=alpha*cx[j][qchoice];
	  future=0.0;
	  for(l=0;l<8;l++) {
            if(node[temp]->child[i][j][l]!=(-1))
	      future+=(node[temp]->denom[i][j][l] * 
		       node[node[temp]->child[i][j][l]]->Jmin);
	  }
	  future=(alpha*future)+cofa+cofu+cofm;
	  if(future<node[temp]->Jmin) {
	    node[temp]->Jmin=future;
	    node[temp]->Opti=i;
	    node[temp]->Optj=j;
          }
        } 
      }
      temp++;
    }
  }
}    
/*****************************************************************************/
void sort_Jmin() {
  short l,iopt,jopt;
  int temp=0;

  while(temp<stop[levels]) {
    if(node[temp]->optflag==TRUE) {
      iopt=node[temp]->Opti;
      jopt=node[temp]->Optj;
      for(l=0;l<8;l++) 
        if(node[temp]->child[iopt][jopt][l]!=EMPTY)
          node[node[temp]->child[iopt][jopt][l]]->optflag=TRUE;
    }
    temp++;
  }
}
/*****************************************************************************/
void init_to_zero(a,i)
short i;
float a[][8][8];{
  short loop1, loop2, loop3;

  for(loop1=0;loop1<i;loop1++)  
    for(loop2=0;loop2<8;loop2++)
	for(loop3=0;loop3<8;loop3++)
	  a[loop1][loop2][loop3]=0.0;
}
/*****************************************************************************/
void pick_mtrx(pchoice, qchoice)
int *pchoice,*qchoice; {
  printf("\nEnter choices of matrixes...\n\n");
  printf("Choice of p matrix:");
  scanf("%d", pchoice);
  printf("Choice of q matrix:");
  scanf("%d", qchoice);
  printf("\n");
}
/*****************************************************************************/
void get_pi_val() {
  int k;

  printf("\nEnter intial pi values...\n\n");
  for(k=0; k<8; k++){
    printf("  Pi value[%d]=",k);
    scanf("%f,",&node[0]->value[k]);
  }
  printf("\n");
}
/*****************************************************************************/
void init_tree(start)
int start[]; {
  int i;

  alloc(node,MAXNODES);

  for(i=1;i<LEVELS+1;i++)
    start[i]=stop[i]=(-1);
  start[0]=0;
  stop[0]=1;

  node[0]->age=0;
  node[0]->prob=1.0;
  node[0]->optflag=TRUE;
  node[0]->left=EMPTY;
  node[0]->right=EMPTY;

  get_pi_val();

  setbuf(stdout,NULL);
}
/*****************************************************************************/
void get_constants(rnd,alpha,levels)
short *levels;
float *rnd, *alpha; {
  printf("\nTo assign the default value to the constants, enter a zero.\n\n");
  printf("Enter value for alpha (default is .9524):");
  scanf("%f",alpha);
  if (*alpha==0.0)
    *alpha=DALPHA;
  printf("\nEnter value for levels (default is 10, maximum is 20):");
  scanf("%d",levels);
  if (*levels==0)
    *levels=DLEVELS;
  printf("\nEnter value for the interval (default is 0.1, minimum is 0.005):");
  scanf("%f",rnd);
  if (*rnd==0.0)
    *rnd=DRND;
}
/*****************************************************************************/
void alloc(node,size)
list node[];
int size; {
  int i;

  for(i=0;i<size;i++)
    node[i]=(list) malloc(sizeof(struct pi));
}
/*****************************************************************************/


#include "/mit/smmadana/proc/clock.proc"
#include "/mit/smmadana/proc/set_mtrx.proc~~~"
#include "outfiles.array"
#include "/mit/smmadana/proc/round.proc"


