该算法的选择、交叉、变异操作都采用了基础的方法,操作方法在代码的注释给出:
选择:二元锦标赛选择法;
交叉:单点交叉;
变异:单点变异
1.主程序 main
clc;clear
nVar = 100; %定义一个变量来接受x的长度
nPop = 30; %定义种群大小
maxIt = 2000; %定义最大种群迭代次数
%在进行选择、交叉、变异之前要先定义子代规模大小
nPc = 0.8; %代表交叉比列
nC = round(nPop * nPc / 2) * 2; %代表子代规模的大小;其中做了偶数化处理
nMu = 0.01; %变异概率
template.x = []; %定义结构体来存储变量x、y 后面经常要用到,所以下面直接生成一个模板
template.y = [];
Parent = repmat(template, nPop, 1); %初始化种群之后的变量,用Parent来接收,代表他是一个父代种群 repmat()矩阵复制命令
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); %定义子代规模后,定义子代数据存放的模板;子代种群会刷新,写进循环内,防止数据不断增长
for j = 1 : nC / 2 %首先生成一个12*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); %变异
offspring(k).y = fun(offspring(k).x); %调用fun()函数,计算y值
end
% 进行种群筛选,如果不进行种群筛选,种群会越来越庞大
newPop = [Parent; offspring];
[~,so] = sort([newPop.y], 'ascend');
newPop = newPop(so);
Parent = newPop(1 : nPop); %进行筛选,只保留前30个,同时前30个也最接近我们需要的结果
disp(['迭代次数:', num2str(It), ',最小值为:', num2str(Parent(1).y)]);
end
2.选择 selectPop
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
3.交叉 crossPop
function [y1,y2] = crossPop(x1,x2) %传进两个个体让他们去交叉
%单点交叉,交换随机点后面的元素,随机点不能为最后一位!
n = numel(x1); %先获取x长度
s = randi([1, n - 1]); %随机生成随机点且不能为最后一位
y1 = [x1(1 : s) x2(s + 1 : end)];
y2 = [x2(1 : s) x1(s + 1 : end)];
end
4.变异 mutatePop
function p = mutatePop(x, mu)
%单点变异:随机指定一个点,原来是1则变为0,原来是0则变为1;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