天天看點

初學遺傳算法的一點點了解(附Matlab實作代碼)

第一次使用matlab模組化,是以摸索了很長久這個軟體,後來發現其實就可以把它當做以前使用的VC++或者是eclipse編輯器就可以,沒有我想的那麼困難。

遺傳算法步驟

初學遺傳算法的一點點了解(附Matlab實作代碼)

我首先是根據老師給的代碼,讀了每一個步驟的每一個算法,然後修改了代碼中的函數部分得到了作業的結果,但是我對最後結果所呈現的圖像并不是非常了解,讀了一些部落格,才有了自己的一點點了解。

遺傳算法中的每一條染色體,對應着遺傳算法的一種基因組編碼也就是一種解決方案,我們使用适應性函數去衡量這個解決方案的優劣。從一種編碼到它的适應度形成了一種映射,相當于在多元函數中求最優解。可以想象,多元曲面裡面有數不清的“山峰”,每一個”小山“對應的是函數自變量的某個區間,"山峰"對應的就是在某個區間内的最優解。這個多元曲面裡面海拔最高的"山峰"就是全局的最優解。遺傳算法的任務就是盡量去爬到最高峰,而不是陷落在 一些小山峰裡。
初學遺傳算法的一點點了解(附Matlab實作代碼)

作業中的問題描述:

初學遺傳算法的一點點了解(附Matlab實作代碼)

我使用matlab所呈現的圖像:

初學遺傳算法的一點點了解(附Matlab實作代碼)

遺傳算法的實作過程

遺傳算法實際是一種對潛在問題進行"數字化"編碼的方案,去建立表現型和基因型的映射關系。

  1. 個體編碼

    本題中使用無符号二進制整數來表示

  2. 初始群體的産生

    (1)首先是種群大小的選擇,這裡取popsize=100,即種群由100個個體組成,染色體長度取chromlength=10,也就是二進制編碼長度為10。

    (2)用随機函數rand()傳回一個100行*10列的随機矩陣,矩陣中的每一個數都是0-1的随機數,再用round()函數把這些随機數四舍五入為0或1,這樣就形成了100個長度為10的二進制字元串

function pop=initpop(popsize,chromlength)
pop = round(rand(popsize,chromlength));
           
  1. 适應度的計算

    (1)把二進制轉換成十進制

    首先是建立表現型到基因型的映射關系,也就是說用二進制編碼來表現圖中的橫坐标x,x也是所要解決問題中的函數自變量,題中要求x是在[5,20]的範圍上。

function pop2 = binary2decimal(pop)
lb=5;  %x的取值範圍下界
ub=20;  %x的取值範圍上界
[px,py]=size(pop)  %px是矩陣的行,py是矩陣的列數,這裡px是種群個數,py為染色體長度
%[r,c]=size(A),當有兩個輸出參數時,size函數将矩陣的行數傳回到第一個輸出變量r,将矩陣的列數傳回到第二個輸出變量c。
for i = 1:py
    pop1(:,i) = 2.^(py-i).*pop(:,i); %冒号代表對所有行都有這樣的操作 
    %py-i相當于說第一列到最後一列的順序倒置過來
end

%sum(.,2)對行求和,得到列向量
temp = sum(pop1,2); 

pop2 = 5+(temp*(ub-lb)/1023)
%根據X的取值範圍進行2進制到10進制的轉換,(ub-lb)相當于一個線段,temp/1023相當于二進制在這個區間上的占比,得到的結果再乘以(ub-lb)得到其在這段線段上的位置,再加上下界,就轉換成了這個區間上的十進制。
           

(2)帶入函數得到适應度

function [objvalue] = cal_objvalue(pop)
x = binary2decimal(pop);%轉化二進制數為x變量的變化域範圍的數值
 objvalue= x+10*sin(5*x)+7*cos(4*x);
           
  1. 選擇運算(輪盤賭算法)

    (1)先計算出群體中所有個體的适應度總和

    (2)其次計算出每個個體的相對适應度的大小,把适應度總和想象成一個輪盤,相對适應度就是每個個體适應度在适應度總和中所占的百分比,即每個個體被遺傳到下一代群體中的機率

    (3)産生一個0-1之間的随機數,依據該随機數出現在上述哪一個機率區域内來确定各個個體被選中的次數

%如何選擇新的個體
%輸入變量:pop二進制種群,fitvalue:适應度值
%輸出變量:newpop選擇以後的二進制種群
function [newpop] = selection(pop,fitvalue)
%構造輪盤
[px,py] = size(pop);
totalfit = sum(fitvalue);%總的适應度值
p_fitvalue = fitvalue/totalfit;%每個适應度值在輪盤中的占比,也就是相對适應度的大小,即為每個個體被遺傳到下一代群體中的機率
p_fitvalue = cumsum(p_fitvalue);%機率求和排序 cumsum()得到輸入矩陣的每個元素對應的列向上(行向左)求和矩陣
ms = sort(rand(px,1));%從小到大排列   生成種群大小的0-1的随機數字,依據該随機數出現在上述哪一個機率區域内來确定各個個體被選
%中的次數
fitin = 1;
newin = 1;%行選擇标量

%選出新的種群
while newin<=px %初始行向量為1,,從第一行開始周遊
    if(ms(newin))<p_fitvalue(fitin)%當産生的随機數字<個體被遺傳到下一代群體中的機率時,即為可遺傳
        newpop(newin,:)=pop(fitin,:);%遺傳給新的種群
        newin = newin+1;%周遊下一行
    else
        fitin=fitin+1;%如果不可遺傳,就檢查下一個更大的區域 
    end
end
           
  1. 交叉運算

    循環周遊,範圍控制在1到數第二行,步長為2。當随機數小于交叉機率時,生成一個随機的交叉點位置。先截取第i行交叉點前面的和第i+1行交叉點後面的編碼進行連接配接;再截取第i+1行交叉點前面編碼和第i行交叉點後面的編碼連接配接。如果随機數大于交叉機率,不交叉,直接把pop中的種群數賦給交叉後的種群數

function [newpop] = crossover(pop,pc)
[px,py] = size(pop);
newpop = ones(size(pop));
for i = 1:2:px-1  %for循環的範圍在1到px-1,步長為2,也就是從第一行到第三行到第五行一直到第px-1行
    if(rand<pc)%當随機數小于交叉機率時才進行交叉
        %rand沒有參數的時候就是從均勻分布中生成一個0-1之間的随機數
        cpoint = round(rand*py);%round是一個四舍五入的函數 用随機數*列數是在随機設定交叉點的位置
        newpop(i,:) = [pop(i,1:cpoint),pop(i+1,cpoint+1:py)];%截取第i行交叉點前面的和第i+1行交叉點後面的進行連接配接
        newpop(i+1,:) = [pop(i+1,1:cpoint),pop(i,cpoint+1:py)];%截取第i+1行交叉點前面的和第i行交叉點後面的進行連接配接
    else %如果随機數大于交叉機率,也就是不進行交叉直接把pop中的種群數賦給交叉後的種群數
        newpop(i,:) = pop(i,:);
        newpop(i+1,:) = pop(i+1,:);
    end
end
           
  1. 變異運算

    從第一行周遊到最後一行,如果産生的随機數小于變異的機率就發生變異,随即産生變異點的位置,對i行變異點的編碼取反。否則直接把種群賦給新的種群

function [newpop] = mutation(pop,pm)
[px,py] = size(pop);
newpop = ones(size(pop));
for i = 1:px %循環從第一行到最後一行
    if(rand<pm) %如果随機數小于變異機率就發生變異
        mpoint = round(rand*py); %随即産生變異點的位置
        if mpoint <= 0
            mpoint = 1; 
        end
        newpop(i,:) = pop(i,:);
        if newpop(i,mpoint) == 0
            newpop(i,mpoint) = 1;
        else newpop(i,mpoint) == 1
            newpop(i,mpoint) = 0;
        %對第i行變異點取反
        end
    else newpop(i,:) = pop(i,:);
    end
end
           
  1. 尋找最優解

    首先初始化最佳個體和最佳适應度值bestindividual和bestfit預設為種族中的第一個個體,從第二行開始如果該行的适應度值大于最佳适應度值,就把該行作為最佳個體,該行适應值作為最佳适應值。

function [bestindividual, bestfit] = best(pop,fitvalue)
[px,py] = size(pop); %擷取矩陣的行數和列數,size()将矩陣的行數給px,列數給py
bestindividual = pop(1,:);%把第一行的所有列彈出 賦給bestindividual,pop() 函數用于移除清單中的一個元素(預設最後一個元素),并且傳回該元素的值。
bestfit = fitvalue(1); %這兩行相當于在初始化最佳個體和最佳适應度值
for i = 2:px %for循環從第二行開始,
    if fitvalue(i)>bestfit %如果改行的适應值大于最佳适應值,
        bestindividual = pop(i,:);%把該行作為最佳個體,
        bestfit = fitvalue(i);%該行适應值為最佳适應值
    end
end
           
  1. mian.m
function main()
clear;
clc;
%種群大小
popsize=100;
%二進制編碼長度
chromlength=10;
%交叉機率
pc = 0.6;
%變異機率
pm = 0.001;
%初始種群
pop = initpop(popsize,chromlength);

for i = 1:100
    %計算适應度值(函數值)
    objvalue = cal_objvalue(pop);
    fitvalue = objvalue;
    %選擇操作
    newpop = selection(pop,fitvalue);
    %交叉操作
    newpop = crossover(newpop,pc);
    %變異操作
    newpop = mutation(newpop,pm);
    %更新種群
    pop = newpop;
    %尋找最優解
    [bestindividual,bestfit] = best(pop,fitvalue);
    x2 = binary2decimal(bestindividual);
    x1 = binary2decimal(newpop);
    y1 = cal_objvalue(newpop);
   if mod(i,50) == 0
  
        figure; %Matlab中的figure指令,能夠建立一個用來顯示圖形輸出的一個視窗對象
        fplot('x+10*sin(5*x)+7*cos(4*x)',[5 20]);%自适應繪圖,第一個參數為函數,第二個參數為坐标軸取值範圍
        hold on;% hold on作用是保持原圖并接受此後繪制的新的曲線,疊加繪圖; 多次疊繪: plot指令可以同時繪制多條曲線
        plot(x1,y1,'*');%最優解用*标注
        title(['疊代次數為n=' num2str(i)]);%num2str函數将數值轉換為字元串
        %plot(x1,y1,'*');
   end
end

fprintf('The best X is --->>%5.2f\n',x2); %指定資料輸出時格式為小數形式
fprintf('The best Y is --->>%5.2f\n',bestfit);