技术好文共享:遗传算法解决函数优化

简介: 技术好文共享:遗传算法解决函数优化

术语说明


由于遗传算法是由进化论和遗传学机理而产生的搜索算法,所以在这个算法中会用到很多生物遗传学知识,下面是我们将会用来的一些术语说明:


一、染色体(Chronmosome)


染色体又可以叫做基因型个体(individuals),一定数量的个体组成了群体(population),群体中个体的数量叫做群体大小。


二、基因(Gene)


基因是串中的元素,基因用于表示个体的特征。例如有一个串S=1011,则其中的1,0,1,1这4个元素分别称为基因。它们的值称为等位基因(Alletes)。


三、基因地点(Locus)


基因地点在算法中表示一个基因在串中的位置称为基因位置(Gene Position),有时也简称基因位。基因位置由串的左向右计算,例如在串 S=1101 中,0的基因位置是3。


四、基因特征值(Gene Feature)


在用串表示整数时,基因的特征值与二进制数的权一致;例如在串 S=1011 中,基因位置3中的1,它的基因特征值为8;基因位置1中的1,它的基因特征值为2。


五、适应度(Fitness)


各个个体对环境的适应程度叫做适应度(fitness)。为了体现染色体的适应能力,引入了对问题中的每一个染色体都能进行度量的函数,叫适应度函数. 这个函数是计算个体在群体中被使用的概率。


操作算法


霍兰德(Holland)教授最初提出的算法也叫简单遗传算法,简单遗传算法的遗传操作主要有三种:选择(selection)、交叉(crossover)、变异(mutation)这也是遗传算法中最常用的三种算法:


1.选择(selection)


选择操作也叫复制操作,从群体中按个体的适应度函数值选择出较适应环境的个体。一般地说,选择将使适应度高的个体繁殖下一代的数目较多,而适应度较小的个体,繁殖下一代的数目较少,甚至被淘汰。最通常的实现方法是轮盘赌(roulette wheel)模型。令Σfi表示群体的适应度值之总和,fi表示种群中第i个染色体的适应度值,它被选择的概率正好为其适应度值所占份额fi/Σfi。


如果适应度值存在负数,我的方法是采用以下公式:


再计算概率和累计概率。


设想群体全部个体的适当性分数由一张饼图来代表 (见图)。


群体中每一染色体指定饼图中一个小块。块的大小与染色体的适应性分数成比例,适应性分数愈高,它在饼图中对应的小块所占面积也愈大。为了选取一个染色体,要做的就是旋转这个轮子,直到轮盘停止时,看指针停止在哪一块上,就选中与它对应的那个染色体。


若产生随机数为0.81,则6号个体被选中。


2.交叉(Crossover)


交叉算子将被选中的两个个体的基因链按一定概率pc进行交叉,从而生成两个新的个体,交叉位置pc是随机的。其中Pc是一个系统参数。根据问题的不同,交叉又为了单点交叉算子(Single Point Crossover)、双点交叉算子(Two Point Crossover)、均匀交叉算子 (Uniform Crossover),在此我们只讨论单点交叉的情况。


单点交叉操作的简单方式是将被选择出的两个个体S1和S2作为父母个体,将两者的部分基因码值进行交换。假设如下两个8位的个体:


S1:1000 1111


S2:1110 1100


产生一个在1到7之间的随机数c,假如现在产生的是2,将S1和S2的低二位交换,后代P1为1100 1111,P2为10101100。在这里高二位与低二位是按从左到右的顺序还是从右到左的顺序,自我感觉效果是一样的,不过也没具体证明,网上是按从右到左的顺序,在这篇文章中的定义都是从左到右的。


3.变异(Mutation)


这是在选中的个体中,将新个体的基因链的各位按概率pm进行异向转化,最简单方式是改变串上某个位置数值。对二进制编码来说将0与1互换:0变异为1,1变异为0。


如下8位二进制编码:


1 1 1 0 1 1 0 0


随机产生一个1至8之间的数i,假如现在k=6,对从左往右的第6位进行变异操作,将原来的1变为0,得到如下串:


1 1 1 0 1 0 0 0


4.精英主义 (Elitism)


仅仅从产生的子代中选择基因去构造新的种群可能会丢失掉上一代种群中的很多信息。也就是说当利用交叉和变异产生新的一代时,我们有很大的可能把在某个中间步骤中得到的最优解丢失。在此我们使用精英主义(Elitism)方法,在每一次产生新的一代时,我们首先把当前最优解原封不动的复制到新的一代中,其他步骤不变。这样任何时刻产生的一个最优解都可以存活到遗传算法结束。不过这篇文章的代码中并没实现这点,以后有机会有时间再贴上代码。


遗传算法的所需参数


说简单点遗传算法就是遍历搜索空间或连接池,从中找出最优的解。搜索空间中全部都是个体,而群体为搜索空间的一个子集。并不是所有被选择了的染色体都要进行交叉操作和变异操作,而是以一定的概率进行,一般在程序设计中交叉发生的概率要比变异发生的概率选取得大若干个数量级。大部分遗传算法的步骤都很类似,常使用如下参数:


Fitness函数:在这篇文章中为:


Fitnessthreshold(适应度阈值):适合度中的设定的阀值,当最优个体的适应度达到给定的阀值,或者最优个体的适应度和群体适应度不再上升时(变化率为零),则算法的迭代过程收敛、算法结束。否则,用经过选择、交叉、变异所得到的新一代群体取代上一代群体,并返回到选择操作处继续循环执行。这篇文章中没使用这个阈值。


P:种群的染色体总数叫种群规模,它对算法的效率有明显的影响,其长度等于它包含的个体数量。太小时难以求出最优解,太大则增长收敛时间导致程序运行时间长。对不同的问题可能有各自适合的种群规模,通常种群规模为 30 至 160。这篇文章中使用的群体规模为20。


pc:在循环中进行交叉操作所用到的概率。交叉概率(Pc)一般取0.6至0.95之间的值,Pc太小时难以向前搜索,太大则容易破坏高适应值的结构。这篇文章中的交叉概率为0.65。


Pm:变异概率,从个体群中产生变异的概率,变异概率一般取0.01至0.03之间的值变异概率Pm太小时难以产生新的基因结构,太大使遗传算法成了单纯的随机搜索。这篇文章中的编译概率为0.01。


另一个系统参数是个体的长度,有定长和变长两种。它对算法的性能也有影响。由于GA是一个概率过程,所以每次迭代的情况是不一样的,系统参数不同,迭代情况也不同。这篇文章中并没用到这个。


遗传步骤


了解了上面的基本参数,下面我们来看看遗传算法的基本步骤。


基本过程为:


对待解决问题进行编码,我们将问题结构变换为位串形式编码表示的过程叫编码;而相反将位串形式编码表示变换为原问题结构的过程叫译码。


随机初始化群体P(0):=(p1, p2, … pn);


计算群体上每个个体的适应度值(Fitness)


评估适应度,对当前群体P(t)中每个个体Pi计算其适应度F(Pi),适应度表示了该个体的性能好坏


按由个体适应度值所决定的某个规则应用选择算子产生中间代Pr(t)


依照Pc选择个体进行交叉操作


仿照Pm对繁殖个体进行变异操作


没有满足某种停止条件,则转第3步,否则进入9


输出种群中适应度值最优的个体


程序的停止条件最简单的有如下二种:完成了预先给定的进化代数则停止;种群中的最优个体在连续若干代没有改进或平均适应度在连续若干代基本没有改进时停止。


代码实现


#include


#include


#include


#include


using namespace std;


const int M = 8; //染色体的数目,群体的大小


const int T = 7; //终止代数


const double pc = 0.6; //交叉概率


const double pm = 0.01; //变异概率


struct Population


{


int g【20】; //将x,y的取值区间分为(2^10-1)份,用20位二进制位表示份数


double x,y;


double fit; //适应函数值


double nfit;


double sumfit; //适应值总和


};


class gaModel{


public:


int rand01() const; //随机生成01


double randab(double,double) const; //随即生成【a,b)的一个数


void initial(Population ); // 初始化函数


void evalueFitness(Population ); // 计算适应度


void select(Population ); // 选择复制函数


void crossover(Population ); // 交叉函数


void mutation(Population ); // 变异函数


void decoding(Population ); // 解码函数


void print(Population ); // 显示函数


Population p【M】;


};


#include "GaModel.h"


int gaModel::rand01() const{


int r = 0;


double q = 0.0;


q = rand()/(RAND_MAX + 0.0);


if(q < 0.5)


r = 0;


else


r = 1;


return r;


}


double gaModel::randab(double a,double b) const{


double c,r;


c = b - a;


r = a + c rand()/(RAND_MAX+1.0);


return r;


}


void gaModel::initial(Population t){


Population po;


srand(time(0));


for(po = t; po < t + M; po++) //初始化群体


for(int j = 0; j < 20; j++)


(po).g【j】 = rand01();


}


void gaModel::evalueFitness(Population t){


double f,xx,yy,temp = 0.0;


Population po1,po2;


double fmax = 0,fmin = 9999999999;


for(po1 = t; po1 < t + M; po1++){ //计算适应值


xx = (po1).x;


yy = (po1).y;


f = xx sin(6 yy) + yy cos(8 xx);//优化函数


(po1).fit = f;


//cout [ (po1).fit [ "测试" [ endl;


}


for(po1 = t; po1 < t + M; po1++){


if((po1).fit > fmax)


fmax = (po1).fit;


if((po1).fit [span style="color: rgba(0, 0, 0, 1)"> fmin)


fmin = (po1).fit;


}


for(po1 = t; po1 < t + M; po1++){


(po1).nfit = ((po1).fit - fmin) / (fmax - fmin + 1);


}


for(po1 = t; po1 < t + M; po1++){ //计算累计适应值,为的是之后的轮盘赌模型


for(po2 = t; po2 <= po1; po2++)


temp = temp + (po2).nfit;


(po1).sumfit = temp;


temp = 0.0;


}


}


void gaModel::select(Population t){ //轮盘赌选择


int i = 0;


Population pt【M】,po;


double s;


srand(time(0));


while(i [span style="color: rgba(0, 0, 0, 1)"> M){


s = randab((t).sumfit,((t + M - 1)).sumfit);


//代码效果参考:http://hnjlyzjd.com/xl/wz_25190.html

for(po = t; po < t + M; po++){

if((po).sumfit >= s){


pt【i】 = (po);


break;


}


else continue;


}


i++;


}


for(i = 0; i < M; i++)


for(int j = 0; j < 20; j++)


t【i】.g【j】 = pt【i】.g【j】;


}


void gaModel::crossover(Population t){ //交叉函数


Population po;


double q; //存放一个0到1的随机数,判定是否交叉


int d,e,tem【20】; //d存放一个从1到19的一个随机整数,用来确定交叉的位置


int k = 0,rpo【5】 = {99,99,99,99,99};//e存放从0到M的一个随机且与当前t【i】中i不同的整数,用来确定交叉的对象


bool tf = true; //rpo存放每次的e,确保所有的染色体都会交叉


srand(time(0));


for(po = t; po < t + M/2; po++){


//代码效果参考:http://hnjlyzjd.com/hw/wz_25188.html

q = rand() / (RAND_MAX + 0.0);

while(true){ //避免自己与自己交叉和交叉过的染色体继续交叉


tf = true;


e = rand() % M;


for(int j = 0; j < M; j++){


if(e == rpo【j】)


tf = false;


}


if(t + e != po && tf)


break;


}


if(q [span style="color: rgba(0, 0, 0, 1)"> pc){


d = 1 + rand() % 19; //确定交叉位置


for(int i = d; i < 20; i++){


tem【i】 = (po).g【i】;


(po).g【i】 = ((t+e)).g【i】;


((t+e)).g【i】 = tem【i】;


}


}


rpo【k】 = e;


k++;


}


}


void gaModel::mutation(Population t){ //变异函数


double q;


Population po;


srand(time(0));


for(po = t; po < t + M; po++){


int i = 0;


while(i < 20){


q = rand() / (RAND_MAX + 0.0);


if(q [span style="color: rgba(0, 0, 0, 1)"> pm)


(po).g【i】 = 1 - (po).g【i】;


i++;


}


}


}


void gaModel::decoding(Population t){ //解码函数


Population po;


int temp,s1 = 0, s2 = 0;


float m,n,dit;


n = ldexp(1.0,10);


dit = (2 - 1) / (n - 1);


for(po = t; po < t + M; po++){


for(int i = 0; i < 10; i++){


temp = ldexp((po).g【i】1.0,i);


s1 = s1 + temp;


}


m = 1 + s1 dit;


(po).x = m;


s1 = 0;


for(int j = 10; j < 20; j++){


temp = ldexp((po).g【j】1.0,j-10);


s2 = s2 + temp;


}


m = 1 + s2 dit;


(po).y = m;


s2 = 0;


}


}


void gaModel::print(Population t){ //显示函数


Population po;


for(po = t; po < t + M; po++){


for(int j = 0; j < 20; j++){


cout [ (po).g【j】;


if((j+1)%5 == 0)


cout [ ' ';


}


cout [ endl;


cout [ "x=" [ (po).x [ ' ' [ "y=" [ (po).y [ ' ' [ "fit=" [ (po).fit [ ' ' [ "nfit=" [ (po).nfit [ ' ' [ "sumfit=" [ (po).sumfit [ endl;


}


}


#include "GaModel.h"


int main(){


int kkk = 0;


gaModel g1;


int gen = 0;


g1.initial(&(g1.p【0】));


g1.print(&(g1.p【0】));


cout [ endl;


g1.decoding(&(g1.p【0】));


g1.print(&(g1.p【0】));


cout [ endl;


g1.evalueFitness(&(g1.p【0】));


g1.print(&(g1.p【0】));


while(gen [span style="color: rgba(0, 0, 0, 1)"> T){


cout [ "gen=" [ gen + 1 [ endl;


g1.select(&(g1.p【0】));


g1.decoding(&(g1.p【0】));


g1.evalueFitness(&(g1.p【0】));


cout [ "sel

相关文章
|
5天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的优化算法及其应用
本文旨在探讨深度学习中常用的优化算法,包括梯度下降、动量方法、AdaGrad、RMSProp和Adam等。通过分析每种算法的原理、优缺点及适用场景,揭示它们在训练深度神经网络过程中的关键作用。同时,结合具体实例展示这些优化算法在实际应用中的效果,为读者提供选择合适优化算法的参考依据。
|
6天前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
21 2
|
8天前
|
机器学习/深度学习 算法 物联网
探究操作系统的心脏:调度算法的演变与优化
本文旨在深入探讨操作系统中核心组件——调度算法的发展脉络与优化策略。通过分析从单任务到多任务、实时系统的演进过程,揭示调度算法如何作为系统性能瓶颈的解决关键,以及在云计算和物联网新兴领域中的应用前景。不同于传统摘要,本文将注重于概念阐释与实例分析相结合,为读者提供直观且全面的理解视角。
|
9天前
|
XML JavaScript 前端开发
学习react基础(1)_虚拟dom、diff算法、函数和class创建组件
本文介绍了React的核心概念,包括虚拟DOM、Diff算法以及如何通过函数和类创建React组件。
15 2
|
11天前
|
算法 搜索推荐 开发者
别再让复杂度拖你后腿!Python 算法设计与分析实战,教你如何精准评估与优化!
在 Python 编程中,算法的性能至关重要。本文将带您深入了解算法复杂度的概念,包括时间复杂度和空间复杂度。通过具体的例子,如冒泡排序算法 (`O(n^2)` 时间复杂度,`O(1)` 空间复杂度),我们将展示如何评估算法的性能。同时,我们还会介绍如何优化算法,例如使用 Python 的内置函数 `max` 来提高查找最大值的效率,或利用哈希表将查找时间从 `O(n)` 降至 `O(1)`。此外,还将介绍使用 `timeit` 模块等工具来评估算法性能的方法。通过不断实践,您将能更高效地优化 Python 程序。
27 4
|
21天前
|
机器学习/深度学习 算法
深度学习中的优化算法:从梯度下降到Adam
本文深入探讨了深度学习中的核心——优化算法,重点分析了梯度下降及其多种变体。通过比较梯度下降、动量方法、AdaGrad、RMSProp以及Adam等算法,揭示了它们如何更高效地找到损失函数的最小值。此外,文章还讨论了不同优化算法在实际模型训练中的表现和选择依据,为深度学习实践提供了宝贵的指导。
49 7
|
13天前
|
算法
基于ACO蚁群优化的UAV最优巡检路线规划算法matlab仿真
该程序基于蚁群优化算法(ACO)为无人机(UAV)规划最优巡检路线,将无人机视作“蚂蚁”,巡检点作为“食物源”,目标是最小化总距离、能耗或时间。使用MATLAB 2022a版本实现,通过迭代更新信息素浓度来优化路径。算法包括初始化信息素矩阵、蚂蚁移动与信息素更新,并在满足终止条件前不断迭代,最终输出最短路径及其长度。
|
16天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于PSO粒子群优化的GroupCNN分组卷积网络时间序列预测算法matlab仿真
本项目展示了一种结合粒子群优化(PSO)与分组卷积神经网络(GroupCNN)的时间序列预测算法。该算法通过PSO寻找最优网络结构和超参数,提高预测准确性与效率。软件基于MATLAB 2022a,提供完整代码及详细中文注释,并附带操作步骤视频。分组卷积有效降低了计算成本,而PSO则智能调整网络参数。此方法特别适用于金融市场预测和天气预报等场景。
|
16天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的优化算法
本文将探讨深度学习中的几种常见优化算法,包括梯度下降、动量方法、AdaGrad、RMSProp和Adam。这些算法在训练神经网络时发挥着重要作用,通过调整学习率和更新策略,能够显著提高模型的训练效率和性能。了解这些优化算法有助于更好地应用深度学习技术解决实际问题。
|
24天前
|
算法 Python
群智能算法:灰狼优化算法(GWO)的详细解读
在优化问题中,寻找最优解是核心目标。灰狼优化算法(GWO)受到自然界灰狼狩猎行为和社会等级结构的启发,通过模拟Alpha(头狼)、Beta(助手狼)、Delta(支配狼)和Omega(普通狼)的角色,高效搜索最优解。本文详细解析GWO的原理与步骤,并提供Python代码实现,帮助读者理解并应用这一算法。
下一篇
无影云桌面