#include "gacalculate.h"
/*
* @projectName ga_calculate
* @brief 计算平均的目标函数值
* @param
* param name:
* @return
* @author TJT
* @date 2024-01-31
*/
double GACalculate::calAvgFitness()
{
double sumFitness = 0.0;
uint i = 0;
while(i < sizepop)
{
try {
sumFitness += individuals.at(i++).fitness;
} catch (out_of_range e) {
cerr << "出现越界异常" << endl;
}
}
return sumFitness / sizepop;
}
/*
* @projectName ga_calculate
* @brief 计算种群适应值之和
* @param
* param name:
* @return
* @author TJT
* @date 2024-01-31
*/
double GACalculate::sumFitnessInverse()
{
double sumFitness = 0.0;
uint i = 0;
// 理论上可能出现越界异常,除零异常
while(i < sizepop)
{
try {
sumFitness += 1.0 / individuals.at(i++).fitness;
} catch (out_of_range e) {
cerr << "出现越界异常" << endl;
}catch(exception e)
{
cerr << "出现除零异常" << endl;
}
}
return sumFitness;
}
/*
* @projectName ga_calculate
* @brief 更新种群中所有个体的适应值,这里其实就是目标函数值
* @param
* param name:
* @return
* @author TJT
* @date 2024-01-31
*/
void GACalculate::updateAllFitness()
{
for(uint i = 0; i < sizepop; ++i)
{
try {
individuals.at(i).fitness = objectFun(individuals[i].chrom, LENCHROM);
} catch (out_of_range e) {
cerr << "出现越界异常" << endl;
}
}
}
uint GACalculate::findBestIndividual()
{
auto res = min_element(individuals.begin(),individuals.end(), [](Individual ele1,Individual ele2){
return ele1.fitness < ele2.fitness;
});
// index的值必定不为负,distance求两个两个迭代器的距离,返回int
uint index = static_cast<uint>(distance(individuals.begin(), res));
return index;
}
uint GACalculate::findWorseIndividual()
{
auto res = max_element(individuals.begin(),individuals.end(), [](Individual ele1,Individual ele2){
return ele1.fitness < ele2.fitness;
});
// index的值必定不为负
uint index = static_cast<uint>(distance(individuals.begin(), res));
return index;
}
GACalculate::GACalculate(uint maxgen, uint sizepop, double pcross, double pmutation)
{
// 初始化部分成员变量
this->maxgen = maxgen;
this->sizepop = sizepop;
this->pcross = pcross;
this->pmutation = pmutation;
// 初始化种群
individuals = initPopulation();
// index的值必定不为负
uint index = findBestIndividual();
// 由于求取最小值,故当前函数值最小的即视为最优个体
last_avgfitness = calAvgFitness();
last_bestfitness = individuals[index].fitness;
best_individual = individuals[index];
}
/*
* @projectName ga_calculate
* @brief 根据传入的一组变量值,计算目标函数值
* @param
* param chrom input: 染色体个体
* lenChrom input:染色体长度
* @return
* @author TJT
* @date 2024-01-29
*/
double GACalculate::objectFun(const double *chrom, const int lenChrom)
{
double objectVal = 0.0;
double valPart1 = 1.0;
double valPart2 = 1.0;
// 可能出现数组越界异常
try {
for(int i = 0; i < lenChrom; ++i)
{
double curX = chrom[i];
valPart1 *= sin(curX);
valPart2 *= sin(5 * curX);
}
objectVal = -5 * valPart1 - valPart2 + 8;
} catch (std::exception e) {
std::cout << e.what() << std::endl;
}
return objectVal;
}
/*
* @projectName ga_calculate
* @brief 初始化一个大小为sizepop的种群
* @param
* param name:
* @return
* @author TJT
* @date 2024-01-31
*/
std::vector<Individual> GACalculate::initPopulation()
{
// 使用系统时间作为种子
std::time_t now = std::time(nullptr);
std::tm* cur_tm = std::localtime(&now);
int seed = cur_tm->tm_hour * 3600 + cur_tm->tm_min * 60 + cur_tm->tm_sec;
// 默认引擎
std::default_random_engine dre(seed);
std::vector<Individual> individuals(sizepop);
for(uint i = 0; i < sizepop; ++i)
{
// 线性插值,对于每个个体的初始值
for(uint j = 0; j < LENCHROM; ++j)
{
// 求取上下界
double lb = lb_arr[j];
double ub = ub_arr[j];
// 随机生成一个 [lb,ub] 之间的数
// 使用均匀分布生成包含两个边界
std::uniform_real_distribution<double> ure(lb,ub);
individuals.at(i).chrom[j] = ure(dre);
}
individuals.at(i).fitness = objectFun(individuals.at(i).chrom, LENCHROM);
}
return individuals;
}
/*
* @projectName ga_calculate
* @brief 遗传算法选择操作,根据个体的适应值大小选择参与交叉的个体
* @param
* param name:
* @return
* @author TJT
* @date 2024-01-29
*/
void GACalculate::select()
{
vector<Individual> newIndividuals(sizepop);
// 存储选择的染色体的下标,这样写是合法的
uint* newIndex = new uint[sizepop];
// 使用系统时间作为种子
std::time_t now = std::time(nullptr);
std::tm* cur_tm = std::localtime(&now);
int seed = cur_tm->tm_hour * 3600 + cur_tm->tm_min * 60 + cur_tm->tm_sec;
// 默认引擎
std::default_random_engine dre(seed);
// 默认生成0到1之间的数
std::uniform_real_distribution<double> ure;
// 计算总的适应值
double sumFitness = sumFitnessInverse();
for(uint i = 0; i < sizepop; ++i)
{
// 生成一个
double curPro = ure(dre);
while(curPro < eps)
{
curPro = ure(dre);
}
// 可能出现除0异常
for(uint j = 0; j < sizepop; ++j)
{
curPro -= 1.0 / individuals[j].fitness / sumFitness;
if(curPro < eps)
{
newIndex[i] = j;
break;
}
}
}
// TODO 2024-01-30 从这里编写代码,需要重新复习深拷贝,浅拷贝的问题
// 利用记录的下标建立新种群,
// TODO 这里的拷贝需要区分是不是深拷贝 2024-01-30
// 这里存在问题
for(uint k = 0; k < sizepop; k++)
{
newIndividuals[k] = individuals[newIndex[k]];
}
// 新种群覆盖旧种群,这里看是否需要使用标准库的copy算法
individuals = newIndividuals;
delete [] newIndex;
}
/*
* @projectName ga_calculate
* @brief 模拟染色体个体之间的交叉操作,交叉针对父代同位单个基因片段进行交叉
* @param
* @return void
* @author TJT
* @date 2024-01-31
*/
void GACalculate::cross()
{
// 使用系统时间作为种子
std::time_t now = std::time(nullptr);
std::tm* cur_tm = std::localtime(&now);
int seed = cur_tm->tm_hour * 3600 + cur_tm->tm_min * 60 + cur_tm->tm_sec;
// 默认引擎
std::default_random_engine dre(seed);
// 生成[0,sizepop-1]的数,用于选择交叉父辈的所处的位置
std::uniform_int_distribution<uint> ure_pos(0,sizepop-1);
std::uniform_int_distribution<uint> ure_cross_pos(0,LENCHROM-1);
// 用于和交叉概率比较
std::uniform_real_distribution<double> ure_pro;
for(uint i = 0; i < sizepop; ++i)
{
double pickPro = ure_pro(dre);
// 确保随机概率非0
while(pickPro < eps)
{
pickPro = ure_pro(dre);
}
// 交叉事件更容易发生,若交叉概率设定较大,则[0,pcross]这边更容易抽到
if(pickPro > pcross)
{
continue;
}
// 父代位置,选择的父代最好是不同的
uint pos1 = ure_pos(dre);
uint pos2 = ure_pos(dre);
// 开始交叉
bool flag = false;
while(!flag)
{
// 单基因片段交叉
// 随机选择交叉的基因片段位置
uint cross_pos = ure_cross_pos(dre);
double val1 = individuals[pos1].chrom[cross_pos];
double val2 = individuals[pos2].chrom[cross_pos];
double cross