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

        Final Project                                 MMU 1996

        ###################################################### 
        #                                                    # 
        #               A Logical Neural Network             #    
        #                                                    # 
        #               A Ram Discriminator Class            # 
        #                                                    # 
        ######################################################
 
        Albrecht Schmidt                              17.09.96 
 
        FILE: CDiscrim.C                           Version 1.0
 
   ************************************************************* */ 

#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

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

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

CDiscrim::CDiscrim(int no_i, int no_inp_ram, int seed) 
{
	DP("\nCDiscrim::CDiscrim(" << no_i << ", " << 
	    no_inp_ram << ", " << seed << ")" );

	no_user_inputs = no_i;
        no_inputs_per_ram = no_inp_ram;
	rand_seed = seed;

	no_rams = (int) ceil((double) no_user_inputs / (double) no_inp_ram);
	no_inputs = no_rams * no_inputs_per_ram;

	DP("\n No of inputs per Ram: " << no_inputs_per_ram <<
           "\n No of Rams          : " << no_rams );

	user_inputV = new double[no_user_inputs];
	extented_inputV = new double[no_inputs];
	mixed_inputV = new double[no_inputs];
	
	int i;
	for(i=0;i<no_rams;i++)
	{
		ram[i] = new CRam(no_inputs_per_ram);
	}
}

CDiscrim::CDiscrim(FILE *fd)
{
        DP("\nCDiscrim::CDiscrim(" << fd << ")" );
 
	char comment[MAX_SEP_LEN];

	// Read the class variables, read the comment but don't use it.
        fscanf(fd, "%li %s\n", &rand_seed, comment);
        fscanf(fd, "%i %s\n", &no_inputs, comment);
        fscanf(fd, "%i %s\n", &no_user_inputs, comment);
        fscanf(fd, "%i %s\n", &no_inputs_per_ram, comment);
        fscanf(fd, "%i %s\n", &no_rams, comment);

        user_inputV = new double[no_user_inputs];
        extented_inputV = new double[no_inputs];
        mixed_inputV = new double[no_inputs];
  
        int i;
        // Read - and initialize the Rams 
        for(i=0;i<no_rams;i++)
        {
                fscanf( fd, "%s\n" , comment);
                if ( comment[0] != '-' ) 
                {
                        cout << "\nNo or wrong Ram file !! \n";
		        cout << "\n Try again !!!! \n";
			return;
                }
                else
                {
                        ram[i] = new CRam(fd);;
                }
                fscanf( fd, "\n");
        }
}

CDiscrim::~CDiscrim() 
{
	DP("\nCDiscrim::~CDiscrim()");

	int i;
	for(i=0;i<no_rams;i++)
        {
                ram[i]->CRam::~CRam();  
        } 

        delete[] user_inputV;
        delete[] extented_inputV;
        delete[] mixed_inputV;
}

 
void  CDiscrim::Learn(TVector inpV)
{
	DP("\nCDiscrim::Learn(" << inpV << ")");
	
	extented_inputV = extentVector(extented_inputV, no_inputs,
				       inpV, no_user_inputs);

	mixed_inputV = randVector(mixed_inputV, extented_inputV, no_inputs, 
				  rand_seed);

        int i;
        for(i=0;i<no_rams;i++)
        {
		// for DEBUG
	        // PrintV(mixed_inputV + (i* no_inputs_per_ram), 
	        //       no_inputs_per_ram, "learnV");
                ram[i]->Store(mixed_inputV + (i* no_inputs_per_ram), 
                              no_inputs_per_ram);
        }
}


float CDiscrim::Recall(TVector inpV)
{
       DP("\nCDiscrim::Recall(" << inpV << ")");
        
        extented_inputV = extentVector(extented_inputV, no_inputs,
                                       inpV, no_user_inputs);
 
        mixed_inputV = randVector(mixed_inputV, extented_inputV, no_inputs,
                                  rand_seed);
 
	float sum=0;
        int i; 
        for(i=0;i<no_rams;i++) 
        { 
                // for DEBUG
                // PrintV(mixed_inputV + (i* no_inputs_per_ram),  
                //       no_inputs_per_ram, "RecallV"); 
                sum += ram[i]->Recall(mixed_inputV + (i* no_inputs_per_ram), 
                                      no_inputs_per_ram);
        }

	DP("\n Desciminator resposne: " << (sum / (float) no_rams) );
	return (sum / (float) no_rams);
}


void CDiscrim::Save(FILE *fd)
{
	DP("\nCDiscrim::Save(" << fd << ")");

        int i;

        // write the class variables
        fprintf(fd, "%li :rand_seed\n", rand_seed);
        fprintf(fd, "%i :no_inputs\n", no_inputs);
        fprintf(fd, "%i :no_user_inputs\n", no_user_inputs);
        fprintf(fd, "%i :no_inputs_per_ram\n", no_inputs_per_ram);
        fprintf(fd, "%i :no_rams\n", no_rams);

        // ask the Rams to store their entries
        for(i=0;i<no_rams;i++)
        {
                fprintf( fd, "-----------------\n");
		ram[i]->Save(fd);
                fprintf( fd, "\n");
        }
}


