智能算法之免疫算法求解TSP問題

Immunity Algorithm免疫算法


前言:本文主要圍繞解決TSP旅行商問題展開,對於機器人的路線規劃以及非線性方程求解的問題等解決方案大家可以直接參考github源碼地址
對於一些其他智能算法例如遺傳算法解決一些現實問題都有實現!! 歡迎小夥伴的star哦~~ 🤭


效果圖:

效果圖

1、什麼是免疫算法

  將免疫概念及其理論應用於遺傳算法,在保留原算法優良特性的前提下,力圖有選擇、有目的地利用待求問題中的一些特徵信息或知識來抑制其優化過程中出現的退化現象,這種算法稱爲免疫算法(Immune Algorithm) IA。人工免疫算法是一種具有生成+檢測 (generate and test)的迭代過程的羣智能搜索算法。從理論上分析,迭代過程中,在保留上一代最佳個體的前提下,免疫算法是全局收斂的。

摘自百度百科

  也就是說,免疫算法的思想來自於生物體的免疫機制,構造具有動態性和自適應性的信息防禦機制,用來抵抗外部無用的有害信息的侵入(退化解),從而保證信息的有效性和無害性(最優解)。
:退化解的來自於變異等操作過後的適應度值低於父類的解。

1.1 生物免疫系統

  在生物課上學過,免疫系統的構成元素主要是淋巴細胞,淋巴細胞包括B細胞和T細胞。

  • T細胞主要在收到抗原刺激後可以分化成淋巴母細胞,產生多種淋巴因子,引起細胞免疫反應。
  • B細胞又稱爲抗體形成細胞,可以產生抗體,抗體會同抗原產生一系列的反應,最後通過吞噬細胞的作用來消滅抗原。並且抗體具有專一性,而且免疫系統具備識別能力和記憶能力,可以對舊抗原做出更快的反應。

免疫系統和一般免疫算法的比較:

免疫系統 免疫算法
抗原 待解決的問題,例如方程最優解、TSP等等
抗體 最優解
抗原識別 問題識別
從記憶細胞產生抗體 找到以往的成功例子
淋巴細胞的分化 最優解的保持
細胞抑制 剩餘候選解的消除
抗體增強 利用遺傳算子產生新的抗體

1.2 免疫算法的基本原理

  免疫遺傳算法解決了遺傳算法早熟收斂的問題,有可能陷入局部最優解的情況,並且遺傳算法具有一定的盲目性,尤其是在交叉和變異的過程中。容易產生相較於父類更加差的解,也就是退化現象的出現。如果在遺傳算法中引入免疫的方法和概念,對遺傳算法全局搜索進行干預,就避免了很多重複的工作。

  免疫算法在面對求解問題的時候,相當於面對各種抗原,可以提前注射疫苗,來一隻退化的現象,從而保持優勝略汰的特點,使算法一直優化下去。

一般的免疫算法分爲下面 3 種情況。

  1. 模仿免疫系統抗體與抗原的識別,結合抗體的產生過程而抽象出來的免疫算法。
  2. 基於免疫系統中的其他特殊機制抽象出來的算法,例如克隆選擇算法。
  3. 和其他智能算法等其他的算法進行融合,例如免疫遺傳算法。

1.3 免疫算法的基本步驟和流程

2、免疫遺傳算法

  免疫遺傳算法和遺傳算法的結構一致,最大的不同之處在於在免疫遺傳算法中引入了濃度調節機制。在進行選擇操作的時候,遺傳算法制只利用了適應度指標對個體進行評價;在免疫遺傳算法當中,免疫遺傳算法中的選擇策略變爲:適應度越高,濃度越小,個體複製的概率越大,反之越小。

  免疫遺傳算法的基本思想就是在傳統的算法基礎上加入一個免疫算子,加入免疫算子的目的就是爲了防止種羣的退化。免疫算子有接種疫苗和免疫選擇兩個步驟組成。免疫遺傳算法可以有效地調節選擇壓力。因此免疫算法可以保持種羣多樣性的能力。

免疫遺傳算法的步驟和流程:

免疫遺傳算法流程

3、免疫算法在TSP問題中的應用

  TSP問題是所有智能算法都要解決的問題,TSP問題就是旅行商問題,旅行商要遍歷所有的城市,並且城市僅能通過一次,並且保證所經過的城市的路徑最小。

3.1、免疫算法的結構

  對於個體的編碼仍然採用和遺傳算法中相同的實數編碼結構。由於本例中要求路徑最低,適應度函數就取爲路徑的倒數。

  採用單點交叉,交叉的位置隨機,類似與遺傳算法。每次遺傳操作後,隨機抽取一些個體進行注射抗體,進行免疫檢測,即對接種了個體進行檢測,如果適應度提高,則繼續,否則就代表着在進行交叉和變異的過程中出現了退化現象,這時個體就會被父類代替,就是下面的表達式:

父類適應度 < 子類適應度 ? 子類 : 父類

3.2、求解 TSP 問題流程圖

3.3、免疫遺傳算法-TSP MatLab 實現

  主要是對參數進行初始化,包括對一些概率參數、初始種羣矩陣,城市初始位置、城市之間的距離矩陣等等。
參數初始化:

N = 20;               
%城市的個數
M = N - 1;               
%種羣的個數
pos = 50 * randn(N,2);
%%生成城市的座標
global D;
%城市距離數據
D = zeros(N,N);
for i = 1 : N
    for j = i + 1 : N
        dis = (pos(i, 1)-pos(j, 1)).^2+(pos(i, 2)-pos(j, 2)).^2;
        D(i, j) = dis^(0.5);
        D(j, i) = D(i, j);
    end
end

%中間結果保存
global TmpResult;
TmpResult = [];
global TmpResult1;
TmpResult1 = [];

[M, N] = size(D);  % 種羣規模
pCharChange = 1;  % 個體換位概率
pStrChange = 0.4;  % 個體移位概率
pStrReverse = 0.4;  % 個體逆轉概率
pCharReCompose = 0.4;  % 個體重組概率
MaxIterateNum = 100;  % 迭代次數

mPopulation = zeros(N-1,N);
mRandM = randperm(N-1);  % 最優路徑
mRandM = mRandM + 1;
for rol = 1:N-1
    mPopulation(rol,:) = randperm(N);%產生初始抗體
end

迭代過程:

count = 0;
figure(2);
while count < MaxIterateNum
    % 產生新抗體
    B = Mutation(mPopulation, [pCharChange pStrChange pStrReverse pCharReCompose]);
    % 計算新產生的抗體對應的適應度,並選擇最優抗體
    mPopulation = SelectAntigen(mPopulation,B);
    % 保存每一代最優的個體
    best_pop(count + 1, :) = mPopulation(1, :);
    count = count + 1;
end

  變異過程,變異的過程主要保存移位、換位、逆轉以及重組操作,這幾個操作之間相互獨立,最後拼接在一起後返回。
變異操作:

function result = Mutation(A, P)
[m,n] = size(A);
% 換位
n1 = round(P(1)*m);  % 變異的個體數
m1 = randperm(m);  % 混淆個體順序
cm1 = randperm(n-1)+1;  % 個體變異的位置
B1 = zeros(n1,n);  % 保存變異後的個體
c1 = cm1(n-1);
c2 = cm1(n-2);
for s = 1:n1
    B1(s,:) = A(m1(s),:);
    tmp = B1(s,c1);
    B1(s,c1) = B1(s,c2);
    B1(s,c2) = tmp;
end

% 移位
n2 = round(P(2)*m);
m2 = randperm(m);
cm2 = randperm(n-1)+1;
B2 = zeros(n2,n);
c1 = min([cm2(n-1),cm2(n-2)]);
c2 = max([cm2(n-1),cm2(n-2)]);
for s = 1:n2
    B2(s,:) = A(m2(s),:);
    B2(s,c1:c2) = DisplaceStr(B2(s,:),c1,c2);
end

% 逆轉
n3 = round(P(3)*m);
m3 = randperm(m);
cm3 = randperm(n-1)+1;
B3 = zeros(n3,n);
c1 = min([cm3(n-1),cm3(n-2)]);
c2 = max([cm3(n-1),cm3(n-2)]);
for s = 1:n3
    B3(s,:) = A(m3(s),:);
    tmp1 = [[c2:-1:c1]',B3(s,c1:c2)'];
    tmp1 = sortrows(tmp1,1);
    B3(s,c1:c2) = tmp1(:,2)';
end

% 重組
n4 = round(P(4)*m);
m4 = randperm(m);
cm4 = randperm(n-1)+1;
B4 = zeros(n4,n);
c1 = min([cm4(n-1),cm4(n-2)]);
c2 = max([cm4(n-1),cm4(n-2)]);
for s = 1:n4
    B4(s,:) = A(m4(s),:);
    B4(s,c1:c2) = CharRecompose(B4(s,c1:c2));
end

% 變異後個體拼接
result = [B1;B2;B3;B4];

上面的涉及幾個函數分別是DisplaceStr()以及CharRecompose()

function result = DisplaceStr(inMatrix, startCol, endCol)
[m,n] = size(inMatrix);
if n <= 1
    result = inMatrix;
    return;
end
switch nargin
    case 1
        startCol = 1;
        endCol = n;
    case 2
        endCol = n;
end
mMatrix1 = inMatrix(:,(startCol + 1):endCol);
result = [mMatrix1, inMatrix(:, startCol)];

function result = CharRecompose(A)
global D;
index = A(1,2:end);
tmp = A(1,1);
result = [tmp];
[m,n] = size(index);
while n>=2
    len = D(tmp,index(1));
    tmpID = 1;
    for s = 2:n
        if len > D(tmp,index(s))
            tmpID = s;
            len = D(tmp,index(s));
        end
    end
    tmp = index(tmpID);
    result = [result,tmp];
    index(:,tmpID) = [];
    [m,n] = size(index);
end
result = [result,index(1)];

  選擇優秀的個體繼續進行後續的操作,對於退化或者次優解進行去除。
選擇抗體:

function result = SelectAntigen(A,B)
global D;
[m,n] = size(A);
[p,q] = size(B);
index = [A;B];
rr = zeros((m+p),2);
rr(:,2) = [1:(m+p)]';
for s = 1:(m+p)
    for t = 1:(n-1)
        rr(s,1) = rr(s,1)+D(index(s,t),index(s,t+1));
    end
    rr(s,1) = rr(s,1) + D(index(s,n),index(s,1));
end
rr = sortrows(rr,1);
ss = [];
tmplen = 0;
for s = 1:(m+p)
    if tmplen ~= rr(s,1)
        tmplen = rr(s,1);
        ss = [ss;index(rr(s,2),:)];
    end
end
global TmpResult;
TmpResult = [TmpResult;rr(1,1)];
global TmpResult1;
TmpResult1 = [TmpResult1;rr(end,1)];
result = ss(1:m,:);

4、結果

結果展示 結果展示

注: 爲了說明方便將代碼直接拆開展示如果需要源碼可以直接最後的源碼地址中找到。

最後

更多精彩內容,大家可以轉到我的主頁:曲怪曲怪的主頁

源碼地址github地址

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