/*************************************************************************
* Project: Library of Evolutionary Algoriths
*************************************************************************
* Author: Changhe Li & Ming Yang
* Email: changhe.lw@google.com Or yangming0702@gmail.com
* Language: C++
*************************************************************************
*  This file is part of EAlib. This library is free software;
*  you can redistribute it and/or modify it under the terms of the
*  GNU General Public License as published by the Free Software
*  Foundation; either version 2, or (at your option) any later version.
*************************************************************************/
// Created: 11 May 2011
// Last modified:


#ifndef GLOBAL_H
#define GLOBAL_H

// for the demon program of EALIB
//#define DEMON_EALIB

#define EALIB

#include<stdlib.h>
#include<time.h>
#include<cmath>
#include<string>
#include<string.h>
#include <sstream>
#include <iostream>
#include <fstream>
#include<climits>
#include <iomanip>
#include <vector>
#include <map>


#include "include.h"
#include "myexcept.h"
#include "StructDec.h"
#include "../Problems/Problem.h"
#include "../RandGenerator/newran.h"



class Problem;
class Algorithm;

template<typename T> Problem * createFunction( int rId,  int rDimNumber, char *rName) { 
	return new T( rId,  rDimNumber, rName); 
}
typedef map<string, Problem * (*)( int rId,  int rDimNumber, char *rName) > BasicFunc;


class Global
{
    public:
        static int  g_dimNumber;                       // number of dimensions: could be number of nodes in TSP, number of items in Knapsack problem

        static Cauchy *gp_cauchyPro;							// cauchy random number for algorithm
        static Normal *gp_normalPro;							// gaussian random number for algorithm
        static Uniform *gp_uniformPro;							// random number of uniform distribution for algorithm
        static Levy *gp_levyPro;
        static Cauchy *gp_cauchyAlg;							// cauchy random number for algorithm
        static Normal *gp_normalAlg;							// gaussian random number for algorithm
        static Uniform *gp_uniformAlg;							// random number of uniform distribution for algorithm
        static Levy *gp_levyAlg;

        static ProblemTag g_proNumber;                          // Problem no.
        static AlgorithmTag g_algNumber;                        // algorithm no.
        static Problem *gp_problem;                             // global pointer to the problem to be solved

        static Algorithm* gp_algorithm;                           // global pointer to the algorithm

        static float g_sigma;                                   // temporal varible

        static int g_tEvals;                                     // total fitness evaluations for a single run
        static int g_numRuns;                                    //  the number of runs
        static int g_changeFre;                                  // the number of fitness evals during a single change, which is equal to g_tEvals for static optimization problems
        static int g_sampleFre;                                 // the frequency to record an results for an algorithm's performance evaluation
        static int g_runIdx;                                    // the indx of current run

        static int g_gPopsize;                                   // the global population size
        static int g_subSize;                                   // the  size of sub-populations
        static float g_overlapDegree;                             // for multi-population methods in DOPs

        static float g_diversityDegree;                         // for CPSOR algorithm

};
void gInitializeRandomArray(int * a,const int &dim,const bool mode=true);	// generate a set of radom numbers from 0-(dim-1) without repeat
int gSign(const double x);
int gRandInt(const int min, const int max,const bool mode=true);
double gRandFloat(const double min, const double max,const bool mode=true);
void gDeleteRandAlg();
void gDeleteRandPro();
void gCreateRandAlg(double seed);
void gCreateRandPro(double seed);
bool gIsTerminate();
bool gIsDynamicAlg();
template <class T>
void gCopy(T* destination, const T* source,const int  dim){
														//copy function
	if(destination==source) return;
	for(int i=0;i<dim;i++)
		destination[i]=const_cast<T*>(source)[i];
}
template <class T>
void gCopy(vector<T> destination,  vector<T>  source,const int  dim){
														//copy function
	for(int i=0;i<dim;i++)
		destination[i]=source[i];
}

inline double gChaoticValue(const double x, const double min, const double max, const double rChaoticConstant=1.0){
														// return a value calculated by logistics function
	if(min>max) return -1;
	double chaotic_value;
	chaotic_value=(x-min)/(max-min);
	chaotic_value=rChaoticConstant*chaotic_value*(1-chaotic_value);
	return min+chaotic_value*(max-min);

}
template <class T>
T gExtremum(T * v,const int size,const Compare type){
														// return min or max value of set V
	T extreme;
	extreme=v[0];
	int index=0;
	if(type==MAX_OPT){
		for(int i=1;i<size;i++){
			if(v[i]>extreme) {
					extreme=v[i];
					index=i;
				}
		}
	}
	else if(type==MIN_OPT){
		for(int i=1;i<size;i++){
				if(v[i]<extreme) {
						extreme=v[i];
						index=i;
					}
			}
	}
	return extreme;
}

template <class T>
int gPartition(int low,int high,T arr[])
{
	T high_vac,low_vac,pivot;
	pivot=arr[low];
	while(high>low){
		high_vac=arr[high];

        while(pivot<=high_vac){
			if(high<=low) break;
			high--;
			high_vac=arr[high];
		}

		arr[low]=high_vac;
		low_vac=arr[low];
		while(pivot>=low_vac){
			if(high<=low) break;
			low++;
			low_vac=arr[low];
		}
		arr[high]=low_vac;
	}
	arr[low]=pivot;

	return low;
}
template <class T>
void gQuickSort(int low,int high,T arr[])
{
  int Piv_index;
  if(low<high){
   Piv_index=gPartition(low,high,arr);
   gQuickSort(low,Piv_index-1,arr);
   gQuickSort(Piv_index+1,high,arr);
  }
}

template<class T>
void gQuickSort(const T &data,int *index, int i, int j){

    if (i>=j) return;
    int left = i+1;
    int right = j;
    int pivot=i;

    while(left<right){
         while(data[index[left]]<data[index[pivot]]&& left<right)         left++;
         while(data[index[right]]>=data[index[pivot]]&&left<right)          right--;

		 if(left<right){
            int t=index[left];
			index[left]=index[right];
			index[right]=t;
		 }
    }

    if(data[index[left]]>data[index[pivot]])  left--;

    if(data[index[left]]<data[index[pivot]]){
        int t=index[left];
        index[left]=index[pivot];
        index[pivot]=t;
    }

    pivot=left;

    gQuickSort(data, index, i, pivot-1);
    gQuickSort(data, index, pivot+1, j);
  }
template<class T>
int gFind(T * data, T item, const int size){
    int i=0;
    for(i=0;i<size;i++){
        if(data[i]==item){
            return i;
        }
    }
    return -1;
}


#endif // GLOBAL_H
