10.2 遗传算法的MATLAB实现(1)
遗传算法(Genetic Algorithm)是模拟自然界生物进化机制的一种算法,即遵循适者生存、优胜劣汰的法则,也就是在寻优过程中有用的保留,无用的则去除。遗传算法在科学和生产实践中表现为在所有可能的解决方法中找出最符合该问题所要求的条件的解决方法,即找出一个最优解。
10.2.1 基本原理
遗传操作是模拟生物基因遗传的做法。在遗传算法中,通过编码组成初始群体后,遗传操作的任务就是对群体的个体按照它们对环境适应度(适应度评估)施加一定的操作,从而实现优胜劣汰的进化过程。从优化搜索的角度而言,遗传操作可使问题的解一代又一代地优化,并逼近最优解。遗传算法过程如图10-7所示。
图10-7 遗传算法过程
遗传操作包括以下3个基本遗传算子(Genetic Operator):选择(Selection)、交叉(Crossover)和变异(Mutation)。
个体遗传算子的操作都是在随机扰动情况下进行的。因此,群体中个体向最优解迁移的规则是随机的。需要强调的是,这种随机化操作和传统的随机搜索方法是有区别的。遗传操作进行高效有向的搜索,而不是如一般随机搜索方法一样进行无向搜索。
遗传操作的效果和上述3个基本遗传算子所取的操作概率、编码方法、群体大小、初始群体,以及适应度函数的设定密切相关。
1.选择
从群体中选择优胜的个体,淘汰劣质个体的操作叫选择。选择算子有时又称为再生算子(Reproduction Operator)。选择的目的是把优化的个体直接遗传到下一代或通过配对交叉产生新的个体再遗传到下一代。
轮盘赌选择法(Roulette Wheel Selection)是最简单也是最常用的选择方法。在该方法中,各个个体的选择概率和其适应度值成比例。设群体大小为n,其中个体i的适应度为fi,则i被选择的概率为。
显然,概率反映了个体i的适应度在整个群体的个体适应度总和中所占的比例。个体适应度越大,其被选择的概率就越大,反之亦然。
计算出群体中各个个体的选择概率后,为了选择交配个体,需要进行多轮选择。每一轮产生一个[0,1]之间的均匀随机数,将该随机数作为选择指针来确定被选个体。
个体被选后,可随机地组成交配对,以供后面的交叉操作。
2.交叉
在自然界生物进化过程中起核心作用的是生物遗传基因的重组(加上变异)。同样,在遗传算法中起核心作用的是遗传操作的交叉算子。所谓交叉,是指把两个父代个体的部分结构加以替换重组而生成新个体的操作。通过交叉,遗传算法的搜索能力得以飞跃提高。
交叉算子根据交叉率将种群中的两个个体随机地交换某些基因,能够产生新的基因组合,期望将有益基因组合在一起。根据编码表示方法的不同,可以有以下算法:
(1)实值重组(Real Valued Recombination)。
● 离散重组(Discrete Recombination)。
● 中间重组(Intermediate Recombination)。
● 线性重组(Linear Recombination)。
● 扩展线性重组(Extended Linear Recombination)。
(2)二进制交叉(Binary Valued Crossover)。
● 单点交叉(Single-point Crossover)。
● 多点交叉(Multiple-point Crossover)。
● 均匀交叉(Uniform Crossover)。
● 洗牌交叉(Shuffle Crossover)。
● 缩小代理交叉(Crossover with Reduced Surrogate)。
最常用的交叉算子为单点交叉。具体操作是:在个体串中随机设定一个交叉点,在实行交叉时,该点前或后的两个个体的部分结构进行互换,并生成两个新个体。下面给出单点交叉的一个例子。
个体A:1 0 0 1 ↑1 1 1 → 1 0 0 1 0 0 0 新个体
个体B:0 0 1 1 ↑0 0 0 → 0 0 1 1 1 1 1 新个体
3.变异
变异算子的基本内容是对群体中的个体串的某些基因座上的基因值做变动。依据个体编码表示方法的不同,可以有以下算法:
● 实值变异。
● 二进制变异。
一般来说,变异算子操作的基本步骤如下:
● 对群体中所有个体以事先设定的变异概率判断是否进行变异。
● 对进行变异的个体随机选择变异位进行变异。
遗传算法引入变异的目的有两个:一是使遗传算法具有局部的随机搜索能力。当遗传算法通过交叉算子已接近最优解邻域时,利用变异算子的这种局部随机搜索能力可以加速向最优解收敛。显然,此种情况下的变异概率应取较小值,否则接近最优解的积木块会因变异而遭到破坏。二是使遗传算法可维持群体多样性,以防止出现未成熟收敛现象。此时收敛概率应取较大值。
在遗传算法中,交叉算子因其全局搜索能力而作为主要算子,变异算子因其局部搜索能力而作为辅助算子。
遗传算法通过交叉和变异这对相互配合又相互竞争的操作而使其具备兼顾全局和局部的均衡搜索能力。
所谓相互配合,是指当群体在进化中陷于搜索空间中某个超平面而仅靠交叉不能摆脱时,通过变异操作可有助于这种摆脱。
所谓相互竞争,是指当通过交叉已形成所期望的积木块时,变异操作有可能破坏这些积木块。如何有效地配合使用交叉和变异操作,是目前遗传算法的一个重要研究内容。
基本变异算子是指对群体中的个体码串随机挑选一个或多个基因座并对这些基因座的基因值做变动。(0,1)二值码串中的基本变异操作如下:
注意:在基因位下方标有*号的基因发生变异。
变异率的选取一般受种群大小、染色体长度等因素的影响,通常选取很小的值,一般取0.001~0.1。
4.终止条件
当最优个体的适应度达到给定的阈值时,或者最优个体的适应度和群体适应度不再上升时,或者迭代次数达到预设的代数时,算法终止。预设的代数一般设置为100~500代。
10.2.2 程序设计
为了更好地在MATLAB中使用遗传算法,本节主要对遗传算法的程序设计和MATLAB工具箱进行讲解。
随机初始化群体P(t) = {x1,x2,…,xn},计算P(t)中个体的适应度值。其MATLAB程序的基本格式如下所示:
Begin t = 0 初始化P(t) 计算P(t)的适应度值: while (不满足停止准则) do begin t = t + 1 从P(t + 1)中选择P(t) 重组P(t) 计算P(t)的适应度值 end
例10-3:求下列函数的最大值。
f(x) = 9 * sin(5x) + 8 * cos(4x),其中 x∈[0, 15]
1.初始化
遗传算法MATLAB子程序如下:
% 初始化 function pop = initpop(popsize, chromlength) pop = round(rand(popsize, chromlength)); % rand随机产生每个单元为{0, 1},行数为popsize,列数为chromlength的矩阵 % roud对矩阵的每个单元进行圆整,这样产生了初识群体 end
● initpop函数的功能是实现群体的初始化。
● popsize表示群体的大小。
● chromlength表示染色体的长度(二值数的长度),长度大小取决于变量的二进制编码的长度。
2.目标函数值
(1)将二进制数转化为十进制数。遗传算法MATLAB子程序如下:
% 将二进制数转换为十进制数 function pop2 = decodebinary(pop) [px, py] = size(pop); % 求pop行和列数 for i = 1 : py pop1(:, i) = 2.^(py - i) .* pop(:, i); end pop2 = sum(pop1, 2); % 求pop1的每行之和 end
(2)将二进制编码转化为十进制数。
decodechrom函数的功能是将染色体(或二进制编码)转换为十进制数,参数spoint表示待解码的二进制串的起始位置。
对于多个变量而言,如有两个变量,采用20位表示,每个变量10位,则第一个变量从1开始,第二个变量从11开始。参数length表示所截取的长度。
遗传算法MATLAB子程序如下:
% 将二进制编码转换成十进制数 function pop2 = decodechorm(pop, spoint, length) pop1 = pop(:, spoint : spoint + length - 1); pop2 = decodebinary(pop1); end
(3)计算目标函数值。
calobjvalue函数的功能是实现目标函数的计算。
遗传算法MATLAB子程序如下:
function [objvalue] = calobjvalue(pop) temp1 = decodechrom(pop, 1, 10); % 将pop每行转化成十进制数 x = temp1 * 10 / 1023; % 将二值域中的数转化为变量域中的数 objvalue = 10 * sin(5 * x) + 7 * cos(4 * x); % 计算目标函数值 end
3.计算个体的适应度值
遗传算法MATLAB子程序如下:
% 计算个体的适应度值 function fitvalue = calfitvalue(objvalue) global Cmin; Cmin = 0; [px, py] = size(objvalue); for i = 1 : px if objvalue(i) + Cmin > 0 temp = Cmin + objvalue(i); else temp = 0.0; end fitvalue(i) = temp; end fitvalue = fitvalue'
4.选择复制
选择复制操作是决定哪些个体可以进入下一代。程序中采用赌轮盘选择法选择,这种方法较易实现。根据方程,选择步骤如下:
①在第t代,计算fsum和pi。
②产生{0,1}的随机数rand(.),求s = rand(.)*fsum。
③求中最小的k,则第k个个体被选中。
④进行N次②、③操作,得到N个个体,成为第t = t+1代群体。
遗传算法MATLAB子程序如下:
%选择复制 function [newpop] = selection(pop, fitvalue) totalfit = sum(fitvalue); % 求适应度值之和 fitvalue = fitvalue / totalfit; % 单个个体被选择的概率 fitvalue = cumsum(fitvalue); % 如fitvalue=[1 2 3 4],则cumsum(fitvalue)=[1 3 6 10] [px,py] = size (pop); ms = sort(rand(px, 1)); % 从小到大排列 fitin = 1; newin = l; while newin <= px if(ms(newin)) < fitvalue(fitin) newpop(newin) = pop(fitin) ; newin = newin + 1; else fitin = fitin + 1; end end
5.交叉
群体中的每个个体之间都以一定的概率pc交叉,即两个个体从各自字符串的某一位置(一般是随机确定)开始互相交换,这类似于生物进化过程中的基因分裂与重组。
例如,假设2个父代个体x1、x2为:
x1=0100110
x2=1010001
从每个个体的第3位开始交叉,交叉后得到2个新的子代个体y1、y2:
y1=0100001
y2=1010110
这样2个子代个体就分别具有了2个父代个体的某些特征。
利用交叉,我们有可能由父代个体在子代组合成具有更高适应度的个体。事实上,交叉是遗传算法区别于其他传统优化方法的主要特点之一。
遗传算法MATLAB子程序如下:
% 交叉 function [newpop] = crossover(pop, pc) [px,py] = size(pop); newpop = ones(size(pop)); for i = 1 : 2 : px - 1 if(rand < pc) cpoint = round(rand * py); newpop(i, :) = [pop(i, 1 : cpoint), pop(i + 1, cpoint + 1 : py)]; newpop(i + 1, :) = [pop(i + 1, 1 : cpoint), pop(i, cpoint + 1 : py)]; else newpop(i, :) = pop(i); newpop(i + 1, :) = pop(i + 1); end end
6.变异
基因的突变普遍存在于生物的进化过程中。变异是指父代中的每个个体的每一位都以概率pm翻转,即由“1”变为“0”,或由“0”变为“1”。
遗传算法的变异特性可以使求解过程随机地搜索到解可能存在的整个空间,因此可以在一定程度上求得全局最优解。
遗传算法MATLAB子程序如下:
%变异 function [newpop] = mutation(pop, pm) [px, py] = size(pop); newpop = ones(size(pop)); for i = 1 : px if(rand < pm) mpoint = round(rand * py); if mpoint <= 0 mpoint = 1; end newpop(i) = pop(i); if any(newpop(i, mpoint)) == 0 newpop(i, mpoint) = 1; else newpop(i, mpoint) = 0; end else newpop(i) = pop(i); end end
7.求出群体中最大的适应度值及其个体
遗传算法MATLAB子程序如下:
%求群体中最大的适应度值 function [bestindividual, bestfit] = best(pop, fitvalue) [px, py] = size(pop); bestindividual = pop(1, :); bestfit = fitvalue(1); for i = 2 : px if fitvalue(i) > bestfit bestindividual = pop(i, :); bestfit = fitvalue(i); end end
8.主程序
遗传算法MATLAB主程序如下:
clear all popsize = 20; % 群体大小 chromlength = 10; % 字符串长度(个体长度) pc = 0.7; % 交叉概率 pm = 0.005; % 变异概率 pop = initpop(popsize, chromlength); % 随机产生初始群体 for i = 1 : 20 % 20为迭代次数 [objvalue] = calobjvalue (pop); % 计算目标函数 fitvalue = calfitvalue(objvalue); % 计算群体中每个个体的适应度 [newpop] = selection(pop,fitvalue); % 复制 [newpop] = crossover(pop, pc); % 交叉 [newpop] = mutation(pop, pc); % 变异 [bestindividual, bestfit] = best(pop, fitvalue); %求出群体中适应度值最大的个体及其适应度值 y(i) = max(bestfit); n(i) = i; pop5 = bestindividual; x(i) = decodechrom(pop5, 1, chromlength) * 10 / 1023; pop = newpop; end fplot(@(x) 9 .* sin(5 .* x) + 8 .* cos(4 .* x)) hold on plot(x, y,'r*') hold off
运行主程序,得到的结果如图10-8所示。
图10-8 遗传算法仿真结果
注意:在遗传算法中有4个参数需要提前设定,一般在以下范围内进行设置。
● 群体大小:20~100。
● 遗传算法的终止进化代数:100~500。
● 交叉概率:0.4~0.99。
● 变异概率:0.0001~0.1。