1 /*****************************************************************************
2   FILE           : $Source: /projects/higgs1/SNNS/CVS/SNNS/tools/sources/analyze.c,v $
3   SHORTNAME      : analyze.c
4   SNNS VERSION   : 4.2
5 
6   PURPOSE        : Network Analyzation Tool
7   NOTES          :
8 
9   AUTHOR         : Stefan Broeckel, Tobias Soyez
10   DATE           : 30.07.92
11 
12   CHANGED BY     : Michael Vogt
13   RCS VERSION    : $Revision: 2.17 $
14   LAST CHANGE    : $Date: 1998/03/17 15:49:54 $
15 
16     Copyright (c) 1990-1995  SNNS Group, IPVR, Univ. Stuttgart, FRG
17     Copyright (c) 1996-1998  SNNS Group, WSI, Univ. Tuebingen, FRG
18 
19 ******************************************************************************/
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 
26 /*****************************************************************************/
27 /* constants                                                                 */
28 /*****************************************************************************/
29 
30 #define  WRONG   1
31 #define  RIGHT   2
32 #define  UNKNOWN 4
33 #define  SPECIFIC 8
34 
35 #define  ON  1
36 #define  OFF 2
37 
38 #define  R402040  1
39 #define  WTA      2
40 #define  band     3
41 
42 
43 /*****************************************************************************/
44 /* type definitions                                                          */
45 /*****************************************************************************/
46 
47 typedef struct
48 {
49   int  no_of_patterns           ;
50   int  no_of_input_units        ;
51   int  no_of_output_units       ;
52   int  startpattern             ;
53   int  endpattern               ;
54   int  input_pattern_included   ;
55   int  teaching_output_included ;
56   int  sub_pattern_present      ;
57 } FileHeaderInfo ;
58 
59 
60 /*****************************************************************************/
61 /* global variables                                                          */
62 /*****************************************************************************/
63 
64 FILE  *in_file  ;
65 FILE  *out_file ;
66 
67 
68 
69 /*****************************************************************************/
70 /* function Error                                                            */
71 /*****************************************************************************/
Error(float * output,float * teaching_output,int no_of_units)72 float Error (float *output, float *teaching_output, int no_of_units)
73 {
74     int    i ;
75     float  e, diff ;
76 
77     e = 0.0 ;
78     for (i = 0 ; i < no_of_units ; i++){
79 	diff = teaching_output[i] - output[i]  ;
80 	e    = e + diff * diff                 ;
81     }
82 
83     return e;
84 }
85 
86 /*****************************************************************************/
87 /* function ClassNo                                                          */
88 /*****************************************************************************/
ClassNo(float * teaching_output,int no_of_units)89 int ClassNo (float *teaching_output, int no_of_units)
90 {
91     int i;
92     float t_max;
93     int t_pos;
94 
95     t_max = teaching_output[0];
96     t_pos = 0;
97 
98     for (i = 1 ; i < no_of_units ; i++) {
99 	if (teaching_output[i] > t_max){
100 	    t_max = teaching_output[i] ;
101 	    t_pos = i ;
102 	}
103     }
104 
105     if (t_max > 0.0)
106 	return t_pos;
107     else
108 	return -1;
109 }
110 
111 /*****************************************************************************/
112 /* The function F_402040 returns :                                           */
113 /*                                                                           */
114 /*    RIGHT   : the output of exactly one unit is >= high               and  */
115 /*              this unit has the greatest teaching output              and  */
116 /*              the output of all the other units is <= low                  */
117 /*                                                                           */
118 /*    WRONG   : the output of exactly one unit is >= high               and  */
119 /*              this unit has NOT the greatest teaching output          and  */
120 /*              the output of all the other units is <= low                  */
121 /*                                                                           */
122 /*    UNKNOWN : in any other case                                            */
123 /*                                                                           */
124 /* high, low  : parameters of F_402040                                       */
125 /*              default values: low = 0.4, high = 0.6                        */
126 /*****************************************************************************/
F_402040(float * output,float * teaching_output,int no_of_units,float high,float low,int * winner)127 int F_402040 (float *output, float *teaching_output, int no_of_units,
128 	      float high, float low, int *winner)
129 {
130     int    o_pos, t_pos, on, off, i;
131     float  t_max;
132 
133     on    = 0 ;
134     off   = 0 ;
135     o_pos = 0 ;
136     t_pos = 0 ;
137     t_max = teaching_output[t_pos] ;
138 
139     for (i = 0 ; i < no_of_units ; i++){
140 	if(output[i] >= high) {
141 	    on++;
142 	    o_pos = i;
143 	}else if (output[i] <= low)
144 	    off++ ;
145 
146 	if (teaching_output[i] > t_max){
147 	    t_max = teaching_output[i] ;
148 	    t_pos = i ;
149 	}
150     }
151 
152     if ((on + off == no_of_units) && (on == 1)) {
153 	*winner = o_pos;
154 	if (t_max > 0.0 && o_pos == t_pos)
155 	    return (RIGHT) ;
156 	else
157 	    return (WRONG) ;
158     }else{
159 	*winner = -1;
160 	return (UNKNOWN) ;
161     }
162 }
163 
164 
165 
166 /*****************************************************************************/
167 /* The function F_WTA returns :                                              */
168 /*                                                                           */
169 /*    RIGHT   :  there is exactly one unit j with maximal output a       and */
170 /*               a > high                                                and */
171 /*               the output of all the other units is < a - low          and */
172 /*               the unit j has the greatest teaching output                 */
173 /*                                                                           */
174 /*    WRONG   :  there is exactly one unit j with maximal output a       and */
175 /*               a > high                                                and */
176 /*               the output of all the other units is < a - low          and */
177 /*               the unit j has NOT the greatest teaching output             */
178 /*                                                                           */
179 /*    UNKNOWN :  in any other case                                           */
180 /*                                                                           */
181 /* high, low  : parameters of F_WTA                                          */
182 /*              default values: low = 0.0, high = 0.0                        */
183 /*****************************************************************************/
F_WTA(float * output,float * teaching_output,int no_of_units,int high,int low,int * winner)184 int F_WTA (float *output, float *teaching_output, int no_of_units, int high,
185 	   int low, int *winner)
186 {
187     int    i, o_pos, t_pos, no_of_max ;
188     float  min, max, max2 , t_max     ;
189 
190 
191     o_pos = t_pos = 0;
192     t_max = teaching_output[0] ;
193     max = min = output[0];
194     no_of_max = 1;
195 
196     for(i=1; i<no_of_units; i++){
197 	if(output[i] > max){
198 	    max       = output[i] ;
199 	    o_pos     = i;
200 	    no_of_max = 1;
201 	}else if (output[i] == max)
202 	    no_of_max++;
203 	else if (output[i] <  min)
204 	    min = output[i] ;
205 
206 	if (teaching_output[i] > t_max){
207 	    t_max = teaching_output[i] ;
208 	    t_pos = i ;
209 	}
210     }
211 
212     max2 = min  ;
213     for (i = 1 ; i < no_of_units ; i++)
214 	if ((output[i] > max2) && (output[i] < max))
215 	    max2 = output[i] ;
216 
217     if ((no_of_max == 1) && (output[o_pos] > high) && (max2  < max - low)){
218 	*winner = o_pos;
219 	if (t_max > 0.0 && o_pos == t_pos)
220 	    return (RIGHT) ;
221 	else
222 	    return (WRONG) ;
223     }else{
224 	*winner = -1;
225 	return (UNKNOWN) ;
226     }
227 }
228 
229 
230 
231 /*****************************************************************************/
232 /* The function F_band returns :                                             */
233 /*                                                                           */
234 /*    RIGHT   : for all units :                                              */
235 /*              the output is >= the teaching output - low              and  */
236 /*              the output is <= the teaching output + high                  */
237 /*                                                                           */
238 /*    WRONG   : for all units :                                              */
239 /*              the output is < the teaching output - low               or   */
240 /*              the output is > the teaching output + high                   */
241 /*                                                                           */
242 /*    UNKNOWN : in any other case                                            */
243 /*                                                                           */
244 /* high, low  : parameters of F_band                                         */
245 /*              default values: low = 0.1, high = 0.1                        */
246 /*****************************************************************************/
F_band(float * output,float * teaching_output,int no_of_units,float high,float low)247 int F_band (float *output, float *teaching_output, int no_of_units, float high,
248 	    float low)
249 {
250     int found_right = 0;
251     int found_wrong = 0;
252     int i;
253 
254     for (i = 0 ; i < no_of_units ; i++){
255 	if ((output[i] <= (teaching_output[i] + high)) &&
256 	    (output[i] >= (teaching_output[i] - low))) {
257 	    if (found_wrong)
258 		return (UNKNOWN);
259 	    else
260 		found_right = 1;
261 	}else{
262 	    if (found_right)
263 		return (UNKNOWN);
264 	    else
265 		found_wrong = 1;
266 	}
267     }
268     if(found_right)
269 	return (RIGHT);
270     else
271 	return (WRONG);
272 }
273 
274 
275 
276 /*****************************************************************************/
277 /*  function get_options                                                     */
278 /*****************************************************************************/
get_options(int argc,char * argv[],int * function,int * sel_cond,int * output_text,float * high,float * low,int * statistics,int * class_statistics,int * confm,int * spec_teach,int * spec_out)279 int get_options (int argc, char *argv[], int *function, int *sel_cond,
280 		 int *output_text, float *high, float *low, int *statistics,
281 		 int *class_statistics, int *confm, int *spec_teach,
282 		 int *spec_out)
283 
284 {
285     int error, c, hl_flag;
286     extern char  *optarg ;
287 
288     *function    = R402040;
289     *sel_cond    = 0;
290     *output_text = OFF;
291     *statistics  = OFF;
292     *class_statistics = OFF;
293     *confm = OFF;
294     in_file = (FILE *) NULL ;
295     out_file = (FILE *) NULL ;
296     hl_flag = 0;
297     error = 0 ;
298 
299     while ((c = getopt (argc, argv, "awruvcme:i:o:h:l:sS:")) != -1)
300 	switch (c){
301         case 'l' :
302 	    sscanf (optarg, "%f", low) ;
303 	    hl_flag = hl_flag | 1 ;
304 	    break ;
305         case 'h' :
306 	    sscanf (optarg, "%f", high) ;
307 	    hl_flag = hl_flag | 2 ;
308 	    break ;
309         case 'e' :
310 	    if(strcmp (optarg, "402040") == 0)
311 		*function = R402040 ;
312 	    else if(strcmp (optarg, "WTA") == 0)
313 		*function = WTA    ;
314 	    else if(strcmp (optarg, "band") == 0)
315 		*function = band    ;
316 	    else error++ ;
317 	    break ;
318         case 'r' :
319 	    *sel_cond = *sel_cond | RIGHT   ;
320 	    break ;
321         case 'w' :
322 	    *sel_cond = *sel_cond | WRONG   ;
323 	    break ;
324         case 'u' :
325 	    *sel_cond = *sel_cond | UNKNOWN ;
326 	    break ;
327         case 'S' :
328 	    *sel_cond = *sel_cond | SPECIFIC ;
329 	    if (sscanf(optarg, "%d %d", spec_teach, spec_out) != 2)
330 		error++;
331 	    break ;
332         case 'a' :
333 	    *sel_cond = WRONG | RIGHT | UNKNOWN ;
334 	    break ;
335         case 'v' :
336 	    *output_text = ON ;
337 	    break ;
338         case 's' :
339 	    *statistics  = ON ;
340 	    break ;
341         case 'c' :
342 	    *class_statistics = ON ;
343 	    break ;
344         case 'm' :
345 	    *confm = ON ;
346 	    break ;
347         case 'i' :
348 	    if ((in_file = fopen(optarg, "r")) == (FILE *) NULL) {
349 		fprintf (stderr, "error:  can't read file %s \n", optarg) ;
350 		error++ ;
351 	    }
352 	    break ;
353         case 'o' :
354 	    if ((out_file = fopen(optarg, "w")) == (FILE *) NULL){
355 		fprintf (stderr, "error:  can't create file %s\n", optarg) ;
356 		error++ ;
357 	    }
358 	    break ;
359         default  : error++ ;
360 	}
361 
362     if (*sel_cond == 0)
363 	*sel_cond = WRONG  ;
364 
365     if ((hl_flag & 1) == 0){
366 	switch (*function){
367 	case R402040 : *low  = 0.4 ; break ;
368 	case WTA     : *low  = 0.0 ; break ;
369 	case band    : *low  = 0.1 ; break ;
370 	}
371     }
372 
373     if ((hl_flag & 2) == 0){
374 	switch (*function){
375 	case R402040 : *high = 0.6 ; break ;
376 	case WTA     : *high = 0.0 ; break ;
377 	case band    : *high = 0.1 ; break ;
378 	}
379     }
380 
381     if (in_file  == (FILE *) NULL)
382 	in_file  = stdin  ;
383     if (out_file == (FILE *) NULL)
384 	out_file = stdout ;
385 
386     return (error) ;
387 }
388 
389 
390 
391 /*****************************************************************************/
392 /* function read_file_header                                                 */
393 /*                                                                           */
394 /* reads from the input file :                                               */
395 /*     no. of patterns                                                       */
396 /*     no. of input units                                                    */
397 /*     no. of output units                                                   */
398 /*     startpattern                                                          */
399 /*     endpattern                                                            */
400 /*****************************************************************************/
read_file_header(FileHeaderInfo * file_header_info)401 int read_file_header (FileHeaderInfo  *file_header_info)
402 {
403     char  str1[80], str2[80], str3[80] ;
404 
405     fscanf (in_file, "%s %s %s", str1, str2, str3) ;
406     if((strcmp(str1, "SNNS") != 0) || (strcmp(str2, "result") != 0) ||
407        (strcmp(str3, "file") != 0)){
408 	fprintf(stderr, "error:  no SNNS result file\n") ;
409 	return 1;
410     }
411 
412     fscanf (in_file, "%*s %*s %*s %*s %*s %*s %*s %*s") ;
413     fscanf (in_file, "%*s %*s %*s %*s     %d",
414 	    &(file_header_info->no_of_patterns));
415     fscanf (in_file, "%*s %*s %*s %*s %*s %d",
416 	    &(file_header_info->no_of_input_units));
417     fscanf (in_file, "%*s %*s %*s %*s %*s %d",
418 	    &(file_header_info->no_of_output_units));
419     fscanf (in_file, "%*s %*s             %d",
420 	    &(file_header_info->startpattern));
421     fscanf (in_file, "%*s %*s             %d", &(file_header_info->endpattern));
422 
423     file_header_info -> sub_pattern_present =
424 	(file_header_info->endpattern) - (file_header_info->startpattern) + 1
425      	     != (file_header_info -> no_of_patterns);
426 
427     fscanf (in_file, "%s", str1) ;
428 
429     if (strcmp (str1, "input") == 0){
430 	fscanf (in_file, "%s %s %s", str2, str3, str1) ;
431 	if((strcmp(str2, "patterns") == 0) && (strcmp(str3, "included") == 0))
432 	    file_header_info->input_pattern_included = 1 ;
433 	else
434 	    file_header_info->input_pattern_included = 0 ;
435     }
436     else
437 	file_header_info->input_pattern_included = 0 ;
438 
439     if(strcmp(str1, "teaching") == 0){
440 	fscanf(in_file, "%s %s %s", str2, str3, str1) ;
441 	if((strcmp(str2, "output") == 0) && (strcmp(str3, "included") == 0))
442 	    file_header_info->teaching_output_included = 1 ;
443 	else{
444 	    file_header_info->teaching_output_included = 0 ;
445 	    fprintf(stderr, "error:  missing teaching_output \n");
446 	    return 1;
447 	}
448     }else{
449         file_header_info->teaching_output_included = 0 ;
450 	fprintf (stderr, "error:  missing teaching_output \n") ;
451 	return 1;
452     }
453 
454     return 0;
455 }
456 
457 
458 
459 /*****************************************************************************/
460 /* main program                                                              */
461 /*****************************************************************************/
main(int argc,char * argv[])462 int main (int argc, char *argv[])
463 {
464     int   pat_no, i, j, result, function, sel_cond, output_text;
465     int   winner, spec_teach, spec_out;
466     int   statistics, class_statistics, confm, class_no, right, wrong, unknown;
467     int   *class_stat_wrong, *class_stat_right,  *class_stat_unknown ;
468     int   **confusion;
469     float low, high, error;
470     float *output, *teaching_output;
471     FileHeaderInfo  file_header_info;
472 
473     if (get_options (argc, argv, &function, &sel_cond, &output_text,
474 		     &high, &low, &statistics, &class_statistics,
475 		     &confm, &spec_teach, &spec_out) != 0) {
476 	fprintf(stderr, "usage: %s [options]        \n", argv[0]) ;
477 	fprintf(stderr, "analyzes result files which are generated by SNNS\n");
478 	fprintf(stderr, "options are:\n");
479 	fprintf(stderr, "\t-w               : report wrong classified ");
480 	fprintf(stderr, "patterns (default)\n") ;
481 	fprintf(stderr,
482 	        "\t-r               : report right classified patterns\n") ;
483 	fprintf(stderr,"\t-u               : report unclassified patterns\n") ;
484 	fprintf(stderr,"\t-a               : same as -w -r -u\n") ;
485 	fprintf(stderr,"\t-S \"t c\"         : report confusion from class t ");
486 	fprintf(stderr,"to c (-1 = noclass)\n") ;
487 	fprintf(stderr,"\t-s               : show statistic information\n") ;
488 	fprintf(stderr,"\t-c               : show class statistic information\n");
489 	fprintf(stderr,"\t-m               : show confusion matrix\n") ;
490 	fprintf(stderr,"\t-v               : verbous mode\n");
491 	fprintf(stderr,"\t-e <function>    : select error function \n") ;
492 	fprintf(stderr,"\t                   <function> = [402040 | WTA | band]\n") ;
493 	fprintf(stderr,"\t                   default = 402040\n") ;
494 	fprintf(stderr,"\t-l <float>       : lower bound level (see documentation) \n") ;
495 	fprintf(stderr,"\t                   default: 0.4 for 402040\n") ;
496 	fprintf(stderr,"\t                   default: 0.0 for WTA\n") ;
497 	fprintf(stderr,"\t                   default: 0.1 for band\n") ;
498 	fprintf(stderr,"\t-h <float>       : upper bound level (see documentation) \n") ;
499 	fprintf(stderr,"\t                   default: 0.6 for 402040\n") ;
500 	fprintf(stderr,"\t                   default: 0.0 for WTA\n") ;
501 	fprintf(stderr,"\t                   default: 0.1 for band\n") ;
502 	fprintf(stderr,"\t-i <input file>  : input result file (default stdin)\n");
503 	fprintf(stderr,"\t-o <output file> : output file (default stdout)\n") ;
504 	return 1;
505     }
506 
507     if (read_file_header (&file_header_info) != 0) {
508 	fprintf (stderr, "error:  invalid file header\n") ;
509 	return 1;
510     }
511 
512     output = (float *) malloc (file_header_info.no_of_output_units
513 			       * sizeof(float)) ;
514     teaching_output = (float *) malloc (file_header_info.no_of_output_units
515 					* sizeof(float)) ;
516     class_stat_wrong = (int *) malloc (file_header_info.no_of_output_units
517 				       * sizeof(int)) ;
518     class_stat_right = (int *) malloc (file_header_info.no_of_output_units
519 				       * sizeof(int)) ;
520     class_stat_unknown = (int *) malloc(file_header_info.no_of_output_units
521 					* sizeof(int)) ;
522     confusion = (int **) malloc((file_header_info.no_of_output_units + 1)
523 				* sizeof(int *));
524 
525     for (i=0; i<= file_header_info.no_of_output_units; i++)	{
526 	confusion[i] = (int *)malloc((file_header_info.no_of_output_units+1)
527 				     * sizeof(int));
528 	for (j=0; j<= file_header_info.no_of_output_units; j++)
529 	    confusion[i][j] = 0;
530     }
531 
532     wrong   = 0;
533     right   = 0;
534     unknown = 0;
535     error   = 0.0;
536 
537     for (i = 0; i < file_header_info.no_of_output_units; i++){
538 	class_stat_wrong[i] = 0;
539 	class_stat_right[i] = 0;
540 	class_stat_unknown[i] = 0;
541     }
542 
543     for (pat_no = 0 ; pat_no < file_header_info.no_of_patterns ; pat_no++){
544 	if (file_header_info.input_pattern_included != 0){
545 	    for (i = 1 ; i <= file_header_info.no_of_input_units ; i++)
546 		fscanf (in_file, "%*f") ;
547 	}
548 
549 	for (i = 0 ; i < file_header_info.no_of_output_units ; i++)
550 	    fscanf (in_file, "%f", &teaching_output[i]) ;
551 
552 	for (i = 0 ; i < file_header_info.no_of_output_units ; i++)
553 	    fscanf (in_file, "%f", &output[i]) ;
554 
555 	switch (function){
556 	case R402040 :
557 	    result = F_402040 (output, teaching_output,
558 			       file_header_info.no_of_output_units,
559 			       high, low, &winner);
560 	    break ;
561 	case WTA :
562 	    result = F_WTA(output, teaching_output,
563 			   file_header_info.no_of_output_units,
564 			   high, low, &winner);
565 	    break ;
566 	case band :
567 	    result = F_band(output, teaching_output,
568 			    file_header_info.no_of_output_units, high, low);
569 	    break ;
570 	}
571 
572 	if(file_header_info.no_of_output_units > 1)
573 	    class_no = ClassNo(teaching_output,
574 			       file_header_info.no_of_output_units);
575 	else
576 	    class_no = abs((int)teaching_output[0]);
577 
578 	if (class_no >= 0){
579 	    switch (result){
580 	    case WRONG:
581 		wrong++;
582 		class_stat_wrong[class_no]++;
583 		break;
584 	    case RIGHT:
585 		right++;
586 		class_stat_right[class_no]++;
587 		break;
588 	    case UNKNOWN:
589 		unknown++;
590 		class_stat_unknown[class_no]++;
591 		break;
592 	    }
593 	}
594 	if (function == R402040 || function == WTA){
595 	    if (class_no >= 0)
596 		if (result != UNKNOWN)
597 		    confusion[class_no][winner]++;
598 		else
599 		    confusion[class_no]
600 			[file_header_info.no_of_output_units]++;
601 	    else
602 		if (result != UNKNOWN)
603 		    confusion[file_header_info.no_of_output_units]
604 			[winner]++;
605 		else
606 		    confusion[file_header_info.no_of_output_units]
607 			[file_header_info.no_of_output_units]++;
608 	}else{
609 	    confm = OFF;
610 	}
611 
612 	if (statistics == OFF){
613 	    if (output_text == OFF){
614 		if((sel_cond & WRONG) == result)
615 		    fprintf(out_file,"%d\n",file_header_info.sub_pattern_present
616 			    ? pat_no+1 : pat_no+file_header_info.startpattern);
617 		else if ((sel_cond & RIGHT) == result)
618 		    fprintf(out_file,"%d\n",file_header_info.sub_pattern_present
619 			    ? pat_no+1 : pat_no+file_header_info.startpattern);
620 		else if ((sel_cond & UNKNOWN) == result)
621 		    fprintf(out_file,"%d\n",file_header_info.sub_pattern_present
622 			    ? pat_no+1 : pat_no+file_header_info.startpattern);
623 		if ((sel_cond & SPECIFIC)
624 		    && spec_teach == class_no && spec_out == winner)
625 		    fprintf(out_file,"%d\n",file_header_info.sub_pattern_present
626 			    ? pat_no+1 : pat_no+file_header_info.startpattern);
627 
628 	    } else {
629 		if      ((sel_cond & WRONG)   == result)
630 		    fprintf(out_file, "wrong   : %d\n",
631 			    file_header_info.sub_pattern_present
632 			    ? pat_no+1 : pat_no+file_header_info.startpattern);
633 		else if ((sel_cond & RIGHT)   == result)
634 		    fprintf(out_file, "right   : %d\n",
635 			    file_header_info.sub_pattern_present
636 			    ? pat_no+1 : pat_no+file_header_info.startpattern);
637 		else if ((sel_cond & UNKNOWN) == result)
638 		    fprintf(out_file, "unknown : %d\n",
639 			    file_header_info.sub_pattern_present
640 			    ? pat_no+1 : pat_no+file_header_info.startpattern);
641 		if ((sel_cond & SPECIFIC)
642 		    && spec_teach == class_no && spec_out == winner)
643 		    fprintf(out_file, "specific : %d\n",
644 			    file_header_info.sub_pattern_present
645 			    ? pat_no+1 : pat_no+file_header_info.startpattern);
646 	    }
647 	}
648 	else
649 	    error = error + Error (output, teaching_output,
650 				   file_header_info.no_of_output_units) ;
651 
652 	if (pat_no < file_header_info.no_of_patterns - 1)
653 	    fscanf (in_file, "%*s") ;
654     }
655 
656     free (output)          ;
657     free (teaching_output) ;
658 
659     if (statistics == ON){
660 	fprintf (out_file, "STATISTICS ( %d patterns )\n",
661 		 file_header_info.no_of_patterns) ;
662 	fprintf (out_file, "wrong   : %5.2f %%  ( %d pattern(s) )\n",
663 		 100.0*wrong  /file_header_info.no_of_patterns, wrong) ;
664 	fprintf (out_file, "right   : %5.2f %%  ( %d pattern(s) )\n",
665 		 100.0*right  /file_header_info.no_of_patterns, right) ;
666 	fprintf (out_file, "unknown : %5.2f %%  ( %d pattern(s) )\n",
667 		 100.0*unknown/file_header_info.no_of_patterns, unknown) ;
668 	fprintf (out_file, "error   : %f\n", error)  ;
669     }
670     if (class_statistics == ON){
671 	fprintf (out_file,"\n\n");
672 	for (i = 0; i < file_header_info.no_of_output_units; i++){
673 	    fprintf(out_file,"1ST ORDER STATISTICS FOR CLASS NO. : %d\n",i);
674 	    fprintf(out_file,"wrong   : %5.2f %%  ( %d pattern(s) )\n",
675 		    100.0*class_stat_wrong[i]  /(class_stat_wrong[i]+
676 						 class_stat_right[i]+
677 						 class_stat_unknown[i]),
678 		    class_stat_wrong[i]) ;
679 	    fprintf (out_file,"right   : %5.2f %%  ( %d pattern(s) )\n",
680 		     100.0*class_stat_right[i]  /(class_stat_wrong[i]+
681 						  class_stat_right[i]+
682 						  class_stat_unknown[i]),
683 		     class_stat_right[i]) ;
684 	    fprintf (out_file,"unknown : %5.2f %%  ( %d pattern(s) )\n",
685 		     100.0*class_stat_unknown[i]/(class_stat_wrong[i]+
686 						  class_stat_right[i]+
687 						  class_stat_unknown[i]),
688 		     class_stat_unknown[i]) ;
689 	    fprintf (out_file,"\n");
690 	}
691     }
692     if (confm == ON){
693 	fprintf(out_file,"\nCONFUSION MATRIX (rows: teaching input, ");
694 	fprintf(out_file,"colums: classification)\n\n");
695 	fprintf(out_file, " class ");
696 	for (i = 0; i < file_header_info.no_of_output_units; i++)
697 	    fprintf(out_file, "|%5d  ", i);
698 	fprintf(out_file, "| unknown\n");
699 	for (i = 0; i < file_header_info.no_of_output_units; i++)
700 	    fprintf(out_file, "-------+");
701 	fprintf(out_file, "-------+--------\n");
702 	for (i = 0; i <= file_header_info.no_of_output_units; i++){
703 	    if (i < file_header_info.no_of_output_units)
704 		fprintf(out_file,"%5d  ", i);
705 	    else
706 		fprintf(out_file,"noclass");
707 	    for (j=0; j<= file_header_info.no_of_output_units; j++)
708 		fprintf(out_file,"|%6d ", confusion[i][j]);
709 	    fprintf(out_file,"\n");
710 	}
711     }
712     return 0;
713 }
714 
715 /*****************************************************************************/
716 /* end of file                                                               */
717 /*****************************************************************************/
718 
719