/* Copyright (c) 1993 by The Johns Hopkins University */


/* OUTPUT.C:  Output Routines */



#include "config.h"
#include "pebls.h"

extern config_type CONFIG;   
extern instance_type data[INSTANCES_MAX];
extern output_type output[CLASSES_MAX+1][TRIALS_MAX];	






/* ------------------------------------------------------------ */
/* PRINT INSTANCES:  For Debugging Purposes Only		*/

void print_instances(void)
{
    int i,f;
    int features, instances;

    instances = CONFIG.instances;
    features = CONFIG.features;


    for (i=0; i<instances; i++)
    {
	printf("INSTANCE %3d: %3s %3d | %d | ",
	       i, data[i].id, data[i].offset, data[i].class_true);
	for (f=0; f<features; f++)
	    printf("%2d ", data[i].value[f]);
	printf("\n");
    }
}



/* ------------------------------------------------------------ */
void initialize_output(void)
{
    int c,t;

    for (c=0; c<CLASSES_MAX+1; c++)
    {
        for (t=0; t<TRIALS_MAX; t++)
	{
	    output[c][t].p = 0;
	    output[c][t].n = 0;
	    output[c][t].u = 0;
	    output[c][t].o = 0;
	}
    }
}



/* ------------------------------------------------------------ */

void compute_output_totals(void)
{
    int c, t;
    int p,n,u,o;
    int trials = CONFIG.trials;
    int classes = CONFIG.classes;


    for (t=0; t<trials; t++)
    {
	for (c=0; c<classes; c++)
	{
	    output[classes][t].p += output[c][t].p;
	    output[classes][t].n += output[c][t].n;
	    output[classes][t].u += output[c][t].u;
	    output[classes][t].o += output[c][t].o;
	}
    }
}


/* ------------------------------------------------------------ */
float get_average(int class, int count)
{
    int t, trials=CONFIG.trials;
    float sum=0.0;

    for (t=0; t<trials; t++)
    {
	switch(count)
	{
	    case PCOUNT: sum += (float) output[class][t].p; break;
	    case NCOUNT: sum += (float) output[class][t].n; break;
	    case UCOUNT: sum += (float) output[class][t].u; break;
	    case OCOUNT: sum += (float) output[class][t].o; break;
	}
    }

    return (sum / (float) trials);
}



/* ------------------------------------------------------------ */
void print_averages(void)
{
    int c, classes = CONFIG.classes;
    float pavg, navg, uavg, oavg;
    float percent, coeff;

    printf("\n\nAVERAGES (%d TRIALS)\n", CONFIG.trials);
    printf("                                    PERCENT  CORRECT   FALSE   CORREL  \n");
    printf(" CLASS    TOTAL     HITS   MISSES   CORRECT  REJECTS   POSTV    COEFF  \n");
    printf("  NAME      #        (P)     (U)      (%%)      (N)      (O)     (C)  \n");
    printf("------   ------   ------   ------   ------   ------   ------   ------  \n");

    for (c=0; c<=classes; c++)
    {
	if (c==classes)
	{
    	    printf("------   ------   ------   ------   ------   ------   ------   ------\n");
	    printf(" TOTAL ");
	}	
	else printf("%6s ", CONFIG.class_name[c]);

  	pavg = get_average(c,PCOUNT);
	navg = get_average(c,NCOUNT);
	uavg = get_average(c,UCOUNT);
	oavg = get_average(c,OCOUNT);
	percent = pavg / (pavg + uavg);
	coeff=corr_coeff((double) pavg, (double) navg, (double) uavg, (double) oavg);

	printf("%8.1f %8.1f %8.1f %8.2f %8.1f %8.1f %8.2f\n",
			pavg+uavg, pavg,uavg,percent,navg,oavg, coeff);
    }
}
	



/* ------------------------------------------------------------ */
void print_output(void)
{
    int i, t, trials;
    int c, classes;
    int p,n,u,o;
    float percent;
    float coeff;

    trials = CONFIG.trials;
    classes = CONFIG.classes;




    if ((CONFIG.output_mode == COMPLETE) &&
	(CONFIG.training_mode != LEAVE_ONE_OUT))
	print_classification_results();


    compute_output_totals();

    if (CONFIG.output_mode != AVERAGES_ONLY)
    {
        for (t=0; t<trials; t++)
	{
	    printf("\n\nTRIAL: %d\n", t+1);
	    printf("                                    PERCENT  CORRECT   FALSE   CORREL  \n");
	    printf(" CLASS    TOTAL     HITS   MISSES   CORRECT  REJECTS   POSTV    COEFF  \n");
	    printf("  NAME      #        (P)     (U)      (%%)      (N)      (O)     (C)  \n");
    	    printf("------   ------   ------   ------   ------   ------   ------   ------  \n");

	    for (c=0; c<=classes; c++)
	    {
	        p = output[c][t].p;
	        n = output[c][t].n;
	        u = output[c][t].u;
	        o = output[c][t].o;

	        percent = (float) p / (p + u);
	        coeff = corr_coeff((double) p,(double) n,(double) u,(double) o);

		if (c==classes)
		{
	    	    printf("------   ------   ------   ------   ------   ------   ------   ------\n");
		    printf(" TOTAL ");
		}
		else printf("%6s ", CONFIG.class_name[c]);
	        printf("%8d %8d %8d %8.2f %8d %8d %8.2f\n",
			p+u, p,u,percent, n,o,coeff);
	    }
  	}
    }


    print_averages();
    

}



/* ------------------------------------------------------------ */
void update_single_output(int instance, int class_nearest, int trial)
{
    int c, classes = CONFIG.classes;
    int class_true;

    class_true = data[instance].class_true;
    

    if (class_true == class_nearest)   /* Correct Classification */
    {
	output[class_true][trial].p++;
	for (c=0; c<classes; c++)
	  if (c != class_true) output[c][trial].n++;
    }
    else
    {
	output[class_true][trial].u++;
	output[class_nearest][trial].o++;
	data[instance].classify_errors++;
    }
}



/* ------------------------------------------------------------ */
void update_output(int trial)
{
    int c, classes = CONFIG.classes;
    int i, instances = CONFIG.instances;
    int class_instance, class_nearest;
    int post_processing = CONFIG.post_processing;
    int start;

    if (CONFIG.training_mode == SPECIFIED_GROUP)
        start = CONFIG.training_instances;
    else start = 0;

    for (i=start; i<instances; i++)
    {
      if (data[i].trained == FALSE)
      {
	class_instance = data[i].class_true;
	if (post_processing != OFF) 
	    class_nearest = data[i].class_pp;
	else class_nearest  = data[i].class_nearest;

    	if (class_instance == class_nearest)   /* Correct Classification */
    	{
	    output[class_instance][trial].p++;
	    for (c=0; c<classes; c++)
	    if (c != class_instance) output[c][trial].n++;
        }
        else
        {
	    output[class_instance][trial].u++;
	    output[class_nearest][trial].o++;
	    data[i].classify_errors++;
        }
      }
    }
}




/* ------------------------------------------------------------ */
/* PRINT_CLASSIFICATION_RESULTS:  For each test instance, print */
/*   the instance's true class, as well as the class as	 	*/
/*   determined by PEBLS.					*/

void print_classification_results(void)
{
    int i, instances = CONFIG.instances;

    printf("\n\n\n");
    printf("                                                WITH   \n");
    printf("              SUBUNIT       TRUE      PEBLS     POST-  \n");
    printf("     ID        OFFSET      CLASS      CLASS    PROCESS \n");
    printf("  --------     ------     ------     ------    ------- \n");
    for (i=0; i<instances; i++)
    {
	if (data[i].trained == FALSE)
	{
	   if (CONFIG.post_processing == OFF)
	     printf("%10s %10d %10s %10s        n/a \n", data[i].id, data[i].offset,
	        CONFIG.class_name[data[i].class_true], 
	        CONFIG.class_name[data[i].class_nearest]);
	   else
	     printf("%10s %10d %10s %10s %10s\n", data[i].id, data[i].offset,
	        CONFIG.class_name[data[i].class_true], 
		CONFIG.class_name[data[i].class_nearest], 
		CONFIG.class_name[data[i].class_pp]);
	}
    }
}




