遺傳算法求解最大值(含matlab代碼)


新手,有什么不足的或者不准確的,大家希望能熱心指出,一起討論交流

問題描述

求解函數f(x) = x * sin(10pi * x) + 2 在區間[-1,2]上的最大值,要求精度10^-6.

代碼部分

具體的理論部分不進行過多的解釋,網上有很多詳細的帖子。直接上代碼,一共有Ga_max.m、bin2dec.m、selection.m、crossover.m、mutation.m五部分組成,第一個是求解最大值的主函數,后面四個分別是二進制轉十進制、選擇、交換、和變異函數

主函數部分

首先確定種群的大小N和每個個體的編碼長度L,隨機生成一個只含0-1的N x L的矩陣P,也就是初始化種群。然后確定進化的相關參數,有:交叉的概率、變異的概率和要進化迭代的次數。
初始化完成后開始進化,也就是開始for循環,首先對x進行解碼碼,對個體(二進制串)轉化成十進制,然后計算個體的適應度。接着要進行遺傳操作(選擇、交叉、變異),完成種群更新。計算新種群的適應度,以及最優個體和最優適應度。
迭代完成后,最后一代的最優個體和最優個體即為所求。
其中,遺傳算法求解最優解時,首先要將實際問題的參數集進行編碼化,常見的類型有二進制編碼和浮點數編碼。
這里采用二進制編碼,因為需要精度達到10-6,也就是說編碼長度L需要滿足:2L > (2-(-1)) * 10^6,這里編碼長度L選取22。

%%
clc
clear
close all
%% 
% 問題 求解f再[x_min,x_max]上的最大值
%需要求解再區間內函數的最大值
f = 'x  .*  sin(x .* 10 * pi) + 2';
x_min = -1;x_max = 2; %自變量取值區間
%初始化參數
N = 100; %種群大小
L = 22; %編碼長度
P = zeros(N,L);  %N個個體,每個個體的編碼長度為L,由01構成
%初始化種群
P = round(rand([N,L]));

%% 迭代
%迭代初始化
pc = 0.6; %交叉概率
pm = 0.05; %變異概率
gen = 500; %迭代次數
fit_mean = [];%平均適應度
fit_opt = [];%最優適應度
iter = 1;%迭代計數器

%開始進化
for iter = 1:gen
   x = bin2dec(P(:,1:L),x_min,x_max);
   fit = eval(f);  
    %select
   P_new = selection(P,fit);
    %crossover
   P_new = crossover(P_new,pc);
    %mutation
   P_new = mutation(P_new,pm);
   
    %更新種群
   P = P_new;
    %計算新種群的適應度
   x = bin2dec(P(:,1:L),x_min,x_max);
   fit = eval(f);
   
   [opt,loc] = max(fit);%記錄最優適應度和最優個體
   fit_mean(iter) = mean(fit);  %記錄適應度均值
   fit_opt(iter) = opt;  %記錄最佳適應度
  
    
    %畫圖部分    
    %初始選取的基因位置  
   if iter == 1
      pause(1)
      figure(1)
      cla
      fplot(f,[x_min,x_max]);
      hold on 
      plot(x,fit,'r*')
      title(['迭代次數iter=',num2str(iter)])
   end
    %基因位置變化記錄   
   if mod(iter,50) == 0
      pause(1)
      figure(1)
      cla
      fplot(f,[x_min,x_max]);
      hold on 
      plot(x,fit,'r*')
      title(['迭代次數iter=',num2str(iter)])
   end
   iter = iter + 1;
    
    
end

fprintf('The Best X -->%5.6f\n',x(loc));
fprintf('The Best Y -->%5.6f\n',opt);

二進制轉十進制函數

注意這里的十進制是指對應解區間的十進制數。如果二進制正常轉到十進制時K,那么這里還要再對k進行“歸一化”。有如下關系:
x = x_min + (x_max - x_min) * k / (2^L - 1)

% 二進制轉十進制
function num = bin2dec(num_bin,n_min,n_max)
% ```
%     num_bin:一串二進制數
%     n_min,n_max:歸一化的上下區間
%     二進制轉化為十進制,再把十進制的數壓縮到[n_min,n_max]區間上
num_bin = fliplr(num_bin);%二進制串左右反轉
[m,n] = size(num_bin);%m個長度n的二進制串
weight = 0:1:n-1;
weight = ones(m,1) * weight;%[m,n]的權重矩陣,每一行都是0,1,2...n-1,2的多少次方
num_dec = sum((num_bin .* 2.^weight)');  %每一分位成對應的權重求和  %轉置是因為sum是列求和
num = n_min + (n_max-n_min) * num_dec ./ (2^n - 1);


end

選擇函數

選擇采用輪盤賭選擇的方式,選擇個體i的概率 pi = fi / sum(fi)。出現的頻數越大,被選中的概率就越大,優勢基因更能夠在種群中擴散。注意代碼中里產生的隨機數是與分布函數做比較的。

%%  selection
function P_new = selection(P,fit)
% % % % 
% 采用輪盤選擇法來選擇需要復制的基金
% P_new : 是新的基因組
% P: 是舊基因組
% fit: 是就基因組所對應的適應度
[m,n] = size(P); %種群中m個個體
p_fit = fit./sum(fit);  %概率
F_fit = cumsum(p_fit);  %分布函數
temp = sort(rand(1,m));    %隨機生產m個概率
fit_p = 1;
new_p = 1;  %兩個指針,一個指新種群,一個指舊的
while new_p <= m  %需要循環m次,把新基因組填滿
     if temp(new_p) < F_fit(fit_p)   %根據隨機參數的概率與分布函數作比較,得出要選擇的基因
         P_new(new_p,:) = P(fit_p,:);  %選擇后完成復制
         new_p = new_p + 1;      %指針加一,尋找下一個要選擇的
     else
         fit_p = fit_p + 1;  %在舊種群中,沒有選中這一個體。加一對下一個進行判斷
     end
end

交叉函數

% crossover
function P_new = crossover(P,pc)
% % % 
% P_new: 新種群
% P : 舊種群
% pc : 交叉概率
[m,n] = size(P);
for i = 1:2:m-1
   if rand < pc  %發生交叉
       p_cross = ceil(rand * n); %發生交叉的點位,兩個個體這一點之后的所有基因交換
       P_new(i,:) =  [P(i,1:p_cross - 1),P(i + 1,p_cross:n)];
       P_new(i+1,:) = [P(i + 1,1:p_cross - 1),P(i,p_cross:n)];%兩個個體交換交叉點后的基因序列
   else
       P_new(i,:) = P(i,:);
       P_new(i + 1,:) = P(i + 1,:);
   end
    
end

變異函數

function P_new = mutation(P,pm)
% % % 
% 變異操作

[m,n] = size(P);
P_new = P;
for i = 1:m
   if rand < pm %發生變異
       p_mutation = ceil(rand*n);%變異的點位
       if P_new(i,p_mutation) == 0
          P_new(i,p_mutation) = 1;
       else
          P_new(i,p_mutation) = 0;  %對變異點的記憶值進行反轉
       end
       
   end
end

結果展示

初始基因位置

迭代100次

迭代200次

迭代300次

迭代400次

迭代500次


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM