/*************************************************************************
* 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: 21 September 2011
// Last modified:
#ifndef POPULATION_H
#define POPULATION_H
#include "Algorithm.h"
#include "Clustering/Group.h"
#include "Optima.h"
#include "../Problems/DOPs/DynamicContinuous.h"
template <class T>
class Population: public virtual Algorithm{
    public:

        virtual ~Population(void);
        virtual void initialize(bool mode=true);
        virtual void initialize(Chromosome & center, double radius, bool mode=true);

        virtual void addIndividual( T &p);
        virtual void addIndividual(Population<T> &s);
        virtual void addIndividual(const int num, const bool mode=true, const bool insize=false);
        virtual void addIndividual( Optima &l);
        virtual void addIndividual( T *indis, const int num);
        virtual void addIndividual( vector<T> &indis);
        virtual void deleteIndividual(const int *id,const int num);
		

        virtual void computeCenter();
		virtual void updateCurRadius(bool mode=false);
		virtual void computeInitialRadius();
        virtual int evolve(){return 0;}            // return 2 if dimensional change happens, 1 for non-dimensonal change, 0 for no change

        Population(void);
        Population(const int rPopsize, bool mode=true);
        Population(Population<T> &s);
        Population(Group<T> &g);
        Population(Chromosome & center, double radius,const int rPopsize,bool mode=true);

        const int findBest(void);
        const int findWorst(void);

        int findNearest(int idx,double &rdis,int mode=1);
        void findNearestPair(int & idx1, int &idx2, int mode=1);

        void updateIndex();
        void updateMaxID();
		void updateIDnIndex();
        virtual Population &operator= ( Population &s);
        void setPopID(const int id){
            m_popID=id;
        }
        void setPopInitialMethod(PopInitMethod rMethod){
            m_initialMethod=rMethod;
        }
        void printPopToFile(ofstream &out);

		void sort(bool mode=true, bool representative=false);					// sort population in the default mode=true for fit-first, mode=false for worst first mode
        double GetAvgDistance(bool mode=true);                                  // return the average distance between individuals
        void rank(bool mode=true);            //evaluate the position (ranking) of each individual in the population, mode=true based on the fitness of itself;otherwise on its representative's fitness
        double getMaxObj(const int idx=0);
        double getMinObj(const int idx=0);
		void setDistanceMode(DistanceMode mode);
    public:
        int m_popsize;                              // swarm size
        int m_maxID;                                // the maximum ID of the population
        T *mp_pop;	                                // the population
        int m_evoNum;                               // the number of generations
        int m_popID;                                // the ID of the populaton
        PopInitMethod m_initialMethod;              // the population initialization method

        int m_bestIdx,m_worstIdx;                   // the indice of the best and worst individual(warning: for non-dominate population, they are equal to -1)

        bool m_flag;                                // for use in some cases, e.g., whether it found an optimum solution or not, ....

        Chromosome m_best;                          // the best one in the population, notice: maynot have the best indi for multi-objective optimization problem
        Chromosome m_center;                        // the center of the population
		double m_initialRadius;						// assumption that a population has a search area, which is defined the average distance of all inidividuals to the pop's center
		double m_curRadius;

		int *mp_orderList;							// indices of ordered individuals

		DistanceMode m_disMode;
        static vector<Population<T>*> msp_subPop;   // populations, warning: it currently can only contain populations belong to the same type
        static int ms_gNumIndis;
        static void updateNumIndis();
        static void printPops();
        static void updateMemoryAll();				//update the memory of all populations when environment changes
        static int findWorstPop();                  // return the index of the worst population whose best indi is the worst among all best indis
        static int findBestPop();                   // return the index of the best population whose best indi is the best among all best indis
        static void increaseDimensionAll();
        static void decreaseDimensionAll();
		static int computePeaksFound();				// return the number of peaks found for multi-population methods for DOPs
        static float getAvgCurRadius();
        static float getAvgInitialRadius();
		void setRadius(double rRadius);
        virtual void freeMemory();
        virtual void allocateMemory(const int rPopsize);
        void updateMemory();
        virtual void increaseDimension();
        virtual void decreaseDimension();
		void reInitializeCenter(vector<Optimum> &opt, Chromosome &chr);

};


template<class T>
vector<Population<T>*> Population<T>::msp_subPop;

template<class T>
int Population<T>::ms_gNumIndis=0;

template<class T>
Population<T>::Population(void):Algorithm(),m_popsize(0),m_maxID(0),mp_pop(0),m_evoNum(0),m_popID(0),m_initialMethod(POP_INIT_UNIFORM),m_flag(false),m_initialRadius(0),m_curRadius(0),mp_orderList(0),m_disMode(DIS_EUCLIDEAN){

}

template<class T>
Population<T>::Population(const int rPopsize,bool mode):Algorithm(),m_popsize(rPopsize),m_maxID(rPopsize),m_evoNum(0),m_popID(0),m_initialMethod(POP_INIT_UNIFORM),m_flag(false),m_disMode(DIS_EUCLIDEAN){
    if(m_popsize<=0){
        mp_pop=0;
        mp_orderList=0;
        return;
    }
	mp_pop= new T[m_popsize];
	initialize(mode);
	computeCenter();
	computeInitialRadius();
	Population<T>::ms_gNumIndis+=m_popsize;
	mp_orderList=new int[m_popsize];
}
template<class T>
Population<T>::Population(Chromosome & center, double radius,const int rPopsize,bool mode):Algorithm(),m_popsize(rPopsize),m_maxID(rPopsize),m_evoNum(0),m_popID(0),m_initialMethod(POP_INIT_UNIFORM),m_flag(false),m_disMode(DIS_EUCLIDEAN){
	mp_pop= new T[m_popsize];
	initialize(center,radius,mode);
	computeCenter();
	computeInitialRadius();
	Population<T>::ms_gNumIndis+=m_popsize;
	mp_orderList=new int[m_popsize];

}

template<class T>
Population<T>::Population( Population &s):Algorithm(){
	allocateMemory(s.m_popsize);
	(*this)=s;
	Population<T>::ms_gNumIndis+=m_popsize;
}
template<class T>
Population<T>::Population(Group<T> &g):Algorithm(),m_popsize(g.m_number),m_maxID(g.m_number),m_evoNum(0),m_popID(0),m_initialMethod(POP_INIT_UNIFORM),m_flag(false),m_disMode(DIS_EUCLIDEAN){
    mp_pop= new T[m_popsize];
    for(int i=0;i<m_popsize;i++){
		mp_pop[i]=g.mp_member[i];
		mp_pop[i].m_index=i;
		mp_pop[i].m_id=i+1;
	}

    findWorst();
	findBest();
	if(m_bestIdx!=-1) m_best=mp_pop[m_bestIdx].getRepresentative();
	computeCenter();
	computeInitialRadius();
	Population<T>::ms_gNumIndis+=m_popsize;
	mp_orderList=new int[m_popsize];
}
template<class T>
void Population<T>::initialize(bool mode){

	for(int i=0;i<m_popsize;i++) mp_pop[i].initialize(i,i+1,m_initialMethod,m_popsize,mode); // index, ID
	m_evoNum=0;
	findWorst();
	findBest();
	if(m_bestIdx!=-1) m_best=mp_pop[m_bestIdx].getRepresentative();
	m_flag=false;
}

template<class T>
void Population<T>::initialize(Chromosome & center, double radius, bool mode){

	for(int i=0;i<m_popsize;i++) mp_pop[i].initialize(center,radius,i,i+1,mode); // index, ID
	m_evoNum=0;
	findWorst();
	findBest();
	if(m_bestIdx!=-1) m_best=mp_pop[m_bestIdx].getRepresentative();
	m_flag=false;
}

template<class T>
void Population<T>::allocateMemory(const int rPopsize){
	m_popsize=rPopsize;
	mp_pop= new T[m_popsize];
	mp_orderList=new int[m_popsize];
}
template<class T>
Population<T> &Population<T>::operator= ( Population &s){
	if(this==&s) return *this;

	if(m_popsize!=s.m_popsize){
		Throw(Logic_error("the size of two populations must be the same in assignment operator"));
		return *this;
	}
    for(int i=0;i<m_popsize;i++) mp_pop[i]=s.mp_pop[i];

	m_maxID=s.m_maxID;
	m_evoNum=s.m_evoNum;
	m_popID=s.m_popID;
	m_flag=s.m_flag;
	m_initialRadius=s.m_initialRadius;
	m_curRadius=s.m_curRadius;
	m_best=s.m_best;
	m_center=s.m_center;
	m_disMode=s.m_disMode;

	gCopy(mp_orderList,s.mp_orderList,m_popsize);

	return *this;
}
template<class T>
Population<T>::~Population(void){
	if(mp_pop){
		freeMemory();
		mp_pop=0;
		Population<T>::ms_gNumIndis-=m_popsize;
		m_popsize=0;
	}
}
template<class T>
void Population<T>::freeMemory(){
	if(mp_pop){
		delete [] mp_pop;
		mp_pop=0;
		delete [] mp_orderList;
		mp_orderList=0;
	}

}

template<class T>
const int Population<T>::findBest(void)
{
	if(m_popsize<1){
		m_bestIdx=-1;
		return m_bestIdx;
	}

	m_bestIdx=0;
	for(int i=1;i<m_popsize;i++){
		if(mp_pop[i]>mp_pop[m_bestIdx]){
			m_bestIdx=i;
		}
	}

    if(m_bestIdx!=0||m_popsize==1){
        return m_bestIdx;
    }
    else if(!(mp_pop[m_bestIdx]>=mp_pop[m_popsize-1])){
        m_bestIdx=-1;

    }
    return m_bestIdx;
}

template<class T>
const int Population<T>::findWorst(void)
{	if(m_popsize<1){
		m_worstIdx=-1;
		return m_worstIdx;
	}
	m_worstIdx=0;
	for(int i=1;i<m_popsize;i++){
		if(mp_pop[i]<(mp_pop[m_worstIdx])){
			m_worstIdx=i;
		}
	}
    if(m_worstIdx!=0||m_popsize==1)	return m_worstIdx;
    else if(!(mp_pop[m_worstIdx]<=mp_pop[1])){
        m_worstIdx=-1;
    }
     return m_worstIdx;
}


 template<class T>
 void Population<T>::addIndividual( T &p){
	int old_size=m_popsize;

	T *t_pop=new T[old_size+1];

	for(int i=0;i<old_size;i++) t_pop[i]=mp_pop[i];

	t_pop[old_size]=p;
	t_pop[old_size].m_index=m_popsize;
	t_pop[old_size].m_id=m_maxID+1;
	

	if(mp_pop)delete [] mp_pop;
	mp_pop=t_pop;
	m_popsize++;
	m_maxID++;
    findWorst();
	findBest();
	if(m_popsize==1)m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-1>0&&mp_pop[m_bestIdx].getRepresentative()>m_best) m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-1==0) m_best=mp_pop[m_bestIdx].getRepresentative();

	computeCenter();
	updateCurRadius();
	ms_gNumIndis+=1;
	delete [] mp_orderList;
	mp_orderList=new int[m_popsize];
 }

template<class T>
void Population<T>::addIndividual( T *indis, const int num){
    // add num individuals
    if(num<1) return;
	T *t_pop=new T[m_popsize+num];

	for(int i=0;i<m_popsize;i++) t_pop[i]=mp_pop[i];

	for(int i=0;i<num;i++){
		m_maxID++;
		t_pop[m_popsize]=indis[i];
		t_pop[m_popsize].m_index=m_popsize;
		t_pop[m_popsize].m_id=m_maxID;
		m_popsize++;
	}
	if(mp_pop)delete [] mp_pop;
	mp_pop=t_pop;

    findWorst();
	findBest();
	if(m_popsize==1)m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-num>0&&mp_pop[m_bestIdx].getRepresentative()>m_best) m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-num==0) m_best=mp_pop[m_bestIdx].getRepresentative();

	computeCenter();
	updateCurRadius();
	ms_gNumIndis+=num;
		delete [] mp_orderList;
	mp_orderList=new int[m_popsize];
}
template<class T>
void Population<T>::addIndividual( vector<T> &indis){
    // add indis.size() individuals
    if(indis.size()<1) return;
	T *t_pop=new T[m_popsize+indis.size()];

	for(int i=0;i<m_popsize;i++) t_pop[i]=mp_pop[i];

	for(int i=0;i<indis.size();i++){
		m_maxID++;
		t_pop[m_popsize]=indis[i];
				t_pop[m_popsize].m_index=m_popsize;
		t_pop[m_popsize].m_id=m_maxID;
		m_popsize++;
	}
	if(mp_pop)delete [] mp_pop;
	mp_pop=t_pop;

    findWorst();
	findBest();
	if(m_popsize==1)m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-indis.size()>0&&mp_pop[m_bestIdx].getRepresentative()>m_best) m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-indis.size()==0) m_best=mp_pop[m_bestIdx].getRepresentative();


	computeCenter();
	updateCurRadius();
	ms_gNumIndis+=indis.size();
		delete [] mp_orderList;
	mp_orderList=new int[m_popsize];
}
template<class T>
void Population<T>::addIndividual(const int num,const bool mode, const bool insize){
    // add num random individuals

    if(num<1) return;
	T *t_pop=new T[m_popsize+num];

	for(int i=0;i<m_popsize;i++) t_pop[i]=mp_pop[i];

	for(int i=0;i<num;i++){
		m_maxID++;
		if(insize)
		t_pop[m_popsize].initialize(m_best,m_initialRadius,m_popsize,m_maxID,mode);
		else
		t_pop[m_popsize].initialize(m_popsize,m_maxID,mode);
				t_pop[m_popsize].m_index=m_popsize;
		t_pop[m_popsize].m_id=m_maxID;
		m_popsize++;
	}
	if(mp_pop)delete [] mp_pop;
	mp_pop=t_pop;

    findWorst();
	findBest();

	if(m_popsize==1)m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-num>0&&mp_pop[m_bestIdx].getRepresentative()>m_best) m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-num==0) m_best=mp_pop[m_bestIdx].getRepresentative();

	computeCenter();
	updateCurRadius();
	ms_gNumIndis+=num;
		delete [] mp_orderList;
	mp_orderList=new int[m_popsize];
}
template<class T>
void Population<T>::addIndividual(Population<T> &s){

	 if(s.m_popsize<1) return;
	T *t_pop=new T[m_popsize+s.m_popsize];

	for(int i=0;i<m_popsize;i++) t_pop[i]=mp_pop[i];

	for(int i=0;i<s.m_popsize;i++){
		m_maxID++;
		t_pop[m_popsize]=s.mp_pop[i];
		t_pop[m_popsize].m_index=m_popsize;
		t_pop[m_popsize].m_id=m_maxID;
		m_popsize++;
	}
	if(mp_pop)delete [] mp_pop;
	mp_pop=t_pop;

    findWorst();
	findBest();

	if(m_popsize==1)m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-s.m_popsize>0&&mp_pop[m_bestIdx].getRepresentative()>m_best) m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-s.m_popsize==0) m_best=mp_pop[m_bestIdx].getRepresentative();

	computeCenter();
	updateCurRadius();
	ms_gNumIndis+=s.m_popsize;
		delete [] mp_orderList;
	mp_orderList=new int[m_popsize];
 }
template<class T>
 void Population<T>::addIndividual( Optima &l){
	if(l.m_number<1) return;
	T *t_pop=new T[m_popsize+l.m_number];

	for(int i=0;i<m_popsize;i++) t_pop[i]=mp_pop[i];

	for(int i=0;i<l.m_number;i++){
		m_maxID++;
		t_pop[m_popsize].initialize(l.mp_optima[i].getLocation(),m_popsize,m_maxID);
				t_pop[m_popsize].m_index=m_popsize;
		t_pop[m_popsize].m_id=m_maxID;
		m_popsize++;
	}
	delete []mp_pop;
	mp_pop=t_pop;

    findWorst();
	findBest();

	if(m_popsize==1)m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-l.m_number>0&&mp_pop[m_bestIdx].getRepresentative()>m_best) m_best=mp_pop[m_bestIdx].getRepresentative();
	else if(m_bestIdx!=-1&&m_popsize-l.m_number==0) m_best=mp_pop[m_bestIdx].getRepresentative();

	computeCenter();
	updateCurRadius();
	ms_gNumIndis+=l.m_number;

		delete [] mp_orderList;
	mp_orderList=new int[m_popsize];
 }

template<class T>
 void Population<T>::deleteIndividual(const int *id,const int num){

	 if(num>m_popsize)
		 Throw(Logic_error("the number of particles going to be deleted should less than the m_popsize"));

	if(m_popsize==num){
		Population<T>::freeMemory();
		m_maxID=0;
		m_popsize=0;
		ms_gNumIndis-=num;
		return ;
	}
	T *t_pop=new T[m_popsize-num];
	for(int i=0,k=0;i<m_popsize;i++,k++){
		int j=0;
		while(j<num&&mp_pop[i].m_id!=id[j]) j++;
		if(j==num)
		t_pop[k]=mp_pop[i];
		else
			k--;
	}
	delete []mp_pop;
	mp_pop=t_pop;
	m_popsize=m_popsize-num;
	updateIndex();
	updateMaxID();
	computeCenter();
	updateCurRadius();
	ms_gNumIndis-=num;
		delete [] mp_orderList;
	mp_orderList=new int[m_popsize];
 }

template<class T>
void Population<T>::updateIndex(){
	 for(int i=0;i<m_popsize;i++)  mp_pop[i].m_index=i;
}

template<class T>
void Population<T>::updateIDnIndex(){
	 for(int i=0;i<m_popsize;i++){
		mp_pop[i].m_index=i;
		mp_pop[i].m_id=i+1;
	}

}
template<class T>
void Population<T>::updateMaxID(){
	int max=mp_pop[0].m_id;
	for(int i=1;i<m_popsize;i++)
		if(max<mp_pop[i].m_id) max=mp_pop[i].m_id;
	m_maxID=max;
}
template<class T>
void Population<T>::updateNumIndis(){
    ms_gNumIndis=0;
    for(unsigned int i=0;i<msp_subPop.size();i++){
		ms_gNumIndis+=msp_subPop[i]->m_popsize;
	}

}

template<class T>
void Population<T>::increaseDimension(){
    Algorithm::m_dimNumber=Global::g_dimNumber;
	for(int i=0;i<m_popsize;i++) mp_pop[i].increaseDimension();
	m_center.increaseDimension();
	m_best.increaseDimension();
	findWorst();
	findBest();
	if(m_bestIdx!=-1&&mp_pop[m_bestIdx].getRepresentative()>m_best) m_best=mp_pop[m_bestIdx].getRepresentative();
	computeCenter();
	updateCurRadius();
}
template<class T>
void Population<T>::decreaseDimension(){
    Algorithm::m_dimNumber=Global::g_dimNumber;
    for(int i=0;i<m_popsize;i++) mp_pop[i].decreaseDimension();
	m_center.decreaseDimension();
	m_best.decreaseDimension();
	findWorst();
	findBest();
	if(m_bestIdx!=-1&&mp_pop[m_bestIdx].getRepresentative()>m_best) m_best=mp_pop[m_bestIdx].getRepresentative();
	computeCenter();
	updateCurRadius();
}
template<class T>
void Population<T>::printPopToFile(ofstream &out){

	for(int i=0;i<this->m_popsize;i++){
		this->mp_pop[i].getRepresentative().printToFile(out);
	}
}

template<class T>
void Population<T>::printPops(){
    //sleep(1);
	ostringstream name;
	name<<"Result//eval"<<Global::gp_problem->getEvaluations()<<"_pop"<<msp_subPop.size()<<"_indi"<<ms_gNumIndis<<".txt";
	ofstream out(name.str().c_str());
	//print peaks
    dynamic_cast<DynamicContinuous*> (Global::gp_problem)->printPeaks(out);
    out<<endl;

    Chromosome x;
    /// print centers of each pop in gnuplot format for 2-D problems
    for(unsigned int i=0;i<msp_subPop.size();i++){
        x=msp_subPop[i]->m_center;
        out<<"plot [0:2*pi] "<<msp_subPop[i]->m_curRadius<<"*sin(t)+"<<x.getGene<double>(0)<<","<<msp_subPop[i]->m_curRadius<<"*cos(t)+"<<x.getGene<double>(1)<<" with lines 1"<<endl;
        out<<"plot [0:2*pi] "<<msp_subPop[i]->m_initialRadius<<"*sin(t)+"<<x.getGene<double>(0)<<","<<msp_subPop[i]->m_initialRadius<<"*cos(t)+"<<x.getGene<double>(1)<<" with lines 2"<<endl;

    }
    ///
    out<<endl;
	for(unsigned int i=0;i<msp_subPop.size();i++){
		for(int j=0;j<msp_subPop[i]->m_popsize;j++)
			msp_subPop[i]->mp_pop[j].printToFile(out);
	}
	out.close();
}

template<class T>
void Population<T>::updateMemoryAll(){

    //printPops();
	for(unsigned int i=0;i<Population<T>::msp_subPop.size();i++){

		Population<T>::msp_subPop[i]->m_best.evaluate(false);
		Population<T>::msp_subPop[i]->m_center.evaluate(false);
		for(int j=0;j<Population<T>::msp_subPop[i]->m_popsize;j++){
			Population<T>::msp_subPop[i]->mp_pop[j].updateMemory();
		}
	}

}
template<class T>
int Population<T>::findWorstPop(){
	if(Population<T>::msp_subPop.size()<1) return -1;
    int idx=0;
    for(unsigned int i=1;i<Population<T>::msp_subPop.size();i++){
		if(Population<T>::msp_subPop[i]->m_best<(Population<T>::msp_subPop[idx]->m_best)) idx=i;
	}
	return idx;
}
template<class T>
int Population<T>::findBestPop(){
	if(Population<T>::msp_subPop.size()<1) return -1;
    int idx=0;
    for(unsigned int i=1;i<Population<T>::msp_subPop.size();i++){
		if(Population<T>::msp_subPop[i]->m_best>(Population<T>::msp_subPop[idx]->m_best)) idx=i;
	}
	return idx;

}


template<class T>
void Population<T>::updateMemory(){

	m_best.evaluate(false);
	m_center.evaluate(false);
	for(int j=0;j<m_popsize;j++){
		mp_pop[j].updateMemory();
	}

}

template<class T>
void Population<T>::computeCenter(){

    switch(Global::gp_problem->getId()){
        case Sphere: case Sphere_Noisy: case S_Sphere: case R_Sphere: case RS_Sphere: case S_Sphere_CEC05: case Sphere_Noisy_CEC05:
               case Rastrigin: case Rastrigin_Noisy: case S_Rastrigin: case R_Rastrigin: case RS_Rastrigin: case S_Rastrigin_CEC05: case RS_Rastrigin_CEC05:
               case Weierstrass: case RS_Weierstrass: case R_Weierstrass: case RS_Weierstrass_CEC05:
               case Griewank: case R_Griewank: case RS_Griewank:  case RS_Griewank_noBounds_CEC05: case Griewank_Rosenbrock_F13_CEC05: case S_Griewank_Rosenbrock_F13_CEC05:
               case Ackley: case Ackley_Noisy: case S_Ackley: case R_Ackley: case RS_Ackley: case RS_Ackley_Bound_CEC05:
               case Step:
               case Quartic_Noisy:
               case Scaffer_F6:  case Expanded_Scaffer_F6_CEC05: case Noncont_Expanded_Scaffer_F6_CEC05: case RS_Expanded_Scaffer_F6_CEC05:
               case Rosenbrock: case S_Rosenbrock: case S_Rosenbrock_CEC05:
               case Schwefel_2_13_CEC05:
               case Schwefel_2_22: case Schwefel_2_22_Noisy: case S_Schwefel_2_22: case R_Schwefel_2_22: case RS_Schwefel_2_22:
               case Schwefel: case Schwefel_Noisy: case S_Schwefel: case R_Schwefel: case RS_Schwefel:
               case Schwefel_1_2: case Schwefel_1_2_Noisy: case S_Schwefel_1_2: case S_Schwefel_1_2_Noisy: case R_Schwefel_1_2: case RS_Schwefel_1_2:  case S_Schwefel_1_2_CEC05:  case S_Schwefel_1_2_Noisy_CEC05:
               case Schwefel_2_21:
               case Schwefel_2_6_Bound_CEC05:
               case Penalized_1:
               case Penalized_2:
               case Noncont_Rastrigin:
               case RS_Elliptic_CEC05: case Elliptic:
               case Com: case R_Com: case Com_CEC05: case H_Com_CEC05: case H_Com_Noisy_CEC05:
               case RH_Com_CEC05: case RH_Com_NarrowBasin_CEC05: case RH_Com_Bound_CEC05:
               case RH_Com_F21_CEC05:  case RH_Com_HighConNumMatrix_F22_CEC05:  case Noncont_RH_Com_F23_CEC05:  case RH_Com_F24_CEC05:  case RH_Com_noBounds_F25_CEC05:
               case M_global1: case M_global2: case M_global3: case M_global4: case M_global5:
               case S_Sphere_CEC08: case Schwefel_2_21_CEC08: case S_Rosenbrock_CEC08: case S_Rastrigin_CEC08: case S_Griewank_CEC08: case S_Ackley_CEC08:
               case RW_Gear_Train: case RW_ParEst_FMSoundWaves:
    ///Dynamic Problems
    case CompositionDBG_DOP: case RotationDBG_DOP: case MovingPeak_DOP: case DF1_DOP:
            for( int i=0;i<Global::g_dimNumber;i++)
			m_center.getGene<double>(i)=0;
            for( int i=0;i<Global::g_dimNumber;i++){
                for(int j=0;j<m_popsize;j++){
                    Chromosome & chr=mp_pop[j].getRepresentative();
                    m_center.getGene<double>(i)+=chr.getGene<double>(i);
                }
                m_center.getGene<double>(i)/=m_popsize;
            }
            break;

        default:
            Throw(Logic_error("population center not defined"));
            break;

    }

	m_center.evaluate(false);

	if(m_center>m_best) m_best=m_center;
	//else m_center=m_best;

}

template<class T>
void Population<T>::computeInitialRadius(){
	m_initialRadius=0;
	m_curRadius=0;
	if(m_popsize<2) return;

	updateCurRadius();
	m_initialRadius=m_curRadius;
}
template<class T>
void Population<T>::updateCurRadius(bool mode){
    //mode=true for distance between representatice to the center; else between pself to the center
	m_curRadius=0;
	if(m_popsize<2) return;

	if(mode){
		for(int j=0;j<this->m_popsize;j++)
			m_curRadius+=mp_pop[j].getRepresentative().getDistance(m_center,m_disMode);
	}else{
		for(int j=0;j<this->m_popsize;j++)
			m_curRadius+=mp_pop[j].m_pself.getDistance(m_center,m_disMode);
	}
	m_curRadius=0.7*m_curRadius/m_popsize;

}
template<class T>
void Population<T>::setDistanceMode(DistanceMode mode){
	m_disMode=mode;
}
template<class T>
int Population<T>::findNearest(int idx,double &rdis,int mode){

    double Min_dis=0;

	int index=0;
    int count=0;

	for(int i=0;i<this->m_popsize;i++){
		if(i==idx) continue;
		count++;
		double d;
		switch(mode){
            case 1:
                d=this->mp_pop[idx].getRepresentative().getDistance(this->mp_pop[i].getRepresentative());
                break;
            case 2:
                d=this->mp_pop[idx].m_pself.getDistance(this->mp_pop[i].getRepresentative());
                break;
            case 3:
                 d=this->mp_pop[idx].getRepresentative().getDistance(this->mp_pop[i].m_pself);
                 break;
            case 4:
                d=this->mp_pop[idx].m_pself.getDistance(this->mp_pop[i].m_pself);
                break;
            default:
                Throw(Invalid_argument("ensure mode is one of the value in [1,2,3,4]"));
                exit(0);
		}
        if(count==1) {
            Min_dis=d;
            index=i;
        }else if(d<Min_dis){
			Min_dis=d;
			index=i;
		}
	}
	rdis=Min_dis;

	return index;
}
template<class T>
void Population<T>::findNearestPair(int & idx1, int &idx2, int mode){

    double mindis,dis;

    for(int i=0;i<this->m_popsize;i++){
       int idx=findNearest(i,dis,mode);
       if(i==0|| mindis>dis){
            idx1=i;
            idx2=idx;
            mindis=dis;
       }

    }

}
template<class T>
void Population<T>::setRadius(double rRadius){
	// for algorithms needed to set radius by users
	m_initialRadius=rRadius;
	size_t start, end;
    start=this->m_algPar.str().find("Radius: ");
    for(size_t i=start;i<this->m_algPar.str().size();i++){
        if(this->m_algPar.str()[i]==';') {
            end=i;
            break;
        }
    }
    stringstream ss;
    ss<<"Radius:  "<<m_initialRadius<<";";
	if(start!=string::npos){
		string result=this->m_algPar.str();
		result.replace(start,end-start+1, ss.str());
		 this->m_algPar.str(result);
	}else this->m_algPar<<ss.str();

}

template<class T>
void Population<T>::increaseDimensionAll(){
    for(unsigned int i=0;i<Population<T>::msp_subPop.size();i++){
		Population<T>::msp_subPop[i]->increaseDimension();
	}
}
template<class T>
void Population<T>::decreaseDimensionAll(){
     for(unsigned int i=0;i<Population<T>::msp_subPop.size();i++){
		Population<T>::msp_subPop[i]->decreaseDimension();
	}

}
template<class T>
void Population<T>::sort(bool mode, bool representative){
	//default value for mode=true and representative=false
	for(int i=0;i<m_popsize;i++) {
		mp_pop[i].m_flag=0;
	}
	int index;
	for(int i=0;i<m_popsize;i++){
		int j=0;
		while(j<m_popsize&&mp_pop[j].m_flag==1) j++;
		index=j;

        for(j=index;j<m_popsize;j++){
			if(mode&&representative){
				if(mp_pop[j].m_flag==0&&mp_pop[j].getRepresentative()>(mp_pop[index].getRepresentative())) index=j;
			}else if(!mode && representative){
				if(mp_pop[j].m_flag==0&&mp_pop[j].getRepresentative()<(mp_pop[index].getRepresentative())) index=j;

			}else if(mode&&!representative){
				if(mp_pop[j].m_flag==0&&mp_pop[j].m_pself>(mp_pop[index].m_pself))	 index=j;
			}else{
				if(mp_pop[j].m_flag==0&&mp_pop[j].m_pself<(mp_pop[index].m_pself))	 index=j;
			}

        }
		mp_orderList[i]=index;
		mp_pop[index].m_flag=1;
	}

}
template<class T>
double Population<T>::GetAvgDistance(bool mode){
    // mode=true for distance between pself else between representative
    if(m_popsize<2) return 0;
    double dis=0;
    for(int i=0;i<m_popsize;i++){
        for(int j=i+1;j<m_popsize;j++){
            if(mode) dis+=mp_pop[i].m_pself.getDistance(mp_pop[j].m_pself);
            else dis+=mp_pop[i].getRepresentative().getDistance(mp_pop[j].getRepresentative());
        }
    }
    return 2*dis/(m_popsize*(m_popsize-1));

}
template<class T>
void Population<T>::rank(bool mode){
    //warning: has been not tested
    for(int i=0;i<m_popsize;i++) {
		mp_pop[i].m_flag=0;
	}
	int index;
	int ranking=0;
	for(int i=0;i<m_popsize;i++){
		int j=0;
		while(j<m_popsize&&mp_pop[j].m_flag==1) j++;
		index=j;
        bool flag=false;
        for(j=index;j<m_popsize;j++){
			if(mode){
				if(mp_pop[j].m_flag==0&&mp_pop[j].m_pself>(mp_pop[index].m_pself))	 {index=j;flag=true;}
			}else{
				if(mp_pop[j].m_flag==0&&mp_pop[j].getRepresentative()>(mp_pop[index].getRepresentative())) {index=j;flag=true;}
			}

        }
        mp_pop[index].m_flag=1;
        if(flag){
            int j=0;
            bool flag_best;
            for(j=0;j<m_popsize;j++){
                if(mp_pop[j].m_flag==1) continue;

                if(mode){
                    if(mp_pop[index].m_pself>mp_pop[j].m_pself){flag_best=true;}
                    else{
                        // nondonimate case
                        flag_best=false;
                        break;
                    }
                }else{
                    if(mp_pop[index].getRepresentative()>(mp_pop[j].getRepresentative())) {flag_best=true;}
                    else{
                        // nondonimate case
                        flag_best=false;
                        break;
                    }
                }
            }
            if(flag_best){
               mp_pop[index].m_ranking=ranking;
               ranking++;
            }else{
                mp_pop[index].m_ranking=ranking;
            }
        }else{
            mp_pop[index].m_ranking=ranking;
        }


	}
}
template<class T>
double Population<T>::getMaxObj(const int idx){
    double obj;
    obj=mp_pop[0].getRepresentative().getObj(idx);

	for(int i=1;i<m_popsize;i++){
		if(obj<mp_pop[i].getRepresentative().getObj(idx)){
			obj=mp_pop[i].getRepresentative().getObj(idx);
		}
	}
    return obj;
}
template<class T>
double Population<T>::getMinObj(const int idx){
    double obj;
    obj=mp_pop[0].getRepresentative().getObj(idx);

	for(int i=1;i<m_popsize;i++){
		if(obj>mp_pop[i].getRepresentative().getObj(idx)){
			obj=mp_pop[i].getRepresentative().getObj(idx);
		}
	}
    return obj;
}

template<class T>
int Population<T>::computePeaksFound(){
	int m_numPeaksFound=0;

	vector<bool> flag(msp_subPop.size(),false);

    for(int k=0;k<dynamic_cast<DynamicProblem*>(Global::gp_problem)->getNumberofPeak();k++ ){
		for(int j=0;j<msp_subPop.size();j++){
		    double *peak=const_cast <double *> (dynamic_cast<DynamicContinuous*>(Global::gp_problem)->getPeak(k));

            if(msp_subPop[j]->m_best.getDistance(peak)<0.1){
                if(! flag[j]&& dynamic_cast<DynamicContinuous*>(Global::gp_problem)->isVisable(k)){
                    flag[j]=true;
                    m_numPeaksFound++;
                    break;
                }
            }
        }

    }
	flag.clear();
	return m_numPeaksFound;

}

template<class T>
float Population<T>::getAvgInitialRadius(){
    if(Population<T>::msp_subPop.size()==0) return 0;
    float r=0;
    for(unsigned int j=0;j<Population<T>::msp_subPop.size();j++){
        r+=Population<T>::msp_subPop[j]->m_initialRadius;
    }
    r/=Population<T>::msp_subPop.size();
    return r;
}
template<class T>
float Population<T>::getAvgCurRadius(){
    if(Population<T>::msp_subPop.size()==0) return 0;
    float r=0;
    for(unsigned int j=0;j<Population<T>::msp_subPop.size();j++){
        r+=Population<T>::msp_subPop[j]->m_curRadius;
    }
    r/=Population<T>::msp_subPop.size();
    return r;

}

template<class T>
void Population<T>::reInitializeCenter(vector<Optimum> &opt, Chromosome &chr){
	// get one random point that is not in any areas of opt. NOTICE: no overlap between opts
	Chromosome rand;
	rand.initialize();
	for(unsigned int i=0;i<opt.size();i++){
		if(rand.getDistance(opt[i].m_location)<opt[i].m_radius){
			//TODU for non-continious space
			double normal=0;
			for(int d=0;d<Global::g_dimNumber;d++) normal+=(rand.getGene<double>(d)-opt[i].m_location.getGene<double>(d))*(rand.getGene<double>(d)-opt[i].m_location.getGene<double>(d));
			normal=sqrt(normal);
			double x1,x2,x3;
			for(int d=0;d<Global::g_dimNumber;d++){
				
				x1=rand.getGene<double>(d); x2=opt[i].m_location.getGene<double>(d);

				rand.getGene<double>(d)+=(opt[i].m_radius)*(rand.getGene<double>(d)-opt[i].m_location.getGene<double>(d))/normal;
				x3=rand.getGene<double>(d);

			}
			break;
		}

	}
	chr=rand;
}
#endif // POPULATION_H
