/***************************************************************************/
/*                  Last Update   12/27/2002
/*
/*						Testing Program for
/*
/*       Learning Vector Quantization Network for Classification 
/*
/*                     Jiang Li and Dr. Manry   
/*
/*					   Signal Processing Lab
/*					    		UTA
/*
/*This a test program for the Learining Vector Quantization Network
/*
/***************************************************************************/



#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
#include <math.h>
#include<conio.h>
#include<string.h>

#define Outfile "LvqTestResult.txt"   /* File to store the testing result */

/* First assign some random seeds for the random number generator */
int IX=3;
int IY=4009;
int IZ=234;


void main(void)                                       /* begain of main */
{

	char *Infile, *Clusterfile, str[100], ch;

											 /* Infile    --> the file name of the testing data
		                                     Outfile      --> the file name to store the testing result
											 Clusterfile  --> well trained cluster center file
	                                         str          --> a string variable to read the data */
	
	FILE *ifs,*fpOut,*fpCluster;             /* ifs    --> the file pointer for the traing data file
											 fpOut     --> the file pointer for the output file in which
	                                                       the well trained cluster centers will be stored
	                                         fpCluster --> the file pointer for the cluster center file */

	int i, j, k, ii, temp1, temp2;           /* i,j,k,ii,temp1,temp2     --> some variables used for iteration */
	                                         
	int N, Nv, Nc, indexClass, indexCluster;
											 /* N         --> No. of elements per pattern to be clustered
											 Nv           --> No. of patterns in the file
								             Nit          --> No. of the iteration to run 
	                                         indexClass   --> Class Membership determined for input pattern
											 indexCluster --> Cluster Membership determined for input pattern */
	
	int Check,*Ncluster;						 /* Check     --> To check the Cluster center file
	                                         Ncluster     --> No. of cluster for each class */
	
	int Out_Flag;                            /* Out_Flag  --> Indicate whether the testing file has desired output? */
	                            
		
	int *ErrorForClass, TotalError;          /* ErrorForClass  --> No. of patterns misclassified for each class 
	                                         TotalError        --> No. of patterns misclassified for the whole data */
	double ErrorPercent;
											 /* ErrorPercent   --> The Percentage of the misclassifed patterns */

	int *NvForClass;                         /* NvForClass   --> No of patterns of each class */

	float *xa, *ty;                          /* xa  --> Vector to store the elements will be clustered
	                                         ty     --> Vector to store the elements will not be clustered, not used */
	
	int ClassId;                             /* ClassId   --> The class membership for the current pattern */

	double  ***Mk;						     /* Mk        --> the centers of clusters */
	
	double  mintemp, distance;	
	                                         /* mintemp     -->  Temp varibal used for minimal distance caculation
	                                         distance       -->  Distance between input vector and a cluster mean */
	                                         	
	double *distW;                           /* Distance Measure */

	char *get_string(char *);                /* Input string */
	int get_int(char *,int, int);            /* Input int varible */
	
	
	/* Initialize variables */
	mintemp = 1e40;
	distance = 0.0;
	indexClass = 0;
	indexCluster = 0;
	TotalError = 0;

	/* Getting relevant information from the user */
	Infile = get_string("Enter input file : ");

	/* Opening the input files in "read" mode */
	ifs= fopen(Infile,"r");
	/* Checking for the existance of the files */
	if (ifs == NULL )
	{
		perror(Infile);
		exit(1);
	}
	
	/* Does this testing file has desired output? */
	printf("\n Does the testing file has desired output? \n");
	printf("\n Choose (0) for NO \n");
	printf("\n        (1) for YES : ");
	Out_Flag = get_int("",0,1);
	
	/* Getting cluster center file */
	Clusterfile = get_string("Enter class center file name: ");
	
	/* Opening the file in "read" mode and checking the existance of the file */
	fpCluster = fopen(Clusterfile,"r");
	if(fpCluster == NULL)
	{
		perror(Clusterfile);
		exit(1);
	}
	
	N = get_int("Enter the No. of Input : ",1,100);

	Nc = get_int("Enter the No. of classes : ",1,100);
	 
	
	/* Read information from the file user inputed*/
	fscanf(fpCluster,"%d",&Check);
	ch = fgetc(fpCluster);
	do
	{
		ch = fgetc(fpCluster);
	}while(ch != '\n');
	fscanf(fpCluster,"%d",&Check);
	if(Check != N)
	{
		printf("The input file's input number does not match the cluster center file!\n");
		exit(1);
	}
	fscanf(fpCluster,"%d",&Check);
	if(Check != Nc)
	{
		printf("The input file's class number does not match the cluster center file!\n");
		exit(1);
	}

	Ncluster = (int*)malloc(sizeof(int)*Nc);
	for(i = 0; i < Nc; i ++)
		fscanf(fpCluster,"%d",&Ncluster[i]);

	/* Allocating Memory dynamically*/

	xa= (float*)malloc(sizeof(float)*(N));
	ty= (float*)malloc(sizeof(float)*(Nc));
	distW = (double*)malloc(sizeof(double)*N);

	ErrorForClass = (int*)malloc(sizeof(int)*Nc);
	NvForClass = (int*)malloc(sizeof(int)*Nc);

	Mk= (double***)malloc(sizeof(double**)*N);
	
	for(i = 0;i < N; i ++)
	{
		Mk[i] = (double**)malloc(sizeof(double*)*100);
		for(j = 0;j<100; j++)
		{
			Mk[i][j]=(double*)malloc(sizeof(double)*Nc);
		}
	}
	
	/* Read the distance measure */
	for(i = 0; i < N; i ++){
		fscanf(fpCluster,"%s",str);
		distW[i] = atof(str);
	}
	/* Read the cluster center from the file */
	for (i=0;i<Nc;i++)
	{
		for (j=0;j<Ncluster[i];j++){
			for(k = 0 ; k < N; k ++){
				fscanf(fpCluster,"%s",str);
				Mk[k][j][i] = atof(str);
			}
		}
		
	}

	/* Initialization */
	Nv= 0;

	for( i = 0; i < Nc ; i ++)
	{
		ErrorForClass[i] = 0;
		NvForClass[i] = 0;
	}

	/* Count the No. of the patterns and No. of patterns for each class */
	while(!feof(ifs))
	{
		Nv++;    

		for (i=0;i<N && !feof(ifs);i++) {
			fscanf(ifs,"%f",&xa[i]);
		}

		if(Out_Flag == 1)
		{
			if (!feof(ifs) ) {
				fscanf(ifs,"%d", &ClassId);
			}
		
			NvForClass[ClassId-1] ++;
		}
	}
	/* pay attention we count one more which is not necessery */
	Nv--;  
	if(Out_Flag) NvForClass[ClassId-1] --;

	
	/* Open a file to store the testing result */
	fpOut = fopen(Outfile,"w");

	/* Checking for the existance of the file */
	if (fpOut == NULL )
	{
		perror(Outfile);
		exit(1);
	}
		
	/* Reset the file pointer to the begining of the file */
	rewind(ifs);
	fprintf(fpOut,"Index\t");
	for(i = 0; i < N; i++)
		fprintf(fpOut,"Input[%d]\t",i);
	fprintf(fpOut,"Class_Id\tDesired_Id\tDistance\n\n");
	i=0;
	while(!feof(ifs))
	{
		i++;
		/* Read inputs */
		for (ii=0;ii<N && !feof(ifs);ii++) {
			fscanf(ifs,"%f",&xa[ii]);
		}
		
		/* Read ClassId if has desired output */
		if(Out_Flag){
			if (!feof(ifs) ) {
				fscanf(ifs,"%d", &ClassId);
			}
		}
		distance = 0.0;	
		/* Find the closest center for each input pattern */
		for(temp1 = 0; temp1 < Nc; temp1 ++)
		{
			for(temp2 = 0; temp2 < Ncluster[temp1]; temp2 ++)
			{
				for(k = 0; k < N; k ++)
				{
					distance += distW[k]*(xa[k] - Mk[k][temp2][temp1])*(xa[k] - Mk[k][temp2][temp1]);
				}
				if(distance<mintemp)
				{
					mintemp=distance;
					indexClass = temp1;
					indexCluster = temp2;
				}
				distance = 0.0;
			}
		
			
		}
		fprintf(fpOut,"%d\t",i);
		for(j = 0;j < N; j ++)
		{
			fprintf(fpOut,"%f\t",xa[j]);
		}

		if(Out_Flag){
			fprintf(fpOut,"%d\t%d\t%f\n",indexClass+1,ClassId,mintemp);
		}
		else{
			fprintf(fpOut,"%d\tN/A\t%f\n",indexClass+1,mintemp);
		}
		mintemp = 1e40;
		/* Count the No. of misclassified patterns */
		if(Out_Flag){
			if(indexClass != ClassId -1) {
				ErrorForClass[ClassId-1] ++;
				TotalError ++;
			}
		}
	
	}

	if(Out_Flag){
		ErrorPercent = (double)TotalError*100.0/(double)Nv;
	}

	/* Output the testing result */
	printf("\n\n There are %d classes.\n",Nc);
	for(i = 0; i < Nc; i ++)
		printf(" There are %d clusters for %dth class.\t",Ncluster[i],i+1);
	
	
	fprintf(fpOut,"There are %d classes.\n",Nc);
	for(i = 0; i < Nc; i ++)
		fprintf(fpOut,"There are %d clusters for %dth class.\n",Ncluster[i],i+1);
	fprintf(fpOut,"\n");
	
	if(Out_Flag){
		for(i = 0; i < Nc; i ++)
		{
			printf(" Class %d has %d error patterns.\n", i,ErrorForClass[i]);
			fprintf(fpOut,"Class %d has %d error patterns.\n", i+1,ErrorForClass[i]);
		}
	
		printf(" Total error patterns are : %d.\n",TotalError);
		printf(" Error percentage is: %f.\n",ErrorPercent);
 	
		fprintf(fpOut,"Total error patterns are : %d.\n",TotalError);
		fprintf(fpOut,"Error percentage is: %f.\n",ErrorPercent);
	}
 
	printf("\n Testing is completed!\n");
	fprintf(fpOut,"Testing is completed!\n");
	
	fcloseall();
 	
}																	/* end of main */

/*************************************************************************/

int get_int(char *title_string,int low_limit, int up_limit)
{
	 int i,error_flag;
	 char *get_string();             /* get string routine */
	 char *cp,*endcp;                /* char pointer */
	 char *stemp;                    /* temp string */

/* check for limit error, low may equal high but not greater */
	 if(low_limit > up_limit) {
		  printf("\nLimit error, lower > upper\n");
		  exit(1);
	 }

/* make prompt string */
	 stemp = (char *) malloc(strlen(title_string) + 60);
	 if(!stemp) {
		  printf("\nString allocation error in get_int\n");
		  exit(1);
	 }
	 sprintf(stemp,"%s [%d...%d]",title_string,low_limit,up_limit);

/* get the string and make sure i is in range and valid */
	 do {
		  cp = get_string(stemp);
		  i = (int) strtol(cp,&endcp,10);
		  error_flag = (cp == endcp) || (*endcp != '\0'); /* detect errors */
		  free(cp);                                   /* free string space */
	 } while(i < low_limit || i > up_limit || error_flag);

/* free temp string and return result */
	 free(stemp);
	 return(i);
}

/*****************************************************************************/
char *get_string(char *title_string)
{
	 char *alpha;                            /* result string pointer */

	 alpha = (char *) malloc(80);
	 if(!alpha) {
		  printf("\nString allocation error in get_string\n");
		  exit(1);
	 }
	 printf(" %s ",title_string);
	 gets(alpha);

	 return(alpha);
}

/****************************************************************************/