遺傳算法應用(實現十進制小數轉換爲二進制)

遺傳算法應用

[1]、[2]、[3]在文章的最後用圖像進行說明。

一、問題概述

    求 y=10sin(5x)+7*|x-5|+10 最大值。函數圖像如圖:
       

二、問題解決
1.產生初始種羣

  用隨機數生成器分別產生8、16、32[1]隨機數作爲初始種羣。
  由於給出的函數定義域是全體實數,且rand()函數只能生成[0,1]的隨機數,我們取一個範圍(如 [0,10])作爲倍率,以產生大於1的數

  代碼如下:

%% 設置變量
N=32;%初始羣體大小,即產生N個在(a,b)範圍內的隨機數
a=0;%自變量取值下界
b=10;%自變量取值上界

%% 1.產生初始羣體
initalGroup10=a+(b-a).*rand([N 1]);%初始羣體,十進制編碼
2.編碼與解碼

  採用二進制編碼,matlab默認編碼位數。matlab中十進制轉二進制函數dec2bin()默認會取最合適的編碼位數。如果指定了編碼位數,則多餘部分會補零。
需要注意的是,matlab中的dec2bin()只能轉換整數部分,小數部分會被自動省去。下面鏈接介紹了一種能將十進制小數轉換爲二進制的方法。這裏我們先用dec2bin()。
matlab實現十進制小數轉換爲二進制

3.確定適應度

   將初始種羣帶入目標函數,目標函數的值定爲適應度。

    %% 2.求初始羣體的適應度
    %適應度函數,即爲目標函數
    adaptLevel = objectFun(initalGroup10);
    %將初始種羣和適應度組合
    initalGroup = [initalGroup10 adaptLevel];

  其中,objectFun() 代碼如下:

function y = objectFun(x)
    y = 10.*sin(5.*x)+7.*abs(x-5)+10;
end
4.複製

  採用輪盤賭的方法確定複製個體。

    %% 3.確定複製個體
    %確定需要複製的個體的序號
    copyIndex=trochalDisk(initalGroup,N);
    %copyIndex返回的序號是對initalGroup排序後的序號,因此對適應度值升序排序
    sortrows(initalGroup,-2);
    %複製後的種羣
    copyGroup10=[];
    for i=1:size(copyIndex)
        copyGroup10=[copyGroup10 initalGroup(copyIndex(i),1)];
    end

  其中,trochalDisk()是輪盤賭實現函數,代碼如下:

function index =trochalDisk(pk,N)
%pk 輪盤每一份的值 
%N  輪盤的份數
    %排序
    sortrows(pk,-2);
    pk=pk(:,2);
    %確定輪盤法則的區間trochal
    trochal=cumsum(pk(:));
    
    %隨機產生N個數,並確定在輪盤的哪個區間
    tc=trochal(1)+(trochal(end)-trochal(1)).*rand([N 1]);
    index=[];
    for i=1:size(tc)
        t=find(trochal>=tc(i));
        index=[index;t(1)];
    end
end
5.交叉和變異

  需要依次確定交叉和變異中的幾個隨機。
1)交叉中有三個隨機:個體隨機、概率可調、編碼位置隨機。

  • 隨機數生成器確定發生交叉的個體序號。
  • 交叉概率爲50%~80%[2],可以上下浮動。採用人爲輸入
  • 隨機數生成器確定發生交叉的編碼位置(產生一個或多個,這裏以多個爲例)。

2)變異中有三個隨機:個體隨機、哪位變異隨機、變異幾位隨機。

  • 隨機數生成器確定發生變異的個體序號。
  • 變異概率爲0.1%~1%[3],可以上下浮動。採用人爲輸入
  • 隨機數生成器確定發生變異的編碼位置(產生一個或多個,用隨機數決定)。

  代碼如下:

crossProbility=0.07;%交叉概率50%~80%,可以上下浮動
variationProbility=0.001;%變異概率0.1%~1%,可以上下浮動
crossGroup = cross(crossProbility,copyGroup10);
variationGroup = variation(variationProbility,crossGroup);

  其中,cross()是交叉實現函數,variation()是變異實現函數。

function crossGroup = cross(probility,group)
%crossGroup 交叉後的種羣
%probility 交叉概率
%group 複製後的種羣

%確定幾個個體發生交叉,讓每兩個相鄰個體發生交叉,因此定爲偶數個
crossNumber=floor(probility*size(group,2));
if rem(crossNumber,2)~=0
    crossNumber = crossNumber+1;
end
%隨機產生個體交叉的序號
crossIndex=floor(1+(size(group,2)-1).*rand([crossNumber 1]));
%隨機產生個體交叉的位置,範圍:1-二進制長度
group2=dec2bin(group);
crossPos=floor(1+(size(group2,2)-1).*rand([crossNumber/2 1]));

%交叉
for i=1:2:crossNumber
%下面這段代碼和C語言中最基本的swamp()函數效果一樣
    temp=group2(crossIndex(i),crossPos:end);
    group2(crossIndex(i),crossPos:end)=group2(crossIndex(i+1),crossPos:end);
    group2(crossIndex(i+1),crossPos:end)=temp;
end
%2進制變爲10進制
crossGroup=bin2dec(group2);
end
function variationGroup = variation(probility,group)
%variationGroup 變異後的種羣
%probility 變異概率
%group 變異後的種羣

%確定幾個個體發生變異
variationNumber=floor(probility*size(group,2));
%隨機產生個體變異的序號
variationIndex=floor(1+(size(group,2)-1).*rand([variationNumber 1]));
group2=dec2bin(group);
%確定發生變異的位置的個數
variationPosNum=floor(1+(size(group2,2)-1));
%隨機產生個體變異的位置,1-二進制長度
variationPos=floor(1+(size(group2,2)-1).*rand([variationPosNum 1]));

%變異
for i=1:variationNumber
    for j=1:variationPosNum
        if group2(variationIndex(i),variationPos(j))==0
            group2(variationIndex(i),variationPos(j))='1';
        else
            group2(variationIndex(i),variationPos(j))='0';
        end
    end
end

variationGroup=bin2dec(group2);
end
6.適應度驗算

  以本次迭代和上一次迭代適應度值改變量是否小於給定精度,決定是否終止循環。

下面給出主函數

clear,clc
%% 設置變量
N=32;%初始羣體大小,即產生N個在(a,b)範圍內的隨機數
a=0;%自變量取值下界
b=10;%自變量取值上界
esp=0.0001;%精度

crossProbility=0.7;%交叉概率50%~80%,可以上下浮動
variationProbility=0.005;%變異概率0.1%~1%,可以上下浮動

maxX=[];
maxAdapt=[];
count=0;%記錄迭代次數

%% 1.編碼,產生初始羣體
initalGroup10=a+(b-a).*rand([N 1]);%初始羣體,十進制編碼
while true
    count=count+1;
    %% 2.求初始羣體的適應度
    %適應度函數,即爲目標函數
    adaptLevel=objectFun(initalGroup10);
    initalGroup=[initalGroup10 adaptLevel];
    
    %% 5.適應度驗算
    %對initalGroup適應度值升序排序
    sortrows(initalGroup,-2);
    
    %畫圖用
    index=find(initalGroup(:,2)==max(initalGroup(:,2)));
    maxX=[maxX initalGroup(index(1),1)];
    %最大適應度,如果求的是目標函數的最小值,就保留最小值
    maxAdapt=[maxAdapt initalGroup(index(1),2)];

    if size(maxX,2)~=1
        if abs(maxX(end)-maxX(end-1))<esp
            break;
        end
    end
    
    %% 3.確定複製個體
    copyIndex=trochalDisk(initalGroup,N);
    copyGroup10=[];
    for i=1:size(copyIndex)
        copyGroup10=[copyGroup10 initalGroup(copyIndex(i),1)];
    end
    
    %% 4.交叉與變異
    %交叉中的隨機:個體隨機、交叉位置隨機、概率可調
    %變異中的隨機:個體隨機、哪位變異隨機、變異幾位隨機
    crossGroup = cross(crossProbility,copyGroup10,a,b,esp);
    variationGroup = variation(variationProbility,crossGroup',a,b,esp);
    
    %% 爲下次循環準備
    %交叉和變異過程中難免會出大於給定範圍的值
    %將所有超出範圍的值設成最大值
    %因爲下面還會給每個數加上小數部分,所以最大值取範圍上界-1
    variationGroup(find(variationGroup>=(b-1)))=b-1;
    %前面說到dec2bin只會編碼整數部分,所以我們在這裏加一個小數部分。
    %可以嘗試一下去掉會是什麼樣子
    initalGroup10=variationGroup+rand([N 1]);
end

下面是一些實驗結果圖和分析過程

  各個圖參數如下:

N=32;%初始羣體大小,即產生N個在(a,b)範圍內的隨機數
a=0;%自變量取值下界
b=10;%自變量取值上界
esp=0.0001;%精度
crossProbility=0.7;%交叉概率50%~80%,可以上下浮動
variationProbility=0.005;%變異概率0.1%~1%,可以上下浮動
   [1]:在圖1所用參數的基礎上,選擇不同種羣大小,發現種羣越大,迭代次數越少,越容易能達到全局最優
   [2]:在圖1所用參數的基礎上,選擇不同交叉概率。做了30多次實驗。。。才疏學淺,實在發現不了任何關係。。。
   [3]:在圖1所用參數的基礎上,選擇不同變異概率。同樣,也沒發現任何關係。。。

   [4]:在圖1所用參數的基礎上,採用十進制小數轉換爲二進制的編碼方式。一定要提高變異概率

   採用含小數的二進制後,二進制編碼位數會加長,需要提高變異概率。
   如 9.9283,dec2bin() 編碼只考慮整數部分,編碼結果是 ‘1001’ ,每次變異產生差爲1的概率是1/16 = 6.25%;而考慮到小數後編碼結果爲 ‘10011110110110100’(整數部分佔4位,小數部分佔13位),每次變異產生差爲1的概率是24/217 = 0.012%。
   綜上,採用含小數的二進制後,變異概率爲編碼方式爲dec2bin()的變異概率的100倍左右,纔會產生比較好的結果。

左圖是變異概率爲0.1%時的結果,右圖是變異概率爲10%時的結果。

到這裏這道題就結束啦!
如果哪裏有錯誤還請大家批評指正呀~~~
或者有哪位發現了交叉概率和變異概率取值的意義,煩請評論區留言呀,不勝感激!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章