粒子羣優化算法(2)離散粒子羣算法

      在上一篇博客 粒子羣優化算法(1)中介紹了基本的粒子羣算法,基本粒子羣算法是基於連續空間(區間)進行搜索,然而在一些實際的工程應用中,我們的待求解的變量可能並不是歷需的,而實一種離散型的變量。這就需要對基本的粒子羣算法做出一些相應的改進。

      在離散粒子羣算法中,將離散問題空間映射到連續粒子運動空間,並做適當的修改。任然保留經典粒子羣算法的速度-位置更新策略。粒子在狀態空間的取值只限於0,1兩個值,而速度的每一個位代表的是粒子位置所對應的位取值爲0/1的可能性。因此在離散粒子羣算法中,粒子速度的更新公式依然保持不變,但是個體最優位置和全局最優位置每一位的取值只能爲0/1。

      離散粒子羣算法速度和位置的更新方式如下所示:


                                        v_{i}(t+1)=v_{i}(t)+c_{1}r_{r}(t)[p_{i,best}(t)-X_{i}(t)]+c_{2}r_{2}(t)[p_{g}(t)-X_{i}(t)]

      粒子速度的更新方式不變,但是其位置的更新方式如下所示:

       s(v_{i,j})=\frac{1}{1+e^{-v_{i,j}}}                        (利用sigmoid函數將例子的速度映射到0-1之間)

      則粒子的速度可以表示爲:

      x_{i,j}=\left\{\begin{matrix} 1, rand()<s(v_{i,j})\\ 0, else \end{matrix}\right.

例如,對於經典的0-1揹包問題:如果採用粒子羣優化算法求解,只能是採用離散的粒子羣算法:
問題描述:

有一個容量爲V的揹包,有N件物品,第i件物品的體積是c(i),價值是w(i).那麼將哪些物品放入揹包中,可以使得價值最大。假設具體的數據如下:

假設N=10, V = 300, 每件物品的體積爲:[95, 75, 23, 73, 50, 22, 6, 57, 89, 98], 物品的價值爲[89, 59,19, 43, 100, 72, 44, 16, 7, 64]

具體的計算流程如下:

1. 對速度進行初始化,對粒子的位置進行初始化,這裏粒子的位置採用的二進制的表示方法。1表示選擇該物體,0表示不選擇該物體。其他的參數的初始化的過程與前面的方法一樣。

源代碼:

clc;
clear all;
NP = 100;      % 種羣個數
G = 200;       % 迭代次數
D = 10;        % 決策變量的維度
c1 = 1.5;      % 學習因子
c2 = 1.5;
w_max = 0.8;   % 慣性權重
w_min = 0.4;
v_max = 5;     % 粒子的速度限制
v_min = -5;
V = 300;       % 揹包容量
capacity = [95 75 23 73 50 22 6 57 89 98];      % 物品的體積
weight = [89 59 19 43 100 72 44 16 7 64];       % 物品的價值
penality = 2;
% 初始化種羣個體
x = (rand(NP,D)>0.5);                        % 產生均勻分佈的二進制串  randn產生的是符合正態分佈的隨機數
v = v_min + rand(NP,D)*(v_max - v_min);      % 速度進行初始化

% 初始化個體最優
individual_best = x;       %  每個個體的歷史最優
pbest = zeros(NP, 1);      %  個體最優位置對應的適應度值
for k=1:NP
    pbest(k, 1) = func(individual_best(k, :), capacity, weight, V, penality);
end

% 初始化全局最優
global_best = zeros(1, D);
global_best_fit = eps;
for k=1:NP
    temp = func(individual_best(k, :), capacity, weight, V, penality);
    if temp > global_best_fit
        global_best = individual_best(k, :);
        global_best_fit = temp;
    end
end

% 進行迭代
for gen = 1:G
    % 計算動態慣性權值
    w = w_max - (w_max-w_min) * gen / G;
    for k=1:NP
        % 更新速度
        v(k, :) = w * v(k, :) + c1 * rand() * (individual_best(k, :) - x(k, :)) + c2 * rand() * (global_best - x(k, :));
        % 邊界條件處理    % 邊界吸收
        for t=1:D
            if v(k, D) > v_max
                v(k, D) = v_max;
            end
            if v(k, D) < v_min
                v(k, D) = v_min;
            end
        end
        % 使用sigmoid函數對速度進行映射
        vs(k, :) = 1./(1+exp(-v(k, :)));
        % 更新粒子的位置
        for t=1:D
            if vs(k, t)>rand()
                x(k, t) = 1;
            else
                x(k, t) = 0;
            end
        end
    end
    % 計算個體歷史最優與全局最優
    % 個體歷史最優
    for k=1:NP
        old_fitness = func(individual_best(k, :), capacity, weight, V, penality);
        new_fitness = func(x(k, :), capacity, weight, V, penality);
        if new_fitness > old_fitness
            individual_best(k, :) = x(k, :);
            pbest(k, 1) = new_fitness;
        end
    end
    % 全局最優
    for k=1:NP
        temp = func(individual_best(k, :), capacity, weight, V, penality);
        if temp > global_best_fit
            global_best = individual_best(k, :);
            global_best_fit = temp;
        end
    end
    global_optimal(gen) = global_best_fit;      % 記錄每次迭代中
end

figure(1)
plot(global_optimal);


% 定義適應度函數
function res = func(x, capacity, weight, bag_volume, penality)
    % 適應度函數的輸入參數
    % x: 可行解  二進制串
    % capacity:  物品的體積
    % bag_volume:  揹包的容積
    % penality:   懲罰係數
    fitness = sum(x.*weight);          % 總的價值
    total_volume = sum(x.*capacity);   % 總的體積
    if total_volume <= bag_volume
        res = fitness;
    else
        res = fitness - penality * (total_volume - bag_volume);
    end
end

運行結果:

除此之外,還可以使用離散粒子羣算法求解單變量的優化問題:
例如,求解函數的極值,函數的表達式如下所示:

                                                                  f(x)=x+6sin(5x)+4cos(3x)

其中:x\in [0,9]

可以畫出函數的圖像,如下所示:

源代碼:

clc;
clear all;
xx = 0:0.05:9;
f_x = xx + 6*sin(4.*xx) + 9*cos(6.*xx);
figure(1)
plot(xx, f_x);
title('f(x)=x+6sin(4x)+9cos(6x)');
xlabel('x');
ylabel('f(x)');

NP = 100;      % 種羣個數
G = 200;       % 迭代次數
D = 10;        % 二進制編碼的爲位數
c1 = 1.5;      % 學習因子
c2 = 1.5;
w_max = 0.8;   % 慣性權重
w_min = 0.4;
v_max = 5;     % 粒子的速度限制
v_min = -5;
x_min = 0;
x_max = 9;
mode = 'min';  % 模式選擇,是求函數的最大值函數函數的最小值  'min' , 'max'

% 初始化種羣個體
x = (rand(NP,D)>0.5);                        % 產生均勻分佈的二進制串  randn產生的是符合正態分佈的隨機數
v = v_min + rand(NP,D)*(v_max - v_min);      % 速度進行初始化

% 初始化個體最優
individual_best = x;       %  每個個體的歷史最優
pbest = zeros(NP, 1);      %  個體最優位置對應的適應度值
for k=1:NP 
    pbest(k, 1) = func(individual_best(k, :), x_max, x_min, D);
end

% 初始化全局最優
if strcmp(mode, 'max')      % 求函數的最大值
    global_best = zeros(1, D);
    global_best_fit = eps;
    for k=1:NP
        temp = func(individual_best(k, :), x_max, x_min, D);
        if temp > global_best_fit
            global_best = individual_best(k, :);
            global_best_fit = temp;
        end
    end
else                        % 求函數的最小值
    global_best = zeros(1, D);
    global_best_fit = inf;
    for k=1:NP
        temp = func(individual_best(k, :), x_max, x_min, D);
        if temp < global_best_fit
            global_best = individual_best(k, :);
            global_best_fit = temp;
        end
    end
end

% 開始迭代
for gen=1:G
    % 計算動態慣性權值
    w = w_max - (w_max-w_min) * gen / G;
    for k=1:NP
        % 更新速度
        v(k, :) = w * v(k, :) + c1 * rand() * (individual_best(k, :) - x(k, :)) + c2 * rand() * (global_best - x(k, :));
        % 邊界條件處理    % 邊界吸收
        for t=1:D
            if v(k, D) > v_max
                v(k, D) = v_max;
            end
            if v(k, D) < v_min
                v(k, D) = v_min;
            end
        end
        % 使用sigmoid函數對速度進行映射
        vs(k, :) = 1./(1+exp(-v(k, :)));
        % 更新粒子的位置
        for t=1:D
            if vs(k, t)>rand()
                x(k, t) = 1;
            else
                x(k, t) = 0;
            end
        end
    end
    
    % 更新粒子的歷史最有位置
    if strcmp(mode, 'min')
        % 個體最優位置
        for k=1:NP
            old_fitness = func(individual_best(k, :), x_max, x_min, D);
            new_fitness = func(x(k, :), x_max, x_min, D);
            if new_fitness < old_fitness
                individual_best(k, :) = x(k, :);     % 個體最優位置更新
            end
        end
        
        % 全局最優位置
        for k=1:NP
            temp = func(individual_best(k, :), x_max, x_min, D);
            if temp < global_best_fit
                global_best = individual_best(k, :);
                global_best_fit = temp;
            end
        end
    else
        % 個體最優位置
        for k=1:NP
            old_fitness = func(individual_best(k, :), x_max, x_min, D);
            new_fitness = func(x(k, :), x_max, x_min, D);
            if new_fitness > old_fitness
                individual_best(k, :) = x(k, :);     % 個體最優位置更新
            end
        end
        
        % 全局最優位置
        for k=1:NP
            temp = func(individual_best(k, :), x_max, x_min, D);
            if temp > global_best_fit
                global_best = individual_best(k, :);
                global_best_fit = temp;
            end
        end
    end
    
    % 記錄函數的適應度值
    fitness_optimal(gen) = global_best_fit;
end

figure(2)
plot(fitness_optimal);
xlabel('x')
ylabel('f(x)');
title(['適應度值  ', num2str(fitness_optimal(end)), ' | ', num2str(x_min+(x_max-x_min)/(2^D-1)*binary2dec(global_best))]);

function res = func(x, xmax, xmin, D)
    % 參數  x 二進制串
    % vmax : 速度的最大值
    % vmin : 速度的最小值
    % D : 二進制的編碼位數
    temp_ = binary2dec(x);
    temp = xmin + (xmax-xmin)/(2^D-1) * temp_;
    res = temp + 6*sin(4*temp) + 9*cos(6*temp);
end

function res = binary2dec(x)
    total_value = 0;
    for k=length(x):-1:1
        total_value = total_value + x(k)*2^(length(x)-k);
    end
    res = total_value;
end

求取最大值,將mode參數設置爲‘max’即可:

求取最小值,將mode參數設置爲‘min’即可:

 

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