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


DF1 *DF1::msp_DF1=0;

DF1::DF1(const int rId, const int rDimNumber, const Encoding rEncoding, const int rNumPeaks):DynamicContinuous(rId,rDimNumber,rEncoding,rNumPeaks){
    allocateMemory(m_dimNumber,m_numPeaks);
    strcpy(ma_name,"DF1");

    initilize();
}

 DF1::~DF1(){
	freeMemory();
	DF1::msp_DF1=0;

}

void  DF1::freeMemory(){

    for (int i=0; i< m_numPeaks; i++){
	delete [] mpp_direction[i];
	}

	delete [] mpp_direction;
	mpp_direction=0;
}
void DF1::allocateMemory(const int rDimNum, const int rPeaks){

	mpp_direction=new int*[rPeaks];
	for (int i=0; i< rPeaks; i++){
        mpp_direction[i]= new int[rDimNum+2];
	}
}
void DF1::reset(){
    int i,j;
    for (i=0; i< m_numPeaks; i++){
        for (j=0; j< m_dimNumber; j++){
          mpp_peak[i][j] = 2*(-0.5+Global::gp_uniformPro->Next());
          mpp_direction[i][j]=gSign(-0.5+Global::gp_uniformPro->Next());
        }
    }

	for (i=0; i< m_numPeaks; i++){
        mp_height[i]= (m_maxHeight-m_minHeight)*Global::gp_uniformPro->Next()+m_minHeight;
        mp_width[i]= (m_maxWidth-m_minWidth)*Global::gp_uniformPro->Next()+m_minWidth;
        mpp_direction[i][m_dimNumber+1]=gSign(-0.5+Global::gp_uniformPro->Next());
        mpp_direction[i][m_dimNumber]=gSign(-0.5+Global::gp_uniformPro->Next());
	}


    calculateGlobalOptima();
    m_changeCounter=0;
    for (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 DF1::initilize(){

    int i,j;

	m_minHeight = 1.0;
	m_maxHeight = 5.0;
	m_minWidth = 1.0 ;
	m_maxWidth = 5.0;

    m_chaoticScale=0.4;
    setChoaticConstant(3.99);

    setSearchRange<double>(-1,1);
    setProblemType(MAX_OPT);
	for (i=0; i< m_numPeaks; i++){
        for (j=0; j< m_dimNumber; j++){
          mpp_peak[i][j] = 2*(-0.5+Global::gp_uniformPro->Next());
          mpp_direction[i][j]=gSign(-0.5+Global::gp_uniformPro->Next());
        }
    }

	for (i=0; i< m_numPeaks; i++){
        mp_height[i]= (m_maxHeight-m_minHeight)*Global::gp_uniformPro->Next()+m_minHeight;
        mp_width[i]= (m_maxWidth-m_minWidth)*Global::gp_uniformPro->Next()+m_minWidth;
        mpp_direction[i][m_dimNumber+1]=gSign(-0.5+Global::gp_uniformPro->Next());
        mpp_direction[i][m_dimNumber]=gSign(-0.5+Global::gp_uniformPro->Next());
	}

/*	m_globalOptima = -100000.0;
	for (i=0;i<m_numPeaks; i++){
	  for (j=0; j<m_dimNumber; j++)
		mp_genes[j]=mpp_peak[i][j];
	  dummy = dummyEval(mp_genes);
	  if (dummy>m_globalOptima)
		m_globalOptima = dummy;
	}*/

    calculateGlobalOptima();
	for (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);

}


/* current_peak_calc determines the mpp_peak of the current best individual */
void DF1::currentPeakCalc (double *gen)
{
  int i;
  double maximum = -100000.0, dummy;



  m_currentPeak = 0;
  maximum = peakFunctionCone(gen, 0);
  for(i=1; i<m_numPeaks; i++){
    dummy = peakFunctionCone(gen, i);
    if (dummy > maximum){
      maximum = dummy;
      m_currentPeak = i;
    }
  }
}


/* evaluation function */
double DF1::evaluate (double const *gen, bool rFlag)
{


    int i;
    double maximum = -100000.0, dummy;

    for(i=0; i<m_numPeaks; i++)
    {
    dummy = peakFunctionCone(const_cast<double *>(gen), i);
    if (dummy > maximum)
      maximum = dummy;
    }
	if(rFlag&&m_evals%m_changeFre==0) mp_bestSoFar[0]=maximum;
	if(rFlag&&mp_bestSoFar[0]<maximum) mp_bestSoFar[0]=maximum;

    if(rFlag)    m_evals++;
    if(rFlag&&m_evals%m_changeFre==0&&m_evals<Global::g_tEvals) DynamicProblem::change();
    return(maximum);
}

/* dummy evaluation function allows to evaluate without being counted */
double DF1::dummyEval (double *gen)
{
  int i;
  double maximum = -100000.0, dummy;

  for(i=0; i<m_numPeaks; i++)
    {
    dummy = peakFunctionCone(gen, i);
    if (dummy > maximum)
      maximum = dummy;
    }

  return(maximum);
}

/* whenever this function is called, the peaks are changed */
void DF1::randomChange()
{
	double s;
	int i,j;
	for (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 (i=0;i<m_numPeaks; i++){
		 for (j=0; j<m_dimNumber; j++){
			 s=chaoticStep(mpp_peak[i][j],((Boundary<double> *)m_searchRange[j])->lower,((Boundary<double> *)m_searchRange[j])->upper,m_chaoticScale);
			 if(boundCheck(mpp_peak[i][j]+s*mpp_direction[i][j],((Boundary<double> *)m_searchRange[j])->lower,((Boundary<double> *)m_searchRange[j])->upper))
				 mpp_direction[i][j]=-1*mpp_direction[i][j];
			 mpp_peak[i][j]+=s*mpp_direction[i][j];
			 mpp_direction[i][j]=Global::gp_uniformPro->Next()<0.5?1:-1;

		 }
	 }
	 for (i=0; i< m_numPeaks; i++){
		 s=chaoticStep(mp_height[i],DF1::m_minHeight,DF1::m_maxHeight);
		 if(boundCheck(mp_height[i]+s*mpp_direction[i][m_dimNumber+1],DF1::m_minHeight,DF1::m_maxHeight))
			 mpp_direction[i][m_dimNumber+1]=-1*mpp_direction[i][m_dimNumber+1];
		 mp_height[i]+= s*mpp_direction[i][m_dimNumber+1];
	 }


	 for (i=0; i< m_numPeaks; i++){
		 s=chaoticStep(mp_width[i],m_minWidth,m_maxWidth);
		 if(boundCheck(mp_width[i]+s*mpp_direction[i][m_dimNumber],DF1::m_minWidth,DF1::m_maxWidth))
			 mpp_direction[i][m_dimNumber]=-1*mpp_direction[i][m_dimNumber];

		  mp_width[i]+= s*mpp_direction[i][m_dimNumber];
	 }

    calculateGlobalOptima();
}


double DF1::peakFunctionCone (double *gen, int peak_number)
{
  int j;
  double dummy;

  dummy =  (gen[0]-mpp_peak[peak_number][0])*(gen[0]-mpp_peak[peak_number][0]);
  for (j=1; j< m_dimNumber; j++)
    dummy += (gen[j]-mpp_peak[peak_number][j])*(gen[j]-mpp_peak[peak_number][j]);
	dummy =mp_height[peak_number]-mp_width[peak_number]*sqrt(dummy);

  return dummy;
}
bool DF1::boundCheck(const double x, const double min, const double max){
	if(x<=min||x>=max) return true;
	else return false;
}
DF1 * DF1::getDF1(){

    if(!DF1::msp_DF1){
        Throw(Logic_error("the DF1 problem is not initialized"));
	}

	return DF1::msp_DF1;
}
void DF1::deleteDF1(){
	if(!DF1::msp_DF1) Throw(Runtime_error("Can not Delete DF1::msp_DF1, in DF1.cpp"));
	delete DF1::msp_DF1;
	DF1::msp_DF1=0;
}

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

void DF1::initialize(int rDim, int rPeaks){
    if(DF1::msp_DF1){
        Throw(Logic_error("the DF1 problem has been already initialized"));
        return;
    }

    DF1::msp_DF1=new DF1(DF1_DOP,rDim,C_BINARY,rPeaks);


}
