算法背景
遗传算法(Genetic Algorithm,GA)是模拟生物在自然环境中的遗传和进化的过程而形成的自适应全局优化搜索算法。遗传算法借鉴了达尔文的进化论和孟德尔的遗传学说。其本质是一种并行、高效、全局搜索的方法,它能在搜索过程中自动获取和积累有关搜索空间的知识,并自适应地控制搜索过程以求得最优解。遗传算法操作使用“适者生存”的原则,在潜在的解决方案种群中逐次产生一个近似最优的方案。在遗传算法的每一代中,根据个体在问题域中的适应度值和从自然遗传学中借鉴来的再造方法进行个体选择,产生一个新的近似解。这个过程导致种群中个体的进化,得到的新个体比原个体更能适应环境,就像自然界中的改造一样。
基本原理
对每个个体都进行上述的进化,包括复制,交叉,变异。然后择优录取。
编码:将问题的可行解,抽象编码为适用于遗传算法的形式。核心思想是根据不同的问题,用一个串对不同的抽象表示。
常见的编码方式如二进制编码:用一个二进制串来表示这个十进制数值。用以求解问题。比如在处理TSP问题时,给你10个城市,需要你不重复的经过每一个城市,某个解依次走过每个城市则可以表示为[3,2,1,4,5,7,6,8,9,0]。
• 给定数值解的区间范围:[1,10]。
• 给定精度:1e-5,两个数值解的间隔。
• 进行编码:为每个数值解分配一个独一无二的二进制串。
【注】用长度有限的二进制串表示在长度无限的区间[1,10],不能全都表示,所以就只能表示其中的一些数,两个数之间的间隔就是精度。其中表示的二进制串并非在数值上等于表示的值,两者是映射一一对应的关系。
要想实现每个数值都能分配一个独一无二的串,那么串所能表示的数值个数就要大于等于数值解的个数。
一个长度为n的串,能表示个数。
例如,区间范围为[1,10],长度为2的串提供的精度为
数值区间长度为L,精度为E的条件下,二进制串的长度n,三者关系为(区间长度除以分段数<精度)
要想达到1e-5的精度,对于区间长度为10,串的长度n应该满足
n=20时,串提供的精度约为0.00000954.
解码:二进制串的索引,就是在问当前串是第几个串。使用二进制转十进制得到。以[1,1]为例,其十进制数为3,对应的数值为1+3*3=10。
一般的,区间范围为[a,b],区间长度为L,即L=b-a,串长为n,当前串对应十进制数为T,精度为E,则该串对应实值解为:
复制策略
• 将个体适应度大小映射为概率进行复制。轮盘赌法是指适应度高的个体有更大概率复制,且复制的份数越多。
• 精英产生精英是指对适应度高的前N/4的个体进行复制,然后用这些个体把后N/4个体替换掉。
• 可以随机复制。
• 由于图像不知,“坏解”也可能与适应度最好的点也近,那么也可以替换掉好解来调整。
交叉策略
• 按顺序两两个体之间按概率交叉。如1和2,2和3等。或者1和2,2和4等,或者1和4这样。
• 按顺序三个及以上个体之间按概率交叉。
• 对适应度高的前N/2个体、甚至N/4的个体之间相互交叉。
• 可随机交叉,对每个个体随机从前N/2中选一个个体交叉。
• 个体中的多段进行交叉。
变异策略
• 每个个体都进行变异。
• 变异不好的,只对适应度低的后N/4的,或者后N/2个个体变异。
• 按适应度大小映射为概率变异。
• 可一个位点变异,也可多个位点变异。
算法实现
复制:按适应度大小映射为概率,进行轮盘赌法复制。 适应度越高的解,按道理越应该高概率的进行复制,且复制的份数应该越多。对于个体𝑥𝑖,计算对应适应度𝑓(xi) -> pi= fxi/f(xi) 。
交叉:1和2,3和4,以一定概率决定是否交叉。若交叉,则二者选择随机一个段进行交叉。
变异:通过扔一个随机数,一定概率决定该个体是否变异,若变异,随机选择一个位点进行变异,按位取反。
【注】轮盘赌法,不是直接对概率比较,而是对概率的累计和进行比较。随机数取值在哪就对那个个体进行复制,Rand = 0 ~ 0.2:表示对 x1 复制Rand = 0.2~0.3:表示对x2复制Rand = 0.3~0.7:表示对x3复制Rand = 0.7~1.0:表示对 x4复制。代码实现技巧方法:
pi= f(xi)/ ∑f(xi) // 得到对应个体概率:0.2 0.1 0.4 0.3
Cs = cumsum(pi)// 累计和:0.2 0.3 0.7 1.0
i = 1 , j = 1
R = sort( rand(4) ) //生成四个随机数再升序排序:0.1 0.5 0.6 0.8
While j <= n
if R(j)< Cs(i)
newx(j) = oldx(i)
j = j + 1
else
i = i + 1
比较结果:
i = 1 , j = 1 : Cs = 0.2 , R = 0.1 newx(1) = oldx(1)
i = 1 , j = 2 : Cs = 0.2 , R = 0.5 --------------------
i = 2 , j = 2 : Cs = 0.3 , R = 0.5 --------------------
i = 3 , j = 2 : Cs = 0.7 , R = 0.5 newx(2) = old(3)
…
相当于把原来乱序的判断做一个顺序的调整,这样可以使得 R< 0.7=>0.3<R< 0.7。
算法分析
优点:参数少,理论优势。变异机制赋予了群体跳出局部极值的能力等。
缺点:容易陷入局部最优。算法实现较为繁琐。
【注】无论是蚁群算法,粒子群算法,免疫算法,鱼群算法,蝙蝠算法,遗传算法,算法思想内涵是一致的:
保底机制 + 更新策略 = 寻得优解。
案例实操
求解𝑓(𝑥) = abs(𝑥 𝑠𝑖𝑛 𝑥 𝑐𝑜𝑠 2𝑥 − 2𝑥𝑠𝑖𝑛 3𝑥 + 3𝑥 𝑠𝑖𝑛 4𝑥 )在[0,50]的最大值。
【实验代码】
%%主程序
function GA()
clear
close all
popsize=20; % 群体大小
chromlength=20; %串的长度(个体长度)
pc=0.6; %交叉概率
pm=0.1; %变异概率
xlim = [0,50];% 求解范围
G = 100 ; %迭代次数
% x = zeros(1,G); % 记录每代个体最优位置
% y = zeros(1,G); % 记录每代最优个体对应的函数值
pop= round( rand(popsize,chromlength) ) ; %随机产生初始群体
decpop = bintodec( pop ,popsize, chromlength,xlim ) ; % 计算初代解对应十进制
fx = calobjvalue(decpop ) ; % 计算初代解的函数值
plotfig(decpop , fx , xlim , 1 ) ; % 绘制图像
[y(1) , l ] = max(fx); x(1) = decpop(l);
for i = 2 : G
decpop = bintodec( pop , popsize, chromlength,xlim ) ; % 计算上一代解对应十进制
fx = calobjvalue(decpop ) ; % 计算上一代解的函数值
fitvalue = calfitvalue(fx) ; % 适应度映射
newpop = copyx(pop,fitvalue,popsize); %复制
newpop = crossover(newpop, pc, popsize,chromlength ); %交叉
newpop = mutation(newpop,pm, popsize,chromlength); %变异
% 这时的newpop是经过复制交叉变异产生的新一代群体
% 下边进行选择择优保留(即实现保底机制)
newdecpop = bintodec( newpop ,popsize, chromlength,xlim ) ;
new_fx = calobjvalue(newdecpop) ; %计算新解目标函数
new_fitvalue = calfitvalue(new_fx); %计算新群体中每个个体的适应度
index = find(new_fitvalue > fitvalue) ;
pop(index, : ) = newpop(index,:) ; % 更新得到最新解
decpop = bintodec( pop ,popsize, chromlength,xlim ) ; %计算新解的十进制
fx = calobjvalue( decpop ) ; %计算结果
plotfig(decpop , fx ,xlim , i ) % 绘制新解的图
% 找出更新后的个体最优函数值
[bestindividual,bestindex] = max( fx ) ;
y(i)=bestindividual; % 记录每一代的最优函数值
x(i)= decpop(bestindex) ; %十进制解
subplot(1,2,2);
plot(1:i,y);
title('适应度进化曲线');
end
[ymax, max_index] = max(y);
disp(['找的最优解位置为:', num2str(x(max_index)) ])
disp(['对应最优解为:', num2str(ymax) ])
end
%******************************************************************************************%
%% 计算适应度
function fitvalue = calfitvalue(fx)
%这里求最大值,并且函数值又都大于0,所以直接使用函数值本身作为适应度值。
% 事实上,不同的问题适应度函数构造方法多种多样。
fitvalue = fx ;
end
%% 复制操作
function newx = copyx(pop, fitvalue,popsize ) %传进来二进制串和对应适应度
% 按照PPT的轮盘赌策略对个体复制
newx = pop; %只是起到申请一个size为pop大小空间的作用,newx之后要更新的
i = 1; j = 1;
p = fitvalue / sum(fitvalue) ; %适应度概率
Cs = cumsum(p) ; %累计和
R = sort(rand(popsize,1)) ; %每个个体的复制概率
while j <= popsize
if R(j) < Cs(i)
newx(j,:) = pop(i,:) ;
j = j + 1;
else
i = i + 1;
end
end
end
%% 交叉操作
function newx = crossover(pop, pc, popsize,chromlength )
% 12 34 56交叉方式,随机选择交叉位点
% 注意个体数为奇数偶数的区别
i = 2 ;
newx = pop ; %申请空间
while i + 2 <= popsize
%将第i 与 第 i -1 进行随机位点交叉
if rand < pc
x1 = pop(i-1,:);
x2 = pop(i,:) ;
r = randperm( chromlength , 2 ) ; %返回范围内两个整数
r1 = min(r); r2 =max(r) ; % 交叉复制的位点
newx(i-1,:) = [x1( 1 : r1-1),x2(r1:r2) , x1(r2+1: end)]; % x1的前半部分,并上交叉过来的x2,并上x1的后半部分
newx(i , : ) = [x2( 1 : r1-1),x1(r1:r2) , x2(r2+1: end)];
end
i = i + 2 ; %更新i
end
end
%% 变异
function newx = mutation(pop,pm, popsize,chromlength)
i = 1 ;
while i <= popsize
if rand < pm %随机生成的数比概率要小
r = randperm( chromlength , 1 ) ;
pop(i , r) = ~pop(i, r);%随便生成一个位置按位取反
end
i = i + 1;
end
newx = pop; %将变异后的结果返回。
end
%% 二进制转十进制函数
function dec = bintodec( pop ,popsize, chromlength,xlim )
dec = zeros(1,popsize);
index = chromlength-1:-1:0;
for i = 1 : popsize
dec(i) = sum(pop(i,:).* (2.^index));
end
dec = xlim(1) + dec*( xlim(2) - xlim(1) ) /( 2 ^ chromlength - 1) ;%解码计算
end
%% 绘制图像
function plotfig(decpop , fx ,xlim,k)
f = @(x) abs(x .* sin(x) .* cos(2 * x) - 2 * x .* sin(3 * x) +3 * x .* sin(4 * x)); % 研究对象函数
x = xlim(1):0.05:xlim(2);
y = f(x) ;
subplot(1,2,1);
plot(x,y,decpop,fx,'o')
title(['第',num2str(k),'次迭代进化'])
pause(0.2)
end
%% 目标函数
function fx = calobjvalue(decpop ) %参数为十进制解
f = @(x) abs(x .* sin(x) .* cos(2 * x) - 2 * x .* sin(3 * x) +3 * x .* sin(4 * x)) ; % 研究对象函数
fx = f(decpop);
end
【运行结果】
>> >找的最优解位置为:47.5586
>> >对应最优解为:219.4966
【注】遗传算法迭代过程中闪现主要是靠交叉变异得来的;粒子群是迭代过程就是相对连续且缓慢。