1. 遗传算法的原理
网上实在太多了,这里就不过多赘述了
2. 主函数
% 遗传算法
% 求sum(x)的最小值(具体要求见fun.m)
clc;clear
nVar = 100; % x的长度
nPop = 30; % 种群规模大小为30
maxIt = 2000; % 最大迭代次数
nPc = 0.8; % 子代规模的比例
nC = round(nPop * nPc/2)*2;% 子代规模的大小 round()得出最接近的整数,同时进行偶数化操作
nMu = 0.01; % 变异概率为0.01
% 用结构体方式来存储变量,使得x,y有一个绑定的关系
template.x = []; % 模板
template.y = []; % 模板
% repmat函数主要是用于快速的产生一个大的矩阵
Parent = repmat(template,nPop,1); % 父染色体,产生一个30*1的矩阵,每行包括x和y
% 初始化种群
for i = 1 : nPop
Parent(i).x = randi([0,1],1,nVar); % 随机生成100个【0,1】的x值
Parent(i).y = fun(Parent(i).x); % 计算适应度,也就是目标函数
end
for It = 1 : maxIt
Offspring = repmat(template,nC/2,2); % 分成两列为了好进行数据的交叉操作
for j = 1 : nC/2
p1 = SelectPop(Parent);
p2 = SelectPop(Parent);
[Offspring(j,1).x, Offspring(j,2).x] = crossPop(p1.x, p2.x); % 进行交叉操作
end
Offspring = Offspring(:); % 变成列的形式,便于写for循环
for k = 1 : nC
Offspring(k).x = mutatePop(Offspring(k).x,nMu); % 进行变异操作
Offspring(k).y = fun(Offspring(k).x);
end
newPop = [Parent;Offspring]; % 新的种群
% ~是不输出此参数,sort返回的第一个参数是数值大小,第二个是索引,’ascend’为升序排列
[~,so]= sort([newPop.y],'ascend'); % 从小到大对y值进行排列
newPop = newPop(so); % 刷新种群排序
Parent = newPop(1 : nPop);
disp(['迭代次数:',num2str(It), ', 最小值为: ', num2str(Parent(1).y)])
end
3 . 选择函数
% 选择函数
function p = SelectPop(Parent)
% 锦标赛选择法
% 锦标赛方法选择策略每次从种群中取出一定数量个体,然后选择其中最好的一个进入子代种群
% 重复该操作,直到新的种群规模达到原来的种群规模
n = numel(Parent); % 父代种群的个数
index = randperm(n); % 随机打乱序列,选中前两个
p1 = Parent(index(1));% 第一个
p2 = Parent(index(2));% 第二个
if p1.y < p2.y
p = p1;
else
p = p2;
end
end
4.交叉函数(单点交叉)
% 交叉函数
function [y1,y2] = crossPop(x1, x2)
%单点交叉
n = numel(x1);% 算出x1的长度
s = randi([1, n-1]);% 随机选出一个交叉点,-1操作是因为如果选择最后一位,就相当于没有交叉
y1 = [x1(1:s) x2(s+1:end)];% 重组
y2 = [x2(1:s) x1(s+1:end)];% 重组
end
5.变异函数(单点变异)
% 变异函数
function p = mutatePop(x,mu)
% 单点变异
if rand <= mu % 单独一个rand是得到一个在(0,1)之间均匀分布的伪随机数
n = numel(x);
s = randi([1,n]);
if x(s) == 0
x(s) = 1;
elseif x(s) ==1
x(s) = 0;
end
end
p = x;
end
6.适应度函数
function y = fun(x)
% 计算输入x的和,x是【0,1】区间的正整数
y = sum(x);
end
% randi()函数
% randi(limin,imax].[m n])
% 产生m*n矩阵,这个矩阵的元素都是处于imin和imax之间的整数