【学习笔记】基于遗传算法和非线性规划的函数寻优算法

2023-10-29 16:50

本文主要是介绍【学习笔记】基于遗传算法和非线性规划的函数寻优算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文是《MATLAB智能算法30个案例分析(第二版)》一书第二章的学习笔记。

一、背景介绍

标准遗传算法的主要本质特征,在于群体搜索策略和简单的遗传算子,这使遗传算法获得了强大的全局最优解能力、问题域的独立性、信息处理的并行性、应用的鲁棒性和操作的简明性。但大量的实践和研究表明,标准的遗传算法存在局部搜索能力差和“早熟”等缺陷,不能保证算法收敛

现有的许多文献中,针对遗传算法存在的上述问题,改进算法主要集中在对遗传算法的编码机制、选择策略、交叉算子、变异算子、特殊算子和参数设计(包括群体规模、交叉概率、变异概率)等

经典的非线性规划算法大多采用梯度下降的方法求解,局部搜索能力强而全局搜索能力弱,容易陷入局部最优解。本文结合两种算法的优点,一方面使用遗传算法进行全局搜索,另一方面使用非线性规划算法进行局部搜索,以得到问题的全局最优解。

二、算法流程

  1. 种群初始化
  2. while  当前迭代次数小于最大迭代次数
  3.  计算适应度;
  4.  选出最优个体的适应度及其染色体
  5.  选择算子;
  6.  交叉算子;
  7.  变异算子;
  8.  if   当前迭代次数满足某个关系
  9.   对每个个体进行非线性规划得到局部最优解,并以此结果为新的染色体继续迭代
  10.  end
  11. end

三、算法实现

以计算函数 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=1nxi2(20xi20)
为例,其中,个体 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

3.1 主函数 main.m
%% 基于遗传算法和非线性规划的函数寻优算法
% 一、结合思想:
% 传统的非线性规划大多采用梯度下降法,局部搜索能力强、全局搜索能力弱
% 遗传算法的全局搜索能力强、局部搜索能力弱% 二、算法流程
% 种群初始化;
% 计算适应度;
% while 当前进化次数 < 最大进化次数
%     选择;
%     交叉;
%     变异;
%     if 当前进化次数满足某个关系
%         对每个个体,进行非线性规划得到局部最优解,并以此为新的染色体继续进化
%     end
% end% 三、代码
clear;clc
% (1)种群初始化
% 1.1 初始参数列表
Nind = 20;                                                          % 种群规模
Lind = 10;                                                          % 染色体个数
maxGen = 200;                                                       % 进化次数(迭代次数)
Pc = 0.6;                                                           % 交叉概率
Pm = 0.01;                                                          % 变异概率
Xmin = [-20, -20, -20, -20, -20, -20, -20, -20, -20, -20 ];         % 下界
Xmax = [20, 20, 20, 20, 20, 20, 20, 20, 20, 20];                    % 上界% 1.2 初始化个体
individuals = struct('fitness', zeros(Nind, 1), 'chrom', []);       % 种群结构体
avg_Fit = [];           % 平均适应度
best_fit = [];          % 最佳适应度
best_chrom = [];        % 最佳适应度对应的个体% 1.3 初始化种群
for i = 1:Nindindividuals.chrom(i,:) = rand(1, Lind).*(Xmax - Xmin)+Xmin;     % 随机产生染色体temp = individuals.chrom(i,:);individuals.fitness(i) = -1*obj_fun(temp);                      % 计算适应度
end
best_chrom = [];                                                    % 历代最优个体
avg_Fit = [];                                                       % 历代适应度平均值
trace = [];                                                         % 历代最优适应度% (2)开始迭代
for gen = 1:maxGen% 计算适应度for i = 1:Nindtemp = individuals.chrom(i,:);individuals.fitness(i) = -1*obj_fun(temp);                  % 计算适应度end% 找出最优适应度及其对应的个体[best_fit best_index] = max(individuals.fitness);best_chrom = [best_chrom;individuals.chrom(best_index,:)];avg_Fit = [avg_Fit; mean(individuals.fitness)];trace = [trace;best_fit];% 选择算子individuals = Select(individuals,Nind);% 交叉操作individuals = Cross(individuals,Pc,Nind,Lind);% 变异操作individuals = Mutation(individuals,Pm,Nind,Lind,Xmax,Xmin);% 非线性规划if do_NLP(gen) == 1A = []; b = []; Aeq = []; Beq = [];for i = 1:Nindx0 = individuals.chrom(i,:);individuals.chrom(i,:) = fmincon(@obj_fun, x0, A, b, Aeq, Beq, Xmin, Xmax);endend
end
trace = -trace;
avg_Fit = -avg_Fit;
clc
disp(['最优适应度为:',num2str(trace(end))])
disp('对应的种群为:')
disp(best_chrom(find(trace == min(trace))-1,:))
plot(trace, 'LineWidth', 1)
title(['适应度进化曲线(最大迭代次数maxGen=',num2str(maxGen),')'])
xlabel('进化次数')
ylabel('适应度')
hold on
plot(avg_Fit, 'LineWidth', 1)
legend('历代最佳适应度', '历代平均适应度')
3.2 选择算子 Select.m

本文使用随机联赛选择作为选择算子。

随机联赛选择也是一种基于个体适应度之间大小关系的选择方法。其基本思想是每次随机选取 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:Nindrace_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
3.3 交叉算子 Cross.m

本文使用模拟二进制交叉算子(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+(1rj)x2j]x2j =21[(1rj)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,uj0.5(2(1uj)1)η+11,0.5uj<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:LindPick = rand;if Pick < Pceta = 0.5;          % 分布因子% 分布因子越大,其产生的后代个体逼近父代个体的概率越大,故SBX算子在局部搜索上表现较强u = rand;if u <= 0.5beta = (2*u)^(1/(1+eta));elsebeta = (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));elsetemp(1,j) = individuals.chrom(index(1),j);temp(2,j) = individuals.chrom(index(2),j);endendnew_individuals.chrom(index(1),:) = temp(1,:);new_individuals.chrom(index(2),:) = temp(2,:);
endend
3.4 变异算子 Mutation.m

本文使用高斯变异算子。高斯变异是改进遗传算法对重点搜索区域的局部搜索性能的另一种变异操作方法。所谓高斯变异操作,是指在进行变异操作时,用符合均值为 μ \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=112ri6)
在进行由 X = x 1 x 2 ⋯ x k ⋯ x l X=x_{1}x_{2}\cdots x_{k}\cdots x_{l} X=x1x2xkxl X = x 1 x 2 ⋯ x k ′ ⋯ x l X=x_1x_2\cdots x_{k}^{'}\cdots x_l X=x1x2xkxl的高斯变异操作时,若变异点 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σ=6UmaxkUmink
则新的基因值 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+6UmaxkUmink(i=112ri6)

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:Nindfor j = 1:LindPick = rand;if Pick < Pmu = (Xmax(j)+Xmin(j))/2;sigma = (Xmax(j)-Xmin(j))/6;new_individuals.chrom(i,j) = u+sigma*(sum(rand([1,12]))-6); endend
endend
3.5 非线性规划函数 do_NLP.m

本文的处理方法比较简单:若当前迭代次数 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) == 0flag = 1;
elseflag = 0;
end
end
3.6 目标函数 obj_fun.m
function fitness = obj_fun(chrom)
% OBJ_FUN 计算染色体序列Chrom对应的染色度
% chrom        input:   染色体序列
% fitness      output:  适应度
x = chrom;
fitness = sum(chrom.^2);
end

四、运行结果

算法运行结果
适应度进化曲线

这篇关于【学习笔记】基于遗传算法和非线性规划的函数寻优算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/301994

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig