本文将简单叙述遗传算法的原理及实现过程,并通过采用工具箱和非工具箱两种方法解决一个在约束条件下求解函数最小值的问题。
前言
遗传算法是1962年Holland教授基于进化机制和自然遗传学提出的一种启发式,并行,随机优化算法。它将待优化问题的求解过程表示成个体“适者生存”的进化过程。将问题的解表示成“染色体”(个体),由多个个体组成的群体经过数次选择,交叉,变异三个进化过程,最终得到最适应环境的个体,即待优化问题的最优解。
一、遗传算法实现过程
在遗传算法中,n维向量X = [x1,x2,…,xn]T可以看作由n个遗传基因组成的一个染色体。染色体X又叫做个体,对于每个个体,要按照一定规矩确定出其适应度。个体适应度与目标函数相关联,个体越接近于目标函数,其适应度越大。通过搜索染色体来解决问题的最优解。
进化过程是以集群为主体。由M个个体组成的群体作为遗传算法的运算对象。遗传算法的运算过程是一个反复迭代的过程。遗传算法包括选择,交叉,变异三个操作。
(1)选择:根据每一个个体的适应度,按照“进化”规则,从群体中选择优良的个体遗传到下一代。
(2)交叉:在群体中按照指定的交叉概率交换随机配对的个体的部分染色体。
(3)变异:在群体中按照指定的变异概率改变个体基因中的一个或者多个
二、matlab实现
1.工具箱实现
代码如下:
[x,fval]=ga(@fitnessfun,n,A,b,Aeq,beq,lb,ub,@nonlcon,options)
其中:
fitnessfun是求最小值的适应度函数;
n:问题待求变量的个数;
A,b分别是是不等式约束AX<=b的系数矩阵和常数项;
Aeq,beq分别是等式约束AeqX = beq的系数矩阵和常数项;
lb,ub分别是是X的下限和上限;
nonlcon是非线性约束函数。
x:待求最优值;
fval:适应度函数的最终值
options是一个包含遗传算法选项设置、属性参数的结构。具体格式如下:
options=gaoptimset('PropertyName1','PropertyValue1','PropertyName 2',' PropertyValue2','PropertyName3','PropertyValue3'......)
仿真例子:
求最小值的适应度函数:
function y=fun(x)
y=3*x(1)-2*x(2)+x(3);
end
主程序:
clear all;
clc;
A=[-1 0 0;1 0 0;0 -1 0;0 1 0;0 0 -1;0 0 1];
b=[-10;10;-10;10;-10;10];
Aeq=[1 1 1];
beq=18;
[x,y]=ga(@fun,3,A,b,Aeq,beq);
x
y
2.非工具箱实现
代码如下:
求最小值的适应度函数:
function y=fun(x)
y=3*x(1)-2*x(2)+(18-x(1)-x(2));
end
选择操作:
function ret=select(individuals,sizepop)
% 该函数用于进行选择操作
% individuals input 种群信息
% sizepop input 种群规模
% ret output 选择后的新种群
%求适应度值倒数
fitness1=1./individuals.fitness; %individuals.fitness为个体适应度值
%个体选择概率
sumfitness=sum(fitness1);
sumf=fitness1./sumfitness;
%采用轮盘赌法选择新个体
index=[];
for i=1:sizepop %sizepop为种群数
pick=rand;
while pick==0
pick=rand;
end
for i=1:sizepop
pick=pick-sumf(i);
if pick<0
index=[index i];
break;
end
end
end
%新种群
individuals.chrom=individuals.chrom(index,:); %individuals.chrom为种群中个体
individuals.fitness=individuals.fitness(index);
ret=individuals;
交叉操作:
function ret=Cross(pcross,lenchrom,chrom,sizepop,bound)
%本函数完成交叉操作
% pcorss input : 交叉概率
% lenchrom input : 染色体的长度
% chrom input : 染色体群
% sizepop input : 种群规模
% ret output : 交叉后的染色体
for i=1:sizepop %每一轮for循环中,可能会进行一次交叉操作,染色体是随机选择的,交叉位置也是随机选择的,%但该轮for循环中是否进行交叉操作则由交叉概率决定(continue控制)
% 随机选择两个染色体进行交叉
pick=rand(1,2);
while prod(pick)==0
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*v1+(1-pick)*v2; %交叉结束
flag1=test(lenchrom,bound,chrom(index(1),:)); %检验染色体1的可行性
flag2=test(lenchrom,bound,chrom(index(2),:)); %检验染色体2的可行性
if flag1*flag2==0
flag=0;
else flag=1;
end %如果两个染色体不是都可行,则重新交叉
end
end
ret=chrom;
变异操作:
function ret=Mutation(pmutation,lenchrom,chrom,sizepop,num,maxgen,bound)
% 本函数完成变异操作
% pcorss input : 变异概率
% lenchrom input : 染色体长度
% chrom input : 染色体群
% sizepop input : 种群规模
% opts input : 变异方法的选择
% pop input : 当前种群的进化代数和最大的进化代数信息
% bound input : 每个个体的上届和下届
% maxgen input :最大迭代次数
% num input : 当前迭代次数
% ret output : 变异后的染色体
for i=1:sizepop %每一轮for循环中,可能会进行一次变异操作,染色体是随机选择的,变异位置也是随机选择的,
%但该轮for循环中是否进行变异操作则由变异概率决定(continue控制)
% 随机选择一个染色体进行变异
pick=rand;
while pick==0
pick=rand;
end
index=ceil(pick*sizepop);
% 变异概率决定该轮循环是否进行变异
pick=rand;
if pick>pmutation
continue;
end
flag=0;
num = 0;
chrom1 = chrom(i,:);
while flag==0&&num<=20
% 变异位置
pick=rand;
while pick==0
pick=rand;
end
pos=ceil(pick*sum(lenchrom)); %随机选择了染色体变异的位置,即选择了第pos个变量进行变异
pick=rand; %变异开始
fg=(rand*(1-num/maxgen))^2;
if pick>0.5
chrom(i,pos)=chrom(i,pos)+(bound(pos,2)-chrom(i,pos))*fg;
else
chrom(i,pos)=chrom(i,pos)+(chrom(i,pos)-bound(pos,1))*fg;
end %变异结束
flag=test(lenchrom,bound,chrom(i,:)); %检验染色体的可行性
num = num+1; % 检验次数设置
end
if num>20 % 如果大于20次,则不变异
chrom(i,:) = chrom1;
end
end
ret=chrom;
编码:
function ret=Code(lenchrom,bound)
%本函数将变量编码成染色体,用于随机初始化一个种群
% lenchrom input : 染色体长度
% bound input : 变量的取值范围
% ret output: 染色体的编码值
flag=0;
while flag==0
pick=rand(1,length(lenchrom));
ret=bound(:,1)'+(bound(:,2)-bound(:,1))'.*pick; %线性插值,编码结果以实数向量存入ret中
flag=test(lenchrom,bound,ret); %检验染色体的可行性
end
测试函数:
function flag=test(lenchrom,bound,code)
% lenchrom input : 染色体长度
% bound input : 变量的取值范围
% code output: 染色体的编码值
t=code; %先解码
t3 =18-t(1)-t(2);
flag=1;
if (t(1)<bound(1,1))||(t(2)<bound(2,1))||(t(1)>bound(1,2))||(t(2)>bound(2,2))||t3<0||t3>10
flag=0;
end
主函数:
clc,clear,close all
% 遗传算法参数初始化
maxgen = 50; % 进化代数,即迭代次数
sizepop = 50; % 种群规模
pcross = [0.7]; % 交叉概率选择,0和1之间
pmutation = [0.01]; % 变异概率选择,0和1之间
%染色体设置
lenchrom=ones(1,2); % t1、t2
bound=[-10,10;-10,10;]; % 数据范围
%---------------------------种群初始化------------------------------------
individuals=struct('fitness',zeros(1,sizepop), 'chrom',[]); %将种群信息定义为一个结构体
avgfitness = []; %每一代种群的平均适应度
bestfitness = []; %每一代种群的最佳适应度
bestchrom = []; %适应度最好的染色体
% 初始化种群
for i=1:sizepop
% 随机产生一个种群
individuals.chrom(i,:)=Code(lenchrom,bound); % 编码(binary和grey的编码结果为一个实数,float的编码结果为一个实数向量)
x=individuals.chrom(i,:);
% 计算适应度
individuals.fitness(i)=fun(x); % 染色体的适应度
end
% 找最好的染色体
[bestfitness bestindex] = min(individuals.fitness);
bestchrom = individuals.chrom(bestindex,:); % 最好的染色体
% 记录每一代进化中最好的适应度和平均适应度
trace = [bestfitness];
% 迭代求解最佳初始阀值和权值
% 进化开始
for i=1:maxgen
disp(['迭代次数: ',num2str(i)])
% 选择
individuals=Select(individuals,sizepop);
% 交叉
individuals.chrom=Cross(pcross,lenchrom,individuals.chrom,sizepop,bound);
% 变异
individuals.chrom=Mutation(pmutation,lenchrom,individuals.chrom,sizepop,i,maxgen,bound);
% 计算适应度
for j=1:sizepop
x=individuals.chrom(j,:); % 解码
individuals.fitness(j)=fun(x); % 染色体的适应度
end
% 找到最小和最大适应度的染色体及它们在种群中的位置
[newbestfitness,newbestindex]=min(individuals.fitness);
[worestfitness,worestindex]=max(individuals.fitness);
% 代替上一次进化中最好的染色体
if bestfitness>newbestfitness
bestfitness=newbestfitness;
bestchrom=individuals.chrom(newbestindex,:);
end
individuals.chrom(worestindex,:)=bestchrom; % 剔除最差个体
trace=[trace;bestfitness]; %记录每一代进化中最好的适应度
end
x = [bestchrom, 20-sum(sum(bestchrom))]; % 最佳个体值
x
bestfitness
仿真结果:
总结
本文简述了遗传算法的原理及通过工具箱和非工具箱两种方法仿真实例。
遗传算法是一种自适应全局随机优化算法,是群体搜索策略和群体中个体之间的信息交换,搜索不依赖于梯度信息,搜索不依赖于初始点,基本上不用搜索空间的知识或其它辅助信息,不与求解空间有紧密关系。
关于算法的具体细节推荐:
MATLAB优化算法案例分析与应用
MATLAB优化算法案例分析与应用(进阶版)