#include "GenAlg.h"
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <random>
#include "OptScheduling.h"
#include "FirstOptScheduling.h"

GenAlg::GenAlg(std::shared_ptr<OptScheduling> optScheduling)
    :mOptScheduling(optScheduling)
{
  
}

double GenAlg::random(int min , int max)
{
    double m1 = (double)(rand() % 101) / 101;                        // 计算 0，1之间的随机小数,得到的值域近似为(0,1)
    min++;                                                                             //将 区间变为(min+1,max),
    double m2 = (double)((rand() % (max - min + 1)) + min);    //计算 min+1,max 之间的随机整数，得到的值域为[min+1,max]
    m2 = m2 - 1;       //令值域为[min,max-1]

    double dd = (m1 + m2) * 100;
    double res = (int)dd;
    return res /100;                                                                //返回值域为(min,max),为所求随机浮点
}

void GenAlg::init(int popsize, double MutRate, double CrossRate, int GenLength, double LeftPoint, double RightPoint)
{
    mPopSize = popsize;
    mMutationRate = MutRate;
    mCrossoverRate = CrossRate;
    mChromoLength = GenLength;
    mTotalFitness = 0;
    mGeneration = 0;

    mBestFitness = 0.0;
    mWorstFitness = 99999999;
    mAverageFitness = 0;
    mMaxPerturbation = 1;

    mLeftPoint = LeftPoint;
    mRightPoint = RightPoint;

    // 清空种群容器，以初始化  
    vecPop.clear();
    for (int i = 0; i < mPopSize; i++)
    {
        // 类的构造函数已经把适应性评分初始化为0  
        vecPop.push_back(Genome());

        // 把所有的基因编码初始化为函数区间内的随机数。  
        for (int j = 0; j < mChromoLength; j++)
        {
                vecPop[i].vecGenome.push_back(random(0,1) * (mRightPoint - mLeftPoint) + mLeftPoint);   
        }
    }
}

void GenAlg::mutate(vector<double>& chromo)
{
    // 遵循预定的突变概率,对基因进行突变  
    for (int i = 0; i < chromo.size(); ++i)
    {
       // 如果发生突变的话  
        if (random(0,1) < mMutationRate)
        {
            // 使该权值增加或者减少一个很小的随机数值  
            chromo[i] += ((random(0,1) - 0.2) * mMaxPerturbation);

            // 左右边界  
            if (chromo[i] < mLeftPoint)
            {
                chromo[i] = mRightPoint;
            }
            else if (chromo[i] > mRightPoint)
            {
                chromo[i] = mLeftPoint;
            }
        }
    }
}

void GenAlg::select(vector<Genome>& genVec)
{
    while (genVec.size() < mPopSize)
    {
        Genome genMe = chromoRoulette();
        if (genMe.vecGenome.size() > 0)
            genVec.push_back(genMe);
    }
}

Genome GenAlg::chromoRoulette()
{
    // 产生一个 0 到种群总适应性评分总和之间的随机数.  mTotalFitness记录了整个种群的适应性分数总和
    double slice = (random(0,1)) * mTotalFitness;

    // 这个基因将承载转盘所选出来的那个个体.  
    Genome theChosenOne;

    // 累计适应性分数的和.  
    double fitnessSoFar = 0;
   
    // 遍历总种群里面的每一条染色体。  
    for (int i = 0; i < mPopSize; ++i)
    {

        //累计适应性分数.  
        fitnessSoFar += vecPop[i].fitness;

        // 如果累计分数大于随机数,就选择此时的基因.  
        if (fitnessSoFar >= slice)
        {
            theChosenOne = vecPop[i];
            break;
        }
    }
    //返回转盘选出来的个体基因  
    return theChosenOne;
}

void GenAlg::calculateBestWorstAvTot()
{
    int total = vecPop.size();
    for (int i = 0; i < total; i++)
    {
        double fitNessTemp = vecPop[i].fitness;

        // 计算总适应度值
        mTotalFitness += fitNessTemp;

        // 查找最好适应度值
        if (mBestFitness < fitNessTemp)
        {
            mBestGenoMe = vecPop[i];
            mBestFitness = fitNessTemp;
        }
            
        // 查找最差适应度值
        if (mWorstFitness > fitNessTemp)
        {
            mWorthGenoMe = vecPop[i];
            mWorstFitness = fitNessTemp;
        }     
    }

    // 计算平均适应度
    mAverageFitness = mTotalFitness / (double)total;
}

void GenAlg::reset()
{
    mPopSize = 0;
    mMutationRate = 0;
    mCrossoverRate =0;
    mChromoLength = 0;
    mTotalFitness = 0;
    mGeneration = 0;

    mBestFitness = 0.0;
    mWorstFitness = 99999999;
    mAverageFitness = 0;
    mMaxPerturbation = 0.001;

    mLeftPoint =0;
    mRightPoint = 0;

    // 清空种群容器，以初始化  
    vecPop.clear();
}

void GenAlg::epoch(vector<Genome>& vecNewPop)
{
    // 计算当前种群适应度值
    calculateBestWorstAvTot();

    // 根据个体自适应度进行选择
    select(vecNewPop);

    vector<Genome> son;
    crossover(vecNewPop, son);

    // 基因变异
    size_t sonTotal = son.size();
    for (int i = 0; i < sonTotal; i++)
    {
        mutate(son[i].vecGenome);
    }

    // 更新种群
    vecPop.clear();
    vecPop = son;

    vecNewPop.clear();
    vecNewPop = son;
}

Genome GenAlg::bestFitness()
{
    return mBestGenoMe;
}

double GenAlg::averageFitness()
{
    return mAverageFitness;
}

double  GenAlg::fitnessfunction(float cost, map<string, double>& monitorValues)
{
    // 计算适应
    double objVal = mOptScheduling->objectiveFunction(cost, monitorValues);
    
    return objVal > 0?objVal:0.0;
}

void GenAlg::decoding(vector<map<string, float>>& genVals)
{
    size_t popSize = vecPop.size();
    for (int i = 0; i < popSize; i++)
    {
        Genome genome = vecPop[i];
        vector<double> genomeValsVec = genome.vecGenome;
        size_t genSize = genomeValsVec.size();

        map<string, float> genMap;
        for (int j = 0; j < genSize; j++)
        {
            genMap.insert(pair<string,float>(mPumpVec[j], genomeValsVec[j]));
        }
        genVals.push_back(genMap);
    }
}

void GenAlg::updateGenomeFitNess(int index, double fitNess)
{
    if (index < 0 || index >= vecPop.size())
        return;

    vecPop[index].fitness = fitNess>0?fitNess:0.0;
}

void GenAlg::crossover(const vector<Genome>& parent, vector<Genome>& son)
{
    size_t pGenSize = parent.size();

    // 种群数组的索引
    std::vector<int> randIndexVec;
    for (int i = 0; i < pGenSize; i++)
        randIndexVec.push_back(i);

    // 随机排序，为了随机配对染色体
    std::random_shuffle(randIndexVec.begin(), randIndexVec.end());

    int left = 0;
    int right = pGenSize - 1;
    while (left < right)
    {
        int indexLeft = randIndexVec[left];
        int indexRight = randIndexVec[right];
        
       Genome genome1 = crossover(parent[indexLeft], parent[indexRight]);
       Genome genome2 = crossover(parent[indexRight], parent[indexLeft]);
       son.push_back(genome1);
       son.push_back(genome2);

        left++;
        right--;
    }
    if (left == right)
        son.push_back(parent[left]);
}

Genome GenAlg::crossover(const Genome& gen1, const Genome& gen2)
{
    Genome geoMe;

    vector<double> genVec1 = gen1.vecGenome;
    vector<double> genVec2 = gen2.vecGenome;

    if (genVec1.size() != genVec2.size())
        return geoMe;

    size_t genSize = genVec1.size();
    for (int i = 0; i < genSize; i++)
    {
        double aa = random(0, 1);
        double newGenVal = genVec1[i]*aa +(1- aa) * genVec2[i];
        if (newGenVal < mLeftPoint)
            newGenVal = mRightPoint;

        if (newGenVal > mRightPoint)
            newGenVal = mLeftPoint;

        geoMe.vecGenome.push_back(newGenVal);
    }

    return geoMe;
}