/* *************************************************************
 
        Final Project                                 MMU 1996

	######################################################
        #                                                    #
	#               A Modular Neural Network             #
        #                                                    #
        #              A TWO-LAYER MODULAR NETWORK           #
	#                                                    #
	######################################################

	Albrecht Schmidt                              09.08.96

	FILE: CMul2L.C                             Version 1.0

   ************************************************************* */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>


#include "neuro.h"
#include "CData.h"
#include "CMLayer.h"
#include "CMul2L.h"

#ifdef PC
   #include <dir.h>
#endif

#ifdef UNIX
   #include <sys/stat.h>
   #include <unistd.h>
#endif

#ifdef SOLARIS
   #include <sys/stat.h>
   #include <unistd.h>
#endif

#define VERSION "1.0"

// #define DP(X) cout << X ;
#define DP(X) ;

//PC
#ifdef PC
double log2(double x)
{
  return (log(x)/log(2));
}
#endif

//SOLARIS
#ifdef SOLARIS
double log2(double x)
{
  return (log(x)/log(2));
}
#endif
 

// the constructor with parameters
CMul2L::CMul2L( int no_u_inps,     // number of user inputs
		int no_cl,         // number of classes
		TNetDef *netL1,    // definition of the
				   // networks in the input layer
		TNetDef *net_m,    // definition of the decision
				   // networks
                char *logfile ,    // the log file
                int mapping ,      // mapping of inputs onto
                                   // the input modules
                TOutRep out_rep )  // the representation of the  
                                   // classes in the first layer 
{
	DP( "\nCMul2L::CMul2L(" << no_u_inps << ", " << no_cl << ", "
				<< netL1 << ", " << net_m << ", "
				<< logfile << ", " << mapping << ", "
				<< out_rep << ")");

	no_user_inps = no_u_inps;
	no_classes   = no_cl;

	no_nets_L1 = (int) ceil((float)no_user_inps / (float)netL1->no_inputs);

	if (out_rep == small)
	   no_out_net_L1 = (int) ceil(log2((double)no_classes));
	else
	   no_out_net_L1 = no_classes;

	no_main_inps = no_nets_L1 * no_out_net_L1;

	no_main_outs = no_classes;


	def_nets_L1 = new TNetDef;
	def_nets_m = new TNetDef;

	def_nets_L1->no_inputs = netL1->no_inputs;
	def_nets_L1->no_layers = netL1->no_layers;
	def_nets_L1->lambda = netL1->lambda;
	def_nets_L1->fct = netL1->fct;
	int i;
	for(i=0;i<netL1->no_layers-1;i++)
	{
		def_nets_L1->neuronL[i] = netL1->neuronL[i];
	}
	def_nets_L1->neuronL[netL1->no_layers-1] = no_out_net_L1;

	layer1 = new CMulLayer (no_nets_L1, no_user_inps,
				def_nets_L1, mapping);

        for(i=0;i<net_m->no_layers-1;i++)
        {
		def_nets_m->neuronL[i] = net_m->neuronL[i];
	}
	def_nets_m->neuronL[net_m->no_layers-1] = no_main_outs;
	main_net = new CBackPro(no_main_inps, net_m->no_layers,
				net_m->lambda, net_m->fct, NO_LOG,
				def_nets_m->neuronL[0], def_nets_m->neuronL[1],
				def_nets_m->neuronL[2], def_nets_m->neuronL[3],
				def_nets_m->neuronL[4], def_nets_m->neuronL[5]);

	if (strcmp(logfile, NO_LOG) == 0)
	{
	   logStatus = OFF;
	}
	else
	{
	   logStatus = ON;
	   logfd = fopen(logfile, "wt");
	   if (logfd == NULL)
	   {
	       cout << ERR_MSG << "can not open file :" << logfile << " !!!";
	       return;
	   }
	   fprintf(logfd, "\n This is the logfile of the\n");
	   fprintf(logfd, "\n M O D U L A R  N E U R A L  N E T W O R K\n");
	   fprintf(logfd, "\n                                   program\n");
	   fprintf(logfd, "\n\n Running Version: %s\n", VERSION);

	   fprintf(logfd, "\nInitialized at %s",Read_SysTime() );
	   fprintf(logfd, "with the follwing pararmeters:\n");

	   fprintf(logfd, "# of user inputs: %i \n", no_user_inps);
	   fprintf(logfd, "# of different classes: %i \n\n", no_classes);

	   fprintf(logfd, "# of nets in the inp layer: %i\n", no_nets_L1);
	   fprintf(logfd, "# inputs in inp layer: %i \n",netL1->no_inputs);
	   fprintf(logfd, "# layers in inp layer: %i \n",netL1->no_layers);
	   fprintf(logfd, "# lambda in inp layer: %f \n",netL1->lambda);
	   fprintf(logfd, "# function in inp layer: %i \n", netL1->fct);
	   for(i=0;i<netL1->no_layers-1;i++)
	   {
		   fprintf(logfd, "# neurons in %i. layer: %i \n",i,
			netL1->neuronL[i]);
	   }
	   fprintf(logfd, "# outputs per net in inp layer: %i \n\n",
						no_out_net_L1);


	   fprintf(logfd, "# inputs in the decision net: %i \n",
						no_main_inps);
	   fprintf(logfd, "# layers in the decision net  : %i \n",
						net_m->no_layers);
	   fprintf(logfd, "# lambda in the decision net  : %f \n",
						net_m->lambda);
	   fprintf(logfd, "# function in the decision net  : %i \n",
						net_m->fct);
	   for(i=0;i<netL1->no_layers-1;i++)
	   {
		   fprintf(logfd, "# neurons in %i. layer: %i \n",i,
			def_nets_m->neuronL[i]);
	   }

	   fprintf(logfd, "# outputs in the decision net: %i \n\n",
						no_main_outs);

	   fprintf(logfd, "this logfile name: %s \n", logfile);
	   fprintf(logfd, "the mapping code %i \n", mapping);
	   if (out_rep == small)
	     fprintf(logfd, "small intermedieate representation\n\n");
	   else
	     fprintf(logfd, "large intermedieate representation\n\n");

	   fprintf(logfd, "weights are initilalized randomly!!!\n\n");

	   fflush(logfd);
	}
	delete def_nets_L1;
	delete def_nets_m;

}

// the constructor from file
CMul2L::CMul2L( char *filename,    // the name of the desciption file
		char *dirname,  // the sub directory
		char *logfile ) // the log file
{
	DP( "\nCMul2L::CMul2L(" << filename << ")" );

	FILE *infile;
	char comment[MAX_STRING_LEN],
	     file_with_net[MAX_STRING_LEN],
	     filename_L1[MAX_STRING_LEN],
	     filename_m[MAX_STRING_LEN];

	// change the directory
	if ( chdir(dirname) == -1 )
	{
	   cout << ERR_MSG << "can't change to:" << dirname << " !!!";
	   return ;
	}

	// Open the Network Desciption file
	infile = fopen(filename, "rt");
	if (infile == NULL)
	{
	      sprintf(file_with_net, "%s.net", filename);
	      infile = fopen(file_with_net, "rt");
	      if (infile == NULL)
	      {
		 cout << ERR_MSG << "can not open file :" << filename << " !!!";
		 return;
	      }
	}

	// Read the class variables, read the comment but don't use it.
	fscanf(infile, "%i %s\n", &no_user_inps, comment);
	fscanf(infile, "%i %s\n", &no_classes, comment);
	fscanf(infile, "%i %s\n", &no_nets_L1, comment);
	fscanf(infile, "%i %s\n", &no_out_net_L1, comment);
	fscanf(infile, "%i %s\n", &no_main_inps, comment);
	fscanf(infile, "%i %s\n", &no_main_outs, comment);
	fscanf(infile, "%s %s\n", filename_L1, comment);
	fscanf(infile, "%s %s\n", filename_m, comment);

	DP("\n No_user_inps: " << no_user_inps <<
	   "\n No_classes: " << no_classes <<
	   "\n No_nets_L1: " << no_nets_L1 <<
	   "\n No_out_net_L1: " << no_out_net_L1 <<
	   "\n No_main_inps: " << no_main_inps <<
	   "\n No_main_outs: " << no_main_outs <<
	   "\n File L1: " << filename_L1 <<
	   "\n File m: " << filename_m << ")" );

	layer1 = new CMulLayer(filename_L1);

	main_net = new CBackPro(filename_m, NO_LOG);

	fclose(infile);

	// change back
	chdir("..");

	if (strcmp(logfile, NO_LOG) == 0)
	{
	   logStatus = OFF;
	}
	else
	{
	   logStatus = ON;
	   logfd = fopen(logfile, "wt");
	   if (logfd == NULL)
	   {
	       cout << ERR_MSG << "can not open file :" << logfile << " !!!";
	       return;
	   }
	   fprintf(logfd, "\n This is the logfile of the\n");
	   fprintf(logfd, "\n M O D U L A R  N E U R A L  N E T W O R K\n");
	   fprintf(logfd, "\n                                   program\n");
	   fprintf(logfd, "\n\n Running Version: %s\n", VERSION);

	   fprintf(logfd, "\nInitialized at %s",Read_SysTime() );
	   fprintf(logfd, "\nwith the follwing pararmeters:\n");

	   fprintf(logfd, "the network description file: %s\n", filename);
	   fprintf(logfd, "the input layer file: %s\n", filename_L1);
	   fprintf(logfd, "the decisio network file: %s\n", filename_m);
	   fprintf(logfd, "# of user inputs: %i \n", no_user_inps);
	   fprintf(logfd, "# of different classes: %i \n\n", no_classes);

	   fprintf(logfd, "# of nets in the inp layer: %i\n", no_nets_L1);
	   fprintf(logfd, "# outputs per net in inp layer: %i \n\n",
						no_out_net_L1);


	   fprintf(logfd, "# inputs in the decision net: %i \n",
						no_main_inps);
	   fprintf(logfd, "# outputs in the decision net: %i \n\n",
						no_main_outs);

	   fprintf(logfd, "this logfile name: %s \n", logfile);
	   fprintf(logfd, "weights are read from file!!!\n\n");

	   fflush(logfd);
	}

}

// the destructor
CMul2L::~CMul2L()
{
	DP( "\nCMul2L::~CMul2L()" );

	// call the destructors of the input layer
	layer1->CMulLayer::~CMulLayer();
	// call the destructor for the decision net
	main_net->CBackPro::~CBackPro();
	// write the log
	if (logStatus == ON)
	{
	    // last entry in logfile
	    fprintf(logfd, "\n\nThe work is done ?! at %s \n", Read_SysTime());
	    fprintf(logfd, "\n\n B Y E !!!\n");
	    // close the logfile
	    fclose(logfd);
	}
}


// function to store the network
int CMul2L::StoreNet( char *filename, char *dirname )
{
	DP( "\nCMul2L::StoreNet(" << filename << ", " << dirname << ")" );

	char *filename_m = new char[MAX_STRING_LEN];
	char *filename_net = new char[MAX_STRING_LEN];
	int change_back = 0;

	FILE *outfile;


	// if the directory is not valid
	// create the directory and change into it
	if ( chdir(dirname) == -1 )
	{
	   if ( dirname[0] != '.' )
	   {
		#ifdef PC
			mkdir(dirname);
		#endif
		#ifdef SOLARIS
			mkdir(dirname, 0777);
		#endif
		#ifdef UNIX
			mkdir(dirname, 0777);
		#endif
	   }
	   else
	   {
	       change_back = 1;
	       cout << WARN_MSG << " "
		    << dirname << " -- strange directory!!!";
	   }
	   // change in the new directory
	   if (chdir(dirname) == -1)
	   {
	      cout << ERR_MSG << "can't change to:" << dirname << " !!!";
	      if (logStatus == ON)
	      {
		  fprintf(logfd, "\n Can not change dir to %s", dirname);
		  fprintf(logfd, " >>> Net not saved!!! \n");
		  fflush(logfd);
	      }

	       return -1;
	   }
	}

	sprintf(filename_net, "%s.net", filename);
	DP("\nWrite the modular Net in file: >>" << filename_net << "<<");


	// open the output file to write
	outfile = fopen(filename_net, "wt");
	if (outfile == NULL)
	{
	      cout << ERR_MSG << "can not open file :" << filename_net << " !!!";
	      if (logStatus == ON)
	      {
		  fprintf(logfd, "\n Can not open %s", filename_net);
		  fprintf(logfd, " >>> Net not saved!!! \n");
		  fflush(logfd);
	      }
	      return -1;
	}

	// make the log entries
	if (logStatus == ON)
	{
	  fprintf(logfd, "\nWrite the Network to file: %s", filename);
	  fprintf(logfd, " in dir: %s at %s\n", dirname, Read_SysTime());
	  fflush(logfd);
	}


	 // Write the class variables, write the comment
	fprintf(outfile, "%i :no_user_inps\n", no_user_inps);
	fprintf(outfile, "%i :no_classes\n", no_classes);
	fprintf(outfile, "%i :no_nets_L1\n", no_nets_L1);
	fprintf(outfile, "%i :no_out_net_L1\n", no_out_net_L1);
	fprintf(outfile, "%i :no_main_inps\n", no_main_inps);
	fprintf(outfile, "%i :no_main_outs\n", no_main_outs);

	DP("\nWrite Layer 1 in file: >>" << filename << ".inp<<");
	fprintf(outfile, "%s.inp :filenames_L1\n", filename);
	layer1->Store(filename);

	// UNIX filename_m = sprintf(filename_m, "%s.m", filename);
	// PC
	sprintf(filename_m, "%s.dec", filename);
	DP("\nWrite MainNet in file: >>" << filename_m << "<<");
	fprintf(outfile, "%s :filename_m\n", filename_m);
	main_net->StoreNet(filename_m);

	// close the ouput file
	fclose(outfile);

	// change the directory back
	if (change_back == 0)	chdir("..");

	// free the allocated memory
	delete filename_m;
	delete filename_net;
	return 1;
}

// reset the weights in the network
void CMul2L::ResetWeights(double min, double max)
{
	DP("\nCMul2L::ResetWeights(" << min << ", " << max << ")");

	layer1->ResetWeights(min, max);
	main_net->ResetWeights(min, max);

	// make the log entries
	if (logStatus == ON)
	{
	  fprintf(logfd, "\n\n Weights are reseted between %f and %f ",
			 min, max);
	  fprintf(logfd, "at: %s\n", Read_SysTime());
	  fflush(logfd);
	}
}

// calculate the response for an input vector (the vector)
// returns the calculated output vector
TVector CMul2L::Apply( TVector resV,  // allocated result vector
		       TVector inV )  // input vector
{
	DP("\nCMul2L::Apply(" << resV << ", " << inV << ")");

	TVector tempV = new double[no_main_inps];

	tempV = layer1->Apply(tempV, inV);

	resV = main_net->Apply(resV, tempV);

	delete[] tempV;

	return resV;
}

// calculate the respone for an input vector (the class number)
// Returns the class number of -1 if the deifference
// between the winner and the runner-up is smaller than diff
int CMul2L::Detect(TVector inV,        // input vector
		   float diff )  // the wanted difference
{
        DP("\nCMul2l::Detect(" << inV << ", " << diff  << ")" );

        TVector result = new double[no_main_outs];

        result = Apply(result, inV);

	// PrintV(result, no_classes , "Res");

  	int winner; 
	winner = WinnerNo(result, no_classes, diff);
        delete[] result;

	return winner;
}

// train the whole network
void CMul2L::Train( char *datafile,
		   int maxStep_1, double maxError_1,
		   int maxStep_m, double maxError_m,
		   char *err_file_1 , char *err_file_m ,
		   double eta, double alpha )
{
	DP("\nCMul2L::Train(" << datafile
	   << ", " << maxStep_1 << ", " << maxError_1
	   << ", " << maxStep_m << ", " << maxError_m
	   << ", " << err_file_1 << ", " << err_file_m
	   << ", " << eta << ", " << alpha << ")" );

	// make the log entries
	if (logStatus == ON)
	{
	  fprintf(logfd, "\nTraining the whole Network !!!\n");
	  fflush(logfd);
	}

	cout << "\n Start training networks in the first layer!";
	cout << "\nStart Time_1: " << Read_SysTime();
	TrainL1(datafile, maxStep_1, maxError_1, err_file_1, eta, alpha );
	cout << "\nStart Time_m: " << Read_SysTime();
	cout << "\n Start training the main networks !";
	Train_m(datafile, maxStep_m, maxError_m, err_file_m, eta, alpha );
	cout << "\nEnd Time: " << Read_SysTime();

	char dummy[MAX_STR_LEN];
	cout << "\n\nPress >RETURN< for the menu!\n";
	gets(dummy);
}

// train the first modular layer on a file
// Returns the number of training steps performed
// or -1 if the datafile does not exist
int CMul2L::TrainL1( char *datafile,    // the data file
		     int maxStep,       // the number of steps (maximal)
		     double maxError,   // the aceptable error
		     char *err_file , //name of the error file
		     double eta,      // lerning constant
		     double alpha ) // momentum
{
	DP("\nCMul2L::TrainL1(" << datafile
	   << ", " << maxStep << ", " << maxError
	   << ", " << err_file
	   << ", " << eta << ", " << alpha << ")" );


	double error;
	int recs, i, j;
	FILE *errfd;
	CData *dat = new CData;
	int *mix;       // permuation array

	// open the error file
	errfd= fopen(err_file, "wt");
	if (errfd == NULL)
	{
	   cout << ERR_MSG << "can not open file :" << err_file << " !!!";
	   if (logStatus == ON)
	   {
	      fprintf(logfd, "\n Can not open %s", err_file);
	      fprintf(logfd, " >>> No Training !!!\n");
	   }
	   return -1;
	}



	TVector iV, clV, oV;
	iV = new double[no_user_inps];
	clV = new double[1];
	oV = new double[no_out_net_L1];

	recs = dat->Read(datafile, no_user_inps, 1);

	// make the log entries
	if (logStatus == ON)
	{
	  fprintf(logfd, "\nTraining the input layer !!!\n");
	  fprintf(logfd, "\nParameters: max. # of steps: %i ", maxStep);
	  fprintf(logfd, "\n            max. Error     : %f", maxError);
	  fprintf(logfd, "\n            data file name : %s ", datafile);
	  fprintf(logfd, "\n            # train. recs. : %i ", recs);
	  fprintf(logfd, "\n            error file name: %s ", err_file);
	  fprintf(logfd, "\n            learnig const. : %f", eta);
	  fprintf(logfd, "\n            momentum const.: %f", alpha);
	  fprintf(logfd, "\n\nStart training at %s ",Read_SysTime() );
	  fflush(logfd);
	}


	// alloacte the memory for the permuatation array
	mix = new int[recs];
	// fill the array in order
	for(i=0; i<recs; i++) mix[i] = i;

	for (j=0;j<maxStep;j++)
	{
		error = 0;
		// make a permutation
		mix = Mix(mix, recs, recs);
		// learn all trainings records
		for(i=0;i<recs; i++)
		{
			// cout << "\n Learn  read: " << i << " --- ";
			iV = dat->GetInV(iV, mix[i]);
			clV = dat->GetOutV(clV, mix[i]);

			oV = Int2BinVector(oV, (int)clV[0], no_out_net_L1);

			error += layer1->Learn(iV, oV, eta, alpha);
		}
		// write error entriy
		error = error / (double)recs;
		fprintf(errfd, "%i %f\n", j, error);
		fflush(errfd);

		// check if the end condition is reached
		if (error <= maxError) break;
		// cout << "\n" << j << " " <<  error;
	}

	dat->CData::~CData();

	if (logStatus == ON)
	{
	  fprintf(logfd, "\nStop training (input layer) at %s ",
			Read_SysTime() );
	  fprintf(logfd, "\n Results : # of steps: %i ", j);
	  fprintf(logfd, "\n           Error     : %f\n", error);
	  fflush(logfd);
	}

	return j;
}

// train the decision network on a file
// Returns the number of training steps performed
// or -1 if the datafile does not exist
int CMul2L::Train_m( char *datafile,    // the data file
		     int maxStep,       // the number of steps (maximal)
		     double maxError,   // the aceptable error
		     char *err_file ,   // name of the error file
		     double eta,        // lerning constant
		     double alpha)      // momentum
{
	DP("\nCMul2L::Train_m(" << datafile
	   << ", " << maxStep << ", " << maxError
	   << ", " << err_file
	   << ", " << eta << ", " << alpha << ")" );


	double error;
	int recs, i, j;
	FILE *errfd;
	CData *dat = new CData;
	int *mix;       // permuation array

	// open the error file
	errfd= fopen(err_file, "wt");
	if (errfd == NULL)
	{
	   cout << ERR_MSG << "can not open file :" << err_file << " !!!";
	   if (logStatus == ON)
	   {
	      fprintf(logfd, "\n Can not open %s", err_file);
	      fprintf(logfd, " >>> No Training !!!\n");
	   }
	   return -1;
	}

	TVector iV, clV, oV, tempV;
	iV = new double[no_user_inps];
	tempV = new double[no_main_inps];
	clV = new double[1];
	oV = new double[no_main_outs];

	recs = dat->Read(datafile, no_user_inps, 1);
	// cout << "\n recs: " << recs;

	// make the log entries
	if (logStatus == ON)
	{
	  fprintf(logfd, "\nTraining the Decision Network !!!\n");
	  fprintf(logfd, "\nParameters: max. # of steps: %i ", maxStep);
	  fprintf(logfd, "\n            max. Error     : %f", maxError);
	  fprintf(logfd, "\n            data file name : %s ", datafile);
	  fprintf(logfd, "\n            # train. recs. : %i ", recs);
	  fprintf(logfd, "\n            error file name: %s ", err_file);
	  fprintf(logfd, "\n            learnig const. : %f", eta);
	  fprintf(logfd, "\n            momentum const.: %f", alpha);
	  fprintf(logfd, "\n\nStart training at %s ",Read_SysTime() );
	  fflush(logfd);
	}

	// alloacte the memory for the permuatation array
	mix = new int[recs];
        // fill the array in order
        for(i=0; i<recs; i++) mix[i] = i;
 
        for (j=0;j<maxStep;j++)
        {


		error = 0;
                // make a permutation
		mix = Mix(mix, recs, recs);
		// learn all trainings records
		for(i=0;i<recs; i++)
                {
			// cout << "\n Learn  read: " << i << " --- " << error;
                        iV = dat->GetInV(iV, mix[i]);
                        clV = dat->GetOutV(clV, mix[i]);
			
        		tempV = layer1->Apply(tempV, iV);


 
                        oV = Int2BitVector(oV, (int)clV[0], no_main_outs);   
                        error += main_net->Learn(tempV, oV, eta, alpha);

			// PrintV(iV, no_user_inps, "iV");
			// PrintV(clV, 1, "clV");
			// PrintV(tempV, no_main_inps, "tempV2");
			// PrintV(oV, no_main_outs, "oV2");

		}
                // write error entriy
		error = error / (double)recs;
                fprintf(errfd, "%i %f\n", j, error);
                fflush(errfd);

                // check if the end condition is reached
                if (error <= maxError) break;
		// cout << "\n" << j << " " <<  error;
        }

	dat->CData::~CData();

	if (logStatus == ON)
	{
	  fprintf(logfd, "\nStop training (decision net) at %s ",
			Read_SysTime() );
	  fprintf(logfd, "\nResults : # of steps: %i ", j);
	  fprintf(logfd, "\n          Error     : %f\n", error);
	  fflush(logfd);
	}

	return j;
}

// test the performance of the network
//Returns the performance in percent (0..100%)
double CMul2L::Test(char *filename, // the data file
		    double diff,    // the required difference between
				    // winner and runner-up
		    int displ )    // if displ > 1 each result is
				    // printed on the screen
{
	DP("\nCMul2L::Train_m(" << filename << ", " << diff
		<< ", " << displ << "))" );


	CData *dat = new CData;

	int i, recs, res_cl;
	int good =0 , bad =0;
	recs = dat->Read(filename, no_user_inps, 1);


	// make the log entries
	if (logStatus == ON)
	{
	  fprintf(logfd, "\nTest the performance !!!\n");
	  fprintf(logfd, "\nParameters: data file name : %s ", filename);
	  fprintf(logfd, "\n            # records      : %i ", recs);
	  fprintf(logfd, "\n            differenc      : %f", diff);
	  fprintf(logfd, "\n            display mode   : %i", displ);
	  fprintf(logfd, "\n\nStart testing at %s ",Read_SysTime() );
	  fflush(logfd);
	}

	// cout << "\nrecs: " << recs;

	double recog;
	TVector iV;
	TVector oV;
	iV = new double[no_user_inps];
	oV = new double[1];
	double *result = new double[no_main_outs];
	double *desV = new double[no_main_outs];

	for(i=0;i<recs; i++)
	{
		iV = dat->GetInV(iV, i);
		oV = dat->GetOutV(oV, i);

		// PrintV(iV, in, "inV");

		result = Apply(result, iV);

		if (displ > 0)
		{
		   cout << "\n read: " << i << " --- ";
		   desV = Int2BitVector(desV, (int)oV[0], no_main_outs);
		   PrintV( desV, no_main_outs, "Desired");
		   PrintV( result, no_main_outs , "Calculated");
		   fprintf(logfd, "\nread: %i", i);
		   fPrintV(logfd, desV, no_main_outs, "Desired");
		   fPrintV(logfd, result, no_main_outs , "Calculated");
		}

		res_cl =  Detect(iV, diff);

		if (oV[0] == res_cl) good++; else bad++;
	}

	recog = ((double)good / (double)recs) * 100;
	// print results on the screen
	cout << "\n\nStatistics: no of records: " << recs;
	cout <<   "\n            no of goods : " << good;
	cout <<   "\n            no of bads  : " << bad;
	cout << "\n\n            recognition : " << recog << "%\n";

	delete result;
	delete desV;
	dat->CData::~CData();

	// make the log entries
	if (logStatus == ON)
	{
	  fprintf(logfd, "\n Test Statistics:\n");
	  fprintf(logfd, "\n Results: # records   : %i ", recs);
	  fprintf(logfd, "\n          # goods     : %i", good);
	  fprintf(logfd, "\n          # bads      : %i", bad);
	  fprintf(logfd, "\n\n          recognition : %f %%\n", recog);
	  fflush(logfd);
	}

	char dummy[MAX_STR_LEN];
	cout << "\n\nPress >RETURN< for the menu!\n";
	gets(dummy);

	return recog;
}

// clculate the output for given input file
void CMul2L::Work(char *infile,  // the input data
		  char *outfile, // the output file
		  int datafiletype,  // the type of the data file
				     // with = 0 or without =1 results
		  int displ,     // if displ > 0 each result is
				 // printed on the screen
		  double diff,   // difference to discriminate
		  int o_mode)     // output mode

{
	CData *dat;
	int i, recs, res_cl;
	FILE * outfd;

	double *inV, *outV;
	double *result = new double[no_main_outs];


	inV  = new double[no_user_inps];
	outV = new double[1];
	dat = new CData();

	// open the output file to write
	outfd = fopen(outfile, "wt");
	if (outfd == NULL)
	{
	      cout << ERR_MSG << "can not open file :" << outfile << " !!!";
	      if (logStatus == ON)
	      {
		  fprintf(logfd, "\n Can not open %s", outfile);
		  fprintf(logfd, " >>> Calaculation not written\n");
		  fflush(logfd);
	      }
	      return;
	}

	if (datafiletype == 0)
	{
		recs = dat->Read(infile, no_user_inps, 1);
	}
	else
	{
		recs = dat->Read(infile, no_user_inps);
	}

	// make the log entries
	if (logStatus == ON)
	{
	  fprintf(logfd, "\n Calculated the output \n");
	  fprintf(logfd, "\n     # input file     : %s", infile);
	  fprintf(logfd, "\n     # output file    : %s",  outfile);
	  fprintf(logfd, "\n     # records        : %i ", recs);
	  fprintf(logfd, "\n     difference       : %f", diff);
	  fprintf(logfd, "\n     display mode     : %i", displ);
	  fprintf(logfd, "\n     datafiletype     : %i", datafiletype);
	  fprintf(logfd, "\n     output mode      : %i", o_mode);
	  fprintf(logfd, "\n\nStart calculating at %s ",Read_SysTime() );
	  fflush(logfd);
	}

	for(i=0; i< recs; i++)
	{
		inV = dat->GetInV(inV, i);

		result = Apply(result, inV);

		res_cl =  Detect(inV, diff);

		if (displ > 0)
		{
		   cout << "\n read: " << i
			<< " --- Result class: " << res_cl << "    ";
		   PrintV( inV, no_user_inps, "InputVec");
		   PrintV( result, no_main_outs , "Calculated");
		   fprintf(logfd, "\nread: %i --- Result class: %i     ",
			i, res_cl);
		   fPrintV(logfd, inV, no_user_inps, "InputVec");
		   fPrintV(logfd, result, no_main_outs , "Calculated");
		}

		WriteVector(inV, no_user_inps, outfd);
		fprintf(outfd, " : ");
		if (o_mode == 0)
		{
			fprintf(outfd, "%i ;\n", res_cl);
		}
		else
		{
			WriteVector(result, no_main_outs, outfd);
			fprintf(outfd, " : %i ;\n", res_cl);
		}
	}

	fclose(outfd);
	delete[] result;
	delete[] outV;
	delete[] inV;
	dat->CData::~CData();

	if (displ > 0)
	{
		char dummy[MAX_STR_LEN];
		cout << "\n\nPress >RETURN< for the menu!\n";
		gets(dummy);
	}
}


// functions to activate the writing of the Logfile
void CMul2L::LogWriteOn()
{
	if (logfd == NULL)
	{
	      cout << WARN_MSG << "There is no Logfile !!!" ;
	      logStatus = OFF;

	}
	else
	{
		logStatus = ON;
		// write log enrties
		fprintf(logfd, "\n Activate writing of Logfile !" );
		fflush(logfd);
	}
}


// functions to deactivate the writing of the Logfile
void CMul2L::LogWriteOff()
{
	if (logStatus == ON)
        {
		// write log enrties
		fprintf(logfd, "\n Deactivate writing of Logfile !" );
		fflush(logfd);
        }
	logStatus = OFF;
}
