上一篇博文写了遗传算法的主要思路,然后摸索了一下工具箱什么的,今天就把代码这个坑先填上。
顺序就按照上一篇博文里面写的步骤来:
问题描述:采用遗传算法和非线性规划的方法求解如下函数的极小值:
其中的变量都在0~0.9π之间。
该函数的最小值为-2,最小值位置为(π/2,π/2,π/2,π/2,π/2)。
1. 先是写适应度函数
个体的适应度是适应度函数值的倒数,上一篇博文中已经用红色字标注出来了,函数值越小的个体,适应度值越大,个体越优。
所以,代码如下:
function y = fun(x)
y = -5 * sin(x(1))*sin(x(2))*sin(x(3))*sin(x(4))*sin(x(5))-
sin(5*x(1))*sin(5*x(2))*sin(5*x(3))*sin(5*x(4))*sin(5*x(5))+8;
其实所谓的适应度函数就是题目所要求的函数,适应度的话,就在下面的程序中取1/y。
2. 选择操作
方法选用的是轮盘赌(一个for循环,取随机),然后组成新的种群。
function ret = select(individuals,sizepop)
%individuals input :种群信息
%sizepop input :种群规模
%opts input :选择方法
%ret input :重组的种群
individuals.fitness = 1./(individuals.fitness);
sunmfitness = sum (individuals.fitness); %求适应度的总和
sumf = individuals.fitness./sumfitness; %求每个函数值适应度的占比
index = []; %建立一个序列
for i = 1:sizepop; %开始轮盘赌
pick = rand; %这里把rand(0-1的随机数)理解成百分比比较好,作为一个概率的比较标准
while pick == 0
pick = rand;
end
for j = 1:sizepop
pick = pick - sumf(j);
if pick<0
index = [index j]; %这里其实就是进行pick和sumf的对比,
%如果pick比sumf小,就放入序列
break;
end
end
end
individuals.chrom = individuals.chrom(index,:);
individuals.fitness = individuals.fitness(index);
ret = individuals;
轮盘赌的想法就是模拟自然选择,把值的大小换算成面积,用随机值来模拟指针,值越大,选中的概率也就越大。
这里可能不是很好理解,在知乎上有很多大佬解读过轮盘赌的方法,比我这个更详细,可以去观摩。毕竟我这个算法只针对这道题。
3. 交叉操作
函数就不解释了,贴个链接:https://blog.csdn.net/zhangqimo/article/details/105292845
function ret = Cross(pcross,lenchrom,chrom,sizepop,bound)
%pcross input :交叉概率
%lenchrom input :%染色体长度
%chrom input :%染色体群
%sizepop input :种群规模
%ret output :交叉后的染色体
for i = 1 : sizepop
pick = rand(1,2);
while prod(pick) == 0 %prod函数是求矩阵元素的积
pick = rand(1,2);
end
index = ceil(pick.*sizepop);
pick = rand;
while pick = 0;
pick = rand;
end
if pick > pcross %如果大于交叉互换的概率就继续进行操作
continue;
end
flag = 0;
while flag == 0
pick = rand;
while pick == 0
pick = rand;
end
pos = ceil(pick.*sum(lenchrom)); %随机选择交叉位置(选择第几个变量进行互换)
pick = rand; %交叉开始
v1 = chrom(index(1),pos);
v2 = chrom(index(2),pos);
chrom(index(1),pos) = pick * v2 + (1-pick) *v1;
chrom(index(2),pos) = pick * v2 + (i-pick) *v2; %交叉结束
flag1 = test(lenchrom,bound,chrom(index(1),:),fcode); %bound为自变量取值的约
%束,该函数检验可行性
flag2 = test(lenchrom,bound,chrom(index(2),:),fcode);
if flag1 * flag2 ==0
flag = 0;
else flag = 1;
end %如果都不行,则重新交叉
end
end
ret = chrom;
4. 变异操作
是从种群中随机选择一个个体,按一定概率变异得到新个体。
function ret = Mutation(pmutation,lenchrom,chrom,sizepoppop,bound)
%pcross input :变异概率
%lenchrom input :染色体长度
%chrom input :染色体群
%sizepop input :种群规模
%pop input :当前种群的进化代数和最大的进化代数信息
%ret output :变异后的染色体
for i = 1 : sizepop
pick = rand; %随机选
while pick == 0
pick = rand;
end
index = ceil(pick * sizepop)
pick = rand;
if pick > pmutation
continue;
end
flag = 0;
while flag == 0;
pick = rand;
while pick == 0;
pick == 0;
end
pos = ceil(pick * sum(lenchrom));
v = chrom(i,pos);
v1 = v - bound(pos,1)
v2 = bound(pos,2) - v;
pick = rand;
%从这里开始变异
if pick>0.5
delta = v2*(1-pick^((1-pop(1)/pop(2))^2);
chrom(i,pos) = v + delta;
else
delta = v1*(1 - pick^((1-pop(1)/pop(2))^2));
chrom(i,pos) = v-delta;
end
flag = test(lenchrom,bound,chrom(i,:),fcode);
end
end
end
ret = chrom;
5. 主程序
遗传算法基本上就是:随机初始化——计算种群适应度,找最优——选择——交叉——变异——寻优——判断结束条件。
具体代码为:
心态有点炸,码的代码被猫一脚踹没了。心情好了更。
更新:主程序
clc
clear
maxgen = 100; %迭代次数
sizepop = 10; %种群规模
pcross = [0.5]; %交叉概率
pmutation = [0.05]; %变异概率
lenchrom = [1 1 1 1 1]; %变量长度
bound = [0 0.5*pi;0 0.5*pi;0 0.5*pi;0 0.5*pi;0 0.5*pi];
%初始化(个体)
individuals = struct('fitness',zeros(1,sizepop),'chrom',[]);
avgfitness = []; %平均适应度
bestfitness = []; %最佳适应度
bestchrom = []; %最佳染色体
%初始化(种群)
for i = 1 : sizepop
individuals.chrom(i,:) = Code(lenchrom,bound);
x = individuals.chrom(i,:);
individuals.fitness(i) = fun(x);
end
%找最优
[bestfitness bestindex] = min(individuals.fitness);
bestchrom = individuals.chrom(bestindex,:);
avgfitness = sum(individuals.fitness)/sizepop;
trace=[]; %记录每一代数值
%进化
for i = 1 :maxgen
%选择
individuals = Select(individuals,sizepop);
avgfitness = sum(individuals.fitness)/sizepop;
%交叉
individuals.chrom = Cross(pcross,lenchrom,individuals.chrom,sizepop,bound);
%变异
individuals.chrom = Mutation(pmutation,lenchrom,individuals.chrom,sizepop,[i maxgen],bound);
%以5代为界限,用求得数值作为初始值进行非线性寻优
if mod(i,5) == 0
individuals.chrom = nonlinear(individuals.chrom,sizepop);
end
%计算适应度
for j = 1:sizepop
x = individuals.chrom(j,:)
individuals.fitness(j) = fun(x);
end
%求最优值所在位置
[newbestfitness,newbestindex] = min(individuals.fitness);
%与上一轮进化求得最优值对比,若更优,则替换
if bestfitness > newbestfitness
bestfitness = newbestfitness;
bestchrom = individuals.chrom(newbestindex,:);
end
avgfitness = sum(individuals.fitness)/sizepop;
trace = [trace;avgfitness bestfitness]; %每一代数据记录
end
6. 非线性寻优
这里得调用工具箱里的fmincon
function ret = nonlinear(chrom,sizepop)
for i = 1 : sizepop
x = fmincon(inline('-5 * sin(x(1))*sin(x(2))*sin(x(3))*sin(x(4))*sin(x(5))-
sin(5*x(1))*sin(5*x(2))*sin(5*x(3))*sin(5*x(4))*sin(5*x(5))'),
chrom(i,:)',[],[],[],[],[0 0 0 0 0].[2.874 2.874 2.874 2.874 2.874]);
ret(i,:)=x';
end
以上就是代码的全部了。
鬼知道我保存了几遍,不得不感叹一句,猫主子的脚是厉害,每次刚好踩到Alt+F4.