问题:利用遗传算法求法f(x)=x*sin(10*pi*x)+2,-1<=x<=2时的最大值
大概步骤就是:
1.随机生成种群,就是-1到2之间的数,只关注保留了小数点后的4位,本来以为是matlab只保留4位小数然而并不是。(问题不大)
2.通过适应度进行选择,就是适应度越高越容易保留下来。这里通过轮盘赌的方式来确定哪些种群留下来。其实是有些个体增加了一下,有些不要啦。比如开始种群为三个个体:0.1111,1.2222,- 0.1111,经过选择后可能变成了:0.1111,1.2222,1.2222。只是可能变成这样额,还有可能是其他情况额。
3.交叉,相当于就是两个个体互相交换基因啦。比如有两个个体:0.1111,1.2222;经过交叉后可能变成:0.1211,1.2122。也仅仅其中可能的一种情况额,到底是哪一位进行交叉是随机的,而且交叉也不定一定进行,只是有一定概率进行而已;
4.变异,这个就是只作用与单个个体;比如有个个体:0.1111,变异后:0.1211。这个变异规则应该有好多种,看自己设吧。下面程序中就是让原来的数加上0.0001当作是变异,当然也可以把+0.01当作变异。变异也只是有可能进行额,它也有可能不进行。
5.变异完后,就是所有的个体就组成新的种群了。就又可以重复1.中的操作啦。
遗传算法,直接贴代码啦。
%%%%%%利用遗传算法求法f(x)=x*sin(10*pi*x)+2,-1<=x<=2时的最大值
%程序问题太多啦,说不定x就跑到定义域外去了,还会找到最小值
%如果定义变异时,是加0.1结果就很奇怪,反正还有好多值得改进的地方,但是用来理解GA算法应该足够啦,感觉也可以把十进制变成2进制来进行操作
clc;close all;clear;
a = -1;%求解区间下界
b = 2;%求解区间上界
cAccuracy = 0.01;%计算精度
NP = 100;%种群的个体数,也就是开始随机生成-1到2上的数的个数
NG = 100;%进化的代数generation
Pc = 0.1;%交叉概率
Pm = 0.5;%变异概率
%%
population = a+(b-a)*rand(1,NP);%随机产生种群,就是-1到2之间的随机数
for generation = 1:NG%大循环,表示经过的代数
%% 选择
fitness = population.*sin(10*pi*population)+2; %适应度函数,因为算出的适应度都是正的,所以可以直接用fx作适应度,但如果有负的,应该就不可以啊
Pfit = fitness/sum(fitness);
for i = 1:NP
disk(i) = sum(Pfit(1:i)); %通过fitness弄出一个(0,1]的轮盘,来进行轮盘赌
end
disknum = rand(1,NP) ;
populationIndex = zeros(1,NP);
for i = 1:NP
for j = 1:NP
if (disknum(i)<=disk(j))
populationChosed(i) = population(j); %通过轮盘赌选择种群population中那些被淘汰,哪些增加啦。可以产生产生新的种群
break;
end
end
end
%% 交叉
for i = 1:NP
for j = 1:6 %这里因为matlab保留了小数点后4位数,加上个位和符号,所以选择了6,应该可以改成任意位数,
populationtemp(i,j)=floor(mod((abs(populationChosed(i)))/10^(-j+1),10)); %将populationChosed的个位,10^-1位..分别存到矩阵中好进行交叉变异
if(populationChosed(i)<0)
populationtemp(i,6)=-1;%存储符号
else
populationtemp(i,6)=1;
end
end
end%%%%上面就是把数的个位,十位(虽然没十位)分别放到数组里用来进行交叉和变异操作
randindex = randperm(NP);%任意两组组合
crossbit = ceil(5*rand(1,NP/2));%交叉的位
for i = 1:2:NP-1
if(rand()<Pc)%交叉是可能发生也可能不发生,满足一定的概率Pc
temp = populationtemp(i,crossbit((i+1)/2));
populationtemp(randindex(i),crossbit((i+1)/2)) = populationtemp(2,crossbit((i+1)/2));%%交叉过程
populationtemp(randindex(i+1),crossbit((i+1)/2)) = temp;
end
end
populaitonCrossed=zeros(NP,1);
for j=1:5
populaitonCrossed = populationtemp(:,j)*10^(-j+1)+populaitonCrossed;%将交叉后的数组重新变成正常的数
end
populaitonCrossed = populaitonCrossed.*populationtemp(:,6);%还要保证正负和交叉以前一样,其实感觉正负也可以当作交叉位的
%% 变异
for i = 1:NP
if(rand()<Pm)%变异发生的概率是Pm
populationmeta(i) = populaitonCrossed(i)+0.0001;%变异就是加0.0001
else
populationmeta(i) = populaitonCrossed(i); %不变异保持原样
end
end
population=populationmeta;
figure;
x=-1:0.011:2;
fx=x.*sin(10*pi*x)+2;
plot(x,fx);
hold on
fxpop = population.*sin(10*pi*population)+2;
stem(population,fxpop);
hold off
saveas(gca,['figure_',num2str(generation),'.jpg']);
end
再附一张gif图吧