/*************************************************************************
* 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 July 2011
// Last modified:
#ifndef GROUP_H
#define GROUP_H

#include "../../Algorithms/Chromosome.h"

template <class T>
class Group{
public:
	Chromosome m_center;
	Chromosome m_best;
	T *mp_member;
	int m_ID;
	int m_number;
	double m_radius;
public:
	Group(const int num);
	Group();
	~Group();
	void initialize( T &p,const int id);
	void initialize(const int num,const int id);
	void initialize( Group &g );
	bool operator ==(const Group &g);
	void merge( Group &g);
	Group & operator=(Group &g);
	void calculateRadius();
};
// implementation of Group class
template<class T>
Group<T>::Group():mp_member(0),m_ID(-1),m_number(-1),m_radius(-1){

}
template<class T>
Group<T>::Group(const int num):m_number(num){
mp_member=new T[m_number];
}
template<class T>
Group<T>::~Group(){
delete [] mp_member;
m_number=0;
}
template<class T>
void Group<T>::initialize( T &p,const int id){
	m_number=1;
	mp_member=new T[m_number];
	mp_member[0]=p;
	m_center=p.getRepresentative();
	m_best=p.getRepresentative();
	m_ID=id;
	m_radius=0;
}
template<class T>
void Group<T>::initialize(const int num,const int id){
	m_number=num;
	mp_member=new T[m_number];
	m_ID=id;
}
template<class T>
void Group<T>::initialize( Group &g ){
	m_number=g.m_number;
	mp_member=new T[m_number];
	for(int i=0;i<m_number;i++)
		mp_member[i]=g.mp_member[i];
	m_center=g.m_center;
	m_ID=g.m_ID;
	m_best=g.m_best;
	m_radius=g.m_radius;
}
template<class T>
void Group<T>::merge( Group &g){

	int t_num=m_number+g.m_number;
	T *t_mem=new T[t_num];
	for(int i=0;i<m_number;i++)
		t_mem[i]=mp_member[i];
	for(int i=0;i<g.m_number;i++)
		t_mem[i+m_number]=g.mp_member[i];
	m_number=t_num;
	delete[] mp_member;
	mp_member=t_mem;

	if(g.m_best>m_best) m_best=g.m_best;
	m_ID=m_ID<g.m_ID?m_ID:g.m_ID;
	calculateRadius();
}
template<class T>
void Group<T>::calculateRadius(){

	m_radius=0;
	if(m_number<2) return;

	switch(Global::gp_problem->getId()){
    case Sphere: case Sphere_Noisy: case S_Sphere: case R_Sphere: case RS_Sphere: case S_Sphere_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 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 Rosenbrock: case S_Rosenbrock: case S_Rosenbrock_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 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 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:
    case CompositionDBG_DOP: case RotationDBG_DOP: case MovingPeak_DOP: case DF1_DOP:
    /// Euclidean distance
        for(unsigned int i=0;i<m_center.mc_length;i++)
		m_center.getGene<double>(i)=0;
        for(unsigned int i=0;i<m_center.mc_length;i++){
            for(int j=0;j<m_number;j++){
                Chromosome & gene=mp_member[j].getRepresentative();
                m_center.getGene<double>(i)+=gene.getGene<double>(i);
            }

            m_center.getGene<double>(i)/=m_number;
        }

        break;
    case Binary_DOP:
        for(unsigned int i=0;i<m_center.mc_length;i++){
            for(unsigned int k=0;k<m_center.getGene(i).m_length;k++){
                int numOnes=0;
                for(int j=0;j<m_number;j++){
                     Chromosome & gene=mp_member[j].getRepresentative();
                    if(gene.getGene<bool>(i,k)) numOnes++;
                }
                if(numOnes>m_number/2)  m_center.getGene<bool>(i,k)=true;
                else  m_center.getGene<bool>(i,k)=false;

            }
        }
        break;
    }
	m_center.evaluate(false);

	if(m_center>m_best) m_best=m_center;

	for(int j=0;j<m_number;j++)
		m_radius+=mp_member[j].getRepresentative().getDistance(m_center);
	m_radius=m_radius/m_number;

}
template<class T>
bool Group<T>::operator ==(const Group &g){

	if(m_number!=g.m_number) return false;
	for(int i=0;i<m_number;i++){
		int j=0;
		while(j<m_number&&mp_member[i].m_ID!=g.mp_member[j].m_ID)j++;
		if(j==m_number) return false;

	}
	return true;
}
template<class T>
Group<T>& Group<T>::operator =( Group &g){

	if(this==&g) return *this;
	if(m_number!=g.m_number) return *this;
	gCopy(mp_member,g.mp_member,m_number);
	m_center=g.m_center;
	m_radius=g.m_radius;
	m_best=g.m_best;
	m_ID=g.m_ID;
	return *this;
}

#endif // GROUP_H
