/*************************************************************************
* 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:

#include "RealDBG.h"

RealDBG::RealDBG(const int rId, const int rDimNumber, const Encoding rEncoding, const int rNumPeaks):DynamicContinuous(rId,rDimNumber,rEncoding,rNumPeaks)
{
    //ctor
    allocateMemory(m_dimNumber,m_numPeaks);
    mppp_rotationPlanes=0;
    setSearchRange<double>(-5,5);

    m_maxHeight=100;
    m_minHeight=10;
    m_maxWidth=10;
    m_minWidth=1;
    setNoisySeverity(0.8);
    setHeightSeverity(5.0);
    setWidthSeverity(0.5);
    setWidth(5); /// value in 1-10


}

void RealDBG::allocateMemory(const int rDimNum, const int rPeaks){
     mp_rotationMatrix= new Matrix [rPeaks];
}

RealDBG::~RealDBG(){
    //dtor
    freeMemory();
}

RealDBG & RealDBG::operator=(const RealDBG & rP){

    if(this==&rP) return *this;

    DynamicContinuous::operator=(rP);
    gCopy(mp_rotationMatrix,rP.mp_rotationMatrix,m_numPeaks);

    m_prediction=rP.m_prediction;

    if(getPeriod()!=rP.getPeriod()){
        Throw(Logic_error("The period must be the same"));
        exit(0);
    }

    for(int i=0;i<m_period;i++){
		for(int j=0;j<m_numPeaks;j++)
            gCopy(mppp_rotationPlanes[i][j],rP.mppp_rotationPlanes[i][j],m_dimNumber);
	}

    return *this;

}
void  RealDBG::freeMemory(){
    delete[] mp_rotationMatrix;

    if(mppp_rotationPlanes){
		for(int j=0;j<getPeriod();j++){
			for(int i=0;i<m_numPeaks;i++)
				delete [] mppp_rotationPlanes[j][i];
			delete []mppp_rotationPlanes[j];
		}
		delete []mppp_rotationPlanes;
	}

	mp_rotationMatrix=0;
	mppp_rotationPlanes=0;
}
bool RealDBG::setPeriod(const int p){
	if(p<1) return false;
	DynamicProblem::setPeriod(p);

	mppp_rotationPlanes=new int**[m_period];
	for(int i=0;i<m_period;i++){
		mppp_rotationPlanes[i]=new int*[m_numPeaks];
		for(int j=0;j<m_numPeaks;j++)
			mppp_rotationPlanes[i][j]=new int[m_dimNumber];
	}
	return true;
}

void RealDBG::correctSolution(){
	for(int j=0;j<m_dimNumber;j++){
		if(mp_genes[j]>((Boundary<double> *)m_searchRange[j])->upper)
			mp_genes[j]=((Boundary<double> *)m_searchRange[j])->upper;
		else if(mp_genes[j]<((Boundary<double> *)m_searchRange[j])->lower)
			mp_genes[j]=((Boundary<double> *)m_searchRange[j])->lower;
	}
}
void RealDBG::heightStandardChange(){

	double step;
	for(int i=0;i<m_numPeaks;i++){
		if(mp_whetherChange[i]==false) continue;
		step=m_heightSeverity*standardChange(getChangeType(),m_minHeight,m_maxHeight);
		mp_height[i]=mp_height[i]+step;
		if(mp_height[i]>m_maxHeight||mp_height[i]<m_minHeight) mp_height[i]=mp_height[i]-step;

	}
}
void RealDBG::positionStandardChange(double angle){

	// for each basic function of dimension n(even number) , R=R(l1,l2)*R(l3,l4)*....*R(li-1,li), 0<=li<=n

	if(getChangeType()==CT_Chaotic){
		for(int i=0;i<m_numPeaks;i++){
		    if(mp_whetherChange[i]==false) continue;
			for(int j=0;j<m_dimNumber;j++)
				mpp_peak[i][j]=gChaoticValue(mpp_peak[i][j],((Boundary<double> *)m_searchRange[j])->lower,((Boundary<double> *)m_searchRange[j])->upper,m_chaoticConstant);
		}
		return;
	}
	int * d=new int[m_dimNumber];
	Matrix I;
	for(int i=0;i<m_numPeaks;i++){

		if((getChangeType()==CT_Recurrent||getChangeType()==CT_RecurrentNoisy)&&m_changeType.counter>=getPeriod()){
			gCopy(d,mppp_rotationPlanes[m_changeType.counter%getPeriod()][i],m_dimNumber);
		}
		else{
			gInitializeRandomArray(d,m_dimNumber,false);
			if(getChangeType()==CT_Recurrent||getChangeType()==CT_RecurrentNoisy)
			gCopy(mppp_rotationPlanes[m_changeType.counter][i],d,m_dimNumber);
		}

		if((getChangeType()==CT_Recurrent||getChangeType()==CT_RecurrentNoisy)&&m_changeType.counter%getPeriod()==0)
			gCopy(mpp_peak[i],mpp_initialPeak[i],m_dimNumber);

		if(mp_whetherChange[i]==false) continue;

		I.Identity();
		for(int j=0;j+1<m_dimNumber;j+=2){
			if(getChangeType()==CT_SmallStep||getChangeType()==CT_LargeStep||getChangeType()==CT_Random)
				angle=standardChange(getChangeType(), -PI,PI);
			I.Set_Rotation(d[j],d[j+1],angle);
			if(j==0) mp_rotationMatrix[i]=I;
			else
				mp_rotationMatrix[i]*I;
		}
		Matrix m(m_dimNumber,1);
		m.setDataRow(mpp_peak[i],m_dimNumber);
		m*mp_rotationMatrix[i];
		gCopy(mp_genes,m.Get_Data()[0].data,m_dimNumber);
		correctSolution();
		gCopy(mpp_peak[i],mp_genes,m_dimNumber);
	}
	delete [] d;
}


void RealDBG::parameterSetting(Problem * rP){

    DynamicContinuous::parameterSetting(rP);

    RealDBG *r_dbg=static_cast<RealDBG *>(rP);
	int dim=m_dimNumberTemp<rP->getDimNumber()?m_dimNumberTemp:rP->getDimNumber();
   int peaks=m_numPeaks<r_dbg->getNumberofPeak()?m_numPeaks:r_dbg->getNumberofPeak();

    m_prediction=r_dbg->m_prediction;


    if(m_changeType.type==CT_Recurrent||m_changeType.type==CT_RecurrentNoisy){
		for(int i=0;i<r_dbg->m_period;i++){
			if(m_changeType.counter<=i) break;
			for(int j=0;j<peaks;j++){
				if(dim==m_dimNumberTemp){// the number of dimensions decreases
					for(int m=0,k=0;k<dim;k++,m++)
						if(r_dbg->mppp_rotationPlanes[i][j][m]==dim) {k--;continue;}
						else
							mppp_rotationPlanes[i][j][k]=r_dbg->mppp_rotationPlanes[i][j][m];

				}else
					gCopy(mppp_rotationPlanes[i][j],r_dbg->mppp_rotationPlanes[i][j],dim);

			}

		}
	}
}

double  RealDBG::standardChange(const ChangeType T, const double min, const double max){
	double step,sign;
	switch(T){
		case CT_SmallStep:
			step=-1+2*Global::gp_uniformPro->Next();
			step=m_alpha*step*(max-min);
			break;
		case CT_Random:
			step=Global::gp_normalPro->Next();
			break;
		case CT_LargeStep:
			step=-1+2*Global::gp_uniformPro->Next();
			if(step>0)sign=1;
			else if(step<0) sign=-1;
			else sign=0;
			step=(m_alpha*sign+(m_maxAlpha-m_alpha)*step)*(max-min);
			break;
		case CT_Recurrent:
		case CT_Chaotic:
		case CT_RecurrentNoisy:
			break;
		}
	return step;
}
void RealDBG::reset(){
    m_changeType.counter=0;
    m_changeCounter=0;
    double *t=new double[m_numPeaks];

	for(int i=0;i<m_numPeaks;i++){
		if(m_changeType.type==CT_Chaotic)
			t[i]=m_minHeight+(m_maxHeight-m_minHeight)*Global::gp_uniformPro->Next();
		else
			t[i]=50;
	}
	setHeight(t);
    delete [] t;


	double **position;
    position=new double*[m_numPeaks];
    for(int i=0;i<m_numPeaks;i++)
        position[i]=new double[m_dimNumber];
    for(int i=0;i<m_numPeaks;i++){
        for(int j=0;j<m_dimNumber;j++){
            position[i][j]=((Boundary<double> *)m_searchRange[j])->lower+(((Boundary<double> *)m_searchRange[j])->upper-((Boundary<double> *)m_searchRange[j])->lower)*Global::gp_uniformPro->Next();
        }
    }
    setPosition(position);


	for(int i=0;i<m_numPeaks;i++)		delete []position[i];
	delete [] position;

    for (int i=0;i<m_numPeaks; i++) gCopy(mpp_prePeak[i],mpp_peak[i],m_dimNumber);
	gCopy(mp_preHeight,mp_height,m_numPeaks);
	gCopy(mp_preWidth,mp_width,m_numPeaks);

	calculateGlobalOptima();
}
void RealDBG::initialize(const ChangeType rT, const bool rFlagDimChange, const bool rFlagNumPeakChange){
    m_flagDimensionChange=rFlagDimChange;
setNumPeaksChange(rFlagNumPeakChange);
    //m_flagNumPeaksChange=rFlagNumPeakChange;


    if(m_flagDimensionChange){
        m_changeType.type=CT_Random;
        m_dirDimensionChange=true;
    }else if(m_flagNumPeaksChange){
         m_changeType.type=CT_Random;
         m_dirNumPeaksChange=true;
    }
    else{
         m_changeType.type=rT;
    }
    m_changeType.counter=0;

    if(m_changeType.type==CT_Recurrent||m_changeType.type==CT_RecurrentNoisy)      setPeriod(12);
    else      setPeriod(0);


    double *t=new double[m_numPeaks];

    setChoaticConstant(3.67);

	for(int i=0;i<m_numPeaks;i++){
		if(m_changeType.type==CT_Chaotic)
			t[i]=m_minHeight+(m_maxHeight-m_minHeight)*Global::gp_uniformPro->Next();
		else
			t[i]=50;
	}
	setHeight(t);
    delete [] t;


	double **position;
    position=new double*[m_numPeaks];
    for(int i=0;i<m_numPeaks;i++)
        position[i]=new double[m_dimNumber];
    for(int i=0;i<m_numPeaks;i++){
        for(int j=0;j<m_dimNumber;j++){
            position[i][j]=((Boundary<double> *)m_searchRange[j])->lower+(((Boundary<double> *)m_searchRange[j])->upper-((Boundary<double> *)m_searchRange[j])->lower)*Global::gp_uniformPro->Next();
        }
    }
    setPosition(position);


	for(int i=0;i<m_numPeaks;i++)		delete []position[i];
	delete [] position;

    for (int i=0;i<m_numPeaks; i++) gCopy(mpp_prePeak[i],mpp_peak[i],m_dimNumber);
	gCopy(mp_preHeight,mp_height,m_numPeaks);
	gCopy(mp_preWidth,mp_width,m_numPeaks);


}

 void RealDBG::restoreInfor(){

     for(int i=0;i<m_numPeaks;i++){
        if(!mp_whetherChange[i]){
            gCopy(mpp_peak[i],mpp_prePeak[i],m_dimNumber);
            mp_height[i]=mp_preHeight[i];
            mp_width[i]=mp_preWidth[i];
        }
     }

  }
