#include "GenAlg.h"

//用随机数初始化种群
CGenAlg::CGenAlg():	m_dMaxDistance	(0),
					m_dMinDistance	(MAXDOUBLE),
					m_dTotalFitness	(0),
					m_dBestFitness	(0),
					m_dAverageFitness(0),
					m_dWorstFitness	(MAXDOUBLE),
					m_cGeneration	(0)
{
	//初始化种群用随机的基因
	for (unsigned int i=0; i<CParams::iPopSize; ++i)
	{
		m_vecPop.push_back(SGenome());
		for (unsigned int j=0; j<CParams::iChromoLength; ++j)
		{
			m_vecPop[i].vecDatas.push_back(CFile::datas[RandInt(0, CParams::lNumData-1)]);
		}
	}
    cout << setprecision(5) << setiosflags(ios::fixed);
	cout << "-----正在进化初始代-----" << endl;
	//更新全部基因组的距离
	for(unsigned int i=0; i< m_vecPop.size(); ++i)
	{
		CalculateDistance(m_vecPop[i]);
	}
	//计算最好的最差的平均的已经总得适应度
	CalculateBestWorstAvTot();
	//排序种群为了扫描和精英选择
	sort(m_vecPop.begin(), m_vecPop.end());

	cout << "初始代进化完成" << endl;
}

//变异基因
void CGenAlg::Mutate(vector<DataType> &chromo)
{
	//通过变异率决定是否变异
	for (unsigned int i=0; i<chromo.size(); ++i)
	{
		//是否干扰权重
		if (RandFloat() < CParams::dMutationRate)
		{
			//在权值中加上或减去一个很小的值
			for(int j=0; j<5; ++j)
			{
				while(true)
				{
					double inc = RandomClamped()*CParams::dMaxPerturbation;
					if(inc+chromo[i].w[j]>0)
					{
						chromo[i].w[j] += inc;
						break;
					}
				}
			}
		}
	}
}

//返回一个赌轮选择法选择的基因
SGenome CGenAlg::GetChromoRoulette()
{
	//生成一个0~全部适应度总数的值
	double Slice = (double)(RandFloat()*m_dTotalFitness);
	//被选中的基因
	SGenome TheChosenOne;
	//通过选中的基因增加适应度到某个程度
	double FitnessSoFar = 0;

	for (unsigned int i=0; i<CParams::iPopSize; ++i)
	{
		FitnessSoFar += m_vecPop[i].dFitness;

		//如果适应度达到随机选择的要求则返回
		if (FitnessSoFar >= Slice)
		{
			TheChosenOne = m_vecPop[i];
			break;
		}
	}
	return TheChosenOne;
}

//杂交基因
void CGenAlg::Crossover(const	vector<DataType> &mum,
						const	vector<DataType> &dad,
								vector<DataType> &baby1,
								vector<DataType> &baby2)
{
	//根据杂交度决定是否杂交
	if ((RandFloat() > CParams::dCrossoverRate) || (mum == dad))
	{
		baby1 = mum;
		baby2 = dad;
		return;
	}
	//确定一个杂交点
	int cp = RandInt(0, CParams::iChromoLength - 1);
	//创建后代
	for (int i=0; i<cp; ++i)
	{
		baby1.push_back(mum[i]);
		baby2.push_back(dad[i]);
	}
	for (unsigned int i=cp; i<mum.size(); ++i)
	{
		baby1.push_back(dad[i]);
		baby2.push_back(mum[i]);
	}
	return;
}

//每个时代进化一次
vector<SGenome> CGenAlg::Epoch()
{
	cout << "-----正在进化第" << ++m_cGeneration << "代-----" << endl;

	//用临时变量存储新的基因组
	vector <SGenome> vecNewPop;

	vecNewPop.clear();

	//选择一些精英
	if (!(CParams::iNumCopiesElite * CParams::iNumElite % 2))
	{
		GrabNBest(CParams::iNumElite, CParams::iNumCopiesElite, vecNewPop);
	}

	//进入遗传循环
	//循环直到新的种群形成
	while (vecNewPop.size() < CParams::iPopSize)
	{
		//抓取两个基因
		SGenome mum = GetChromoRoulette();
		SGenome dad = GetChromoRoulette();

		//通过杂交生成一些后代
		vector<DataType> baby1, baby2;

		Crossover(mum.vecDatas, dad.vecDatas, baby1, baby2);

		//变异
		Mutate(baby1);
		Mutate(baby2);

		//写入新种群
		vecNewPop.push_back(SGenome(baby1, 0));
		vecNewPop.push_back(SGenome(baby2, 0));
	}

	//新种群写入当前种群
	m_vecPop = vecNewPop;

	//重置变量
	Reset();

	//更新全部基因组的适应度
	for(unsigned int i=0; i< m_vecPop.size(); ++i)
	{
		CalculateDistance(m_vecPop[i]);
	}
	//计算最好的最差的平均的已经总得适应度
	CalculateBestWorstAvTot();
	//排序种群为了扫描和精英选择
	sort(m_vecPop.begin(), m_vecPop.end());

	cout << "第" << m_cGeneration << "代进化完成!" << endl;

	return m_vecPop;
}
/*
//适合度变换排序
void CGenAlg::FitnessScaleRank()
{
	const int FitnessMultiplier = 1;

	for (unsigned int i=0; i<CParams::iPopSize; i++)
	{
		m_vecPop[i].dFitness = i * FitnessMultiplier;
	}

	//重新计算值
	CalculateBestWorstAvTot();
}
*/
//保留前NBest名中的前NumCopies个
void CGenAlg::GrabNBest(int			NBest,
						const int	NumCopies,
						vector<SGenome>	&Pop)
{
	//选择必要的副本进入下一阶段
	while(NBest--)
	{
		for (int i=0; i<NumCopies; ++i)
		{
			Pop.push_back(m_vecPop[(CParams::iPopSize - 1) - NBest]);
		}
	}
}

//计算单个基因组的距离总和
void CGenAlg::CalculateDistance(SGenome &SGen)
{
	double m_dMinD = MAXDOUBLE;
	double m_Dis = 0;
	SGen.dFitness = 0;
	SGen.dDistance = 0;

	for(unsigned int i=0; i<CFile::datas.size(); ++i)
	{
		m_dMinD = MAXDOUBLE;
		for(unsigned int j=0; j<SGen.vecDatas.size(); ++j)
		{
			m_Dis = Distance(CFile::datas[i], SGen.vecDatas[j]);
			if(m_dMinD > m_Dis)	m_dMinD = m_Dis;
		}
		SGen.dDistance += m_dMinD;
	}
	if(SGen.dDistance > m_dMaxDistance)
	{
		m_dMaxDistance = SGen.dDistance;
	}
	if(SGen.dDistance < m_dMinDistance)
	{
		m_dMinDistance = SGen.dDistance;
		m_sFittestGenome = SGen;
	}
}

//计算各种适应度
void CGenAlg::CalculateBestWorstAvTot()
{
	m_dTotalFitness = 0;

	double HighestSoFar = 0;
	double LowestSoFar  = MAXDOUBLE;

	for (unsigned int i=0; i<CParams::iPopSize; ++i)
	{
		m_vecPop[i].dFitness = (m_dMaxDistance+1) - m_vecPop[i].dDistance;

		if (m_vecPop[i].dFitness > HighestSoFar)
		{
			HighestSoFar	 = m_vecPop[i].dFitness;
			m_dBestFitness	 = HighestSoFar;
		}
		if (m_vecPop[i].dFitness < LowestSoFar)
		{
			LowestSoFar     = m_vecPop[i].dFitness;
			m_dWorstFitness = LowestSoFar;
		}

		m_dTotalFitness	+= m_vecPop[i].dFitness;
	}//下一个染色体

	m_dAverageFitness = m_dTotalFitness / CParams::iPopSize;

	cout << "#目前最佳距离:"	<< m_dMinDistance	<< endl;
	cout << "*当代平均适应度:"	<< m_dAverageFitness<< endl;
	cout << "*当代最佳适应度:"	<< m_dBestFitness	<< endl;
}

//重置
void CGenAlg::Reset()
{
	m_dMaxDistance		= 0;
	m_dTotalFitness		= 0;
	m_dBestFitness		= 0;
	m_dWorstFitness		= MAXDOUBLE;
	m_dAverageFitness	= 0;
}
