/*************************************************************************
* 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 "RotationDBG.h"

RotationDBG * RotationDBG::msp_rdbg=0;

RotationDBG::RotationDBG(const int rId, const int rDimNumber, const Encoding rEncoding, const int rNumPeaks,
                         const ChangeType rT,float const rChangingRatio, const bool rFlagDimChange,const bool rFlagNumPeakChange):RealDBG(rId,rDimNumber,rEncoding,rNumPeaks){
    //ctor
    strcpy(ma_name,"Rotation DBG");
    initialize(rT,rChangingRatio,rFlagDimChange,rFlagNumPeakChange);
}

RotationDBG::~RotationDBG()
{
    //dtor
    RotationDBG::msp_rdbg=0;
}

void  RotationDBG::setWidth(const double w){

    for(int i=0;i<m_numPeaks;i++)
        if(m_changeType.type==CT_Chaotic)
            mp_width[i]=m_minWidth+(m_maxWidth-m_minWidth)*Global::gp_uniformPro->Next();
        else
            mp_width[i]=w;
};

RotationDBG& RotationDBG::operator =(const RotationDBG & r_dbg){
	if(this==& r_dbg) return *this;
	RealDBG::operator =(r_dbg);
	return *this;
}
void RotationDBG::randomChange(){

    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);

	heightStandardChange();
	widthStandardChange();
	positionStandardChange(0);

	restoreInfor();
    calculateGlobalOptima();
     updateNumberofChanges();
	m_changeType.counter++;
}
void RotationDBG::recurrentChange(){
    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);


	double initial_angle;

	double height_range=m_maxHeight-m_minHeight;
	double width_range=m_maxWidth-m_minWidth;
	for(int i=0;i<m_numPeaks;i++){
	    if(mp_whetherChange[i]==false) continue;
		initial_angle=(double)getPeriod()*i/m_numPeaks;
		mp_height[i]=m_minHeight+height_range*(sin(2*PI*(m_changeType.counter+initial_angle)/getPeriod())+1)/2.;
		mp_width[i]=m_minWidth+width_range*(sin(2*PI*(m_changeType.counter+initial_angle)/getPeriod())+1)/2.;
	}
	initial_angle=PI*(sin(2*PI*(m_changeType.counter)/getPeriod())+1)/12.;
	positionStandardChange(initial_angle);

    restoreInfor();
	calculateGlobalOptima();
	 updateNumberofChanges();
	m_changeType.counter++;
}
void RotationDBG::chaoticChange(){

    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);

	for(int i=0;i<m_numPeaks;i++){
	    if(mp_whetherChange[i]==false) continue;
		mp_height[i]=gChaoticValue(mp_height[i],m_minHeight,m_maxHeight);
		mp_width[i]=gChaoticValue(mp_width[i],m_minWidth,m_maxWidth);
	}
	positionStandardChange(0);

	restoreInfor();
    calculateGlobalOptima();
     updateNumberofChanges();
	m_changeType.counter++;
}
void RotationDBG::smallStepChange(){

    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);

	heightStandardChange();
	widthStandardChange();
	positionStandardChange(0);

	restoreInfor();
	calculateGlobalOptima();
	 updateNumberofChanges();
	m_changeType.counter++;
}
void RotationDBG::largeStepChange(){

    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);

	heightStandardChange();
	widthStandardChange();
	positionStandardChange(0);

	restoreInfor();
	calculateGlobalOptima();
	 updateNumberofChanges();
	m_changeType.counter++;
}
void RotationDBG::recurrentNoisyChange(){

    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);

	double initial_angle;
	double height_range=m_maxHeight-m_minHeight;
	double width_range=m_maxWidth-m_minWidth;
	double noisy;
	for(int i=0;i<m_numPeaks;i++){
        if(mp_whetherChange[i]==false) continue;
		initial_angle=(double)getPeriod()*i/m_numPeaks;
		mp_height[i]=sinValueNoisy(m_changeType.counter,m_minHeight,m_maxHeight,height_range,initial_angle,m_noisySeverity);
		mp_width[i]=sinValueNoisy(m_changeType.counter,m_minWidth,m_maxWidth,width_range,initial_angle,m_noisySeverity);
	}
	initial_angle=PI*(sin(2*PI*(m_changeType.counter)/getPeriod())+1)/12.;

	noisy=m_noisySeverity*Global::gp_normalPro->Next();
	positionStandardChange(initial_angle+noisy);

    restoreInfor();
	calculateGlobalOptima();
    updateNumberofChanges();
	m_changeType.counter++;
}
double RotationDBG::evaluate( double const * x, bool rFlag){

	gCopy(mp_genes,x,m_dimNumber);
	for(int i=0;i<m_numPeaks;i++){
		mp_fit[i]=0;
		for(int j=0;j<m_dimNumber;j++)
			mp_fit[i]+=(mp_genes[j]-mpp_peak[i][j])*(mp_genes[j]-mpp_peak[i][j]);
		if(mp_fit[i]!=0) mp_fit[i]=sqrt(mp_fit[i]/m_dimNumber);
		mp_fit[i]=mp_height[i]/(1+mp_width[i]*mp_fit[i]);
	}
	double obj=gExtremum(mp_fit,m_numPeaks,MAX_OPT);

	if(rFlag&&m_evals%m_changeFre==0) mp_bestSoFar[0]=obj;

	if(rFlag&&mp_bestSoFar[0]<obj) mp_bestSoFar[0]=obj;
    if(rFlag)    m_evals++;
    if(rFlag&&m_evals%m_changeFre==0&&m_evals<Global::g_tEvals) DynamicProblem::change();

	return  obj;
}

void RotationDBG::widthStandardChange(){
	double step;
	for(int i=0;i<m_numPeaks;i++){
        if(mp_whetherChange[i]==false) continue;
		step=m_widthSeverity*standardChange(m_changeType.type,m_minWidth,m_maxWidth);
		mp_width[i]=mp_width[i]+step;

		if(mp_width[i]>m_maxWidth||mp_width[i]<m_minWidth) mp_width[i]=mp_width[i]-step;

	}
}

void RotationDBG::changeDimension(){
    /// no need to preserve  previous information, e.g., positions, heights, width....


	RotationDBG* r_dbg=new RotationDBG(RotationDBG_DOP,m_dimNumberTemp,C_DECIMAL,m_numPeaks,m_changeType.type
                                    ,m_changePeakRatio,m_flagDimensionChange,m_flagNumPeaksChange);
	if(m_changeType.type==CT_Recurrent||m_changeType.type==CT_RecurrentNoisy)
		r_dbg->setPeriod(m_period);

	r_dbg->parameterSetting(this);
	r_dbg->calculateGlobalOptima();

    RealDBG::freeMemory();
	DynamicContinuous::freeMemory();
    Problem::freeMemory();

    Problem::allocateMemory(m_dimNumberTemp);
    DynamicContinuous::allocateMemory(m_dimNumberTemp,m_numPeaks);
    RealDBG::allocateMemory(m_dimNumberTemp,m_numPeaks);

    m_dimNumber=m_dimNumberTemp;
    setPeriod(m_period);
	*this=*r_dbg;
	delete r_dbg;

}

void RotationDBG::parameterSetting(Problem * rP){
	RealDBG::parameterSetting(rP);
}

RotationDBG* RotationDBG::getRotationDBG(){
     if(!RotationDBG::msp_rdbg){
        Throw(Logic_error("the RotationDBG problem is not initialized"));
        return NULL;
    }

    return RotationDBG::msp_rdbg;

}
void RotationDBG::deleteRotationDBG(){
    if(RotationDBG::msp_rdbg){
        delete RotationDBG::msp_rdbg;
        RotationDBG::msp_rdbg=0;
    }
}
void RotationDBG::initialize(int rDim, int rPeaks,const ChangeType rT,float const rChangingRatio, const bool rFlagDimChange,const bool rFlagNumPeakChange){
    if(RotationDBG::msp_rdbg){
        Throw(Logic_error("the RotationDBG problem has been already initialized"));
        return;
    }
    if((unsigned int)rDim>msc_MaxDimensionNumber|| (unsigned int) rDim<msc_MinDimensionNumber){
        stringstream  oss;
        oss<<"the number of dimensions should be within ["<<msc_MinDimensionNumber<<","<<msc_MaxDimensionNumber<<"]";
        Throw(Out_of_range(oss.str().c_str()));
        return;
    }
    RotationDBG::msp_rdbg=new RotationDBG(RotationDBG_DOP,rDim,C_DECIMAL,rPeaks,rT,rChangingRatio,rFlagDimChange,rFlagNumPeakChange);

}
bool RotationDBG::isInitialized(){
    if(RotationDBG::msp_rdbg!=0) return true;
	else return false;

}
void RotationDBG::initialize(const ChangeType rT,float const rChangingRatio, const bool rFlagDimChange,const bool rFlagNumPeakChange){
    RealDBG::initialize(rT,rFlagDimChange,rFlagNumPeakChange);
    setNumberofChanges(rChangingRatio);
    setProblemType(MAX_OPT);
	calculateGlobalOptima();
}


void  RotationDBG::changeNumPeaks(){

    RotationDBG* r_dbg=new RotationDBG(RotationDBG_DOP,m_dimNumber,C_DECIMAL,m_numPeaksTemp,m_changeType.type
                                    ,m_changePeakRatio,m_flagDimensionChange,m_flagNumPeaksChange);

	if(m_changeType.type==CT_Recurrent||m_changeType.type==CT_RecurrentNoisy)
		r_dbg->setPeriod(m_period);
	r_dbg->parameterSetting(this);
	r_dbg->calculateGlobalOptima();


    RealDBG::freeMemory();
	DynamicContinuous::freeMemory();

    DynamicContinuous::allocateMemory(m_dimNumber,m_numPeaksTemp);
    RealDBG::allocateMemory(m_dimNumber,m_numPeaksTemp);


    m_numPeaks=m_numPeaksTemp;
    setPeriod(m_period);
	*this=*r_dbg;
	delete r_dbg;

}

