/*************************************************************************
* 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:
#include "Particle.h"
#include "../../ToolnDef/Global.h"
Particle::Particle():Individual(),m_flag(0){

    allocateMemory(Global::g_dimNumber);
	initializeVmax();

}


Particle::~Particle()
{
   freeMemory();
}

void Particle::allocateMemory(const int rSize){
    mp_vMax=new VMax[rSize];
	mp_vel=new double[rSize];

}
void Particle::freeMemory(){
    delete []mp_vMax;
	delete [] mp_vel;
	mp_vel=0; mp_vMax=0;

}


void Particle::initializeVmax(){
    for(int i=0;i<Global::g_dimNumber;i++){
	    double l,u;
	    Global::gp_problem->getSearchRange<double>(l,u,i);
		// for static optimization problems
		if(Global::gp_problem->getProblemCat()==CAT_STATIC)
			mp_vMax[i].m_max=(u-l)/2;
		else // for dynamic problems
			mp_vMax[i].m_max=(u-l)/5;
		mp_vMax[i].m_min=-mp_vMax[i].m_max;

	}

}

Particle::Particle( Particle& other):Individual(other){
    //copy ctor
	allocateMemory(Global::g_dimNumber);
	m_pbest=other.m_pbest;
	m_flag=other.m_flag;
	gCopy(mp_vel,other.mp_vel,Global::g_dimNumber);
	gCopy(mp_vMax,other.mp_vMax,Global::g_dimNumber);
}
Particle::Particle(const Particle& other):Individual(const_cast<Particle&>(other)){
	allocateMemory(Global::g_dimNumber);
	m_pbest=const_cast<Particle&>(other).m_pbest;
	m_flag=const_cast<Particle&>(other).m_flag;
	gCopy(mp_vel,const_cast<Particle&>(other).mp_vel,Global::g_dimNumber);
	gCopy(mp_vMax,const_cast<Particle&>(other).mp_vMax,Global::g_dimNumber);
}
Particle& Particle::operator=( Particle& rhs){
    if (this == &rhs) return *this; // handle self assignment
    //assignment operator
    Individual::operator=(rhs);

	m_pbest=rhs.m_pbest;
	m_flag=rhs.m_flag;

	gCopy(mp_vel,rhs.mp_vel,Global::g_dimNumber);
	gCopy(mp_vMax,rhs.mp_vMax,Global::g_dimNumber);
    return *this;
}

void Particle::initialize(bool mode){

	Individual::initialize(mode);
	initializeVelocity();
	m_pbest=m_pself;
	m_flag=0;


}
void Particle::initialize(const int ridex,const int rid,bool mode){

	Individual::initialize(ridex,rid,mode);
	initializeVelocity();

	m_pbest=m_pself;
	m_flag=0;
}

void Particle::initialize(int rIdx,int rID,PopInitMethod rMethod, int rPopsize,bool mode){
    Individual::initialize(rIdx,rID,rMethod,rPopsize,mode);
	initializeVelocity();

	m_pbest=m_pself;
	m_flag=0;
}
void Particle::initialize( Chromosome &p,const int ridex,const int rid){

    Individual::initialize(p,ridex,rid);
	initializeVelocity();
	m_pbest=m_pself;
	m_flag=0;

}
void Particle::initialize(Chromosome &p,double radius, const int ridex,const int rid,bool mode){

	Individual::initialize(p,radius,ridex,rid,mode);
	initializeVelocity();
	m_pbest=m_pself;
	m_flag=0;
}


double Particle::getVelocity(){
	 int i;
	double ve=0;

	for( i=0;i<Global::g_dimNumber;i++)
		ve+=mp_vel[i]*mp_vel[i];
	if(ve==0.0) return 0;
	return sqrt(ve);
}
void Particle::initializeVelocity(){
	double u,l;
	for( int i=0;i<Global::g_dimNumber;i++){
	    Global::gp_problem->getSearchRange<double>(l,u,i);
		mp_vel[i]=(u-l)*(-0.5+Global::gp_uniformAlg->Next())/2;
	}
}

void Particle::move( Chromosome & lbest,  Chromosome &gbest,double w, double c1, double c2){
	double u,l;

	for( int j=0;j<Global::g_dimNumber;j++){
		Global::gp_problem->getSearchRange<double>(l,u,j);
		mp_vel[j]=w*mp_vel[j]+c1*Global::gp_uniformAlg->Next()*(lbest.getGene<double>(j)-m_pself.getGene<double>(j))+c2*Global::gp_uniformAlg->Next()*(gbest.getGene<double>(j)-m_pself.getGene<double>(j));

		if(mp_vel[j]>mp_vMax[j].m_max)	mp_vel[j]=mp_vMax[j].m_max;
		else if(mp_vel[j]<mp_vMax[j].m_min)		mp_vel[j]=mp_vMax[j].m_min;

		m_pself.getGene<double>(j)=m_pself.getGene<double>(j)+mp_vel[j];
		//if(m_pself.getGene<double>(j)>u||m_pself.getGene<double>(j)<l) m_pself.getGene<double>(j)=l+(u-l)*Global::gp_uniformAlg->Next();
		}
		m_pself.validate();
		m_pself.evaluate();

}


void Particle::moveBound( Chromosome & lbest ,  Chromosome &gbest,double w, double c1, double c2){
	double u,l,cur_x;
	for( int j=0;j<Global::g_dimNumber;j++){
		Global::gp_problem->getSearchRange<double>(l,u,j);

		if(m_pself.getGene<double>(j)==l||m_pself.getGene<double>(j)==u){
				double p=Global::gp_uniformAlg->Next();
				m_pself.getGene<double>(j)=p*lbest.getGene<double>(j)+(1-p)*m_pself.getGene<double>(j);
			}
		cur_x=m_pself.getGene<double>(j);
		mp_vel[j]=w*mp_vel[j]+c1*Global::gp_uniformAlg->Next()*(lbest.getGene<double>(j)-m_pself.getGene<double>(j))+c2*Global::gp_uniformAlg->Next()*(gbest.getGene<double>(j)-m_pself.getGene<double>(j));

		if(mp_vel[j]>mp_vMax[j].m_max)	mp_vel[j]=mp_vMax[j].m_max;
		else if(mp_vel[j]<mp_vMax[j].m_min)		mp_vel[j]=mp_vMax[j].m_min;


			m_pself.getGene<double>(j)=m_pself.getGene<double>(j)+mp_vel[j];

			if(m_pself.getGene<double>(j)>u||m_pself.getGene<double>(j)<l){
				m_pself.getGene<double>(j)=cur_x-l<u-cur_x?cur_x-(cur_x-l)*Global::gp_uniformAlg->Next():cur_x+(u-cur_x)*Global::gp_uniformAlg->Next();
				//m_pself.getGene<double>(j)=cur_x+(gSign(cur_x)*u-cur_x)*Global::gp_uniformAlg->Next();
			}
			cur_x=m_pself.getGene<double>(j);
		}
	m_pself.evaluate();
}


void Particle::NormalMutation(double *avg_v){
	double l,u;
	for( int j=0;j<Global::g_dimNumber;j++){

			Global::gp_problem->getSearchRange<double>(l,u,j);
			//if(Global::gp_uniformAlg->Next()<1/Global::g_dimNumber)
			m_pself.getGene<double>(j)=m_pself.getGene<double>(j)+avg_v[j]*Global::gp_normalAlg->Next();
			if(m_pself.getGene<double>(j)>u||m_pself.getGene<double>(j)<l)
				m_pself.getGene<double>(j)=l+(u-l)*Global::gp_uniformAlg->Next();
	}
	m_pself.evaluate();
}



/*
void Particle::CPSO(const double *lbest , const double *gbest, int * members, int num, Chromosome &global_best,double w, double c1, double c2){

	double l,u;
	unsigned int k,j;
	for( k=0;k<(unsigned int)num;k++){
			j=members[k];
			Global::gp_problem->getSearchRange<double>(l,u,j);

			mp_vel[j]=w*mp_vel[j]+c1*Global::gp_uniformAlg->Next()*(lbest[j]-m_pself.getGene<double>(j))+c2*Global::gp_uniformAlg->Next()*(gbest[j]-m_pself.getGene<double>(j));
				if(fabs(mp_vel[j])>mp_vMax[j])
						mp_vel[j]=gSign(mp_vel[j])*mp_vMax[j];
				m_pself.getGene<double>(j)=m_pself.getGene<double>(j)+mp_vel[j];
			if(m_pself.getGene<double>(j)>u||m_pself.getGene<double>(j)<l){
				m_pself.getGene<double>(j)=gSign(m_pself.getGene<double>(j))*u;
			}
	}
	for( k=0;k<(unsigned int)members[0];k++)
		m_pself.getGene<double>(k)=global_best.getGene<double>(k);
	for(k=members[num-1]+1;k<Global::g_dimNumber;k++)
		m_pself.getGene<double>(k)=global_best.getGene<double>(k);
	m_pself.evaluate();
}
void Particle::APSO( Chromosome & lbest ,  Chromosome &gbest,double w, double c1,double c2){
	 double u,l;
	for(unsigned int j=0;j<Global::g_dimNumber;j++){
		Global::gp_problem->getSearchRange<double>(l,u,j);

		mp_vel[j]=w*mp_vel[j]+c1*Global::gp_uniformAlg->Next()*(lbest.getGene<double>(j)-m_pself.getGene<double>(j))+c2*Global::gp_uniformAlg->Next()*(gbest.getGene<double>(j)-m_pself.getGene<double>(j));
		if(fabs(mp_vel[j])>mp_vMax[j])
			mp_vel[j]=gSign(mp_vel[j])*mp_vMax[j];

			m_pself.getGene<double>(j)+=mp_vel[j];
			if(m_pself.getGene<double>(j)>u||m_pself.getGene<double>(j)<l)
				return;
		}
	m_pself.evaluate();
 }
*/

/*void Particle::repelMove(const Chromosome<double> &lbest,const Chromosome<double> &nearest,const Local_Optima &converge_optima,const Local_Optima &non_converge_optima, double w,double c1,double c2){
	double l,u;
	double cur_x;

	for(int j=0;j<Global::g_dimNumber;j++){
			l=Global::boundary.lower;
			u=Global::boundary.upper;

			if(m_pself[j]==l||m_pself[j]==u){
				double p=Global::gp_uniformAlg->Next();
				m_pself[j]=p*lbest[j]+(1-p)*m_pself[j];
			}
			cur_x=m_pself[j];
			double belta=1;
			double v_r=0;
			if(converge_optima.numbers+non_converge_optima.numbers>0){
				belta=Global::gp_uniformAlg->Next()+0.5;
				for(int i=0;i<converge_optima.numbers;i++){
					double dis=m_pself.Distance(converge_optima.optima[i].location);
					if(dis==0) dis=0.00001;

					if(dis<converge_optima.optima[i].radius)
					v_r+=c2*Sign(m_pself[j]-converge_optima.optima[i].location[j])*converge_optima.optima[i].radius/dis;

				}
				for(int i=0;i<non_converge_optima.numbers;i++)
				{

					double dis=m_pself.Distance(non_converge_optima.optima[i].location);
					if(dis==0) dis=0.00001;

					if(dis<non_converge_optima.optima[i].radius)
					v_r+=c2*Sign(m_pself[j]-non_converge_optima.optima[i].location[j])*non_converge_optima.optima[i].radius/dis;
				}
			}
			mp_vel[j]=w*mp_vel[j]+c1*Global::gp_uniformAlg->Next()*(lbest[j]-m_pself[j])+c2*Global::gp_uniformAlg->Next()*(nearest[j]-m_pself[j])+v_r;

			if(fabs(mp_vel[j])>mp_vMax[j])
					mp_vel[j]=Sign(mp_vel[j])*mp_vMax[j];
			m_pself[j]=m_pself[j]+mp_vel[j];


			if(m_pself[j]>u||m_pself[j]<l){
				m_pself[j]=cur_x+(Sign(cur_x)*u-cur_x)*Global::gp_uniformAlg->Next();
			}
	}
	m_pself.Fun_Obj();
}
*/
void Particle::initialize( Chromosome *w, int mode,bool mode2){
	Individual::initialize(w,mode,mode2);
	initializeVelocity();
	m_pbest=m_pself;

}

void Particle::printToFile(ofstream & out){
        m_pbest.printToFile(out);
}

void Particle::increaseDimension(){

    Individual::increaseDimension();
    freeMemory();
    allocateMemory(Global::g_dimNumber);
    initializeVelocity();
    initializeVmax();
    m_pbest.increaseDimension();

}
void Particle::decreaseDimension(){
    Individual::decreaseDimension();
    freeMemory();
    allocateMemory(Global::g_dimNumber);
    initializeVelocity();
    initializeVmax();
    m_pbest.decreaseDimension();
}
Chromosome & Particle::getRepresentative(){
    return m_pbest;
}
void Particle::updateMemory(){
    Individual::updateMemory();
    m_pbest.evaluate(false);
}


void Particle::setVmax(float rMin, float rMax){
	for(int i=0;i<Global::g_dimNumber;i++){
		mp_vMax[i].m_max=rMax;
		mp_vMax[i].m_min=rMin;

	}

}
void Particle::setVmax(float *rMin, float *rMax){
	for(int i=0;i<Global::g_dimNumber;i++){
	    mp_vMax[i].m_max=rMax[i];
		mp_vMax[i].m_min=rMin[i];

	}

}
