遗传算法解决实际例的学习笔记

该文详细解释了一段遗传算法的MATLAB代码,包括画函数图、定义参数、计算适应度、染色体复制、交叉和变异操作,以及如何寻找最优解和展示适应度进化曲线。整个过程涉及目标函数、种群、二进制编码和解码、交叉概率及变异概率等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 我很大程度上是理解了这些代码的意思。

首先是画出函数图

figure(1);
hold on;

t = 0:0.01:10;
y = t + 10*sin(5*t) + 7*cos(4*t);
plot(t, y)

 上面这个代码的意思是,首先建立图像1,t的取值范围是在0~10之间,步伐是0.01 。

接下来是定义我们要求的目标函数,plot把图画出来。 

接下来第一步骤,定义遗传算法的参数

NP=50;          %种群数量
L=20;           %二进制位串长度
Pc=0.8;         %交叉率
Pm=0.1;         %变异率
G=100;          %最大遗传代数
Xs=10;          %在区间[0,10]求函数的极值
Xx=0;           %定义域下限 
f=randi([0,1],NP,L);  %随机产生第一代随机种群
trace=zeros(1,G);     %创建数组,用于记录每一代,适应度最好的函数值
for k=1:G%开始进行一代一代的循环


 上面这段代码的意思是,首先定义参数,并且给它们赋值。

 用到了语法randi,它的意思是随机生成0或者1,50行,20列。

 50行呢,每行代表一个个体

 20列呢,每列代表一个基因。

 然后语法zeros的意思是,X = zeros(sz1,...,szN) 返回由零组成的 sz1×...×szN 数组,其中 sz1,...,szN 指示每个维度的大小。例如,zeros(2,3) 将返回一个 2×3 矩阵。

上面代码的意思就是,创建1X100列的矩阵,每一列代表那一代的适应度最高的函数值。

然后是优化,第二步骤,计算适应度


  %%%%%%第2步,计算染色体适应度%%%%,
    for i=1:NP
        U=f(i,:);               %一条染色体
        m=0;
        for j=1:L
            m=U(j)*2^(j-1)+m;       %二进制转十进制的过程
        end
        x(i)=Xx+m*(Xs-Xx)/(2^L-1);  %将染色体解码在函数定义域
        Fit(i)=func1(x(i));         %适应度,即目标函数的值
    end
    plot(t,y,'b-',x,func1(x),'ro')
    pause(0.4)

    %求适应度最优%
    maxFit=max(Fit);            %目标函数最大值
    minFit=min(Fit);            %目标函数最小值
    rr=find(Fit==maxFit);
    %最大值在Fit数组中的位置,返回一个数组,因为可能有几个相同的最大值
    %这点要特别注意,所以下面不能直接用rr
    fBest=f(rr(1,1),:);         %最优适应度,有多个相同值时只取第一个
    xBest=x(rr(1,1));           %最优适应度对应的染色体
    Fit=(Fit-minFit)/(maxFit-minFit);   %归一化适应度值

上面这段代码开始有点东西了。

 首先,外层循环是 for i=1:NP,表示对种群中的每个染色体进行循环操作,其中 NP 是种群的大小。在循环内部,首先通过 U=f(i,:) 获取当前染色体的二进制编码,这行代码的作用是取出种群矩阵 f 中的第 i 行,即第 i 个染色体。

 然后,通过一个内层循环 for j=1:L,对该染色体的每个基因进行遍历。L 是染色体的长度,即基因的数量。在内层循环中,通过 m=U(j)*2^(j-1)+m 将二进制编码转换为十进制的过程。这行代码的作用是将二进制编码中的每个基因乘以相应的权重并求和,以得到一个十进制数值 m

  接下来,通过 x(i)=Xx+m*(Xs-Xx)/(2^L-1) 将染色体解码到函数定义域,其中 XxXs 是函数定义域的上下界。这行代码的作用是将十进制数值 m 映射到函数定义域内的实数值,并将结果存储在向量 x 中的第 i 个位置。

   最后,通过 Fit(i)=func1(x(i)) 计算解码后的染色体的适应度,即目标函数的值。func1 是一个自定义的函数,用于计算染色体解码后的实数值在目标函数上的表现。

 总结起来,这段代码是对种群中的每个染色体进行遍历,将其二进制编码转换为十进制数值,并解码到函数定义域内,然后计算解码后染色体的适应度。

第三步骤染色体复制

%%%%%第3步,复制染色体%%%%
    sum_Fit=sum(Fit);
    fitvalue=Fit./sum_Fit;      %可以看作概率密度f
    fitvalue=cumsum(fitvalue);  %可以看作概率累计F
    ms=sort(rand(NP,1));        %随机生成(0,1)的有序概率密度NP大小向量
    fiti=1;
    newi=1;
    %由ms可以看出这是一种随机的复制方式,但总趋势是将适应度比较大的遗传下去
    while newi <=NP
        if (ms(newi)<fitvalue(fiti))
            nf(newi,:)=f(fiti,:);
            newi=newi+1;
        else
            fiti=fiti+1;
        end
    end

上面这段代码呢,用的是轮盘赌方法。

 首先,先把它们加起来,然后每个适应度值去除以总和,就是占比的概率,概率越大表示被选中的概率越高。

 然后,通过 fitvalue=cumsum(fitvalue) 对概率密度向量进行累积求和操作,得到一个类似于概率累计分布的向量之后随机生成0,1的向量。这个向量表示了每个染色体被选中的累积概率,值越大表示累积概率越高。然后,通过 ms=sort(rand(NP,1)) 随机生成一个大小为 NP 的有序概率密度向量 ms。这个向量的元素是在区间 (0,1) 内均匀分布的随机数,通过排序使得它们有序。

 接下来,通过一个循环 while newi <=NP 对新的种群 nf 进行构建。在循环内部,通过判断 ms(newi) 是否小于 fitvalue(fiti) 来决定是否选择染色体进行复制。如果是,则将第 fiti 行的染色体 f(fiti,:) 复制到新的种群 nf 的第 newi 行。

 然后,将 newi 自增1,表示已经选择了一个染色体进行复制。如果 ms(newi) 不小于 fitvalue(fiti),则将 fiti 自增1,表示尝试选择下一个染色体进行复制。

 重复这个过程,直到新的种群 nf 中的所有染色体都被复制完成。

 综上所述,这段代码实现了一种随机的选择方式,但整体趋势是将适应度较大的染色体更有可能被选择和遗传到下一代种群中。

第四步染色体交叉操作

 %%%%%%%%第4步,基于概率的交叉操作%%%%%%%%
    for i=1:2:NP
        p=rand;
        if p<Pc                     %控制交叉的染色体总数
            q=randi([0,1],1,L);     %随机生成要交叉的基因位置
            for j=1:L
                if q(j)==1
                    temp=nf(i+1,j);
                    nf(i+1,j)=nf(i,j);
                    nf(i,j)=temp;   %两条相邻染色体在指定位置进行交叉
                end
            end
        end
    end

 上面这段代码实现了交叉操作。用于在选择的染色体中进行基因交叉。

 首先,通过 for i=1:2:NP 循环,从种群中选择相邻的两条染色体进行交叉操作(一次选取2个染色体进行交叉,就像父母)。这里使用步长为2,即每次选择相邻的两个染色体进行交叉。在每次循环中,首先生成一个随机数 p=rand,用于确定是否进行交叉操作。

 如果 p 小于交叉概率阈值 Pc,则进行交叉操作;否则,跳过本次循环,不进行交叉操作。

 如果确定进行交叉操作,则通过 q=randi([0,1],1,L) 随机生成一个大小为L的二进制序列 q,用于确定哪些基因位置要进行交叉。接着,通过一个循环 for j=1:L 遍历染色体的每个基因位置。

 在循环内部,通过判断 q(j) 是否等于1,即确定是否对该基因位置进行交叉。如果 q(j) 等于1,则进行交叉操作。首先,将第 i+1 行染色体的第 j 个基因值存储到临时变量 temp 中。然后,将第 i 行染色体的第 j 个基因值替换为第 i+1 行染色体的第 j 个基因值,将第 i+1 行染色体的第 j 个基因值替换为 temp

这样,交叉操作就完成了。

 总结起来,这段代码的循环逻辑是从种群中选择相邻的两条染色体,根据交叉概率和随机生成的二进制序列,对这两条染色体的指定基因位置进行交叉操作。循环的步长为2,确保选择的染色体是相邻的。

第五步骤变异

 %%%%%%%%%第五步,基于概率的变异操作%%%%%%%%%%%%

    i=1;
    while i<=round(NP*Pm)       %控制变异染色体总数
        h=randi([1,NP],1,1);    %随机选取一个染色体进行变异
        for j=1:round(L*Pm)     %控制染色体上变异基因总数
            g=randi([1,L],1,1); %随机选取一个基因进行变异
            nf(h,g)=~nf(h,g);   %变异,即取反
        end
        i=i+1;
    end
    f=nf;                    %新一代种群
    f(1,:)=fBest;            %保留最优个体在新种群中
    trace(k)=maxFit;         %历代最优是应当由,即最大函数值
end

上面这段代码是遗传算法中的变异操作。

 首先,定义一个变量 i,初始值为1。通过 while i<=round(NP*Pm) 循环,控制变异染色体的总数。NP 是种群大小,Pm 是变异概率。

 在每次循环中,首先通过 h=randi([1,NP],1,1) 随机选择一个染色体进行变异。这里使用 randi 函数生成一个随机整数,范围是从1到种群大小 NP

 接着,通过 for j=1:round(L*Pm) 循环控制染色体上进行变异的基因总数。L 是染色体的长度,Pm 是变异概率。

 在循环内部,通过 g=randi([1,L],1,1) 随机选择一个基因进行变异。这里使用 randi 函数生成一个随机整数,范围是从1到染色体长度 L

 然后,通过 nf(h,g)=~nf(h,g) 对选定的染色体的指定基因进行变异操作。使用 ~ 运算符对基因取反,即将基因的值由0变为1,或由1变为0。

 完成所有变异操作后,将新的一代种群存储到变量 f 中,即 f=nf。同时,保留最优个体在新种群中,即将最优个体的染色体赋值给新种群的第一行,即 f(1,:)=fBest。这样可以确保最优个体在新一代种群中得到保留。

 最后,将历代最优的适应度值(目标函数最大值)赋给 trace(k),用于记录历代最优的变化过程。

 总结起来,这段代码的循环逻辑是根据变异概率和随机选择的染色体和基因位置,对染色体进行变异操作。每次循环选择一个染色体进行变异,并随机选择若干个基因进行变异。完成所有变异操作后,更新新一代种群,并保留最优个体。循环结束后,记录历代最优的适应度值。

最后输出最优解

disp('最优解');
disp(xBest);                 %最优个体,也就是最优解
figure
plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')
  function fit=func1(x)
fit=x+10*sin(5*x)+7*cos(4*x);
end 

 在代码的主体部分,首先通过 disp('最优解') 显示一条消息,表明接下来将显示最优个体(最优解)。

 然后,通过 disp(xBest) 显示变量 xBest,它存储了最优个体的值,即最优解。

 接下来,通过 figure 创建一个新的图形窗口。

 通过 plot(trace) 绘制适应度进化曲线,其中 trace 存储了历代最优的适应度值。横坐标表示迭代次数,纵坐标表示目标函数的值。

 最后,通过 xlabelylabeltitle 分别设置图形的 x 轴标签、y 轴标签和标题,以便更好地描述图形的含义。

 定义了一个函数 func1(x),用于计算目标函数的值。目标函数的表达式为 x+10*sin(5*x)+7*cos(4*x)

函数 func1(x) 的输入参数是变量 x,代表问题的自变量。在这里,它表示染色体解码后得到的实数值。

函数体内的表达式 fit=x+10*sin(5*x)+7*cos(4*x) 计算了目标函数的值。其中,x 代表自变量的值。

 总的来说,这段代码定义了一个目标函数 func1(x),并展示了最优解和适应度进化曲线。目标函数用于评估染色体的适应度,而适应度进化曲线则反映了遗传算法在每一代迭代中适应度的变化情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值