SGA2主要是對NSGA算法的改進。NSGA是N. Srinivas 和 K. Deb在1995年發表的一篇名為《Multiobjective function optimization using nondominated sorting genetic algorithms》的論文中提出的該算法在快速找到Pareto前沿和保持種群多樣性方面都有很好的效果,不過在這么多年的應用中也出現了如下的一些問題:
function nsga_2_optimization
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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;%% parent_chromosome 競標賽選擇的適合繁殖的父代 M 目標函數數量 V維度(決策變量的個數) mu = 20;%交叉和變異算法的分布指數 mum = 20; %%min_range = zeros(1, V); %下界 生成1*30的個體向量 全為0 %%max_range = ones(1,V); %上界 生成1*30的個體向量 全為1 這個在這里用來約束解(Xi)的范圍%%offspring_chromosome不一定生成了500個后代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);%對新的種群進行快速非支配排序%%精英選擇 從子代和父代中選出Pop個chromosome = replace_chromosome(intermediate_chromosome, M, V, pop);%選擇合并種群中前N個優先的個體組成新種群%%每計算100代清空下控制臺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
2.目標函數:evaluate_objective
這里采用的是兩目標函數:ZDT1??ZDT1是MOP中常用的測試函數
%%目標函數 ZDT1是MOP中常用的測試函數
%%這里有兩個目標函數 f1 f2 這里就是求f1 f2值得公式
function f = evaluate_objective(x, M, V)%%計算每個個體的M個目標函數值
%%決策變量就是解的個數
%%f(i,V + 1: K) = evaluate_objective(f(i,:), M, V); % M是目標函數數量 V是決策變量個數 f(:,1)就是取f 矩陣的第1列。
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
function f = initialize_variables(N, M, V, min_range, max_range)%f是一個由種群個體組成的矩陣
%M目標函數數量
%V維度(決策變量的個數)
%N 種群數量
min = min_range; %下界 生成1*30的個體向量 全為0
max = max_range; %上界 生成1*30的個體向量 全為1K = 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個決策變量, %%-ppppppppppp%這行代碼為每個個體的所有決策變量在約束條件內隨機取值endf(i,V + 1: K) = evaluate_objective(f(i,:), M, V); % M是目標函數數量 V是決策變量個數 f(:,1)就是取f 矩陣的第1列。%為了簡化計算將對應的目標函數值儲存在染色體的V + 1 到 K的位置。%%k+1-V 存的是目標函數的值
end
4.快速非支配排序和擁擠度計算代碼:non_domination_sort_mod
unction f = non_domination_sort_mod(x,M,V) 此函數根據非支配對當前popultion進行排序。 第一個前面的所有個體的等級為1, 第二個前面的個體被賦予等級2, 依此類推。在分配等級之后,計算每個前沿中的擁擠度。 N - 目標空間總體大小 M - 目標函數的數量 2 V - 決策變量的數量
%% 對初始種群開始排序 快速非支配排序
% 使用非支配排序對種群進行排序。該函數返回每個個體對應的排序值和擁擠距離,是一個兩列的矩陣。
% 并將排序值和擁擠距離添加到染色體矩陣中
%M + V + 1 M + V + 2 存的是分層等級
%x 進來時是200行(種群個數)*32列(30列x1-x30 2列 f1 f2)
%x出去時33列存的是當前個體的層級 1為最高
function f = non_domination_sort_mod(x, M, V)
%%chromosome = non_domination_sort_mod(chromosome, M, V); x/chromosome是解
%%其中包括了30個解和 目標函數的值 共32個 M 目標函數數量 V決策變量個數
[N, ~] = size(x);% N為矩陣x的行數,也是種群的數量
clear m
front = 1;%front記錄了當前正在篩選那一層級的個體
F(front).f = []; %f是一個數組 用于存放當前front層級的個體
individual = [];%%存放個體i的支配個體的信息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;%1代表最高等級 改個體i的層級為1F(front).f = [F(front).f i];%等級為1的非支配解集 f是個矩陣 在F(front).f 矩陣后面加上 i 賦值給F(front).f 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(F(front).f(i)).p(j) 代表front層個體所支配的一個個體individual(individual(F(front).f(i)).p(j)).n = ...%...表示的是與下一行代碼是相連的, 這里表示個體j的被支配個數減1 individual(individual(F(front).f(i)).p(j)).n - 1; %因為層級最高為1(層級為1 即這時n為0)的在上面已經篩選完 這個循環里面的n最少為1 都被支配%代表去掉front層的個體后,front層個體所支配的一個個體的被支配的個數為0時,這時它是這時候的優解之一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)];endendendend%%到這已經完成了下一層級的個體的篩選front = front + 1;F(front).f = Q;
end%x(:,M + V + 1)就是取x矩陣的第M + V + 1列 temp在這里沒用 為了就是得到index_of_fronts%這里想讓這個矩陣按照第M+V+1也就層級進行排序,因為matlab沒有直接排序的方法,所以采取這樣的方法 x本身的順序沒有變%sorted_based_on_front存儲了排序后的矩陣
[temp,index_of_fronts] = sort(x(:,M + V + 1));%對個體的代表排序等級的列向量進行升序排序 index_of_fronts表示排序后的值對應原來的未排序的矩陣在當前列的行下標
%x(:,M + V + 1) 就是取這個矩陣的M + V + 1列
for i = 1 : length(index_of_fronts)sorted_based_on_front(i,:) = x(index_of_fronts(i),:);%sorted_based_on_front中存放的是x矩陣按照排序等級升序排序后的矩陣 index_of_fronts(i)放到第i行
endcurrent_index = 0;
%% Crowding distance 計算每個個體的擁擠度for front = 1 : (length(F) - 1)%這里減1是因為代碼55行這里,F的最后一個元素為空,這樣才能跳出循環。所以一共有length-1個排序等級distance = 0;y = [];previous_index = current_index + 1; %% current_index記錄的是每一層級的第一個個體在sorted_based_on_front的下標-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));%按照目標函數值排序 先按目標f1的值排序 再按f2排序 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存放按照目標函數值排序后的y矩陣 在這里的y已經對層級進行過排序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) %%如果這一層級里只有一個個體 則這一層的個體fi的距離為無窮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); %%這里是歸一化處理 用最簡單的標準化方法 讓間距的值小一點 y的M + V + 1 + 1記錄f1的擁擠度 M + V + 1 + 2記錄endendenddistance = [];distance(:,1) = zeros(length(F(front).f),1);%%初始化 這個列向量用于保存當前front層的每一個體的擁擠度for i = 1 : Mdistance(:,1) = distance(:,1) + y(:,M + V + 1 + i); %%將y的f1的距離和f2的距離相加作為該個體的擁擠度endy(:,M + V + 2) = distance;y = y(:,1 : M + V + 2); %%應該是可省的z(previous_index:current_index,:) = y; %%在這里 previous_index記錄該層級中第一個個體在矩陣中的行下標 current_index記錄該層級中最后一個個體在矩陣中的行下標
end
f = z();%得到的是已經包含等級和擁擠度的種群矩陣 并且已經按等級和擁擠距離排序
1.首先將父代種群C i C_iCi?和子代種群D i D_iDi?合成種群R i R_iRi?。 2.根據以下規則從種群R i R_iRi?生成新的父代種群C i + 1 C_{i+1}Ci+1?: ??????①根據Pareto等級從低到高的順序,將整層種群放入父代種群C i + 1 C_{i+1}Ci+1?,直到某一層該層個體不能全部放入父代種群C i + 1 C_{i+1}Ci+1?; ??????②將該層個體根據擁擠度從大到小排列,依次放入父代種群C i + 1 C_{i+1}Ci+1?中,直到父代種群C i + 1 C_{i+1}Ci+1?填滿。
function f = replace_chromosome(intermediate_chromosome, M, V,pop)%精英選擇策略
%%replace_chromosome(intermediate_chromosome, M, V, pop)
%%intermediate_chromosom 子代和父代兩代種群放在一起進行非支配排序后的矩陣%%生成新的種群(精英策略)
[N, m] = size(intermediate_chromosome);
%%獲得按層級進行排序的種群索引
[temp,index] = sort(intermediate_chromosome(:,M + V + 1)); %%Matlab中沒有辦法直接讓矩陣按照某一列直接排序所以只養血clear temp m
%%獲得按層級排序后的種群 前面非支配選擇不是已經排過序了?
for i = 1 : N sorted_chromosome(i,:) = intermediate_chromosome(index(i),:);
end%獲得這個種群最大的層級
max_rank = max(intermediate_chromosome(:,M + V + 1));%%用于保存當前新的種群中已經篩選到的個體數量
previous_index = 0;
for i = 1 : max_rank%%找到當前層級的所有個體current_index = max(find(sorted_chromosome(:,M + V + 1) == i));%%這樣寫避免了遍歷尋找當前層級為i的個體 直接得到當前層級個體最大的索引,因為已經排過序%%所以根據current_index就可以得到當前層級的所有個體%%current_inde的位置就代表了當前已經篩選出了多少個個體了 因為前面排過序%當該層級的個體大于所需的種群大小時if current_index > pop%%總共需要篩選出pop個個體,remaining保存還需篩選出多少個體新一代種群才達到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');%%獲得該層級中擁擠距離大的remaining個 個體for j = 1 : remainingf(previous_index + j,:) = temp_pop(temp_sort_index(j),:);endreturn;elseif current_index < pop%%小于Pop 說明新種群中個體數量<pop 還需遍歷下一層級f(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