遗传算法编码问题
对于遗传算法而言,如何将问题的解转换为“染色体”是一个关键问题。通常而言实数编码解决的是约束优化问题,整数编码求的是组合优化问题。选择合适的编码是解决遗传算法问题的基础工作。
对于非字符串编码方法来说,在编码和解码之间存在三个核心的问题:
“染色体”的可行性:解码之后的解是否是在可行域内,是否违背约束 “染色体”的合法性:产生的解是否在解空间内,产生的解有可能不在解空间内编码空间和解码空间匹配的不唯一:有可能会产生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+x1⋅sin(4∗π∗x1)+x2⋅sin(20∗π∗x2)s.t−3.0≤x1≤12.04≤x2≤5.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)];构建交叉、变异算子。可以看出实数编码与二进制编码的交叉、变异算子的构建也存在很大的不同,在本示例中,我们采用
X′1=λ1X1+(1−λ2X2)X′2=λ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~~
南方听雨,北方阳光和煦,新的一周,加油↖(^ω^)↗
