本文是《MATLAB智能算法30个案例分析(第二版)》一书第二章的学习笔记。
标准遗传算法的主要本质特征,在于群体搜索策略和简单的遗传算子,这使遗传算法获得了强大的全局最优解能力、问题域的独立性、信息处理的并行性、应用的鲁棒性和操作的简明性。但大量的实践和研究表明,标准的遗传算法存在局部搜索能力差和“早熟”等缺陷,不能保证算法收敛。
现有的许多文献中,针对遗传算法存在的上述问题,改进算法主要集中在对遗传算法的编码机制、选择策略、交叉算子、变异算子、特殊算子和参数设计(包括群体规模、交叉概率、变异概率)等。
经典的非线性规划算法大多采用梯度下降的方法求解,局部搜索能力强而全局搜索能力弱,容易陷入局部最优解。本文结合两种算法的优点,一方面使用遗传算法进行全局搜索,另一方面使用非线性规划算法进行局部搜索,以得到问题的全局最优解。
以计算函数 f ( x ) = ∑ i = 1 n x i 2 ( − 20 ⩽ x i ⩽ 20 ) f\left( x \right) =\sum_{i=1}^n{x_{i}^{2}}\left( -20\leqslant x_i\leqslant 20 \right) f(x)=i=1∑nxi2(−20⩽xi⩽20) 为例,其中,个体 x x x的维度 n n n为10.这是一个简单的平方和函数,只有一个极小点 x = ( 0 , 0 , ⋯ , 0 ) x=(0,0,\cdots,0) x=(0,0,⋯,0),理论最小值 f ( 0 , 0 , ⋯ , 0 ) = 0 f\left(0,0,\cdots,0\right)=0 f(0,0,⋯,0)=0。
本文使用随机联赛选择作为选择算子。
随机联赛选择也是一种基于个体适应度之间大小关系的选择方法。其基本思想是每次随机选取 N N N个个体,选出其中适应度最高的一个个体遗传到下一代群体中。
在随机联赛选择操作中,只有个体适应度之间的大小比较运算,而无个体适应度之间的算术运算,所以它对个体适应度去正值还是取负值无特别影响。
随机联赛选择的具体操作过程为: (1)从群体中随机选取 N N N个个体进行适应度大小的比较,将其中适应度最高的个体遗传到下一代群体中。 (2)将上述过程重复 M M M次( M M M为种群规模),就可得到下一代群体中的 M M M个个体。
function new_individuals = Select(individuals, Nind) % select 选择算子,基于随机联赛策略选择较优的个体 % individuals input: 种群 % Nind input: 种群规模 % new_chrom output: 经选择算子生成的新种群 N = 2; % 每次随机选择的个体数 index = []; % 存储每次选择的个体的索引 for i = 1:Nind race_indi_index = randi(Nind, [2,1]); % 被选中的个体的索引 race_indi_fit = individuals.fitness(race_indi_index); % 被选中的个体的适应度 bigger_index = find(individuals.fitness == max(race_indi_fit)); index = [index; bigger_index(1)]; end individuals.chrom = individuals.chrom(index,:); individuals.fitness = individuals.fitness(index,:); new_individuals = individuals; end本文使用模拟二进制交叉算子(Simulated Binary Crossover,SBX),主要思想是在使用浮点数编码/实数编码时,可以模拟二进制编码的操作,计算公式如下: x 1 j ~ = 1 2 [ ( 1 + r j ) x 1 j + ( 1 − r j ) x 2 j ] x 2 j ~ = 1 2 [ ( 1 − r j ) x 2 j + ( 1 + r j ) x 2 j ] \widetilde{x_{1j}}=\frac{1}{2}\left[ \left( 1+r_j \right) x_{1j}+\left( 1-r_j \right) x_{2j} \right] \\ \widetilde{x_{2j}}=\frac{1}{2}\left[ \left( 1-r_j \right) x_{2j}+\left( 1+r_j \right) x_{2j} \right] x1j =21[(1+rj)x1j+(1−rj)x2j]x2j =21[(1−rj)x2j+(1+rj)x2j] 其中, x 1 j x_{1j} x1j、 x 2 j x_{2j} x2j分别表示两个父代第 j j j个基因, r j r_{j} rj为参数,由下面的公式确定: r j = { ( 2 u j ) 1 η + 1 , u j ⩽ 0.5 ( 1 2 ( 1 − u j ) ) 1 η + 1 , 0.5 ⩽ u j < 1 r_j=\begin{cases} \left( 2u_j \right) ^{\frac{1}{\eta +1}}, u_j\leqslant 0.5\\ \left( \frac{1}{2\left( 1-u_j \right)} \right) ^{\frac{1}{\eta +1}}, 0.5\leqslant u_j<1\\ \end{cases} rj=⎩⎨⎧(2uj)η+11,uj⩽0.5(2(1−uj)1)η+11,0.5⩽uj<1 其中, u j u_{j} uj为 [ 0 , 1 ] [0,1] [0,1]上的随机数, η \eta η为分布指数,Deb和Agrawal建议 η = 1 \eta=1 η=1。
function new_individuals = Cross(individuals, Pc, Nind, Lind) % Cross 使用模拟二进制交叉算子(SBX),随机选择两个个体进行染色体的交叉 % individuals input: 种群 % Pc input: 交叉概率 % Nind input: 种群规模 % Lind input: 染色体长度 % new_individuals output: 经交叉操作后产生的新种群 new_individuals = individuals; for i = 1:Nind % 随机选择两个个体 index = randi(Nind, [2,1]); cross_indi = individuals.chrom(index, :); temp = zeros(2, Lind); % 进行交叉操作 for j = 1:Lind Pick = rand; if Pick < Pc eta = 0.5; % 分布因子 % 分布因子越大,其产生的后代个体逼近父代个体的概率越大,故SBX算子在局部搜索上表现较强 u = rand; if u <= 0.5 beta = (2*u)^(1/(1+eta)); else beta = (2*(1-u))^(1/(1+eta)); end % 交叉 temp(1,j) = 0.5*((1+beta)*individuals.chrom(index(1),j) + (1-beta)*individuals.chrom(index(2),j)); temp(2,j) = 0.5*((1-beta)*individuals.chrom(index(1),j) + (1+beta)*individuals.chrom(index(2),j)); else temp(1,j) = individuals.chrom(index(1),j); temp(2,j) = individuals.chrom(index(2),j); end end new_individuals.chrom(index(1),:) = temp(1,:); new_individuals.chrom(index(2),:) = temp(2,:); end end本文使用高斯变异算子。高斯变异是改进遗传算法对重点搜索区域的局部搜索性能的另一种变异操作方法。所谓高斯变异操作,是指在进行变异操作时,用符合均值为 μ \mu μ、方差为 σ 2 \sigma^2 σ2的正态分布的一个随机数来替换原有基因值。
具体实现高斯变异时,一个符合正态分布的随机数 Q Q Q可由一些符合均匀分布的随机数利用公式来近似产生。假定有12个在 [ 0 , 1 ] [0,1] [0,1]范围内均匀分布的随机数 r i ( i = 1 , 2 , ⋯ , 12 ) r_{i}(i=1,2,\cdots,12) ri(i=1,2,⋯,12),则符合 N ( μ , σ 2 ) N(\mu,\sigma^2) N(μ,σ2)正态分布的一个随机数可由下式求得: Q = μ + σ ⋅ ( ∑ i = 1 12 r i − 6 ) Q=\mu +\sigma \cdot \left( \sum_{i=1}^{12}{r_i-6} \right) Q=μ+σ⋅(i=1∑12ri−6) 在进行由 X = x 1 x 2 ⋯ x k ⋯ x l X=x_{1}x_{2}\cdots x_{k}\cdots x_{l} X=x1x2⋯xk⋯xl向 X = x 1 x 2 ⋯ x k ′ ⋯ x l X=x_1x_2\cdots x_{k}^{'}\cdots x_l X=x1x2⋯xk′⋯xl的高斯变异操作时,若变异点 x k ′ x_{k}^{'} xk′处的基因值取值范围为 [ U m i n k , U m a x k ] [U_{min}^{k},U_{max}^{k}] [Umink,Umaxk],并假设: μ = U min k + U max k 2 σ = U max k − U min k 6 \mu =\frac{U_{\min}^{k}+U_{\max}^{k}}{2} \\ \sigma =\frac{U_{\max}^{k}-U_{\min}^{k}}{6} μ=2Umink+Umaxkσ=6Umaxk−Umink 则新的基因值 x k ′ x_{k}^{'} xk′可由以下公式确定: x k ′ = U min k + U max k 2 + U max k − U min k 6 ( ∑ i = 1 12 r i − 6 ) x_{k}^{'}=\frac{U_{\min}^{k}+U_{\max}^{k}}{2}+\frac{U_{\max}^{k}-U_{\min}^{k}}{6}\left( \sum_{i=1}^{12}{r_i-6} \right) xk′=2Umink+Umaxk+6Umaxk−Umink(i=1∑12ri−6)
function new_individuals = Mutation(individuals, Pm, Nind, Lind, Xmax, Xmin) % Mutation 对种群中每个个体,使用高斯变异算子,随机选取一点进行变异 % individuals input: 种群 % Pm input: 变异概率 % Nind input: 种群规模 % Lind input: 染色体长度 % Xmax input: 自变量的上界 % Xmin input: 自变量的下界 % new_individuals output: 经交叉操作后产生的新种群 new_individuals = individuals; for i = 1:Nind for j = 1:Lind Pick = rand; if Pick < Pm u = (Xmax(j)+Xmin(j))/2; sigma = (Xmax(j)-Xmin(j))/6; new_individuals.chrom(i,j) = u+sigma*(sum(rand([1,12]))-6); end end end end本文的处理方法比较简单:若当前迭代次数 g e n gen gen为20的整数倍,则返回1,表示使用MATLAB内置的 f m i n c o n fmincon fmincon函数进行非线性规划;反之则返回0,不进行非线性规划。
function flag = do_NLP(gen) % do_NLP 判断当前迭代次数是否满足进行非线性规划的条件 % gen input: 当前迭代次数 % flag output: 是否可行,1为可进行,0位不可进行 if mod(gen,20) == 0 flag = 1; else flag = 0; end end
