#include "FSchwefel_2_13.h"
#include "../../Algorithms/DE/Ming_DE/Ming_Global.h"

FSchwefel_2_13::FSchwefel_2_13(){
    //ctor
}
FSchwefel_2_13::FSchwefel_2_13(const int rId, const int rDimNumber, char *rName):BenchmarkFunction(rId, rDimNumber, rName){
     a = new int * [m_dimNumber];
     b = new int * [m_dimNumber];
     alpha = new double[m_dimNumber];
    for(int i=0; i<m_dimNumber; ++i) {
          a[i] = new int [m_dimNumber];
          b[i] = new int [m_dimNumber];
     }
//     for(int i=0; i<m_dimNumber; ++i) {
//          for(int j=0; j<m_dimNumber; ++j) {
//               a[i][j] = int(-100.0 + Global::gp_uniformPro->Next() * 200);
//               b[i][j] = int(-100.0 + Global::gp_uniformPro->Next() * 200);
//          }
//          alpha[i] = -PI + Global::gp_uniformPro->Next() * 2 * PI;
//     }
     setSearchRange<double>(-PI, PI);
     initialize();
}
FSchwefel_2_13::FSchwefel_2_13(const int rId, const int rDimNumber, char *rName, double rL, double rU):BenchmarkFunction(rId, rDimNumber, rName){
     a = new int * [m_dimNumber];
     b = new int * [m_dimNumber];
     alpha = new double[m_dimNumber];
    for(int i=0; i<m_dimNumber; ++i) {
          a[i] = new int [m_dimNumber];
          b[i] = new int [m_dimNumber];
     }
    setSearchRange<double>(rL,rU);
    initialize();
}
FSchwefel_2_13::FSchwefel_2_13(const int rId, const int rDimNumber, char *rName, double *rL, double *rU):BenchmarkFunction(rId, rDimNumber, rName){
     a = new int * [m_dimNumber];
     b = new int * [m_dimNumber];
     alpha = new double[m_dimNumber];
    for(int i=0; i<m_dimNumber; ++i) {
          a[i] = new int [m_dimNumber];
          b[i] = new int [m_dimNumber];
     }
    setSearchRange<double>(rL,rU);
    initialize();
}
FSchwefel_2_13::~FSchwefel_2_13(){
    //dtor
    for(int i=0; i<m_dimNumber; ++i) {
          delete[] a[i];
          delete[] b[i];
    }
    delete[] a;
    delete[] b;
    delete[] alpha;
}

void FSchwefel_2_13::initialize(){
    setOriginalGlobalOpt();
    loadData();
    setGlobalOpt();
    setBias(-460);
    setGlobalOpt();
    setAccuracy(1.0e-2);
}

void FSchwefel_2_13::loadData()
{
     string sa;
	char astr[100];
	sprintf(astr,"%d",m_dimNumber);
	strcat(astr,"Dim.txt");
	sa=astr;
	sa.insert(0,gProName[m_id]+"_a_");
	sa.insert(0,probDataPath);

	string sb;
	sprintf(astr,"%d",m_dimNumber);
	strcat(astr,"Dim.txt");
	sb=astr;
	sb.insert(0,gProName[m_id]+"_b_");
	sb.insert(0,probDataPath);

	string salpha;
	sprintf(astr,"%d",m_dimNumber);
	strcat(astr,"Dim.txt");
	salpha=astr;
	salpha.insert(0,gProName[m_id]+"_alpha_");
	salpha.insert(0,probDataPath);

	ifstream in_a;
	in_a.open(sa.data());
	ifstream in_b;
	in_b.open(sb.data());
	ifstream in_alpha;
	in_alpha.open(salpha.data());
	if(in_a.fail()){
	     for(int i=0; i<m_dimNumber; ++i) {
               for(int j=0; j<m_dimNumber; ++j) {
                    a[i][j] = int(-100.0 + Global::gp_uniformPro->Next() * 200);
               }
	     }
          ofstream out(sa.c_str());
          for(int i=0; i<m_dimNumber; ++i) {
               for(int j=0;j<m_dimNumber;j++)  {
                    out<<a[i][j]<<" ";
               }
          }
          out.close();
	}else{
	     for(int i=0; i<m_dimNumber; ++i) {
             for(int j=0;j<m_dimNumber;j++) {
                 in_a>>a[i][j];
               }
	     }
	}
	in_a.close();

	if(in_b.fail()){
	     for(int i=0; i<m_dimNumber; ++i) {
               for(int j=0; j<m_dimNumber; ++j) {
                    b[i][j] = int(-100.0 + Global::gp_uniformPro->Next() * 200);
               }
	     }
          ofstream out(sb.c_str());
          for(int i=0; i<m_dimNumber; ++i) {
               for(int j=0;j<m_dimNumber;j++)  {
                    out<<b[i][j]<<" ";
               }
          }
          out.close();
	}else{
	     for(int i=0; i<m_dimNumber; ++i) {
             for(int j=0;j<m_dimNumber;j++) {
                 in_b>>b[i][j];
               }
	     }
	}
	in_b.close();

	if(in_alpha.fail()){
	     for(int i=0; i<m_dimNumber; ++i) {
               alpha[i] = -PI + Global::gp_uniformPro->Next() * 2 * PI;
	     }
          ofstream out(salpha.c_str());
          for(int i=0; i<m_dimNumber; ++i) {
                    out<<alpha[i]<<" ";
          }
          out.close();
	}else{
	     for(int i=0; i<m_dimNumber; ++i) {
                 in_alpha>>alpha[i];
	     }
	}
	in_alpha.close();
}


void FSchwefel_2_13::setGlobalOpt(){
    m_globalOpt.m_knownFlag=true;
    gCopy(m_globalOpt.mp_location,mp_translation,m_dimNumber);
    for(int i=0; i<m_dimNumber; i++) m_globalOpt.mp_location[i]+=alpha[i];
    m_globalOpt.m_value=BenchmarkFunction::evaluate(m_globalOpt.mp_location,false);
}

double FSchwefel_2_13::evaluate_(double const *x){
     double result = 0;
     for(int i=0; i<m_dimNumber; ++i) {
          double A = 0;
          double B = 0;
          for(int j=0; j<m_dimNumber; ++j) {
               A += a[i][j] * sin(alpha[j]) + b[i][j] * cos(alpha[j]);
               B += a[i][j] * sin(x[j]) + b[i][j] * cos(x[j]);
          }
          result += pow((A - B), 2.0);
     }
     return result + m_bias;
}
