在上一篇博客 粒子羣優化算法(1)中介紹了基本的粒子羣算法,基本粒子羣算法是基於連續空間(區間)進行搜索,然而在一些實際的工程應用中,我們的待求解的變量可能並不是歷需的,而實一種離散型的變量。這就需要對基本的粒子羣算法做出一些相應的改進。
在離散粒子羣算法中,將離散問題空間映射到連續粒子運動空間,並做適當的修改。任然保留經典粒子羣算法的速度-位置更新策略。粒子在狀態空間的取值只限於0,1兩個值,而速度的每一個位代表的是粒子位置所對應的位取值爲0/1的可能性。因此在離散粒子羣算法中,粒子速度的更新公式依然保持不變,但是個體最優位置和全局最優位置每一位的取值只能爲0/1。
離散粒子羣算法速度和位置的更新方式如下所示:
粒子速度的更新方式不變,但是其位置的更新方式如下所示:
(利用sigmoid函數將例子的速度映射到0-1之間)
則粒子的速度可以表示爲:
例如,對於經典的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
運行結果:
除此之外,還可以使用離散粒子羣算法求解單變量的優化問題:
例如,求解函數的極值,函數的表達式如下所示:
其中:
可以畫出函數的圖像,如下所示:
源代碼:
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’即可: