|
目录
一、基本介绍
1、遗传算法(单目标)
2、NSGA-Ⅱ(多目标)
二、代码实现
1、常用函数
(1)动态数组
(2)产生随机数
(3)以概率选择
(4)for新用法
2、单目标实现
(1)结构体个体
(2)适应值
(3)随机初始化种群
(4)选择
(i)概率选择 o(n)
(ii)竞争选择 o(cn)
(iii)排序选择 o(nlgn)
(5)交叉
(6)变异
(7)完整代码
3、多目标实现
(1)非支配排序
(i)准确计算rank o(n^2)
(ii)随机竞争,淘汰被支配者 o(n)
(iii)其他选择过程操作
三、总结
一、基本介绍
1、遗传算法(单目标)
类似达尔文的进化理论,在生存压力下,种群中具有优势基因的个体更容易存活下去,并产生后代。
将最终目标设计为生存压力,在一定目标取向下,整体向更优的趋势演化。个体为一次的结果,个体基因为具体方案,通过染色体复制,基因重组和基因变异,产生可能存在的更优势个体。
2、NSGA-Ⅱ(多目标)
用非对称排序取代单目标的生存压力。首先,支配的含义是目前在二维坐标中有 A 点和 B 点两个不重合的点,仅当 XA<XB且 15 YA<YB时,称 A 支配 B,反之称 B 支配 A。其余情况称互不支配。 其次,互不支配的所有个体组成 Pareto 集,最优的 Pareto 集为其解集内个体不被其他所 有个体支配,称为 Pareto 最优解,标记为 RANK1,只被 RANK1 支配而不被其他个体 支配的 Pareto 集标记为 RANK2,以此类推能将所有个体按 RANK 等级排序,该排序过 程为非支配排序。 NSGA-Ⅱ为在遗传算法的基础上适应度评估以非支配排序的 RANK 等级为评估标准, RANK 越小,生存压力越小。
二、代码实现
1、常用函数
(1)动态数组
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers; // 创建一个整数类型的向量
// 添加元素到向量末尾
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);
// 获取向量的大小(元素个数)
size_t size = numbers.size();
// 访问向量中的元素
int first_element = numbers[0]; // 使用下标访问
int last_element = numbers.back(); // 获取末尾元素
// 修改向量中的元素
numbers[1] = 25; // 修改第二个元素
// 删除向量末尾的元素
numbers.pop_back();
// 插入元素到指定位置
numbers.insert(numbers.begin() + 1, 15); // 在第二个位置插入元素
// 删除指定位置的元素
numbers.erase(numbers.begin() + 2); // 删除第三个元素
// 清空向量中的所有元素
numbers.clear();
// 判断向量是否为空
bool is_empty = numbers.empty();
return 0;
}
(2)产生随机数
int
int rand(int min,int max)//生成[min,max]随机数
{
int randomValue;
randomValue = (rand() % (max - min + 1)) + min;//范围[min,max]
return randomValue;
}
int main()
{
srand(time(0));
int a=rand(,);
}
int->double
wei=10000.0; //保留位数
maxx=1.0; //最大值范围
suan=maxx*wei;
cr=rand(0,suan)/wei;
cy=rand(0,suan)/wei;
cb=rand(0,suan)/wei;
double
#include <iostream>
#include <random>
using namespace std;
int main() {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<> dis(-1.0, 1.0);
for (int i = 0; i < 10; ++i) {
double random_value = dis(gen);
cout << random_value << " ";
}
return 0;
}
random_device 初始化随机数生成器
random_device rd; 生成随机数的函数为(命名为)rd
mt19937 是 Mersenne Twister 19937 伪随机数生成器的一个实现,它是 C++ 标准库中的一个类模板。Mersenne Twister 是一种高质量的伪随机数生成器,其主要特点是周期长且随机性较好,适用于多种随机数生成需求。
mt19937 gen(rd()); 使gen产生随机数
uniform_real_distribution<> 是 C++ 标准库中的一个随机数分布类,用于生成指定范围内均匀分布的随机实数。它的作用是将伪随机数生成器产生的随机整数转换为指定范围内的随机实数。
uniform_real_distribution<> dis(min, max); 使dis产生min到max的随机实数
调用:double random_value = dis(gen);
(3)以概率选择
#include <iostream>
#include <random>
#include <vector>
using namespace std;
int main() {
vector<double> probabilities = {0.1, 0.3, 0.6}; // 每个事件的概率
random_device rd;
mt19937 gen(rd());
discrete_distribution<> distribution(probabilities.begin(), probabilities.end());
for (int i = 0; i < 10; ++i) {
int random_index = distribution(gen); // 根据概率分布生成随机整数索引
cout << "Selected index: " << random_index << endl;
}
return 0;
}
discrete_distribution 这个分布类的构造函数可以接受一个容器,其中存储了每个事件或状态的概率。这些概率可以是正数,但它们的总和必须等于 1。 discrete_distribution 会根据probabilities中的概率生成整数值,使得概率较高的事件更有可能被选中。
调用:int random_index = distribution(gen);
(4)for新用法
for (数据类型 变量名 : 容器名) {
// 在这里使用变量名来访问容器中的元素
}
for (double var : individual.variables) {
// 这里的 var 将依次遍历 individual.variables 中的每个元素
}
for (const 数据类型& 变量名 : 容器名) {
// 在这里使用变量名来访问容器中的元素
}
for (const vector<int>& front : fronts) {
// 这里的 front 将依次遍历 fronts 容器中的每个 vector<int> 类型的元素
}
2、单目标实现
(1)结构体个体
struct Individual {
double value; // 个体的基因值
double fitness; // 个体的适应度值
};
(2)适应值
double fitness_function(double x) {
return x * x; // 返回 x 的平方作为适应度函数
}
因目标而定
(3)随机初始化种群
void initialize_population(vector<Individual>& population) {
random_device rd; // 创建一个随机设备,用于生成随机种子
mt19937 gen(rd()); // 创建一个 Mersenne Twister 19937 伪随机数生成器,使用上述随机设备生成的种子来初始化
uniform_real_distribution<> dis(-10.0, 10.0); // 创建一个均匀分布的随机数分布,范围在 -10.0 到 10.0 之间
// 为每个个体赋予随机基因值和计算对应的适应度值
for (int i = 0; i < population.size(); ++i) {
population[i].value = dis(gen);
population[i].fitness = fitness_function(population[i].value);
}
}
(4)选择
(i)概率选择 o(n)
vector<Individual> selection(const vector<Individual>& population) {
vector<double> fitness_values(population.size()); // 创建一个储存适应度值的数组,大小与种群大小相同
for (int i = 0; i < population.size(); ++i) {
fitness_values[i] = population[i].fitness; // 将种群中每个个体的适应度值存储到适应度值数组中
}
double total_fitness = 0.0; // 初始化总适应度值为0
for (double fitness : fitness_values) {
total_fitness += fitness; // 计算总适应度值,将每个个体的适应度值相加
}
vector<double> probabilities(population.size()); // 创建一个储存选择概率的数组,大小与种群大小相同
for (int i = 0; i < population.size(); ++i) {
probabilities[i] = fitness_values[i] / total_fitness; // 计算每个个体的选择概率,适应度值除以总适应度值
}
vector<Individual> selected_population; // 创建一个储存选择后个体的新种群
random_device rd; // 创建一个随机设备,用于生成真正的随机种子
mt19937 gen(rd()); // 创建一个 Mersenne Twister 19937 伪随机数生成器,使用上述随机设备生成的种子来初始化
discrete_distribution<> distribution(probabilities.begin(), probabilities.end()); // 创建一个离散分布,使用选择概率数组初始化
// 使用离散分布来选择新的个体,并将其添加到新的种群中
for (int i = 0; i < population_size; ++i) {
int index = distribution(gen); // 根据离散分布随机选择一个索引
selected_population.push_back(population[index]); // 将选择的个体添加到新的种群中
}
return selected_population; // 返回经过选择操作后的新种群
}
存在退化可能(目前),应该可修改,将最优值直接复制保留等
(ii)竞争选择 o(cn)
Individual tournamentSelection(const std::vector<Individual>& population) {
const int tournamentSize = 5;
Individual best = population[rand() % POPULATION_SIZE];
for (int i = 1; i < tournamentSize; ++i) {
Individual candidate = population[rand() % POPULATION_SIZE];
if (candidate.fitness > best.fitness) { // 使用大于号进行比较以找到适应度最大值
best = candidate;
}
}
return best;
}
相互竞争选取胜者
存在退化可能(目前),应该可修改,将最优值直接复制保留等
(iii)排序选择 o(nlgn)
int size = sizeof(daan) / sizeof(daan[0]);
sort(daan , daan + size);
保留所有最优解
(5)交叉
void crossover(Individual& child1, Individual& child2) {
int crossover_point = rand() % 2; // 固定在一半位置交叉
// 交换基因值以进行交叉
if (crossover_point == 0) {
swap(child1.value, child2.value);
}
}
(6)变异
void mutate(Individual& individual) {
random_device rd; // 创建一个随机设备,用于生成真正的随机种子
mt19937 gen(rd()); // 创建一个 Mersenne Twister 19937 伪随机数生成器,使用上述随机设备生成的种子来初始化
uniform_real_distribution<> dis(-0.5, 0.5); // 创建一个均匀分布的随机数分布,范围在 -0.5 到 0.5 之间
// 在一定概率下对基因值进行微小变化
if (rand() / double(RAND_MAX) < mutation_rate) {
individual.value += dis(gen);
}
individual.fitness = fitness_function(individual.value);
}
(7)完整代码
#include <iostream>
#include <vector>
#include <random>
using namespace std;
const int population_size = 50; // 种群大小
const double mutation_rate = 0.1; // 变异率
const int generations = 100; // 迭代代数
// 定义适应度函数
double fitness_function(double x) {
return x * x; // 返回 x 的平方作为适应度函数
}
// 结构体定义,用于存储个体和其对应的适应度值
struct Individual {
double value; // 个体的基因值
double fitness; // 个体的适应度值
};
// 初始化种群
void initialize_population(vector<Individual>& population) {
random_device rd; // 创建一个随机设备,用于生成随机种子
mt19937 gen(rd()); // 创建一个 Mersenne Twister 19937 伪随机数生成器,使用上述随机设备生成的种子来初始化
uniform_real_distribution<> dis(-10.0, 10.0); // 创建一个均匀分布的随机数分布,范围在 -10.0 到 10.0 之间
// 为每个个体赋予随机基因值和计算对应的适应度值
for (int i = 0; i < population.size(); ++i) {
population[i].value = dis(gen);
population[i].fitness = fitness_function(population[i].value);
}
}
// 选择操作
vector<Individual> selection(const vector<Individual>& population) {
vector<double> fitness_values(population.size()); // 创建一个储存适应度值的数组,大小与种群大小相同
for (int i = 0; i < population.size(); ++i) {
fitness_values[i] = population[i].fitness; // 将种群中每个个体的适应度值存储到适应度值数组中
}
double total_fitness = 0.0; // 初始化总适应度值为0
for (double fitness : fitness_values) {
total_fitness += fitness; // 计算总适应度值,将每个个体的适应度值相加
}
vector<double> probabilities(population.size()); // 创建一个储存选择概率的数组,大小与种群大小相同
for (int i = 0; i < population.size(); ++i) {
probabilities[i] = fitness_values[i] / total_fitness; // 计算每个个体的选择概率,适应度值除以总适应度值
}
vector<Individual> selected_population; // 创建一个储存选择后个体的新种群
random_device rd; // 创建一个随机设备,用于生成真正的随机种子
mt19937 gen(rd()); // 创建一个 Mersenne Twister 19937 伪随机数生成器,使用上述随机设备生成的种子来初始化
discrete_distribution<> distribution(probabilities.begin(), probabilities.end()); // 创建一个离散分布,使用选择概率数组初始化
// 使用离散分布来选择新的个体,并将其添加到新的种群中
for (int i = 0; i < population_size; ++i) {
int index = distribution(gen); // 根据离散分布随机选择一个索引
selected_population.push_back(population[index]); // 将选择的个体添加到新的种群中
}
return selected_population; // 返回经过选择操作后的新种群
}
// 单点交叉操作
void crossover(Individual& child1, Individual& child2) {
int crossover_point = rand() % 2; // 固定在一半位置交叉
// 交换基因值以进行交叉
if (crossover_point == 0) {
swap(child1.value, child2.value);
}
}
// 变异操作
void mutate(Individual& individual) {
random_device rd; // 创建一个随机设备,用于生成真正的随机种子
mt19937 gen(rd()); // 创建一个 Mersenne Twister 19937 伪随机数生成器,使用上述随机设备生成的种子来初始化
uniform_real_distribution<> dis(-0.5, 0.5); // 创建一个均匀分布的随机数分布,范围在 -0.5 到 0.5 之间
// 在一定概率下对基因值进行微小变化
if (rand() / double(RAND_MAX) < mutation_rate) {
individual.value += dis(gen);
}
individual.fitness = fitness_function(individual.value);
}
int main() {
vector<Individual> population(population_size); // 创建一个种群,大小为种群大小
initialize_population(population); // 初始化种群
for (int generation = 0; generation < generations; ++generation) {
population = selection(population); // 使用选择操作选择新一代个体
vector<Individual> new_population; // 创建一个储存新一代个体的新种群
while (new_population.size() < population_size) {
int index1 = rand() % population_size; // 随机选择一个索引
int index2 = rand() % population_size; // 随机选择另一个索引
Individual child1 = population[index1]; // 获取父代个体1
Individual child2 = population[index2]; // 获取父代个体2
// 交叉操作
crossover(child1, child2); // 对父代个体进行交叉操作
// 变异操作
mutate(child1); // 对父代个体1进行变异操作
mutate(child2); // 对父代个体2进行变异操作
new_population.push_back(child1); // 将变异后的个体1添加到新种群
new_population.push_back(child2); // 将变异后的个体2添加到新种群
}
population = new_population; // 更新种群为新一代种群
// 寻找当前代中最优个体的适应度值
double best_fitness = -1.0; // 初始化最优适应度值为负数
for (const Individual& individual : population) {
if (individual.fitness > best_fitness) {
best_fitness = individual.fitness; // 更新最优适应度值
}
}
// 输出当前代的信息
cout << "Generation " << generation + 1 << ": Best fitness = " << best_fitness << endl;
}
// 寻找最终种群中的最优解
double best_fitness = -1.0; // 初始化最优适应度值为负数
double best_individual = 0.0; // 初始化最优个体的基因值
for (const Individual& individual : population) {
if (individual.fitness > best_fitness) {
best_fitness = individual.fitness; // 更新最优适应度值
best_individual = individual.value; // 更新最优个体的基因值
}
}
// 输出算法结束后的结果
cout << "Genetic algorithm finished." << endl;
cout << "Best solution: x = " << best_individual << ", f(x) = " << best_fitness << endl;
return 0; // 返回0,表示程序正常结束
}
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
const int POPULATION_SIZE = 50; // 种群大小
const int NUM_GENERATIONS = 100; // 迭代代数
const double MUTATION_RATE = 0.1; // 变异率
// 目标函数:f(x) = -x^2
double objectiveFunction(double x) {
return x * x;
}
// 个体表示
struct Individual {
double x; // x 值
double fitness; // 适应度值
Individual() {
x = (double)rand() / RAND_MAX * 20.0 - 10.0; // 初始随机值在 -10 到 10 之间
fitness = objectiveFunction(x);
}
};
// 初始化种群
std::vector<Individual> initializePopulation() {
std::vector<Individual> population(POPULATION_SIZE);
return population;
}
// 使用锦标赛选择法选择父代个体
Individual tournamentSelection(const std::vector<Individual>& population) {
const int tournamentSize = 5;
Individual best = population[rand() % POPULATION_SIZE];
for (int i = 1; i < tournamentSize; ++i) {
Individual candidate = population[rand() % POPULATION_SIZE];
if (candidate.fitness > best.fitness) { // 使用大于号进行比较以找到适应度最大值
best = candidate;
}
}
return best;
}
// 交叉两个父代个体以产生子代个体
Individual crossover(const Individual& parent1, const Individual& parent2) {
Individual child;
// 简单的平均交叉
child.x = (parent1.x + parent2.x) / 2.0;
return child;
}
// 对个体进行变异
void mutate(Individual& individual) {
if (rand() / static_cast<double>(RAND_MAX) < MUTATION_RATE) {
individual.x += (double)rand() / RAND_MAX * 0.2 - 0.1; // 小范围随机变化
}
}
int main() {
srand(static_cast<unsigned int>(time(0)));
// 初始化种群
std::vector<Individual> population = initializePopulation();
for (int generation = 0; generation < NUM_GENERATIONS; ++generation) {
// 创建下一代种群
std::vector<Individual> newPopulation;
for (int i = 0; i < POPULATION_SIZE; ++i) {
Individual parent1 = tournamentSelection(population);
Individual parent2 = tournamentSelection(population);
Individual child = crossover(parent1, parent2);
mutate(child);
newPopulation.push_back(child);
}
// 用新种群替换旧种群
population = newPopulation;
// 在当前代中找到最优个体
double bestFitness = population[0].fitness;
double bestX = population[0].x;
for (const Individual& individual : population) {
if (individual.fitness > bestFitness) { // 使用大于号进行比较以找到适应度最大值
bestFitness = individual.fitness;
bestX = individual.x;
}
}
std::cout << "第 " << generation << " 代:最优 x = " << bestX << ",最优适应度 = " << bestFitness << std::endl;
}
return 0;
}
3、多目标实现
(1)非支配排序
(i)准确计算rank o(n^2)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 定义个体结构体,存储个体的目标值、支配计数、被支配集合、等级等信息
struct Individual {
vector<double> objectives; // 个体的目标值
int domination_count; // 支配该个体的个体数目
vector<int> dominated_set; // 被该个体支配的个体集合的索引
int rank; // 个体的等级
};
// 非支配排序函数
void non_dominated_sort(vector<Individual>& population) {
int n = population.size(); // 种群大小
// 对每个个体进行处理
for (int i = 0; i < n; ++i) {
population[i].domination_count = 0; // 初始化支配计数
population[i].dominated_set.clear(); // 清空被支配集合
// 比较个体 i 与其他个体 j 的目标值关系
for (int j = 0; j < n; ++j) {
if (i == j) continue; // 跳过与自己的比较
// 判断是否个体 i 支配个体 j
if (population[i].objectives[0] <= population[j].objectives[0] &&
population[i].objectives[1] <= population[j].objectives[1]) {
population[i].dominated_set.push_back(j); // 将 j 添加到被支配集合中
}
// 判断是否个体 j 支配个体 i
else if (population[j].objectives[0] <= population[i].objectives[0] &&
population[j].objectives[1] <= population[i].objectives[1]) {
population[i].domination_count++; // 增加支配计数
}
}
// 如果个体 i 没有被其他个体支配,设置其为第一等级
if (population[i].domination_count == 0) {
population[i].rank = 1;
}
}
int current_rank = 1; // 当前等级
while (true) {
vector<int> next_front; // 下一个前沿
// 遍历每个个体,处理与当前等级关联的个体
for (int i = 0; i < n; ++i) {
if (population[i].rank == current_rank) {
// 更新被支配个体的支配计数
for (int j : population[i].dominated_set) {
population[j].domination_count--;
// 如果支配计数为零,设置等级并将其添加到下一个前沿中
if (population[j].domination_count == 0) {
population[j].rank = current_rank + 1;
next_front.push_back(j);
}
}
}
}
// 如果下一个前沿为空,退出循环
if (next_front.empty()) {
break;
}
current_rank++; // 更新等级
}
}
int main() {
// 创建个体并初始化目标值等信息
vector<Individual> population = {
{{3, 2}, 0, {}, 0},
{{4, 1}, 0, {}, 0},
{{2, 3}, 0, {}, 0},
{{1, 4}, 0, {}, 0},
{{3, 1}, 0, {}, 0}
};
// 对种群进行非支配排序
non_dominated_sort(population);
// 输出每个个体的等级信息
for (int i = 0; i < population.size(); ++i) {
cout << "个体 " << i + 1 << " 等级:" << population[i].rank << endl;
}
return 0;
}
(ii)随机竞争,淘汰被支配者 o(n)
洗牌算法:打乱数组下标。得到可以遍历的随机数组,以打乱后数组为指针
#include <iostream>
#include <vector>
#include <random>
#include <algorithm>
using namespace std;
// 洗牌算法函数
void shuffle_algorithm(vector<int>& array) {
random_device rd;
mt19937 gen(rd());
// 使用随机生成的索引,交换数组中的元素
for (int i = array.size() - 1; i > 0; --i) {
uniform_int_distribution<int> dis(0, i);
int j = dis(gen);
swap(array[i], array[j]);
}
}
int main() {
// 创建一个包含10个整数的数组
vector<int> array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 使用洗牌算法打乱数组顺序
shuffle_algorithm(array);
// 输出打乱后的数组
cout << "ready:";
for (int num : array) {
cout << num << " ";
}
cout << endl;
return 0;
}
具体实现
void select()
{
int n=20000;
int nnn=1;
int head=0,tail=n-1,mid=0;
Person zhong[21000];
while(n>10000)
{
//cout<<nnn<<endl;
nnn++;
if(nnn>=100)break;
mid=0;
for(int i=0;i<n;i++)
{
if(daan[i].sc <=1)
{
zhong[mid].cost =daan[i].cost ;
zhong[mid].sc =daan[i].sc ;
zhong[mid].type[1] =daan[i].type[1] ;
zhong[mid].type[2] =daan[i].type[2] ;
zhong[mid].type[3] =daan[i].type[3] ;
mid++;
}
}
for(int i=0;i<mid;i++)
swap(daan[i],zhong[i]);
n=mid;
//cout<<"mid:"<<mid<<endl;
//cout<<"n:"<<n<<endl;
std::vector<int> sequence(n);
for (int i = 0; i < n; i++)
{
sequence[i] = i;
}
// 使用洗牌算法打乱向量
for (int i = n - 1; i > 0; i--)
{
int j = std::rand() % (i + 1);
std::swap(sequence[i], sequence[j]);
}
head=0,tail=n-1,mid=0;
//开始竞争
if(n%2)
{
swap(daan[sequence[tail]],zhong[mid]);
mid++;
}
while(head<tail)
{
if(daan[sequence[head]].cost <=daan[sequence[tail]].cost &&daan[sequence[head]].sc <=daan[sequence[tail]].sc)
{
swap(daan[sequence[head]],zhong[mid]);
mid++;
n-=1;
}
else if(daan[sequence[head]].cost >=daan[sequence[tail]].cost &&daan[sequence[head]].sc >=daan[sequence[tail]].sc)
{
swap(daan[sequence[tail]],zhong[mid]);
mid++;
n-=1;
}
else
{
swap(daan[sequence[head]],zhong[mid]);
mid++;
swap(daan[sequence[tail]],zhong[mid]);
mid++;
}
head++;
tail--;
}
for(int i=0;i<mid;i++)
{
swap(daan[i],zhong[i]);
}
}
int kk=0;
while(n<=10000)
{
daan[mid].cost =daan[kk].cost ;
daan[mid].sc =daan[kk].sc ;
daan[mid].type[1] =daan[kk].type[1] ;
daan[mid].type[2] =daan[kk].type[2] ;
daan[mid].type[3] =daan[kk].type[3] ;
n++;
mid++;
kk++;
}
//cout<<"mid:"<<mid<<endl;
//cout<<"n:"<<n<<endl;
}
(iii)其他选择过程操作
void crowding_distance_assignment(vector<Individual>& front) {
// 拥挤度距离计算的实现
// ...
}
bool compare_crowding(const Individual& a, const Individual& b) {
// 拥挤度比较的实现
// ...
}
点之间越靠近,拥挤度越大,优先保留拥挤度小的点。
三、总结
更适用于一组初始值,单一属性起点的优化类问题,一组数据经不同组合、不同顺序产生不同结果。目前还不会设置两条染色体、和显隐性的设置。
[code]
原文链接:https://blog.csdn.net/jokery404/article/details/132220901[/code] |
|