遗传算法的手工模拟计算示例(通俗易懂)(包含遗传算法原理、遗传算法代码)

下面是关于“遗传算法”的几个不错的学习资源

  1. 遗传算法介绍及手工模拟计算示例(文字版)
    遗传算法介绍及手工模拟计算示例(视频讲解版)

  2. 遗传算法原理介绍(包含二进制编码、解码原理,算法实现,视频讲解版)并分析了选择、交叉、变异的一些思路

学习笔记:

遗传算法简介

遗传算法(Genetic Algorithm,GA)是借鉴生物界进化规律(适者生存和优胜劣汰遗传机制)而演化出来的一类随机搜索算法。最早由美国Michigan大学的Holland教授于20世纪70年代首次提出,起源于60年代对自然和人工自适应系统的研究。复制该算法非常适合于处理传统优化方法难以解决的复杂的和非线性的优化问题。

遗传算法流程

ps概念:
基因:对应每个解的组成分量;
个体:单个个体,相当于待求解优化问题的一个解;
种群:很多个体组成的群体;
适应度:度量某个物种对于生存环境的适应程度;
选择:以一定的概率从种群中选择若干个个体,让其基因有机会遗传给下一代。一般来说,选择过程是一种基于适应度的优胜劣汰的过程;
交叉:两个染色体的某一相同位置DNA被切断,前后两串分别交叉组合成两个新的染色体,也即是基因重组或杂交;
变异:以一定概率将种群中一些交叉后的个体进行变异,产生新的染色体,也即是改变基因。

在这里插入图片描述

由遗传算法流程图可以看出,使用上述三种遗传算子(选择算子、交叉算子、变异算子)的遗传算法的主要运算过程如下所述:

  1. 初始化种群。设置迭代次数(进化代数)计数器t←0;设置最大迭代次数(进化代数)T;随机生成M个个体作为初始群体P(0)。
  2. 计算种群上每个个体适应度值。计算第t代群体P(t)中各个个体的适应度。
  3. 选择运算。将选择算子作用于群体。
  4. 交叉运算。将交叉算子作用于群体,按概率Pc进行交叉操作。
  5. 变异运算。将变异算子作用于群体,按概率Pm进行变异操作。第t代群体P(t)经过选择、交叉、变异运算之后得到下一代(t+1代)群体P(t+1)。
  6. 终止条件判断。若t≤T,则:t←t+1,转到步骤2;若t>T,则以进化过程中得到的具有最优适应度的个体作为问题的满意解或最优解输出,终止计算。

**PS:启发式算法背后的思想都是一样的——择优进化,即根据一定的策略使差的解向好的方向发展,使好的解变得更好。其中可以利用保底机制,即下一代的解若比上一代差,则不更新;下一代的解若比上一代好,则更新。 保底机制+更新策略+启发式思想=最优解/近似最优解

%% 遗传算法Matlab代码(此时示例的目标函数为f(x)=x.^2,求最小值)
%% 采用二进制编码方式;选择算子采用轮盘赌方式;交叉算子采用两点交叉法;变异算子采用基本位变异算子(即对于二进制编码符号串所表示的个体,若需要进行变异操作的某一基因座上的原有基因值为0,则将其变为1%% 参考up https://www.bilibili.com/video/BV14a411C7s8?spm_id_from=333.880.my_history.page.click&vd_source=77722e5d7039d559546697b243150ac0

%% 主程序
function GA()

clc
clear
popsize = 30;       % 种群大小
chromlength = 20;   % 串的长度(个体长度)
pc = 0.6;           % 交叉概率
pm = 0.2;           % 变异概率
xlim = [0,50];    % 求解范围
Maxiter = 200;            % 迭代次数
% x = zeros(1,Maxiter);     % 记录每代个体最优位置
% y = zeros(1,Maxiter);     % 记录每代最优个体对应的函数值

pop = round(rand(popsize,chromlength)); % 随机产生初始种群  直接生成的二进制串
% rand(popsize,chromlength)生成一个由介于 01 之间,即取值(0,1)的均匀分布的随机数组成的 popsize×chromlength 矩阵
% round(X) 将X的每个元素四舍五入为最近的整数。在对等情况下,即有元素的小数部分恰为 0.5 时,round 函数会偏离零四舍五入到具有更大幅值的整数。
% 这样随机生成的初试种群的值 非01
decpop = bintodec(pop,popsize,chromlength,xlim); % 计算初始解对应的十进制
fx = calobjvalue(decpop);  % 计算初始解的函数值,形状为1×popsize的矩阵
plotfig(decpop,fx,xlim,1); % 画出初始函数图
[y(1),I] = min(fx);        %[M,I] = mix(A) 返回 A 中最小值,以及最小值对应的索引。
x(1) = decpop(I);          % 获取最小值对应的变量x

for i = 2:Maxiter
    decpop = bintodec(pop,popsize,chromlength,xlim); % 计算上一代解对应的十进制
    fx = calobjvalue(decpop); % 计算上一代解的函数值
    fitvalue = calfitvalue(fx); % 适应度映射
    newpop = copyx(pop,fitvalue,popsize); % 复制
    newpop = crossover(newpop,pc,popsize,chromlength); %交叉
    newpop = mutation(newpop,pm,popsize,chromlength); % 变异
    % 这时的newpop是经过复制交叉变异产生的新一代群体
    % 下面进行选择择优保留(即优胜劣汰)
    newdecpop = bintodec(newpop,popsize,chromlength,xlim);
    new_fx = calobjvalue(newdecpop); % 计算新解目标函数
    new_fitvalue = calfitvalue(new_fx); % 计算新群体中所有个体的适应度
    index = find(new_fitvalue < fitvalue);  % find(X) 返回一个包含数组X中每个非零元素的线性索引的向量。即若新解的值小于更新前解的值,获取新解的索引(本示例是求最小值)
    
    pop(index,:) = newpop(index,:) % 更新得到最新解
    decpop = bintodec(pop,popsize,chromlength,xlim); % 计算新解的十进制
    fx = calobjvalue(decpop); % 计算结果
    plotfig(decpop,fx,xlim,i); % 绘制新解的图
    % 找出更新后的个体最优函数值
    [bestindividual,bestindex] = min(fx);
    y(i) = bestindividual; % 记录每一代的最优函数值
    x(i) = decpop(bestindex); % 十进制解
    subplot(1,2,2);
    plot(1:i,y);
    title('适应度进化曲线');
    i = i+1;
end
[ymin,min_index] = min(y);
disp(['最优解对应的位置为:', num2str(x(min_index))])
disp(['最优解为:', num2str(ymin)])
end

%% 计算适应度
function fitvalue = calfitvalue(fx)
% 这里求最小值,并且函数值又都大于等于0,所以直接使用函数值本身作为适应度值
% 不同的问题构造适应度函数的方法不同
fitvalue = fx;
end

%% 复制操作 按适应度大小映射为概率,进行轮盘赌复制
% 轮盘赌基本思想:适应度越高的解,按道理越应该高概率的进行复制,且复制的份数应该越多
function newx = copyx(pop,fitvalue,popsize) % 传进来二进制串和对应适应度值
% 利用轮盘赌策略对个体进行复制
newx = pop; % 只是起到申请size为pop大小空间的作用,newx之后要更新的
i = 1; j = 1;
p = fitvalue / sum(fitvalue);  % 对于每个个体,计算对应适应度.即被选择的概率
Cs = cumsum(p);            
% cumsum(A) 从 A 中的第一个其大小不等于 1 的数组维度开始返回 A 的累积和
% 如p为 0.2 0.1 0.4 0.3 则对应 Cs 为0.2 0.3 0.7 1.0
R = sort(rand(popsize,1)); % 每个个体的复制概率,升序排序
while j <= popsize
    if R(j) < Cs(i)
        newx(j,:) = pop(i,:);
        j = j+1;
    else
        i = i+1;
    end
end
end

%% 交叉操作 1234,以一定概率决定是否交叉。若交叉,则两者选择随机一个段进行交叉
function newx = crossover(pop,pc,popsize,chromlength)
% 12 34 56交叉方式,随机选择交叉位点
% 注意个体数为奇数偶数的区别
i = 2;
newx = pop; % 申请空间
while i+2 <= popsize
    % 将第i与i-1进行随机位点交叉
    if rand < pc
        x1 = pop(i-1,:);  % 第i-1个个体
        x2 = pop(i,:);    % 第i个个体
        r = randperm(chromlength,2); % 返回范围内两个整数   p = randperm(n,k)返回行向量,其中包含在 1 到n之间随机选择的k个唯一整数。
        r1 = min(r); r2 = max(r); % 交叉复制的位点
        newx(i-1,:) = [x1(1:r1-1),x2(r1:r2),x1(r2+1:end)];
        newx(i,:) = [x2(1:r1-1),x1(r1:r2),x2(r2+1:end)];
    end
    i = i + 2; % 更新i   2,4,6,8...
end
end

%% 变异 按照一定概率决定该个体是否变异,若变异,随机选择一个位点进行变异:按位取反
function newx = mutation(pop,pm,popsize,chromlength)
i = 1;
while i <= popsize
    if rand < pm
        r = randperm(chromlength,1);
        pop(i,r) = ~ pop(i,r);  % 按位取反
    end
    i = i+1;
end

newx = pop; % 将变异后的结果返回
end

%% 二进制转十进制函数
function dec = bintodec(pop,popsize,chromlength,xlim)
dec = zeros(1,chromlength);
index = chromlength-1:-1:0;  % chromlength=10 chromlength-1:-1:09 8 7 6 ... 0
for i = 1:popsize
    dec(i) = sum(pop(i,:).*(2.^index)); % 将二进制数转成十进制
end
dec = xlim(1) + dec*(xlim(2) - xlim(1)) / (2 ^ chromlength -1); % 获得二进制串对应的实值解
end

%% 绘制图像
function plotfig(decpop,fx,xlim,k)
f = @(x) (x.^2);
x = xlim(1):0.05:xlim(2);
y = f(x);
subplot(1,2,1);
plot(x,y,decpop,fx,'o');
title(['第',num2str(k),'次迭代进化'])
pause(0.1); % pause(n) 暂停执行 n 秒,然后继续执行。必须启用暂停,此调用才能生效。
end

%% 目标函数
function fx = calobjvalue(decpop) % 参数为十进制
f = @(x) (x.^2);
fx = f(decpop);
end



上面程序结果
在这里插入图片描述
遗传算法解决TSP问题代码实例

猜你喜欢

转载自blog.csdn.net/qq_41238751/article/details/126819070