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

        Final Project                                 MMU 1996

        ######################################################
        #                                                    #
        #               A Logical Neural Network             #   
        #                                                    #
        #               A Ram Based logical NN               #
        #                                                    #
        ######################################################

        Albrecht Schmidt                              17.09.96

        FILE: CRamNet.C                            Version 1.0

   ************************************************************* */
#include <iostream.h>
#include <stdlib.h>

#include "CSupport.h"
#include "CData.h"
#include "CRam.h"
#include "CDiscrim.h"
#include "CRamNet.h"

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


CRamNet::CRamNet(int no_i, int no_c, int no_i_p_r = 8,  int overl = 1)
{
    	DP("\nCRamNet::RamNet(" << no_i << ", " << no_c << ", " << 
            no_i_p_r << ", " << overl << ")" );

	overlapp = overl;
	no_classes = no_c;
        no_inps_per_ram = no_i_p_r;
        no_user_inputs = no_i;
     
	no_discrim = no_classes * overlapp;
 	DP("\n No of Discriminators: " << no_discrim ); 

	int i,j;
	for(i=0; i<overlapp; i++)
	{
	  for(j=0; j<no_classes; j++)
	  {
	     discrim[(i*no_classes) + j] = new CDiscrim(no_user_inputs, 
					                no_inps_per_ram, 
						        (long) i+1);
	     DP("\n allocated Discriminator No. " << (i*no_classes) + j );
	  }
        }
}

CRamNet::CRamNet(char *filename)
{
	DP("\nCRamNet::RamNet(" << filename << ")") ;

        FILE *infile;
        char comment[MAX_SEP_LEN];
        int i;

        // Open the Network Desciption file
        infile = fopen(filename, "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_classes, comment);
        fscanf(infile, "%i %s\n", &no_user_inputs, comment);
        fscanf(infile, "%i %s\n", &no_inps_per_ram, comment);
        fscanf(infile, "%i %s\n", &overlapp, comment);
        fscanf(infile, "%i %s\n", &no_discrim, comment);

        for(i=0;i<no_discrim;i++)
        {
                fscanf( infile, "%s\n" , comment);
                if ( comment[0] != '-' ) 
                {
                        cout << "\nWrong Networkfile !! \n";
                        cout << "Try again !!! \n";
                        return;
                }
                else
                {
                        discrim[i] = new CDiscrim(infile);
                }
                fscanf( infile, "\n");
        }
}



CRamNet::~CRamNet()
{
    	DP("\nCRamNet::~RamNet()" );
	int i;
	for(i=0;i<no_discrim; i++)
	{
 	    discrim[i]->CDiscrim::~CDiscrim();
	    DP("\n deallocated Discriminator No. " << i );
	}
}


void CRamNet::Learn(TVector inV, int class_no)
{
        DP("\nCRamNet::Learn(" << inV << ", " << class_no << ")" );
        int i; 
        for(i=0;i<overlapp; i++)
        {
            discrim[class_no+(no_classes*i)]->Learn(inV);
            DP("\n Discriminator No. " << class_no+(no_classes*i) ); 
        } 
}
 
void CRamNet::Learn(char *filename)
{
        DP("\nCRamNet::Learn(" << filename << ")" );
	
	CData *dat= new CData();

	int recs;

        // out length = 1 --> the class number !!!
	recs = dat->Read(filename, no_user_inputs , 1);

 	TVector iV;
  	TVector oV;

  	iV = new double[no_user_inputs];
  	oV = new double[1];

  	int i;
  	for(i=0;i<recs; i++)
  	{
    		// cout << "\n read: " << i << " --- ";
    		iV = dat->GetInV(iV, i);
    		oV = dat->GetOutV(oV, i);

    		// PrintV(iV, no_user_inputs, "inV");
    		// PrintV(oV, 1, "outV");

    		Learn(iV, (int) oV[0]);
  	}
}

   

int CRamNet::Detect(TVector inV, float diff = 0.01) // Returns the class
{
        DP("\nCRamNet::Detect(" << inV << ", " << diff  << ")" );


        TVector result = new double[no_classes];

        result = Recall(result, inV);

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

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

        return winner;
}


TVector CRamNet::FullRecall(TVector resV, TVector inV)
{
        DP("\nCRamNet::FullRecall(" << resV << ", " << inV  << ")" );

        int i;
        for(i=0;i<no_discrim; i++)
        {
            resV[i] = discrim[i]->Recall(inV);
            DP("\n Response Discriminator No. " << i << "is " << resV[i] );
        }
	return resV;
}


TVector CRamNet::Recall(TVector resV, TVector inV)
{
        DP("\nCRamNet::Recall(" << resV << ", " << inV  << ")" );

        int i,j; 
        for(j=0; j<no_classes; j++)
        {
 	  resV[j] = 0;
          for(i=0; i<overlapp; i++)
          {
	    resV[j] += discrim[(i*no_classes) + j]->Recall(inV);
            DP("\n Response Discriminator No. " << (i*no_classes) + j 
                << " is " << resV[j] );
	  }
	  resV[j] = resV[j] / (float) overlapp;
        }
        return resV;
}
 

void CRamNet::StoreNet(char * filename)
{
        DP("\nCRamNet::StoreNet(" << filename << ")" );
 
        FILE *outfile; 
        int i;    
 
        // open the output file to write 
        outfile = fopen(filename, "wt"); 
        if (outfile == NULL) 
        { 
              cout << ERR_MSG << "can not open file :" << filename << " !!!"; 
              return; 
        } 
 
        // write the calss variables 
        fprintf(outfile, "%i :no_classes\n", no_classes);
        fprintf(outfile, "%i :no_user_inputs\n", no_user_inputs);
        fprintf(outfile, "%i :no_inps_per_ram\n", no_inps_per_ram); 
        fprintf(outfile, "%i :overlapp\n", overlapp); 
        fprintf(outfile, "%i :no_discrim\n", no_discrim); 
 
        // ask the Discriminators to store their entries   
        for(i=0;i<no_discrim;i++)
        { 
                fprintf( outfile, "-----New_Discriminator------------\n"); 
                discrim[i]->Save(outfile); 
                fprintf( outfile, "\n"); 
        }
 
        fprintf( outfile, "END." );
        // close the ouput file
        fclose(outfile);
}

void CRamNet::Test(char* filename, float diff )
{
	CData dat;

	int i, recs, result;

  	TVector iV;
  	TVector oV;

  	iV = new double[no_user_inputs];
  	oV = new double[1];


  	recs = dat.Read(filename, no_user_inputs , 1);
 
  	cout << "\nrecs: " << recs;

 
	int good= 0;
  	int bad = 0;
 
 	for(i=0;i<recs; i++)
  	{
    		iV = dat.GetInV(iV, i);
    		oV = dat.GetOutV(oV, i);
	 
    		result =  Detect(iV, diff);
    		cout << "\n Tuple: " << i 
                     << " calc. class : " << result
                     << " desi. class : " << oV[0];
 
    		if (result == oV[0]) good++; else bad++;
	}
     	cout << "\n\nStatistics: no of values: " << recs;
       	cout <<   "\n            no of goods : " << good;
       	cout <<   "\n            no of bads  : " << bad;
       	cout << "\n\n            recognition : " <<
       	((float)good/(float)recs) *100 << "%\n";

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

}

void CRamNet::Work(char* in_file, char* out_file) 
{
 cout << "\n\n Sorry not implmented yet :  CRamNet::Work(...) \n";
}


