简单的遗传算法问题之实数编码(二)

遗传算法编码问题及实数编码示例
本文探讨了遗传算法中实数编码的重要性,包括编码的可行性、合法性以及编码空间和解码空间的匹配问题。通过旅行商问题举例,分析了不同编码方式的优缺点,并提出了一些改进策略。此外,介绍了实数编码在解决无约束问题时的适应度函数、种群初始化、交叉变异算子的构建方法,强调了调整交叉概率和变异概率对全局搜索能力的影响。

遗传算法编码问题

对于遗传算法而言,如何将问题的解转换为“染色体”是一个关键问题。通常而言实数编码解决的是约束优化问题,整数编码求的是组合优化问题。选择合适的编码是解决遗传算法问题的基础工作。

对于非字符串编码方法来说,在编码和解码之间存在三个核心的问题:

  1. “染色体”的可行性:解码之后的解是否是在可行域内,是否违背约束 “
  2. 染色体”的合法性:产生的解是否在解空间内,产生的解有可能不在解空间内
  3. 编码空间和解码空间匹配的不唯一:有可能会产生n对1 和1对n的mapping, 其中1对n的mapping会导致整个过程的失败。

编码示例(TSP问题)

TSP问题描述:假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。(为了更直观的示例,我们将n设为6,六个城市的编码分别为1,2,3,4,5,6)

这里写图片描述

1.将解直接编码为二进制,如果有6个城市,则编码为30个二进制。 但这种编码不能直接判断约束条件,会产生很多不可行解。

2.循环路径编码,将所有城市的编码的序号作为一个解。(132465) 但是会产生n对1的mapping, (132465 ;324651;1564231 对应的都是同一个解),做交叉、变异很可能产生不合法解,因此在做交叉、变异的时候要规避产生不合法的解。

3.第三种编码,将编码位置作为城市序号,如城市1到城市3,则编码第一位为3,城市2到城市4,则编码第二位为4,以此类推,可以将循环路径编码中的132465;324651等,编码为342615,这种编码方式可以减少冗余,进行有效的同一循环路径的判断,但若直接进行交叉变异容易产生具有子回路的不可行解,如243615这种编码中的城市3到城市3,这属于不可行解,这种具有子回路的不可行解不好判断。

论文tips:改mutation 和crossover的

选择
crowding strategy: 将与子代最像的父代替换掉,加强了种群的多样性

Stochastic Sampling
(1) Roulette wheel selection :实数优化和组合优化
(2) Stochastic universal sampling

Deterministic Sampling
(1) (u+λ)-selection : 适合组合优化
(2) (u, λ)-selection
(3) Truncation selection
(4) Block selection
(5) Elitist selection
(6) The generational replacement
(7) Steady-state reproduction

Mixed Sampling
(1) Tournament selection: 随机抽取10个,将这10个里面选一个最好的解放进下一代
(2) Binary tournament selection
(3) Stochastic tournament selection
(4) Remainder stochastic sampling

tips:常用的方法为Roulette wheel selection 和(u+λ)-selection

实数编码示例
在上一篇博客的示例中我们采用了二进制编码了解决了一个无约束问题,在这里我们将采用实数编码来解决同样的问题。

问题描述

maxf(x1,x2)=21.5+x1sin(4πx1)+x2sin(20πx2)s.t3.0x112.04x25.8

首先我们需要构建适应度函数fun1

function y = fun1(x)
%目标函数
y = 21.5+x(:,1).*sin(1*pi*x(:,1))+x(:,2).*sin(2*pi*x(:,2));

然后,种群初始化。我们可以看出实数编码的种群初始化相对来说较为简单,种群的个体就是问题的解,不需要如二进制编码那样使用transform函数进行转换。

function pop = initialization(pop)
%种群初始化

pop.individual = rand(pop.size,2);
pop.individual(:,1) = pop.individual(:,1)*15-3;
pop.individual(:,2) = pop.individual(:,2)*2+4;

pop.solution = pop.individual;%种群的个体即为解
pop.obj = fun1(pop.solution);%计算目标函数值

%------------------------------------------------------------

n = find(pop.obj == max(pop.obj),1);%当前种群最优解下标

%记录最优二进制个体和实数解,以及最佳及平均目标函数值
pop.bestIndividual = pop.individual(n,:);
pop.bestSolution = pop.solution(n,:);
pop.perfom = [max(pop.obj),mean(pop.obj)];

构建交叉、变异算子。可以看出实数编码与二进制编码的交叉、变异算子的构建也存在很大的不同,在本示例中,我们采用

X1=λ1X1+(1λ2X2)X2=λ1X2+(1λ2X1)

构建交叉算子

采用

X=X+Δ(Δ)

构建变异算子

同时为了防止在适应度评价过程中将最优解扔掉,我们选择每次评价之后直接将最优解放入到下一代中。

function pop = newPop(pop)

%选择算子产生新种群
pop = selection(pop);

%执行交叉和变异算子
pop = crossover(pop);
pop = mutation(pop);

%适应度评价(计算目标函数值)
pop.solution = pop.individual;
pop.obj = fun1(pop.solution);

%随机将子代中某一个个体替换为最优解  即将最优解保存下来
t = ceil(rand*pop.size);
pop.individual(t,:) = pop.bestIndividual(end,:);
pop.solution(t,:) = pop.bestSolution(end,:);
pop.obj(t,:) = pop.perfom(end,1);

%------------------------------------------------------------

n = find(pop.obj == max(pop.obj),1);%当前种群最优解下标

%记录最优二进制个体和实数解,以及最佳及平均目标函数值
pop.bestIndividual(end+1,:) = pop.individual(n,:);
pop.bestSolution(end+1,:) = pop.solution(n,:);
pop.perfom(end+1,:) = [max(pop.obj),mean(pop.obj)];


%------------------------------------------------------------
function pop = selection(pop)
%选择函数
p = pop.obj/sum(pop.obj);%计算生存概率
pp = cumsum(p);%计算累计概率

for i = 1:pop.size
    r = rand;%产生一个随机数
    k(i) = find(pp>=r,1);%随机数落在哪个累积概率区间,即对应的个体被选中,记录下标
end
%把选中的个体放入新种群
pop.individual = pop.individual(k,:);
pop.solution = pop.solution(k,:);
pop.obj = pop.obj(k,:);

%------------------------------------------------------------
function pop = crossover(pop)
%交叉算子
for i = 1:pop.size/2%遍历每一对个体
    if rand<pop.cr%依交叉概率执行交叉操作
        %提取待交叉个体
        a1 = pop.individual(2*(i-1)+1,:);
        a2 = pop.individual(2*i,:);

        aa = rand;

        pop.individual(2*(i-1)+1,:) = aa*a1+(1-aa)*a2;
        pop.individual(2*i,:) = aa*a2+(1-aa)*a1;

    end
end


%------------------------------------------------------------
function pop = mutation(pop)
%变异算子
for i = 1:pop.size%遍历每个个体
    if rand<pop.mr%依概率执行变异
        n = ceil(rand*2);
        pop.individual(i,n) = pop.individual(i,n) + pop.ma*randn;% 变异
        if n == 1
            pop.individual(i,n) = max(min(pop.individual(i,n),12),-3);
        else
            pop.individual(i,n) = max(min(pop.individual(i,n),6),4);
        end
    end
end

构建好这些函数之后,看过上一篇博客的小伙伴都知道,接下来,我们要开始来运行我们的遗传算法啦
首先,画个等值线图

clear all
close all

% rand('state',1) %设置随机数生成器的状态
% randn('state',1)

[X,Y] = meshgrid(-3:0.15:12,4:0.02:6); % 生成绘图用均匀采样的二维决策变量点坐标

for i = 1:size(X,2)
    x = [X(:,i),Y(:,i)];
    Z(:,i) = fun1(x); %计算目标函数值
end

figure(1)
contour(X,Y,Z) %绘制等值线图
hold on

这里写图片描述

可以看出,跟上一次的没啥差别,嗯,好像都是在说废话的样子,有差别就不是同一个问题了

接下来,干嘛呢?设置相应的参数,初始化

pop.size = 20;%种群规模
pop.cr = 0.4;%交叉概率
pop.mr = 0.4;%变异概率
pop.ma = 1;

pop = initialization(pop);%初始化种群
figure(1)
plot(pop.solution(:,1),pop.solution(:,2),'ok','MarkerSize',10,'LineWidth',2)
plot(pop.bestSolution(end,1),pop.bestSolution(end,2),'ok','MarkerSize',10,'LineWidth',2,'MarkerFaceColor','g')
hold off

这里写图片描述
细心的小伙伴可能看出来了,我们的交叉概率变小,变异概率变大了,这是因为在这个问题中,如果变异概率太小,则其全局搜索能力会比较弱,很容易最后会得到一个局部最优解。

最后,到了我们激动人心的时刻了,开始求解

for i = 1:100
    pop = newPop(pop);%生成新一代种群
    %重新绘制等值线图
    figure(1)
    contour(X,Y,Z)
    hold on
    plot(pop.solution(:,1),pop.solution(:,2),'ok','MarkerSize',10,'LineWidth',2)
    plot(pop.bestSolution(end,1),pop.bestSolution(end,2),'ok','MarkerSize',10,'LineWidth',2,'MarkerFaceColor','g')
    hold off
    pause(0.05)
end

这里写图片描述

图中绿色的小点点就是我们求的最优解啦,开心O(∩_∩)O~~


南方听雨,北方阳光和煦,新的一周,加油↖(^ω^)↗

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值