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

        ###################################################### 
        #                                                    # 
        #               A Modular Neural Network             #    
        #                                                    # 
        #             THE SINGLE NEURON-CELL CLASS           # 
        #                                                    # 
        ###################################################### 
   
        Albrecht Schmidt                              09.08.96   
    
        FILE: CCell.C                              Version 1.0 
  
   ************************************************************* */ 
 
#include <iostream.h>
#include <stdlib.h>
#include <math.h>

#include "global.h"
#include "CCell.h"

// #define PRINT 1
// #define DEBUG 1

/* ---------------------------------------------------------------------
	The Implementation of the constructor/destructor
-------------------------------------------------------------------- */
// Constructor of the Class
CCell::CCell(int no_inps, TFunction fct)
{
	#if DEBUG
	   cout << "\n Constructor!";
	   cout << "\n CCell::CCell(...) \n";
	   cout << "\n no_inputs: " << no_inps;
	   cout << "\n function:  " << fct;
	#endif

	int i;

	// Assign the parameters to the variables
	no_inputs       = no_inps;
	function        = fct;

	// Assign default values
	lambda          = 1;

	// allocate memory for the delta weights (values =0)
	deltaWeightV     = new TNum[no_inputs];
        for(i=0;i<no_inputs;i++)
		deltaWeightV[i] = 0;
	// allocate memory for the weights (no values in yet!)
	weightV         = new TNum[no_inputs];
}

// Destructor of the Class
CCell::~CCell()
{
	#if DEBUG
	   cout << "\n CCell::~CCell()    Destructor! \n";
	#endif

	// give the memory back
	delete[] weightV;
	delete[] deltaWeightV;
}


/* ---------------------------------------------------------------------
		The Implementation of the accessing functions
-------------------------------------------------------------------- */
// function to set the weight vector in the neuron
void CCell::SetDeltaWeights(TVector in_weightV)
{
        #if DEBUG
           cout << "\n CCell::SetDeltaWeights(...) \n";
        #endif
 
        // set all the delta weights, memory is allocated in the
        // constructor function
        int i;
        for(i=0;i<no_inputs;i++)
        {
              deltaWeightV[i]=in_weightV[i];
              #if DEBUG
                      cout << " w[" << i << "]=" << deltaWeightV[i] ;
              #endif
        }
}
 
// function to get the weights of the neuron back
TVector CCell::GetDeltaWeights(TVector returnV)
{
        #if DEBUG
                cout << "\n CCell::GetDeltaWeights() \n";
        #endif
 
        int i;
 
        // copy the delta weights in the return value vector
        for(i=0;i<no_inputs;i++)
        {
              returnV[i]=deltaWeightV[i];
              #if DEBUG
                cout << " r[" << i << "]=" << returnV[i] ;
              #endif
        }
 
        return returnV;
}
 

// function to set the weight vector in the neuron
void CCell::SetWeights(TVector in_weightV)
{
	#if DEBUG
	   cout << "\n CCell::SetWeights(...) \n";
	#endif

	// set all the weights, memory is allocated in the
	// constructor function
	int i;
	for(i=0;i<no_inputs;i++)
	{
	      weightV[i]=in_weightV[i];
	      #if DEBUG
		      cout << " w[" << i << "]=" << weightV[i] ;
	      #endif
	}
}

// function to get the weights of the neuron back
TVector CCell::GetWeights(TVector returnV)
{
	#if DEBUG
		cout << "\n CCell::GetWeights() \n";
	#endif

	int i;

	// copy the weights in the return value vector
	for(i=0;i<no_inputs;i++)
	{
	      returnV[i]=weightV[i];
	      #if DEBUG
		cout << " r[" << i << "]=" << returnV[i] ;
	      #endif
	}

	return returnV;
}


// function to get the weights of the neuron back
double CCell::GetWeight(int no)
{
	#if DEBUG
		cout << "\n CCell::GetWeight(...) \n";
	#endif

	return weightV[no-1];
}


// function to set the lambda constant
void CCell::SetLambda(double l)
{
	#if DEBUG
		cout << "\n CCell::SetLambda(...) \n";
	#endif
	lambda = l;
}

// function to get the lambda value of the neuron back
double CCell::GetLambda()
{
	#if DEBUG
		cout << "\n CCell::GetLambda() \n";
	#endif
	return lambda;
}

// function to get the number of inputs
int CCell::GetNoInputs()
{
	#if DEBUG
		cout << "\n CCell::GetNoInputs() \n";
	#endif
	return no_inputs;
}


/* ---------------------------------------------------------------------
		The Implementation of the weight calculations
-------------------------------------------------------------------- */
// function calculates the net value, that is the scale product of the
// input vector and the according weights
double CCell::Net(TVector inputV)
{
	#ifdef DEBUG
		cout << "\n CCell::Net(...) \n";
	#endif

	int i;
	double net=0;

	// scale product of all inputs with the according weights
	for(i=0;i<no_inputs;i++)
	{
	      net=net + inputV[i]*weightV[i];
	}

	#ifdef PRINT
		cout << "\n net: " << net << "\n";
	#endif

	return net;
}

// function to apply an input vector to the Neuron
double CCell::Out(TVector inputV)
{
	#ifdef DEBUG
	   cout << "CCell::Out(...) \n";
	#endif
	double net, out;

	// calculate the sum of all inputs
	net=Net(inputV);

	// apply the function which is specified to net
	switch( function )
	{
	  case uni_pol:
		{
		  out = 1.0 / (1.0 + exp(-1*lambda*net));
		  #ifdef DEBUG
		     cout << "\nFunction: cont_uni \n";
		  #endif
		  break;
		}
	  case bi_pol:
		{
		  out = (2.0 / (1.0 + exp(-1*lambda*net))) - 1;
		  #ifdef DEBUG
		     cout << "\nFunction: cont_bi \n";
		  #endif
		  break;
		}
	  default:
		{
		  cerr << "\n\nWarning: No Neuron Function specified!\n";
		  out = net;
		}
	}

	// return the calculated output value of the neuron
	#ifdef PRINT
		cout << "\n out: " << out << "\n";
	#endif

	return out;
}

