遗传算法的代码实现

本章通过讲解一道例题,带大家介绍遗传算法如何用代码实现

一、问题提出

二、参数设置

NP为种群个体数,我们会在这么多数量的种群中进行基因的交换与变异。
惩罚系数是在计算适应度时用的,若我们的选择超出了适应度的范围,就把适应度减去一个比较大的数,而在实时脚本文件中,函数可以放在文件的最下面,这样就不用定义全局变量了

Np = 80;    % 种群个体数                        
N = 12;    % 物品数
V = 350;    % 背包容量  

Pc = 0.85;      % 交叉概率                  
Pv = 0.02;      % 变异概率
Gtime = 150;    % 遗传代数(迭代次数)                        
                           
C = [78,39,90,82,61,52,12,37,49,55,64,8];  % 物品体积
W = [64,37,22,41,76,34,22,21,10,57,32,12]; % 物品价值

alpha = 5;  % 惩罚系数

二、开始迭代,种群初始化

我们先随机获得一个初始的种群,利用randi函数生成一个由0-1组成的,80行12列的矩阵。一行代表一个个体,行上面的数字代表基因
t=1:Gtime代表我们要在80个个体中迭代Gtime次
在循环的开始,我们先要计算出每个个体的适应度,找到出适应度最优的个体

population = randi([0,1],Np,N);     %随机获得初始种群

% 开始迭代
for t = 1:Gtime
    % 求每个个体的适应度
    for i = 1:Np
         fit(i) = fitness(population(i,:),C,W,V,alpha);
    end
    maxfit = max(fit);  % 适应度最大值(本轮迭代最优解的函数值)
    minfit = min(fit);
    
    % find函数找到满足等式的元素(最优个体)下标(在群体里的序号是几),可能有多个
    findex = find(fit == maxfit);
    fBest = population(findex(1,1),:);  % 根据序号选中最优个体

三、进行轮盘赌法,选中适应度大的个体

我们想要选择适应度大的个体进行基因交叉(对应自然界中强者才有资格交配),但是这里我们并没有直接给适应度大的个体排序(因为适应度大,基因可能也非常相似,从而一直陷入局部最优),而是利用轮盘赌法,使得适应度大的个体有更大的概率被选中,但适应度小的个体也有一定的概率被选中
这里我们的fitvalue的最大值是1,但我们生成的数组最大值到不了1(开区间),因此不会出现fit_i比new_i先到Np的情况,所以我们在代码中设置跳出循环的条件是new_i > Np

fitvalue = fit ./ sum(fit);     % 被选中的概率,适应度越高的概率越大,累加为1

   fitvalue = cumsum(fitvalue);    % 累计概率。第i个元素,是原第1到i个元素之和
   bet = sort(rand(Np,1));         % 随机生成Np个(种群个体数)0到1的数并排序
   fit_i = 1;
   new_i = 1;
   while new_i <= Np
       % 排名第fit_i的个体,相应的累积概率大于轮盘中第new_i大的随机数时被选中
       if (fitvalue(fit_i)) > (bet(new_i))   
           %fprintf("选中第%d个个体,",fit_i)
           choosef(new_i,:) = population(fit_i,:);     % 该个体选中,赋值给choosef
           new_i = new_i + 1;  
           %fprintf("轮盘随机数变为%d;",new_i)
       else
           %fprintf("第%d个个体未被选中,",fit_i)
           fit_i = fit_i + 1;
           %fprintf("准备查看第%d个个体",fit_i)
       end
   end

四、基因交叉

对被选中的个体进行基因交叉,被交叉位置的基因由我们的随机数来决定

% 交叉操作:第i个个体和第i+1个个体,进行第j位的基因互换
    for i = 1:2:Np  % 第1个和第2个个体,第3和第4个个体……两两交叉
        p = rand;   % 随机生成一个0到1之间的数,满足均匀分布
        if p < Pc   % 交叉概率Pc=0.85,及有85%的概率满足if语句
            q = randi([0,1],1,N);  % 生成1行N列的矩阵,其中元素随机是0或1
            for j = 1:N            % 对于12个物品基因(0或1),随机选中某些基因来进行交叉
                if q(j) == 1        % 随机生成的q中该位置元素为1,意味着第j个物品基因被选中进行交叉
                    temp = choosef(i + 1,j);            % 第i+1个个体的第j个基因赋值给临时变量
                    choosef(i + 1,j) = choosef(i,j);    % 第i个个体的第j个基因赋值给第i+1个个体
                    choosef(i,j) = temp;                % 同样,第i+1个个体的第j个基因复制给第i个个体,完成交叉
                end
            end
        end
    end

五、变异操作

    for n = 1:Np        % 每个个体
        for m = 1:N     % 每个基因
            variation = rand(1,1);      % 生成一个大于0小于1的随机数
            if variation < Pv           % Pv=0.02,则有2%的概率满足if
                choosef(n,m) = ~choosef(n,m);   % 符号"~"是取反,0变1,1变0
            end
        end
    end
    population = choosef;       % 交叉和变异后的群体
    population(1,:) = fBest;    % 把交叉变异前的最优个体保留在群体首位
    trace(t) = maxfit;          % 本轮迭代的最优适应度
end

六、输出结果

fBest;    % 迭代之后的最优个体
figure
plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('遗传算法适应度迭代')
posted @ 2024-08-26 16:12  卢宇博  阅读(19)  评论(0编辑  收藏  举报