本人最近研究NSGA2算法,网上有很多示例代码,但是基本没有注释,代码看起来很头疼,因此我最近把整个代码研读了一遍,并做上中文注释,希望可以帮助到一些和我一样的初学者们。贴出代码之前,首先介绍一下NSGA2遗传算法的流程图:流程图中我把每个详细的步骤用号码标出来,对应下文的代码部分。

首先贴出主函数代码,对应整个流程图:

function nsga_2_optimization
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%此处可以更改
%更多机器学习内容请访问omegaxyz.com
pop = 200; %种群数量
gen = 500; %迭代次数
M = 2; %目标函数数量
V = 30; %维度(决策变量的个数)
min_range = zeros(1, V); %下界 生成1*30的个体向量 全为0
max_range = ones(1,V); %上界 生成1*30的个体向量 全为1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
chromosome = initialize_variables(pop, M, V, min_range, max_range);%初始化种群
chromosome = non_domination_sort_mod(chromosome, M, V);%对初始化种群进行非支配快速排序和拥挤度计算for i = 1 : genpool = round(pop/2);%round() 四舍五入取整 交配池大小tour = 2;%竞标赛  参赛选手个数parent_chromosome = tournament_selection(chromosome, pool, tour);%竞标赛选择适合繁殖的父代mu = 20;%交叉和变异算法的分布指数mum = 20;offspring_chromosome = genetic_operator(parent_chromosome,M, V, mu, mum, min_range, max_range);%进行交叉变异产生子代 该代码中使用模拟二进制交叉和多项式变异 采用实数编码[main_pop,~] = size(chromosome);%父代种群的大小[offspring_pop,~] = size(offspring_chromosome);%子代种群的大小clear tempintermediate_chromosome(1:main_pop,:) = chromosome;intermediate_chromosome(main_pop + 1 : main_pop + offspring_pop,1 : M+V) = offspring_chromosome;%合并父代种群和子代种群intermediate_chromosome = non_domination_sort_mod(intermediate_chromosome, M, V);%对新的种群进行快速非支配排序chromosome = replace_chromosome(intermediate_chromosome, M, V, pop);%选择合并种群中前N个优先的个体组成新种群if ~mod(i,100)clc;fprintf('%d generations completed\n',i);end
endif M == 2plot(chromosome(:,V + 1),chromosome(:,V + 2),'*');xlabel('f_1'); ylabel('f_2');title('Pareto Optimal Front');
elseif M == 3plot3(chromosome(:,V + 1),chromosome(:,V + 2),chromosome(:,V + 3),'*');xlabel('f_1'); ylabel('f_2'); zlabel('f_3');title('Pareto Optimal Surface');
end
 

1 初始化代码

function f = initialize_variables(N, M, V, min_range, max_range)%f是一个由种群个体组成的矩阵
min = min_range;
max = max_range;
K = M + V;%%K是数组的总元素个数。为了便于计算,决策变量和目标函数串在一起形成一个数组。
%对于交叉和变异,利用目标变量对决策变量进行选择
for i = 1 : Nfor j = 1 : Vf(i,j) = min(j) + (max(j) - min(j))*rand(1);%f(i j)表示的是种群中第i个个体中的第j个决策变量,%这行代码为每个个体的所有决策变量在约束条件内随机取值endf(i,V + 1: K) = evaluate_objective(f(i,:), M, V); % M是目标函数数量 V是决策变量个数%为了简化计算将对应的目标函数值储存在染色体的V + 1 到 K的位置。
end

2 快速非支配排序和拥挤度计算代码

%% 对初始种群开始排序 快速非支配排序
% 使用非支配排序对种群进行排序。该函数返回每个个体对应的排序值和拥挤距离,是一个两列的矩阵。
% 并将排序值和拥挤距离添加到染色体矩阵中
function f = non_domination_sort_mod(x, M, V)
[N, ~] = size(x);% N为矩阵x的行数,也是种群的数量
clear m
front = 1;
F(front).f = [];
individual = [];for i = 1 : Nindividual(i).n = 0;%n是个体i被支配的个体数量individual(i).p = [];%p是被个体i支配的个体集合for j = 1 : Ndom_less = 0;dom_equal = 0;dom_more = 0;for k = 1 : M        %判断个体i和个体j的支配关系if (x(i,V + k) < x(j,V + k))  dom_less = dom_less + 1;elseif (x(i,V + k) == x(j,V + k))dom_equal = dom_equal + 1;elsedom_more = dom_more + 1;endendif dom_less == 0 && dom_equal ~= M % 说明i受j支配,相应的n加1individual(i).n = individual(i).n + 1;elseif dom_more == 0 && dom_equal ~= M % 说明i支配j,把j加入i的支配合集中individual(i).p = [individual(i).p j];endend   if individual(i).n == 0 %个体i非支配等级排序最高,属于当前最优解集,相应的染色体中携带代表排序数的信息x(i,M + V + 1) = 1;F(front).f = [F(front).f i];%等级为1的非支配解集end
end
%上面的代码是为了找出等级最高的非支配解集
%下面的代码是为了给其他个体进行分级
while ~isempty(F(front).f)Q = []; %存放下一个front集合for i = 1 : length(F(front).f)%循环当前支配解集中的个体if ~isempty(individual(F(front).f(i)).p)%个体i有自己所支配的解集for j = 1 : length(individual(F(front).f(i)).p)%循环个体i所支配解集中的个体individual(individual(F(front).f(i)).p(j)).n = ...%...表示的是与下一行代码是相连的, 这里表示个体j的被支配个数减1individual(individual(F(front).f(i)).p(j)).n - 1;if individual(individual(F(front).f(i)).p(j)).n == 0% 如果q是非支配解集,则放入集合Q中x(individual(F(front).f(i)).p(j),M + V + 1) = ...%个体染色体中加入分级信息front + 1;Q = [Q individual(F(front).f(i)).p(j)];endendendendfront =  front + 1;F(front).f = Q;
end[temp,index_of_fronts] = sort(x(:,M + V + 1));%对个体的代表排序等级的列向量进行升序排序 index_of_fronts表示排序后的值对应原来的索引
for i = 1 : length(index_of_fronts)sorted_based_on_front(i,:) = x(index_of_fronts(i),:);%sorted_based_on_front中存放的是x矩阵按照排序等级升序排序后的矩阵
end
current_index = 0;%% Crowding distance 计算每个个体的拥挤度for front = 1 : (length(F) - 1)%这里减1是因为代码55行这里,F的最后一个元素为空,这样才能跳出循环。所以一共有length-1个排序等级distance = 0;y = [];previous_index = current_index + 1;for i = 1 : length(F(front).f)y(i,:) = sorted_based_on_front(current_index + i,:);%y中存放的是排序等级为front的集合矩阵endcurrent_index = current_index + i;%current_index =isorted_based_on_objective = [];%存放基于拥挤距离排序的矩阵for i = 1 : M[sorted_based_on_objective, index_of_objectives] = ...sort(y(:,V + i));%按照目标函数值排序sorted_based_on_objective = [];for j = 1 : length(index_of_objectives)sorted_based_on_objective(j,:) = y(index_of_objectives(j),:);% sorted_based_on_objective存放按照目标函数值排序后的x矩阵endf_max = ...sorted_based_on_objective(length(index_of_objectives), V + i);%fmax为目标函数最大值 fmin为目标函数最小值f_min = sorted_based_on_objective(1, V + i);y(index_of_objectives(length(index_of_objectives)),M + V + 1 + i)...%对排序后的第一个个体和最后一个个体的距离设为无穷大= Inf;y(index_of_objectives(1),M + V + 1 + i) = Inf;for j = 2 : length(index_of_objectives) - 1%循环集合中除了第一个和最后一个的个体next_obj  = sorted_based_on_objective(j + 1,V + i);previous_obj  = sorted_based_on_objective(j - 1,V + i);if (f_max - f_min == 0)y(index_of_objectives(j),M + V + 1 + i) = Inf;elsey(index_of_objectives(j),M + V + 1 + i) = ...(next_obj - previous_obj)/(f_max - f_min);endendenddistance = [];distance(:,1) = zeros(length(F(front).f),1);for i = 1 : Mdistance(:,1) = distance(:,1) + y(:,M + V + 1 + i);endy(:,M + V + 2) = distance;y = y(:,1 : M + V + 2);z(previous_index:current_index,:) = y;
end
f = z();%得到的是已经包含等级和拥挤度的种群矩阵 并且已经按等级排序排序

3 竞标赛选择代码

function f = tournament_selection(chromosome, pool_size, tour_size)
[pop, variables] = size(chromosome);%获得种群的个体数量和决策变量数量
rank = variables - 1;%个体向量中排序值所在位置
distance = variables;%个体向量中拥挤度所在位置
%竞标赛选择法,每次随机选择两个个体,优先选择排序等级高的个体,如果排序等级一样,优选选择拥挤度大的个体
for i = 1 : pool_sizefor j = 1 : tour_sizecandidate(j) = round(pop*rand(1));%随机选择参赛个体if candidate(j) == 0candidate(j) = 1;endif j > 1while ~isempty(find(candidate(1 : j - 1) == candidate(j)))%防止两个参赛个体是同一个candidate(j) = round(pop*rand(1));if candidate(j) == 0candidate(j) = 1;endendendendfor j = 1 : tour_size% 记录每个参赛者的排序等级 拥挤度c_obj_rank(j) = chromosome(candidate(j),rank);c_obj_distance(j) = chromosome(candidate(j),distance);endmin_candidate = ...find(c_obj_rank == min(c_obj_rank));%选择排序等级较小的参赛者,find返回该参赛者的索引if length(min_candidate) ~= 1%如果两个参赛者的排序等级相等 则继续比较拥挤度 优先选择拥挤度大的个体max_candidate = ...find(c_obj_distance(min_candidate) == max(c_obj_distance(min_candidate)));if length(max_candidate) ~= 1max_candidate = max_candidate(1);endf(i,:) = chromosome(candidate(min_candidate(max_candidate)),:);elsef(i,:) = chromosome(candidate(min_candidate(1)),:);end
end

4、5 交叉 变异代码

function f  = genetic_operator(parent_chromosome, M, V, mu, mum, l_limit, u_limit)
[N,m] = size(parent_chromosome);%N是交配池中的个体数量clear m
p = 1;
was_crossover = 0;%是否交叉标志位
was_mutation = 0;%是否变异标志位for i = 1 : N%这里虽然循环N次,但是每次循环都会有概率产生2个或者1个子代,所以最终产生的子代个体数量大约是2N个if rand(1) < 0.9%交叉概率0.9child_1 = [];child_2 = [];parent_1 = round(N*rand(1));if parent_1 < 1parent_1 = 1;endparent_2 = round(N*rand(1));if parent_2 < 1parent_2 = 1;endwhile isequal(parent_chromosome(parent_1,:),parent_chromosome(parent_2,:))parent_2 = round(N*rand(1));if parent_2 < 1parent_2 = 1;endendparent_1 = parent_chromosome(parent_1,:);parent_2 = parent_chromosome(parent_2,:);for j = 1 : Vu(j) = rand(1);if u(j) <= 0.5bq(j) = (2*u(j))^(1/(mu+1));elsebq(j) = (1/(2*(1 - u(j))))^(1/(mu+1));endchild_1(j) = ...0.5*(((1 + bq(j))*parent_1(j)) + (1 - bq(j))*parent_2(j));child_2(j) = ...0.5*(((1 - bq(j))*parent_1(j)) + (1 + bq(j))*parent_2(j));if child_1(j) > u_limit(j)child_1(j) = u_limit(j);elseif child_1(j) < l_limit(j)child_1(j) = l_limit(j);endif child_2(j) > u_limit(j)child_2(j) = u_limit(j);elseif child_2(j) < l_limit(j)child_2(j) = l_limit(j);endendchild_1(:,V + 1: M + V) = evaluate_objective(child_1, M, V);child_2(:,V + 1: M + V) = evaluate_objective(child_2, M, V);was_crossover = 1;was_mutation = 0;else%if >0.9parent_3 = round(N*rand(1));if parent_3 < 1parent_3 = 1;endchild_3 = parent_chromosome(parent_3,:);for j = 1 : Vr(j) = rand(1);if r(j) < 0.5delta(j) = (2*r(j))^(1/(mum+1)) - 1;elsedelta(j) = 1 - (2*(1 - r(j)))^(1/(mum+1));endchild_3(j) = child_3(j) + delta(j);if child_3(j) > u_limit(j) % 条件约束child_3(j) = u_limit(j);elseif child_3(j) < l_limit(j)child_3(j) = l_limit(j);endend child_3(:,V + 1: M + V) = evaluate_objective(child_3, M, V);was_mutation = 1;was_crossover = 0;end% if <0.9if was_crossoverchild(p,:) = child_1;child(p+1,:) = child_2;was_cossover = 0;p = p + 2;elseif was_mutationchild(p,:) = child_3(1,1 : M + V);was_mutation = 0;p = p + 1;end
endf = child;

交叉算法选择的是模拟二进制交叉,变异算法选择的是多项式变异, 算法的具体过程大家可以在网上查阅一下

8 生成新的种群(精英策略)

function f  = replace_chromosome(intermediate_chromosome, M, V,pop)%精英选择策略[N, m] = size(intermediate_chromosome);
[temp,index] = sort(intermediate_chromosome(:,M + V + 1));clear temp m
for i = 1 : Nsorted_chromosome(i,:) = intermediate_chromosome(index(i),:);
endmax_rank = max(intermediate_chromosome(:,M + V + 1));previous_index = 0;
for i = 1 : max_rankcurrent_index = max(find(sorted_chromosome(:,M + V + 1) == i));if current_index > popremaining = pop - previous_index;temp_pop = ...sorted_chromosome(previous_index + 1 : current_index, :);[temp_sort,temp_sort_index] = ...sort(temp_pop(:, M + V + 2),'descend');for j = 1 : remainingf(previous_index + j,:) = temp_pop(temp_sort_index(j),:);endreturn;elseif current_index < popf(previous_index + 1 : current_index, :) = ...sorted_chromosome(previous_index + 1 : current_index, :);elsef(previous_index + 1 : current_index, :) = ...sorted_chromosome(previous_index + 1 : current_index, :);return;endprevious_index = current_index;
end
 

本例子选择的测试函数是ZDT1, 目标评价函数如下:

function f = evaluate_objective(x, M, V)%%计算每个个体的M个目标函数值
f = [];
f(1) = x(1);
g = 1;
sum = 0;
for i = 2:Vsum = sum + x(i);
end
sum = 9*(sum / (V-1));
g = g + sum;
f(2) = g * (1 - sqrt(x(1) / g));
end
 

经历500次迭代后的pareto最优解集:

NSGA2算法及其代码相关推荐

  1. 多目标优化算法matlab代码大合集

    [NSGA2]基于NSGA2算法求解多目标优化问题Matlab源码2 [水母搜索优化器算法]基于水母搜索优化器算法求解多目标优化问题(JellyfishSearchOptimizer,JSO)[粒子群 ...

  2. dst matlab,DSTcode DST跟踪算法MATLAB代码,复杂环境中仿多目标 实现的单 Other systems 其他 272万源代码下载- www.pudn.com...

    文件名称: DSTcode下载  收藏√  [ 5  4  3  2  1 ] 开发工具: matlab 文件大小: 82 KB 上传时间: 2017-03-17 下载次数: 0 提 供 者: Mar ...

  3. 浅谈网络爬虫中广度优先算法和代码实现

    前几天给大家分享了网络爬虫中深度优先算法的介绍及其代码实现过程,没来得及上车的小伙伴们可以戳这篇文章--浅谈网络爬虫中深度优先算法和简单代码实现.今天小编给大家分享网络爬虫中广度优先算法的介绍及其代码 ...

  4. 计算1至1000间的合数c语言,输出1000以内的素数的算法(实例代码)

    输出1000以内的素数的算法(实例代码) 代码如下所示: 复制代码 代码如下: #include "stdafx.h" #include #include bool IsSushu ...

  5. dijkstra算法matlab代码_头脑风暴优化(BSO)算法(附MATLAB代码)

    BSO讲解https://www.zhihu.com/video/1252605855767736320 B站搜索:随心390,同步观看视频 各位小伙伴可在闲鱼搜索 优化算法交流地,即可搜索到官方闲鱼 ...

  6. C语言 | 基于51单片机实现MPU6050的卡尔曼滤波算法(代码类2)

    github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 之前写过一个博客(代码分享:单片机开发 | ...

  7. php三个数字比较大小排序,php中常用的4种实现数字大小排序的冒泡选择等算法函数代码...

    分别用冒泡排序法,快速排序法,选择排序法,插入排序法将下面数组中按照从小到大的顺序进行排序. 本站收录这篇文章php中常用的4种实现数字大小排序的冒泡选择等算法函数代码,详细解说文章中相关排序 冒泡 ...

  8. java做a_Java编程实现A*算法完整代码

    前言 A*搜寻算法俗称A星算法.这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法.常用于游戏中 通过二维数组构建的一个迷宫,"%"表示墙壁,A为起点,B为终点,&qu ...

  9. 多元线性回归算法python实现_手写算法-Python代码推广多元线性回归

    1.梯度下降-矩阵形式 上篇文章介绍了一元线性回归,包括Python实现和sklearn实现的实例.对比,以及一些问题点,详情可以看这里: 链接: 手写算法-Python代码实现一元线性回归 里面封装 ...

最新文章

  1. Vue 生命周期记录_学习笔记
  2. h5打开App的方法。
  3. 引用外部jQuery地址
  4. 开源大数据周刊-第44期
  5. linux内核学习之四:进程切换简述
  6. abb限位开关已打开drv1_广告雕刻机限位开关触发
  7. docker启动顺序
  8. C#单例模式的简单使用
  9. CANOpen同步报文
  10. activity 点击后传递数据给fragment_【磨叽教程】Android进阶之Fragment的管理以及事务执行...
  11. 2021想学UI设计,你必需要知道这些
  12. [验证码实现] Captcha 验证码类,一个很个性的验证码类 (转载)
  13. mysql 单精度和双经度,mysql – 计算距离给定2点,纬度和经度
  14. Magic Swf2Gif(SWF转换GIF)绿色汉化版 V1.35
  15. Karen与测试 奇迹淫巧+快速幂
  16. ERP系统操作难吗?
  17. Vue单文件组件TypeScript写法
  18. 数介牵手亿阳,ALEIYE深入运营商大数据
  19. 搞定 conda 安装包报错问题
  20. configure: error: no acceptable C compiler found in $PATH 问题解决

热门文章

  1. linux jobs继续运行,Linux jobs等前后台运行命令详解
  2. php 上传apk包到cdn_网站cdn加速,cdn防御系统
  3. opencv:Gamma校正
  4. linux那些事之TLB(Translation-Lookaside Buffer)无效操作
  5. 2021.08.22学习内容torch.cat()和torch.stack()函数
  6. finetune代码实战讲解(李沐)
  7. curring函数,以及高阶函数
  8. copyToLocalFile报出空异常
  9. 如何在JS判断是否为IE浏览器
  10. django连接自定义mysql,Django中使用自定义Manager管理多个Mysql数据库