备战数学建模37-遗传算法GA(攻坚战1)
Posted nuist__NJUPT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了备战数学建模37-遗传算法GA(攻坚战1)相关的知识,希望对你有一定的参考价值。
目录
一、遗传算法的概念
1.1、基本概念
遗传算法(Genetic Algorithm,GA):模仿生物的遗传进化原理,通过选择、交叉、变异等操作,使得种群个体的适应性不断提高,物竞天择,适者生存。智能算法,全局搜索寻优。
遗传算法的特点如下:
遗传算法的应用领域比较广泛,具体涉及的应用领域如下:
我们看三个概念,即个体,种群,适应度。初始解组成的是个体,多个个体组成的称为种群,适应度是指衡量个体适应高低的,适应度函数一般就是指的目标函数。
下面看一下编码和解码的概念,本文中的编码和解码如下,编码是指将原来的个体改变成能进行选择,交叉,和变异等操作的染色体的过程。而解码就是将染色体转换成为原始的个体,即最优解。编码是遗传算法解决问题的先决条件和关键步骤,常用的编码方式有:二进制编码,浮点数编码等。一般来说,二进制编码比浮点型编码的搜索能力更强,浮点型编码在种群多样性的操作更具多样性。
下面看一下遗传操作的选择,交叉与变异。选择操作就是选择好的进行遗传,交叉就是随机配对,变异就是改变基因到其对应的基因。
1.2、遗传算法的基本过程
遗传算法的基本过程如下:主要包括:收集问题参数并编码成染色体,初始化种族群体,通过选择交叉,变异等遗传操作更新群体,并计算群体的适应度,直到达到迭代次数或者适应度值不发生改变,则终止循环,并对染色体进行解码,即可得到问题的最优解。
下面看一下遗传算法的具体步骤:
首先,我们需要确定决策变量和约束条件,这个通常根据题意获得。然后建立模型,需要确定目标函数,然后需要找出个体,并对个体进行编码,编码是非常重要的,常用的编码方式是二进制编码。
标准的遗传算法基本是采用二进制编码,就是将个体(决策变量)用二进制串连在一起,构成染色体。编码完成,最后留下满足适应度函数的染色体后,还需要进行解码成个体,所以需要确定解码方法。其实就是还原成原来的决策变量。
然后,我们需要确定个体适应度的量化方法,即确定适应度函数,通过适应度函数去求解最优的决策变量,一般比较常用的就是直接将目标函数作为适应度函数,当然也有其它方法去确定适应度函数。
有了适应度函数后,我们就可以确定选择,交叉和变异的方式,个体选择常用的方法是按比例适应度分配,个体的适应度在总适应度的比例越大,即被选取的概率越大,遗产因子就会在种群中逐渐扩大。
计算出每个个体的选择概率后,我们就使用轮盘赌法进行选择,其实就是概率越大,轮盘所占比例越大,被选中的可能越大。
遗传的相关操作除了选择之外,还有交叉和变异,我们下面看一下交叉操作,交叉其实就是序列的交换,交叉率不宜过大,也不宜过小,一般取0.4-0.9。
下面看一下变异操作,对于二进制编码的变异,就是将1变成0,或者将0变成1,也应该选取合适的变异率,变异率过大和过小都不好。
1.3、遗传算法的具体步骤
遗传算法的具体步骤如下:首先对个体编码成染色体,初始化群体并计算解码后的适应值,然后进行遗传操作形成下一代群体, 判断是否满足要求,不满足则继续迭代,直到满足要求或者达到迭代次数。
二、遗传算法经典案例
2.1、遗传算法求解函数极大值问题
用标准遗传算法求函数f(x)=x+10sin(5x)+7cos(4x) 的最大值,其中 x 的取值范围为[0,10]。这是一个有多个局部极值的函数。
下面是使用遗传算法求解该函数模型最大值的具体步骤:
(1)初始化种群数目为 NP=50,染色体的编码方式选择二级制编码,二进制编码长度为 L=20,遗传算法的最大进化迭代数为 G=100,交叉概率 取Pc=0.8,变异概率取Pm=0.1。
(2)产生初始种群,将二进制编码转换成十进制,计算个体适应度值,并进行归一化;采用基于轮盘赌的选择操作、基于概率的交叉和变异操作,产生新的种群,并把历代的最优个体保留在新种群中,进行下一步遗传操作。
(3)判断是否满足终止条件:若满足,则结束搜索过程,输出优化值;若不满足,则继续进行迭代优化。
优化结束后,其适应度进化曲线如下图所示,最优个体 x= 7.8569,函数 f(x)的最大值为 24.8554。这个值不是固定的,每次执行都会有些许波动。
遗传算法的具体流程图如下:
完整的matlab代码如下,注释很全:
%遗传算法求函数极值
clear
clc
NP = 50; %种群数量
L = 20; %二进制位串长度
Pc = 0.8; %交叉率
Pm = 0.1; %变异率
G = 100; %最大遗传迭代次数
Xs = 10; %个体最小值
Xx = 0; %个体最大值
f = randi([0,1],NP,L); %随机获得初始种群
%遗传算法
for k = 1:G
for i = 1:NP
U = f(i,:); %遍历每个种群
m = 0;
for j = 1:L %遍历种群的每个二进制位
m = U(j)*2^(j-1)+m ; %将二进制转换成十进制
end
x(i) = Xx+m*(Xs-Xx)/(2^L-1); %对染色体进行解码得到个体
Fit(i) = func1(x(i)); %通过目标函数计算个体的适应度
end
maxFit = max(Fit); %适应度最大值
minFit = min(Fit); %适应度最小值
rr = find(Fit==maxFit); %找到适应度最大值的的位置
fBest = f(rr(1,1),:); %最适应的种群
xBest = x(rr(1,1)); %最适应的染色体,即个体
Fit = (Fit-minFit)/(maxFit-minFit); %归一化适应度值
%基于轮盘赌法的选择操作
sum_Fit = sum(Fit) ; %对适应度进行求和
fitvalue = Fit./sum_Fit; %求每个适应度被选中的概率
fitvalue = cumsum(fitvalue) ; %得到累加后的概率
ms = sort(rand(NP,1)) ; %随机生成概率值,并由小到大排序
fiti = 1;
newi = 1;
while newi <= NP
if ms(newi) < fitvalue(fiti) %如果随机生成的概率值小于被选中的概率
nf(newi,:) = f(fiti,:); %找到选择出来的染色体
newi = newi+1;
else %不满足条件,继寻找合适的染色体
fiti = fiti+1;
end
end
%交叉操作,就是二进制对应0和1的互换
for i = 1:2:NP %遍历种群
p = rand ; %随机产生的一个概率
if p > Pc %要保证随机产生的概率大于交叉率
q = rand(1,L);
for j = 1:L
if q(j)==1 %只要随机产生的位置等于1,就进行交叉
%将被选择的二级制进行交换,即交叉
temp = nf(i+1,j);
nf(i+1,j) = nf(i,j);
nf(i,j) = temp;
end
end
end
end
%变异操作,就是二进制取反操作
i = 1;
while i <= round(NP*Pm)
h = randi([1,NP],1,1); %随机选取一个需要变异的染色体
for j = 1:round(L*Pm)
g = randi([1,L],1,1); %随机选取需要变异的基因数
nf(h,g) =~ nf(h,g); %取反变异
end
i = i+1;
end
f = nf; %更新种群
f(1,:) = fBest; %保留最优个体在新种群中
trace(k) = maxFit; %保存最优的适应度
end
disp('最优个体如下:') ;
disp(xBest) ;
disp('函数最大值:') ;
disp(func1(xBest)) ;
figure
plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')
适应度函数即目标函数如下:
function result = func1(x)
fit = x+10*sin(5*x)+7*cos(4*x);
result = fit;
end
迭代过程的适应度进行如下,最终的值在24.85左右,即函数的最值为24.85左右。
2.2、遗传算法求解函数极小值问题
(1)初始化种群数目为 NP=100,染色体的编码方式选择二级制编码,二进制编码长度为 L=10,遗传算法的最大进化迭代数为 G=1000,交叉概率 取Pc=0.8,变异概率取Pm=0.1。
(2)产生初始种群,将二进制编码转换成十进制,计算个体适应度值;采用基于轮盘赌的选择操作、基于概率的交叉和变异操作,产生新的种群,并把历代的最优个体保留在新种群中,进行下一步遗传操作。
(3)判断是否满足终止条件:若满足,则结束搜索过程,输出优化值;若不满足,则继续进行迭代优化。
%遗传算法求函数极值
clear
clc
NP = 100; %种群数量
L = 10; %二进制位串长度
Pc = 0.8; %交叉率
Pm = 0.1; %变异率
G = 1000; %最大遗传迭代次数
Xs = 20; %个体上限
Xx = -20; %个体下线
f = randi([0,1],NP,L); %随机获得初始种群
%遗传算法
for k = 1:G
for i = 1:NP
U = f(i,:); %遍历每个种群
m = 0;
for j = 1:L %遍历种群的每个二进制位
m = U(j)*2^(j-1)+m ; %将二进制转换成十进制
end
x(i) = Xx+m*(Xs-Xx)/(2^L-1); %对染色体进行解码得到个体
Fit(i) = -func2(x(i)); %通过目标函数计算个体的适应度
end
maxFit = max(Fit); %适应度最大值
%minFit = min(Fit); %适应度最小值
rr = find(Fit==maxFit); %找到适应度最小值的的位置
fBest = f(rr(1,1),:); %最适应的种群
xBest = x(rr(1,1)); %最适应的染色体,即个体
% Fit = (Fit-minFit)/(maxFit-minFit); %归一化适应度值
%基于轮盘赌法的选择操作
sum_Fit = sum(Fit) ; %对适应度进行求和
fitvalue = Fit./sum_Fit; %求每个适应度被选中的概率
fitvalue = cumsum(fitvalue); %得到累加后的概率
ms = sort(rand(NP,1)) ; %随机生成概率值,并由小到大排序
fiti = 1;
newi = 1;
while newi <= NP
if ms(newi) < fitvalue(fiti) %如果随机生成的概率值小于被选中的概率
nf(newi,:) = f(fiti,:); %找到选择出来的染色体
newi = newi+1;
else %不满足条件,继寻找合适的染色体
fiti = fiti+1;
end
end
%交叉操作,就是二进制对应0和1的互换
for i = 1:2:NP %遍历种群
p = rand ; %随机产生的一个概率
if p > Pc %要保证随机产生的概率大于交叉率
q = rand(1,L);
for j = 1:L
if q(j)==1 %只要随机产生的位置等于1,就进行交叉
%将被选择的二级制进行交换,即交叉
temp = nf(i+1,j);
nf(i+1,j) = nf(i,j);
nf(i,j) = temp;
end
end
end
end
%变异操作,就是二进制取反操作
i = 1;
while i <= round(NP*Pm)
h = randi([1,NP],1,1); %随机选取一个需要变异的染色体
for j = 1:round(L*Pm)
g = randi([1,L],1,1); %随机选取需要变异的基因数
nf(h,g) =~ nf(h,g); %取反变异
end
i = i+1;
end
f = nf; %更新种群
f(1,:) = fBest; %保留最优个体在新种群中
trace(k) = -maxFit; %保存最大的适应度
end
disp('最优个体如下:') ;
disp(xBest) ;
disp('函数最小值:') ;
disp(func2(xBest)) ;
figure
plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')
适应度函数如下:
function result=func2(x)
summ=sum(x.^2);
result=summ;
end
运行结果如下:
2.3、遗传算法求解旅行商问题(TSP)
[旅行商问题](TSP)。假设有一个旅行商人要拜访全国31个省会城市,他需要选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。对路径选择的要求是:所选路径的路程为所有路径之中的最小值。全国31个省会城市的坐标为[1304 2312;3639 1315;4177 2244;37121399;3488 1535;3326 1556;3238 1229;4196 1004;4312 790;4386 570;3007 1970;2562 1756;2788 1491;2381 1676;1332695;3715 1678;3918 2179;4061 2370;3780 2212;3676 2578;4029 2838;4263 2931;3429 1908;3507 2367;3394 2643;34393201;2935 3240;3140 3550;2545 2357;2778 2826;2370 2975]。
(1)初始化种群数目为NP=200,最大遗传迭代数目为G=1000,染色体基因个数为N=31,即城市数目。
(2)产生初始种群,计算个体适应度值,即路径长度;采用基于概率的方式选择进行操作的个体;对选中的成对个体,随机交叉所选中的成对城市坐标,以确保交叉后路径每个城市只到访一次;对选中的单个个体,随机交换其一对城市坐标作为变异操作,产生新的种群,进行下一次遗传操作。
(3)判断是否满足终止条件:若满足,则结束搜索过程,输出优化值;若不满足,则继续进行迭代优化。
Matlab代码如下:
%遗传算法解决TSP问题
clear
close all;
clc;
C=[1304 2312;3639 1315;4177 2244;3712 1399;3488 1535;3326 1556;...
3238 1229;4196 1044;4312 790;4386 570;3007 1970;2562 1756;...
2788 1491;2381 1676;1332 695;3715 1678;3918 2179;4061 2370;...
3780 2212;3676 2578;4029 2838;4263 2931;3429 1908;3507 2376;...
3394 2643;3439 3201;2935 3240;3140 3550;2545 2357;2778 2826;...
2370 2975];%省会城市坐标
N=size(C,1);%C的行数,即城市数目
D=zeros(N);%N*N的零矩阵,初始化任意两个城市距离间隔矩阵
%求任意两个城市距离间隔矩阵
for i=1:N
for j=1:N
D(i,j)=((C(i,1)-C(j,1))^2+(C(i,2)-C(j,2))^2)^0.5;
end
end
NP=200;%种群数目
G=1000;%最大遗传迭代数
f=zeros(NP,N);%NP*N的零矩阵,用于存储种群
F=[];%种群更新中间存储
for i=1:NP
f(i,:)=randperm(N);%1~N之间的随机数,随机生成初始种群
end
R=f(1,:);%用于存储最优种群
len=zeros(NP,1);%用于存储路径长度
fitness=zeros(NP,1);%用于存储归一化适应值
gen=0;
%遗传算法循环,小于最大遗传迭代次数,则继续更新下一代
while gen<G
%计算路径长度
for i=1:NP
len(i,1)=D(f(i,N),f(i,1));
for j=1:(N-1)
len(i,1)=len(i,1)+D(f(i,j),f(i,j+1));
end
end
maxlen=max(len);%最长路径
minlen=min(len);%最短路径
%更新最短路径
rr=find(len==minlen);
R=f(rr(1,1),:);
%计算归一化适应值
for i=1:length(len)
fitness(i,1)=(1-((len(i,1)-minlen)/(maxlen-minlen+0.001)));
end
%选择操作
nn=0;
for i=1:NP
if fitness(i,1)>=rand
nn=nn+1;
F(nn,:)=f(i,:);
end
end
[aa,bb]=size(F);
while aa<NP
nnper=randperm(nn);
A=F(nnper(1),:);
B=F(nnper(2),:);
%交叉操作
W=ceil(N/10);%交叉点个数
p=unidrnd(N-W+1);%随机选择交叉范围,从p到p+W
for i=1:W
x=find(A==B(p+i-1));
y=find(B==A(p+i-1));
temp=A(p+i-1);
A(p+i-1)=B(p+i-1);
B(p+i-1)=temp;
temp=A(x);
A(x)=B(y);
B(y)=temp;
end
%变异操作
p1=floor(1+N*rand());
p2=floor(1+N*rand());
while p1==p2
p1=floor(1+N*rand());
p2=floor(1+N*rand());
end
tmp=A(p1);
A(p1)=A(p2);
A(p2)=tmp;
tmp=B(p1);
B(p1)=B(p2);
B(p2)=tmp;
F=[F;A;B];
[aa,bb]=size(F);
end
if aa>NP
F=F(1:NP,:);%保持种群规模为n
end
f=F;%更新种群
f(1,:)=R;%保留每代最优个体
clear F;
gen=gen+1 ;
Rlength(gen)=minlen;
end
figure
for i=1:N-1
plot([C(R(i),1),C(R(i+1),1)],[C(R(i),2),C(R(i+1),2)],'bo-');
hold on;
end
title(['优化最短距离:',num2str(minlen)]);
figure
plot(Rlength)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')
运行结果如下:
2.4、遗传算法求解背包问题
[0-1背包问题]。有N件物品和一个容量为V的背包。第i件物品的体积是c(i),价值是w(i)。求解将哪些物品放入背包可使物品的体积总和不超过背包的容量,且价值总和最大。假设物品数量为10,背包的容量为300。每件物品的体积为[95,75,23,73,50,22,6,57,89,98],价值为[89,59,19,43,100,72,44,16,7,64]。
(1)初始化种群数目为Np =50,染色体基因维数为L=10,最大进化代数为G=100。
(2)产生二进制初始种群,其中1表示选择该物品,0表示不选择该物品。取适应度值为选择物品的价值总和,计算个体适应度值,当物品体积总和大于背包容量时,对适应度值进行惩罚计算。
(3)对适应度进行归一化,采用基于轮盘赌的选择操作、基于概率的交叉和变异操作,产生新的种群,并把历代的最优个体保留在新种群中,进行下一步遗传操作。
(4)判断是否满足终止条件:若满足,则结束搜索过程,输出优化值;若不满足,则继续进行迭代优化。
matlab代码如下:
%遗传算法解决0-1背包问题
clear
close all;
clc;
NP = 50;%种群规模
L = 10;%物品件数
Pc = 0.8;%交叉率
Pm = 0.05;%变异率
G = 100;%最大遗传代数
V = 300;%背包容量
C = [95,75,23,73,50,22,6,57,89,98]; %物品体积
W = [89,59,19,43,100,72,44,16,7,64];%物品价值
afa = 2; %惩罚函数系数
f = randi([0,1],NP,L);%随机获得初始种群
maxFit = 0 ;
%遗传算法循环部分
for k = 1:G
%适应度计算,即计算总价值
for i = 1:NP
Fit(i) = func4(f(i,:),C,W,V,afa);
end
maxFit = max(Fit);%最大价值
minFit = min(Fit);%最小价值
rr = find(Fit==maxFit);
fBest = f(rr(1,1),:);%历代最优个体
Fit = (Fit - minFit)/(maxFit - minFit);%归一化适应度值
%基于轮盘赌的选择
sum_Fit = sum(Fit); %求适应度和
fitvalue = Fit./sum_Fit;%求被选中的概率
fitvalue = cumsum(fitvalue);%累加
ms = sort(rand(NP,1)); %随机生成的概率,并按照由小到大排序
fiti = 1;
newi = 1;
while newi <= NP
if (ms(newi)) < fitvalue(fiti) %被选中的概率大于随机生成的
nf(newi,:) = f(fiti,:); %选择复制
newi = newi + 1;
else
fiti = fiti + 1;
end
end
%基于概率的交叉操作
for i = 1:2:NP
p = rand;
if p > Pc
q = randi([0,1],1,L);
for j = 1:L
if q(j)==1;
temp = nf(i + 1,j);
nf(i + 1,j) = nf(i,j);
nf(i,j) = temp;
end
end
end
end
%基于概率的变异操作
for m = 1:NP
for n = 1:L
r = rand(1,1);
if r < Pm
nf(m,n) = ~nf(m,n);
end
end
end
f = nf;
f(1,:) = fBest; %保留最优个体在新种群中
trace(k) = maxFit; %历代最优适应度
end
disp('最优个体如下:') ;
disp(fBest) ;
disp('最大价值如下:') ;
disp(maxFit) ;
figure
plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')
适应度函数的代码如下:
%适应度函数,求物品价值总和
function result = func4(f,C,W,V,afa)
fit = sum(f.*W); %物品价值总和
TotalSize = sum(f.*C); %物品总体积
if TotalSize <= V %物品总体积小于背包容量
fit = fit;
else %物品总体积大于背包容量
fit = fit - afa * (TotalSize - V);
end
result = fit;
end
运行结果如下:其实10个物品,1表示选择该物品,0表示不选择该物品,最后的最大总价值为388
以上是关于备战数学建模37-遗传算法GA(攻坚战1)的主要内容,如果未能解决你的问题,请参考以下文章