/* *************************************************************
 
        Final Project                                 MMU 1996
 
        ######################################################
        #                                                    #
        #               A Modular Neural Network             #   
        #                                                    #
        #          A Class for the Support Functions         #   
        #                                                    #
        ######################################################
 
        Albrecht Schmidt                              17.09.96
 
        FILE: CSupport.C                           Version 1.0 
 
   ************************************************************* */ 
#include <iostream.h>
#include <stdlib.h>
#include <math.h>

#include "global.h"
#include "CSupport.h"

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

#ifdef UNIX 
	#include <sys/types.h>
	#include <sys/time.h>
	#include <sys/timeb.h>
  	#include <time.h>
#endif

#ifdef SOLARIS
        #include <sys/types.h>
        #include <sys/time.h>
        #include <sys/timeb.h>
        #include <time.h>
#endif

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

#define PRG_NAME "\nCSupport"

// #define DEBUG 1

// make a random mapping from inVect -> randVect with start 
// value rndStart for Random generator
double *CSupport::randVector(double *randVect , double *inVect, 
                             int len, int rndStart)
{
        DP("\nCSupport::randVector(" << randVect << ", "
            << inVect << ", " << len << ", " << rndStart << ")");
 

        int i;
	if (rndStart !=0)
	{
        	// alloacte the memory for the permuatation array
        	int *mix;
        	mix = new int[len];
        	// fill the array in order

        	for(i=0; i<len; i++) mix[i] = i;
        	srand((long)rndStart);
        	mix = Mix(mix, len, len);

        	// cout << " ---- n";
        	// for(i=0; i<len; i++) cout << mix[i];
        	// cout << "\n";

        	for(i=0;i<len;i++)
        	{
            		// change the values
            		randVect[i] = inVect[mix[i]];
        	}
		delete[] mix;
	}
	else
	/* if rndStart == 0 then no permutation !!! */
	{
	        for(i=0;i<len;i++)
                {
                        // change the values
                        randVect[i] = inVect[i];
                }
	}
        return randVect ;
}

// make a mapping from inVect -> randVect using the array mix
double *CSupport::randVector(double *randVect , double *inVect,
                             int len, int* mix)
{
        DP("\nCSupport::randVector(" << randVect << ", "
            << inVect << ", " << len << ", " << mix << ")");

        int i;
        // cout << " ---- n";
        // for(i=0; i<len; i++) cout << mix[i];
        // cout << "\n";

        for(i=0;i<len;i++)
        {
                // change the values
                randVect[i] = inVect[mix[i]];
        }
        return randVect ;
}

// enlarge the vector inVect with len inLen to a vector exVect
// with len exLen, fill the enlarge componets with fillVal 
double *CSupport::extentVector(double *exVect, int exLen,
		     double *inVect, int inLen, double fillVal )
{
        DP("\nCSupport::extentVector(" << exVect << ", " << exLen
            << inVect << ", " << inLen << ", " << fillVal << ")");
         
        int i;
 
        for(i=0;i<inLen;i++)
        {
                exVect[i] = inVect[i];
        }
        for(i=inLen;i<exLen;i++)
        {
                exVect[i] = fillVal;
        }
 
        return exVect;
}
 
// return the winner number of a vector
int CSupport::WinnerNo(TVector inV, int len, float diff )
{
        DP("\nCSupport::WinnerNo(" << inV << ", " 
            << len << ", " << diff << ")");

        double max;
        int pos, i;
 
        max = inV[0];
        pos = 0;
        for(i=1;i<len;i++)
        {
            if (inV[i] > max)
            {
                max = inV[i];
                pos = i;
            }
        }

 
        for(i=1;i<len;i++)
        {
            if (i != pos)
            {
                if (fabs(inV[i] - inV[pos]) < diff)
                {
                    pos = -1;
                    break;
                }
            }
        }      

 
	return pos;
}

// random value in [0,1]
double CSupport::frand()
{
        #if DEBUG
                cout << PRG_NAME << "::frand()";
        #endif
 
	return ( (double)(rand()%NO_RAND)/( (double)NO_RAND) );
}

// Write a Vector in a File
void CSupport::WriteVector(TVector vect, int no_elements, FILE* fh)
{
        #if DEBUG
                cout << PRG_NAME << "::WriteVector(...)";
        #endif
 
        int i;
 
        for(i=0;i<no_elements;i++)
        {
                fprintf(fh, "%.3f ", vect[i]);
                if ( (i !=0) && (i % 40 ==0) ) fprintf(fh, "\n");
	}
}


 
// Write a int Vector in a File
void CSupport::WriteIntVector(TVector vect, int no_elements, FILE* fh)
{
        #if DEBUG
                cout << PRG_NAME << "::WriteIntVector(...)";
        #endif
 
        int i;
 
	for(i=0;i<no_elements;i++)
        {
		// PC UNIX was with rint()
		fprintf(fh, "%i ", (int) (vect[i] + 0.5));
                if ( (i !=0) && (i % 40 ==0) ) fprintf(fh, "\n");
        }
}
 


// Read a Vector from the File 
TVector CSupport::ReadVector(TVector valueV, int no_elements, FILE* fh)
{
	#if DEBUG
		cout << PRG_NAME << "::ReadVector(...)";
	#endif

	double invalue;
	int i;

	for(i=0;i<no_elements;i++)
	{
	   // read the next double value
	   fscanf(fh, "%lf", &invalue);
	   // check if it is out of range
	   if ( fabs(invalue) > MAX_WEIGHT )
	   {
	       cout << WARN_MSG << " Weights in file probably out of range!";
	       cout << "\n MAX_WEIGHT is " << MAX_WEIGHT;
	   }
	   // store in the vector
	   valueV[i] = invalue;
	}
	return valueV;
}

// Read a Vector from the File and return 0 for ok, -1 for not ok
int CSupport::ReadVecCheck(TVector valueV, int no_elements, FILE* fh)
{
	#if DEBUG
		cout << PRG_NAME << "::ReadVecCheck(...)";
	#endif

	double invalue;
	int i, r, ret = 0;

	for(i=0;i<no_elements;i++)
	{
	   // read the next double value
	   r = fscanf(fh, "%lf", &invalue);
	   // if there is a error while reading set return to -1
	   if (r < 1) ret = -1;
	   // check if it is out of range
	   if ( fabs(invalue) > MAX_WEIGHT )
	   {
	       cout << WARN_MSG << " Weights in file probably out of range!";
	       cout << "\n MAX_WEIGHT is " << MAX_WEIGHT;
	   }
	   // store in the vector
	   valueV[i] = invalue;
	}
	return ret;
}



// make a permutation of the given Vector
int * CSupport::Mix(int * p, int len,int  change)
{
	#if DEBUG
		cout << PRG_NAME << "::Mix(...)";
	#endif

	int a,b, i, tmp;
	for(i=0;i<change;i++)
	{
	    // find two positions
	    a = (int) (frand() * (len-1));
	    b = (int) (frand() * (len-1));
   	    // change the values
            tmp = p[a];
            p[a] = p[b];
            p[b] = tmp;
	}
	return p;
}

// prints a error message
void CSupport::FileWarning(char * filename)
{
     cout << ERR_MSG << ": "<< filename;
     cout << " is no correct data & target file (size or structure)";
}

// write a vector to file (only 3 digits)
void CSupport::fPrintV(FILE *fd, TVector v, int len, char* t)
{
        #ifdef DEBUG
                cout << PRG_NAME << "::fPrintV(...)\n";
        #endif

        int i;
        fprintf(fd, "\n %s(", t);
        for(i=0;i<len-1;i++)
        {
                fprintf(fd, "%.3f;",  v[i]);
        }
        fprintf(fd, "%.3f)",  v[len-1]);
}

// print a Vector on the screen
void CSupport::PrintV(TVector v, int len, char* t)
{
	#ifdef DEBUG
		cout << PRG_NAME << "::PrintV(...)\n";
	#endif

	int i;
	cout << "\n" << t << "(";
	for(i=0;i<len-1;i++)
	{
		cout << v[i] << ";";
	}
	cout << v[len-1] << ")";
}

// initialize the random number generator with the time
void CSupport::Randomize()
{
	#ifdef DEBUG
		cout << PRG_NAME << "::Randomize()\n";
	#endif

	#ifdef SOLARIS
		char ts[30];
		strcpy(ts, Read_SysTime());
		long seed;
		seed = (long) (ts[0] * ts[10] * ts[12] * ts[13] * 
                               ts[15] * ts[16] * ts[18] * ts[19]);
		#ifdef DEBUG
			printf("\nseed = %li \n", seed);
		#endif
		srand( seed );
	#endif
	#ifdef UNIX
		struct timeb now;
		long seed ;

		ftime(&now);
		seed = (long)(now.millitm * (now.time % 100)) ;
		#ifdef DEBUG
			printf("\nseed = %li \n", seed);
		#endif
		srand( seed );
	#endif
	#ifdef PC
		randomize();
	#endif

}

// generate a random vector 
TVector CSupport::RandomV(TVector returnVector, int no, double min, double max)
{
	#ifdef DEBUG
		cout << PRG_NAME << "::RandomV(...)\n";
	#endif

	int i;
	double scale;

	scale = max - min;

	for(i=0;i<no;i++)
	{
		   returnVector[i]=min + (frand() * scale); // UNIX
	}
	#ifdef DEBUG
		PrintV(returnVector, no, "RandRes");
	#endif
	return returnVector;
}

/* reads the Systemtime and returns a String */
char *CSupport::Read_SysTime()
{
   time_t t;
   time(&t);
   return ctime(&t);
}

// convert an interger into a binary vector
TVector CSupport::Int2BinVector(TVector resV, int theInt, int len)
{
	DP( "\nCSupport::Int2BinVector( " << resV << ", "
		<< theInt << ", " << len << ")" );
	
        int i; 
        for(i=0;i<len;i++)
        {
		resV[i] = theInt % 2;
		theInt = theInt / 2;
	}

   	// PrintV(resV, len, "BinVectRes"); 
	return resV;
}

// convert an interger into a binary vector
// length for the return vector == max number used
TVector CSupport::Int2BitVector(TVector resV, int theInt, int len)
{
	DP( "\nCSupport::Int2BitVector( " << resV << ", "
		<< theInt << ", " << len << ")" );
	
	int i;
	for(i=0;i<len;i++)
	{
		resV[i] = 0;
	}
	if ( (theInt < len) && (theInt >=0) )
	{
		resV[theInt] = 1;
	}
	else
	{
 		cout << WARN_MSG << " Vector to short - not converted!";
	}
	
   	// PrintV(resV, len, "BitVectRes"); 
	return resV;
}

// calculate 2 to the power of i 
int CSupport::pow_2(int i)
{
	DP( "\nCSupport::pow_2(" << i << ")" );
	
	if (i < 0 ) return -1;
	
	int j, sum = 1;
	for(j=1; j<=i ;j++)
		sum += sum;

	return sum; 
}

