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


DynamicContinuous::DynamicContinuous(const int rId, const int rDimNumber, const Encoding rEncoding, const int rNumPeaks):DynamicProblem(rId,rDimNumber,rEncoding, rNumPeaks),m_numChangePeaks(m_numPeaks),m_changePeakRatio(1.0),m_accuracy(0.01){

	allocateMemory(m_dimNumber,m_numPeaks);
	for (int i=0; i< m_numPeaks; i++) mp_whetherChange[i]=true;
    m_proPar<<"Changing peaks ratio:"<<m_changePeakRatio<<"; ";
}

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

void DynamicContinuous::allocateMemory(const int rDimNum, const int rPeaks){

    mp_genes = new double[rDimNum];
	mpp_peak = new double*[rPeaks];
	mpp_prePeak= new double*[rPeaks];
    mpp_initialPeak=new double*[rPeaks];
    mp_width=new double[rPeaks];
    mp_height=new double[rPeaks];
    mp_preHeight=new double[rPeaks];
    mp_preWidth=new double[rPeaks];
    mp_fit=new double[rPeaks];

	for (int i=0; i< rPeaks; i++){
        mpp_peak[i]= new double[rDimNum];
        mpp_prePeak[i]= new double[rDimNum];
        mpp_initialPeak[i]= new double[rDimNum];
	}
	mp_whetherChange=new bool[rPeaks];
	mp_globalOptimaIdx=new bool[rPeaks];

	for(int i=0;i<rDimNum;i++)  m_searchRange[i]=new Boundary<double>();

}
void  DynamicContinuous::freeMemory(){
    delete [] mp_genes;
	for (int i=0; i< m_numPeaks; i++){
		delete [] mpp_peak[i];
		delete [] mpp_prePeak[i];
		delete[] mpp_initialPeak[i];

	}
	delete [] mpp_peak;
	delete [] mpp_prePeak;
	delete[] mpp_initialPeak;
	delete[] mp_height;
	delete[] mp_width;
	delete[] mp_preHeight;
	delete[] mp_preWidth;
	delete[] mp_fit;
	delete [] mp_whetherChange;
	delete [] mp_globalOptimaIdx;

    for(int i=0;i<m_dimNumber;i++) delete  (Boundary<double>*) m_searchRange[i];

    mp_genes=0;
    mpp_peak=0;
    mpp_prePeak=0;
    mpp_initialPeak=0;
    mp_height=0;
    mp_width=0;
    mp_preHeight=0;
    mp_preWidth=0;
    mp_fit=0;
    mp_whetherChange=0;

}

double DynamicContinuous::getGlobalMax()const{
	return m_globalOptima;
}
bool DynamicContinuous::getObjGlobalOpt(double *rObj, int rNumObj){
    *rObj=m_globalOptima;
    return true;
}
 void DynamicContinuous::printFun(ofstream & out){

	 for(int i=0;i<m_numPeaks;i++){

		 for(int j=0;j<m_dimNumber;j++)
			 out<<mpp_peak[i][j]<<" ";
		out<<endl;
	 }
 }

const double * const DynamicContinuous::getPeak(const int p)const {
	 if(p<0||p>=m_numPeaks) {
		 Throw(Out_of_range("Please give right value of peak index [0,] "));
		 exit(0);
	 }
	return mpp_peak[p];
}

const double * const DynamicContinuous::getPrePeak(const int p) const{
	 if(p<0||p>=m_numPeaks) {
		 Throw(Out_of_range("Please give right value of peak index [0,] "));
		 exit(0);
	 }
	return  mpp_prePeak[p];
}
const double * const * const DynamicContinuous::getAllPeaks()const {
	 return  mpp_peak;
 }

 double DynamicContinuous::getPeakHeight(const int p)const{

	if(p<0||p>=m_numPeaks) {
		 Throw(Out_of_range("Please give right value of peak index [0,] "));
		 exit(0);
	 }
    return mp_height[p];
}


 double DynamicContinuous::getPrePeakHeight(const int p)const {

    if(p<0||p>=m_numPeaks) {
		 Throw(Out_of_range("Please give right value of peak index [0,] "));
		 exit(0);
	 }
    return mp_preHeight[p];

}
double DynamicContinuous::getPrePeakWidth(const int p)const{

        if(p<0||p>=m_numPeaks) {
		 Throw(Out_of_range("Please give right value of peak index [0,] "));
		 exit(0);
	 }
    return mp_preWidth[p];
}
const bool * const DynamicContinuous::getGlobalOptimaIdx() const{

	 return mp_globalOptimaIdx;
 }
int DynamicContinuous::getNumberofGlobalOptPeak()const{
    return m_maxPeaksNumber;
}

 void DynamicContinuous::setNumberofChanges(const int n){
	 if(n<1||n>m_numPeaks) {
        Throw(Out_of_range("the number of changing peaks is invalid"));
        exit(0);
	 }

	m_numChangePeaks=n;
	m_changePeakRatio=n/(float)m_numPeaks;
	updateNumberofChanges();

    size_t start, end;
    start=m_proPar.str().find("Changing peaks ratio:");
    for(int i=start;i<m_proPar.str().size();i++){
        if(m_proPar.str()[i]==';') {
            end=i;
            break;
        }
    }
    stringstream ss;
    ss<<"Changing peaks ratio:"<<m_changePeakRatio<<"; ";
    string result=m_proPar.str();
    result.replace(start,end-start+1, ss.str());
    m_proPar.str(result);

 }
void DynamicContinuous::setNumberofChanges(const float rRatio){
	 if(rRatio<0||rRatio>1) {
        Throw(Out_of_range("the ratio of changing peaks is invalid"));
        exit(0);
	 }

	m_changePeakRatio=rRatio;
	m_numChangePeaks=(int)(m_numPeaks*m_changePeakRatio)>1?(int)(m_numPeaks*m_changePeakRatio):1;
    updateNumberofChanges();

    size_t start, end;
    start=m_proPar.str().find("Changing peaks ratio:");
    for(int i=start;i<m_proPar.str().size();i++){
        if(m_proPar.str()[i]==';') {
            end=i;
            break;
        }
    }
    stringstream ss;
    ss<<"Changing peaks ratio:"<<m_changePeakRatio<<"; ";
    string result=m_proPar.str();
    result.replace(start,end-start+1, ss.str());
    m_proPar.str(result);

 }

 void DynamicContinuous::updateNumberofChanges(){
	 if(m_numChangePeaks==m_numPeaks){
	 for(int i=0;i<m_numPeaks;i++) mp_whetherChange[i]=true;
	 return;
	 }
	int *a=new int[m_numPeaks];

	gInitializeRandomArray(a,m_numPeaks,false);

	for(int i=0;i<m_numPeaks;i++) mp_whetherChange[i]=false;
	for(int i=0;i<m_numChangePeaks;i++) mp_whetherChange[a[i]]=true;
	delete []a;

 }
void DynamicContinuous::setHeightSeverity(const double rS){
    m_heightSeverity=rS;
}
void DynamicContinuous::setWidthSeverity(const double rS){
    m_widthSeverity=rS;
}
DynamicContinuous & DynamicContinuous::operator=(const DynamicContinuous &rDCP){
    if(this==&rDCP) return *this;

    if(m_dimNumber!=rDCP.m_dimNumber||m_numPeaks!=rDCP.m_numPeaks) return *this;

    DynamicProblem::operator=(rDCP);

    gCopy(mp_genes,rDCP.mp_genes,m_dimNumber);

    for(int i=0;i<m_numPeaks;i++){
        gCopy(mpp_peak[i],rDCP.mpp_peak[i],m_dimNumber);
        gCopy(mpp_prePeak[i],rDCP.mpp_prePeak[i],m_dimNumber);
        gCopy(mpp_initialPeak[i], rDCP.mpp_initialPeak[i],m_dimNumber);

    }
    gCopy(mp_height,rDCP.mp_height,m_numPeaks);
    gCopy(mp_width,rDCP.mp_width,m_numPeaks);
    gCopy(mp_preHeight,rDCP.mp_preHeight,m_numPeaks);
    gCopy(mp_preWidth,rDCP.mp_preWidth,m_numPeaks);
    gCopy(mp_fit,rDCP.mp_fit,m_numPeaks);
    gCopy(mp_whetherChange,rDCP.mp_whetherChange,m_numPeaks);

    m_minHeight=rDCP.m_minHeight;
    m_maxHeight=rDCP.m_maxHeight;
    m_heightSeverity=rDCP.m_heightSeverity;

    m_minWidth=rDCP.m_minWidth;
    m_maxWidth=rDCP.m_maxWidth;
    m_widthSeverity=rDCP.m_widthSeverity;

    m_globalOptima=rDCP.m_globalOptima;
    gCopy(mp_globalOptimaIdx,rDCP.mp_globalOptimaIdx,m_numPeaks);


    m_currentBest=rDCP.m_currentBest;
    m_currentPeak=rDCP.m_currentPeak;
    m_maxPeaksNumber=rDCP.m_maxPeaksNumber;

    m_numChangePeaks =rDCP.m_numChangePeaks;
    m_changePeakRatio=rDCP.m_changePeakRatio;

    m_accuracy=rDCP.m_accuracy;


    for(int j=0;j<m_dimNumber;j++){
        ((Boundary<double> *)m_searchRange[j])->setBoundary(((Boundary<double> *)rDCP.m_searchRange[j])->lower,((Boundary<double> *)rDCP.m_searchRange[j])->upper);
    }


    return *this;
}
void DynamicContinuous::parameterSetting(Problem * rP){
    DynamicProblem::parameterSetting(rP);

	DynamicContinuous *dcp=static_cast<DynamicContinuous *>(rP);

	int dim=m_dimNumberTemp<rP->getDimNumber()?m_dimNumberTemp:rP->getDimNumber();

    int peaks=m_numPeaks<dcp->getNumberofPeak()?m_numPeaks:dcp->getNumberofPeak();

    for(int i=0;i<peaks;i++){
        gCopy(mpp_peak[i],dcp->mpp_peak[i],dim);
        gCopy(mpp_prePeak[i],dcp->mpp_prePeak[i],dim);
        gCopy(mpp_initialPeak[i], dcp->mpp_initialPeak[i],dim);

    }
    gCopy(mp_height,dcp->mp_height,peaks);
    gCopy(mp_width,dcp->mp_width,peaks);
    gCopy(mp_preHeight,dcp->mp_preHeight,peaks);
    gCopy(mp_preWidth,dcp->mp_preWidth,peaks);
    gCopy(mp_fit,dcp->mp_fit,peaks);
    gCopy(mp_whetherChange,dcp->mp_whetherChange,peaks);

    m_minHeight=dcp->m_minHeight;
    m_maxHeight=dcp->m_maxHeight;
    m_heightSeverity=dcp->m_heightSeverity;

    m_minWidth=dcp->m_minWidth;
    m_maxWidth=dcp->m_maxWidth;
    m_widthSeverity=dcp->m_widthSeverity;

    m_globalOptima=dcp->m_globalOptima;
    gCopy(mp_globalOptimaIdx,dcp->mp_globalOptimaIdx,peaks);

    m_currentBest=dcp->m_currentBest;
    m_currentPeak=dcp->m_currentPeak;
    m_maxPeaksNumber=dcp->m_maxPeaksNumber;

    m_accuracy=dcp->m_accuracy;

    m_changePeakRatio=dcp->m_changePeakRatio;
    m_numChangePeaks =(int)(m_changePeakRatio*peaks)>1?(int)(m_changePeakRatio*peaks):1;//dcp->m_numChangePeaks;

    for(int j=0;j<dim;j++){
        ((Boundary<double> *)m_searchRange[j])->setBoundary(((Boundary<double> *)dcp->m_searchRange[j])->lower,((Boundary<double> *)dcp->m_searchRange[j])->upper);
    }

}

void DynamicContinuous::calculateGlobalOptima(){

    m_globalOptima=gExtremum(mp_height,m_numPeaks,m_problemType);
        m_maxPeaksNumber=0;
	  for(int i=0;i<m_numPeaks;i++){
	      mp_globalOptimaIdx[i]=false;
		 if(mp_height[i]==m_globalOptima){
		     m_maxPeaksNumber++;
		     mp_globalOptimaIdx[i]=true;
		 }
	  }
    computeNumVisablePeaks();
}

void DynamicContinuous::setHeight(const double *h){
    gCopy(mp_height,h,m_numPeaks);
}


//const double **p

void DynamicContinuous::setPosition(const double * const * const p){
    for(int i=0;i<m_numPeaks;i++){
        gCopy(mpp_peak[i],p[i],m_dimNumber);
        gCopy(mpp_initialPeak[i],(p[i]),m_dimNumber);
    }
}
const double *const DynamicContinuous::getHeight() const{
    return mp_height;
}
void DynamicContinuous::setWidth(const double w){
    for(int i=0;i<m_numPeaks;i++)
        mp_width[i]=w;
}
void DynamicContinuous::printPeak( const int rIdx){

    cout<<"the "<<rIdx<<"th peak, height: "<<mp_height[rIdx]<<" position:"<<endl;

    for(int i=0;i<m_dimNumber;i++){
        cout<<mpp_peak[rIdx][i]<<" ";
    }
    cout<<endl;
}
void DynamicContinuous::printPeaks(ofstream & out){
    for(int j=0;j<m_numPeaks;j++){
         for(int i=0;i<m_dimNumber;i++){
            out<<mpp_peak[j][i]<<" ";
        }
        out<<mp_height[j]<<endl;
    }

}
void DynamicContinuous::setAccuracy(double rAcc){
    m_accuracy=rAcc;

}
double DynamicContinuous::getAccuracy(){
    return m_accuracy;
}
bool DynamicContinuous::getKnownFlagGOpt(){
    return true;
}

int DynamicContinuous::getNumofVisablePeaks(){
    return m_numVisablePeaks;

}
void DynamicContinuous::computeNumVisablePeaks(){
    m_numVisablePeaks=m_numPeaks;
    for(int i=0;i<m_numPeaks;i++){
        double height=evaluate(mpp_peak[i],false);
        switch(m_problemType){
            case MIN_OPT:
                if(height<mp_height[i]) m_numVisablePeaks--;
                break;
            case MAX_OPT:
                if(height>mp_height[i]) m_numVisablePeaks--;
                break;
        }
    }

}
bool DynamicContinuous::isVisable(const int rIdx){

    double height=evaluate(mpp_peak[rIdx],false);
    switch(m_problemType){
        case MIN_OPT:
            if(height<mp_height[rIdx]) return false;
            break;
        case MAX_OPT:
            if(height>mp_height[rIdx]) return false;
            break;
    }
    return true;

}
