💯Genetic Algorithm
1.遗传算法有三个基本操作:选择、交叉、变异
- 选择:选择出优良个体,使他有机会作为父代为下一代繁衍子孙
- 交叉:个体随机搭配,以交叉概率交换部分染色体,得到新的个体,继承父类特性
- 变异:概率低,生产新个体
2.步骤
- 选择算子
- 二元锦标赛选择
- 从父代种群中随机选择2个个体
- 比较2个个体的适应度
- 适应度值最大的个体被选中,其余淘汰
function p = BTS(Parent)
% 二元锦标赛选择
% 先读取父代有多少个个体
n = numel(Parent);
% 随机生成一个序列
index = randperm(n);
% 选择2个个体出来(第一个、第二个)
players = Parent(index(1 : 2));
% 降序排列,存储下标
[~ , so] = sort([players.firness],'descend');
% 等于第一个个体
p = players(so(1));
end
- 多元锦标赛选择
- 从父代种群中随机选择N个个体
- 比较N个个体的适应值
- 适应度最大的个体被选中,其余淘汰
function p = MTS(Parent,count)
n = numel(Parent);
if count >= n
error(‘设置参赛个体数必须小于父代种群规模!’
else
% 随机生成一个序列
index = randperm(n);
% 选择多个个体出来
players = Parent(index(1:count));
% 降序排列,存储下标
[~ , so] = sort([players.fitness],'descend');
p = players(so(1));
end
end
- 轮盘赌选择
- 计算每个个体的相应适应度值(轮盘面积)
- 计算每个个体的累计概率
- 轮盘选择个体,被选中的概率域 个体适应度成正比
function p = RWS(Parent)
% 计算相对适应度值
Px = [Parent.fitness] ./ sum([Parent.fitness]);
% 计算累积概率(归一化的处理)
Cx = cumsum(Px);
% 找到随机点落在线上的区间
i = find(rand <= Cx,1,'frist');
p = Parent(i);
end
- 交叉算子
- 单点交叉
function [y1,y2] = crossPop(x1,x2)
% 单点交叉
% 先获取长度
n = numel(x1);
% 选择一个交换点,进行交换(不可以选择最后一个点)
s = randi([1,n - 1]);
% 将其重组,完成交叉操作
y1 = [x1(1 : s) x2(s + 1 : end)];
y2 = [x2(1 : s) x1(s + 1 : end)];
end
- 多点交叉
function [o1,o2] = MPC(p1,p2)
% 多点交叉
% 先获取长度
n = numel(p1);
% 选择两个交换点,进行交换,randperm:生产2个不可重复的数
s = randperm(n - 1,2);
point1 = min(s);
point2 = max(s);
o1 = [p1(1 : point1) p2(point1 + 1 : point2) p1(point2 + 1 : end)];
o2 = [p2(1 : point1) p1(point1 + 1 : point2) p2(point2 + 1 : end)];
end
- 均匀交叉
function [o1,o2] = UC(p1,p2)
n = numel(p1);
% alpha是一个数组
alpha = randi([0,1],1,n);
o1 = alpha .* p1 + (1 - alpha) .* p2;
o1 = alpha .* p2 + (1 - alpha) .* p1;
end
- 变异算子
- 单点变异
function o = SPM(p,nMu)
if rand <= nMu
n = numel(p);
s = randi([1,n]);
% 二进制编码,反转
p(s) = 1 - p(s);
end
o = p;
end
- 均匀变异
function o = UM(p,nMu)
r = rand(size(p));
% 找到小于变异概率的位置
index = find(r <= nMu);
% 找到原来的位置
p(index) = 1 - p(index);
o = p;
end
nMu大,单点变异快
nMu小,均匀变异快
3. 实例
实例一:y = sum(x);
clc;clear
nVar = 100;
%种群的规模大小,会生成30个个体
nPop = 30;
% 定义最大的迭代次数
maxIt = 3000;
% 交叉比例
nPc = 0.8;
% 变异概率
nMu = 0.01
% 子代规模的大小(奇数与奇数进行交叉,返回奇数)
nC = round(nPop * nPc / 2) * 2;
% 定义一个结构体,想让x和y具有绑定的关系
template.x = [];
template.y = [];
% 初始化种群用parent接受,代表父代种群
Parent = repmat(template,nPop,1);
for i = 1 : nPop
% 模板定义好,就可以初始化种群
Parent(i).x = randi([0,1],1,nVar);
%计算适应度值
Parent(i).y = fun(Parent(i).x);
end
for It = 1 : maxIt
% 子代的数据存放模板定义一下(子代是时刻刷新的)
Offspring = repmat(template,nC / 2,2);
% 先生成12 * 2 的子代中心
for j = 1 : nC / 2
% 先选择2个个体
p1 = selectPop(Parent);
p2 = selectPop(Parent);
% 进行交叉的操作
[Offspring(j,1).x,Offspring(j,2).x] = crossPop(p1.x,p2.x)
end
% 变异的过程
Offspring = Offspring(:)
% 对子代进行遍历
for k = 1 : nC
Offspring(k).x = mutatePop(Offspring(k).x,nMu);
% 计算y值
Offspring(k).y = fun(Offspring(k).x);
end
% 对子代进行筛选
% 将父代和子代进行拼接
newPop = [Parent;Offspring];
% 排序
[~,so] = sort([newPop.y],'ascend');
% 根据下标刷新一下
newPop = newPop(so);
% 将其变为父代
Parent = newPop(1:nPop);
disp(['迭代次数:',num2str(It),'最小值:',num2str(Parent(1).y)]);
end
function p = selectPop(Parent)
% 锦标赛选择法
n = numel(Parent); % 先读取父代有多少个个体
% 随机生成一个序列,选择2个个体出来
index = randperm(n);
% 每次会生成不同的30个个体,我们把1/2进行比赛
p1 = Parent(index(1));
p2 = Parent(index(2));
if p1.y <= p2.y
p = p1;
else
p = p2
end
end
function [y1,y2] = crossPop(x1,x2)
% 单点交叉
% 先获取长度
n = numel(x1);
% 选择一个交换点,进行交换(不可以选择最后一个点)
s = randi([1,n - 1]);
% 将其重组,完成交叉操作
y1 = [x1(1 : s) x2(s + 1 : end)];
y2 = [x2(1 : s) x1(s + 1 : end)];
end
function p = mutatePop(x,mu)
% 单点变异
% mu:变异概率
if rand <= mu
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
function y = fun(x)
y = sum(x);
end
实例二:y = x .^ 3 + 3 * x + 15;求最大值
clc;clear;
% 区间的最大值和最小值
xmin = -10;
xmax = 10;
% 二进制编码的长度(染色体长度小,就快,但是精度低)
nVar = 10;
% 种群的规模
nPop = 30;
% 最大的迭代次数
maxIt = 50;
% 每次进化可以产生多少个体(比例控制)
nPc = 0.8;
% 变异概率
nMu = 0.01;
% 初代种群的个数
nC = round(nPop * nPc / 2) * 2;
% 模板(将十进制的存储)
template.x = [];
template.x_dec = [];
template.y = [];
% 模板三十行,一列
Parent = repmat(template,nPop,1);
% 记录每一次迭代的最优个体
best = zeros(nPop,1);
% 初始化种群->得到初代的种群
for i = 1 : nPop
% 将Parent的每个x生成一行12列的数组
Parent(i).x = randi([0,1],1,nVar);
% 把二进制结果转换为我们需要的十进制范围里面
Parent(i).x_dec = xmin + (xmax - xmin) * bin2dec(num2str(Parent(i).x)) / ( 2 ^ nVar - 1);
Parent(i).y = fun( Parent(i).x_dec);
end
for it = 1 : maxIt
% 子代变成2列的形式,便于交叉
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
% 将分为2段的恢复,恢复为一列的形式
Offspring = Offspring(:);
% 变异
for k = 1 : nC
Offspring(k).x = mutatePop(Offspring(k).x,nMu);
Offspring(k).x_dec = xmin + (xmax - xmin) * bin2dec(num2str(Offspring(k).x)) / ( 2 ^ nVar - 1);
Offspring(k).y = fun( Offspring(k).x_dec);
end
%组合,将父代
newPop = [Parent;Offspring];
% 排序
[~,so] = sort([newPop.y],'descend');
newPop = newPop(so);
% 筛选+淘汰(保证父代种群只有三十个)
Parent = newPop(1 : nPop) ;
% 最优个体存放
best(it,1) = Parent(1).y;
end
plot(best)
选择、变异、交叉变异同实例1