1.修改框架的目的
之前有不少問如下動(dòng)態(tài)圖是怎么繪制的?
這個(gè)是使用java編寫的代碼實(shí)現(xiàn)的吏夯,方式較為復(fù)雜此蜈,把每一代的位置畫在一張圖中,然后按順序合成gif動(dòng)態(tài)圖噪生。用java實(shí)現(xiàn)這種方式非常復(fù)雜裆赵,需要自己去實(shí)現(xiàn)繪制代碼,然后保存成圖片再合成跺嗽。單繪制圖像的代碼就有幾百行战授,而且有不少未解決的bug,比如一些位置的點(diǎn)只能用黑色或者白色才會(huì)在動(dòng)態(tài)圖中顯示桨嫁。
將代碼用matlab實(shí)現(xiàn)之后植兰,發(fā)現(xiàn)使用matlab繪制動(dòng)態(tài)圖要比java容易一萬倍,其效果如圖璃吧。
所以在這里對(duì)優(yōu)化算法框架進(jìn)行一個(gè)小小的更新楣导,讓每個(gè)算法都能繪制群體位置動(dòng)態(tài)圖。
2.算法框架的修改
使用matlab繪制動(dòng)態(tài)圖的原理和使用java繪制的原理一樣:即將每一代的所有個(gè)體的位置保存下來畜挨,然后每一代繪制成一張圖筒繁,最后按順序合成動(dòng)態(tài)圖。
這里我們需要修改的部分由兩點(diǎn):
1.保存所有個(gè)體的位置巴元;
2.繪制群體的位置毡咏。
圖像的顯示以及動(dòng)態(tài)圖gif的生成,matlab已經(jīng)幫我們完成逮刨,不需要單獨(dú)去編碼實(shí)現(xiàn)呕缭。
需要修改的代碼文件列表:
優(yōu)化算法matlab實(shí)現(xiàn)(二)框架編寫中的框架。
文件名 | 描述 |
---|---|
..\optimization algorithm\frame\Unit.m | 個(gè)體 |
..\optimization algorithm\frame\Algorithm_Impl.m | 算法主體 |
只需要修改這兩個(gè)文件即可修己,不需要修改其他文件臊旭。
文件..\optimization algorithm\frame\Unit.m中需要添加個(gè)體的歷史位置及保存歷史位置的方法,其實(shí)現(xiàn)如下:
% 個(gè)體基類
classdef Unit< handle
properties
% 個(gè)體的位置
position;
% 個(gè)體的適應(yīng)度值
value;
% 記錄所有的位置,畫圖用
position_history_list;
end
methods
function self = Unit()
end
% 將當(dāng)前位置保存到position_history_list中
function save(self)
self.position_history_list=[self.position_history_list;self.position];
end
end
end
文件..\optimization algorithm\frame\ Algorithm_Impl.m中每一代都需要調(diào)用上面的save方法來保存圖像箩退,其實(shí)現(xiàn)如下:
% 記錄最優(yōu)值
for i = 1:self.size
if(self.unit_list(i).value>self.value_best)
self.value_best = self.unit_list(i).value;
self.position_best = self.unit_list(i).position;
end
% 保存每一代的位置
self.unit_list(i).save();
end
文件..\optimization algorithm\frame\ Algorithm_Impl.m中需要繪制群體位置的方法袱耽,其實(shí)現(xiàn)如下:
% 繪制動(dòng)態(tài)圖,2維圖像:step為步長(zhǎng)(幾代繪制一張圖像)泽裳,is_save用來判斷是否保存gif動(dòng)態(tài)圖
function draw2_gif(self,step,is_save,name)
if self.dim < 2
disp('維度太低,無法繪制圖像');
return
end
if step < 1
step = 1;
end
f1 = figure;
% 遍歷每一代
for i = 1:self.iter_max
% 如果不滿足步長(zhǎng)袋狞,則跳過
if mod(i,step) > 0 && i>1
% 必須要繪制第一代,否則matlab會(huì)報(bào)錯(cuò)袭灯,原因未知
continue
end
% 遍歷每一個(gè)個(gè)體
for s = 1:self.size
cur_position = self.unit_list(s).position_history_list(i,:);
scatter(cur_position(1),cur_position(2),10,'b','filled');
hold on;
end
% 將文字繪制在左上角
text(self.range_min_list(1),self.range_max_list(2),num2str(i),'FontSize',20);
% 繪制顯示區(qū)域
range_size_x = self.range_max_list(1)-self.range_min_list(1);
range_size_y = self.range_max_list(2)-self.range_min_list(2);
axis([self.range_min_list(1)-0.2*range_size_x,self.range_max_list(1)+0.2*range_size_x, self.range_min_list(2)-0.2*range_size_y, self.range_max_list(2)+0.2*range_size_y]);
axis equal;
% 固定橫縱坐標(biāo)軸
set(gca,'XLim',[self.range_min_list(1)-0.1*range_size_x self.range_max_list(1)+0.1*range_size_x]);
set(gca,'YLim',[self.range_min_list(2)-0.1*range_size_y self.range_max_list(2)+0.1*range_size_y]);
% 每0.1繪制一次
pause = 0.1;
% 需要保存git則設(shè)置is_save = true
if is_save
%下面是保存為GIF的程序
frame=getframe(gcf);
% 返回單幀顏色圖像
imind=frame2im(frame);
% 顏色轉(zhuǎn)換
[imind,cm] = rgb2ind(imind,256);
filename = [name,'_2d.gif'];
if i==1
imwrite(imind,cm,filename,'gif', 'Loopcount',inf,'DelayTime',1e-2);
else
imwrite(imind,cm,filename,'gif','WriteMode','append','DelayTime',pause);
end
end
% 繪制完就清除,繪制下一代
clf;
end
% 繪制完成關(guān)閉窗口
close(f1);
end
上面繪制的是2維動(dòng)態(tài)圖,我們可以將其類推至3維咪笑,來繪制3維動(dòng)態(tài)圖。當(dāng)然圖像最多只能繪制到3維娄涩,畢竟我們生活在3維空間窗怒,只能直觀看到3維。
% 繪制動(dòng)態(tài)圖,3維圖像:step為步長(zhǎng)(幾代繪制一張圖像)蓄拣,is_save用來判斷是否保存gif動(dòng)態(tài)圖
function draw3_gif(self,step,is_save,name)
if self.dim < 3
disp('維度太低扬虚,無法繪制三維圖像');
return
end
if step < 1
step = 1;
end
f1 = figure;
% 遍歷每一代
for i = 1:self.iter_max
% 如果不滿足步長(zhǎng),則跳過
if mod(i,step) > 0 && i>1
% 必須要繪制第一代球恤,否則matlab會(huì)報(bào)錯(cuò)辜昵,原因未知
continue
end
% 遍歷每一個(gè)個(gè)體
for s = 1:self.size
cur_position = self.unit_list(s).position_history_list(i,:);
scatter3(cur_position(1),cur_position(2),cur_position(3),10,'b','filled');
hold on;
end
% 將文字繪制在左上角
text(self.range_min_list(1),self.range_max_list(2),self.range_max_list(3),num2str(i),'FontSize',20);
% 繪制顯示區(qū)域
range_size_x = self.range_max_list(1)-self.range_min_list(1);
range_size_y = self.range_max_list(2)-self.range_min_list(2);
range_size_z = self.range_max_list(3)-self.range_min_list(3);
axis([self.range_min_list(1)-0.2*range_size_x,self.range_max_list(1)+0.2*range_size_x, self.range_min_list(2)-0.2*range_size_y, self.range_max_list(2)+0.2*range_size_y,self.range_min_list(3)-0.2*range_size_z, self.range_max_list(3)+0.2*range_size_z]);
axis equal;
% 固定橫縱坐標(biāo)軸
set(gca,'XLim',[self.range_min_list(1)-0.1*range_size_x self.range_max_list(1)+0.1*range_size_x]);
set(gca,'YLim',[self.range_min_list(2)-0.1*range_size_y self.range_max_list(2)+0.1*range_size_y]);
set(gca,'ZLim',[self.range_min_list(3)-0.1*range_size_z self.range_max_list(3)+0.1*range_size_z])
% 每0.1繪制一次
pause = 0.1;
% 需要保存git則設(shè)置is_save = true
if is_save
%下面是保存為GIF的程序
frame=getframe(gcf);
% 返回單幀顏色圖像
imind=frame2im(frame);
% 顏色轉(zhuǎn)換
[imind,cm] = rgb2ind(imind,256);
filename = [name,'_3d.gif'];
if i==1
imwrite(imind,cm,filename,'gif', 'Loopcount',inf,'DelayTime',1e-2);
else
imwrite(imind,cm,filename,'gif','WriteMode','append','DelayTime',pause);
end
end
% 繪制完就清除,繪制下一代
clf;
end
% 繪制完成關(guān)閉窗口
close(f1);
end
3維圖像效果如圖:
3.完整框架代碼
總目錄:..\optimization algorithm
框架目錄:..\optimization algorithm/frame
框架文件:
文件名 | 描述 |
---|---|
..\optimization algorithm\frame\Unit.m | 個(gè)體 |
..\optimization algorithm\frame\Algorithm_Impl.m | 算法主體 |
文件內(nèi)容:
Unit.m
% 個(gè)體基類
classdef Unit< handle
properties
% 個(gè)體的位置
position;
% 個(gè)體的適應(yīng)度值
value;
% 記錄所有的位置,畫圖用
position_history_list;
end
methods
function self = Unit()
end
% 將當(dāng)前位置保存到position_history_list中
function save(self)
self.position_history_list=[self.position_history_list;self.position];
end
end
end
Algorithm_Impl.m
% 優(yōu)化算法基類
classdef Algorithm_Impl < handle
properties
%當(dāng)前最優(yōu)位置
position_best;
%當(dāng)前最優(yōu)適應(yīng)度
value_best;
%歷史最優(yōu)適應(yīng)度
value_best_history;
%歷史最優(yōu)位置
position_best_history;
%是否為求最大值,默認(rèn)為是
is_cal_max;
%適應(yīng)度函數(shù)咽斧,需要單獨(dú)傳入
fitfunction;
% 調(diào)用適應(yīng)度函數(shù)次數(shù)
cal_fit_num = 0;
end
properties(Access = protected)
%維度
dim;
%種群中個(gè)體的數(shù)量
size;
%最大迭代次數(shù)
iter_max;
%解空間下界
range_min_list;
%解空間上界
range_max_list;
%種群列表
unit_list;
end
methods
% 運(yùn)行堪置,調(diào)用入口
function run(self)
tic
self.init()
self.iteration()
toc
disp(['運(yùn)行時(shí)間: ',num2str(toc)]);
end
% 繪制動(dòng)態(tài)圖,2維圖像
function draw2_gif(self,step,is_save,name)
if self.dim < 2
disp('維度太低,無法繪制圖像');
return
end
if step < 1
step = 1;
end
f1 = figure;
% 遍歷每一代
for i = 1:self.iter_max
% 如果不滿足步長(zhǎng)张惹,則跳過
if mod(i,step) > 0 && i>1
% 必須要繪制第一代舀锨,否則matlab會(huì)報(bào)錯(cuò),原因未知
continue
end
% 遍歷每一個(gè)個(gè)體
for s = 1:self.size
cur_position = self.unit_list(s).position_history_list(i,:);
scatter(cur_position(1),cur_position(2),10,'b','filled');
hold on;
end
% 將文字繪制在左上角
text(self.range_min_list(1),self.range_max_list(2),num2str(i),'FontSize',20);
% 繪制顯示區(qū)域
range_size_x = self.range_max_list(1)-self.range_min_list(1);
range_size_y = self.range_max_list(2)-self.range_min_list(2);
axis([self.range_min_list(1)-0.2*range_size_x,self.range_max_list(1)+0.2*range_size_x, self.range_min_list(2)-0.2*range_size_y, self.range_max_list(2)+0.2*range_size_y]);
axis equal;
% 固定橫縱坐標(biāo)軸
set(gca,'XLim',[self.range_min_list(1)-0.1*range_size_x self.range_max_list(1)+0.1*range_size_x]);
set(gca,'YLim',[self.range_min_list(2)-0.1*range_size_y self.range_max_list(2)+0.1*range_size_y]);
% 每0.1繪制一次
pause = 0.1;
% 需要保存git則設(shè)置is_save = true
if is_save
%下面是保存為GIF的程序
frame=getframe(gcf);
% 返回單幀顏色圖像
imind=frame2im(frame);
% 顏色轉(zhuǎn)換
[imind,cm] = rgb2ind(imind,256);
filename = [name,'_2d.gif'];
if i==1
imwrite(imind,cm,filename,'gif', 'Loopcount',inf,'DelayTime',1e-2);
else
imwrite(imind,cm,filename,'gif','WriteMode','append','DelayTime',pause);
end
end
% 繪制完就清除宛逗,繪制下一代
clf;
end
% 繪制完成關(guān)閉窗口
close(f1);
end
% 繪制動(dòng)態(tài)圖,3維圖像
function draw3_gif(self,step,is_save,name)
if self.dim < 3
disp('維度太低雁竞,無法繪制三維圖像');
return
end
if step < 1
step = 1;
end
f1 = figure;
% 遍歷每一代
for i = 1:self.iter_max
% 如果不滿足步長(zhǎng),則跳過
if mod(i,step) > 0 && i>1
% 必須要繪制第一代拧额,否則matlab會(huì)報(bào)錯(cuò)碑诉,原因未知
continue
end
% 遍歷每一個(gè)個(gè)體
for s = 1:self.size
cur_position = self.unit_list(s).position_history_list(i,:);
scatter3(cur_position(1),cur_position(2),cur_position(3),10,'b','filled');
hold on;
end
% 將文字繪制在左上角
text(self.range_min_list(1),self.range_max_list(2),self.range_max_list(3),num2str(i),'FontSize',20);
% 繪制顯示區(qū)域
range_size_x = self.range_max_list(1)-self.range_min_list(1);
range_size_y = self.range_max_list(2)-self.range_min_list(2);
range_size_z = self.range_max_list(3)-self.range_min_list(3);
axis([self.range_min_list(1)-0.2*range_size_x,self.range_max_list(1)+0.2*range_size_x, self.range_min_list(2)-0.2*range_size_y, self.range_max_list(2)+0.2*range_size_y,self.range_min_list(3)-0.2*range_size_z, self.range_max_list(3)+0.2*range_size_z]);
axis equal;
% 固定橫縱坐標(biāo)軸
set(gca,'XLim',[self.range_min_list(1)-0.1*range_size_x self.range_max_list(1)+0.1*range_size_x]);
set(gca,'YLim',[self.range_min_list(2)-0.1*range_size_y self.range_max_list(2)+0.1*range_size_y]);
set(gca,'ZLim',[self.range_min_list(3)-0.1*range_size_z self.range_max_list(3)+0.1*range_size_z])
% 每0.1繪制一次
pause = 0.1;
% 需要保存git則設(shè)置is_save = true
if is_save
%下面是保存為GIF的程序
frame=getframe(gcf);
% 返回單幀顏色圖像
imind=frame2im(frame);
% 顏色轉(zhuǎn)換
[imind,cm] = rgb2ind(imind,256);
filename = [name,'_3d.gif'];
if i==1
imwrite(imind,cm,filename,'gif', 'Loopcount',inf,'DelayTime',1e-2);
else
imwrite(imind,cm,filename,'gif','WriteMode','append','DelayTime',pause);
end
end
% 繪制完就清除,繪制下一代
clf;
end
% 繪制完成關(guān)閉窗口
close(f1);
end
end
methods (Access = protected)
% 構(gòu)造函數(shù)
function self = Algorithm_Impl(dim,size,iter_max,range_min_list,range_max_list)
self.dim =dim;
self.size = size;
self.iter_max = iter_max;
self.range_min_list = range_min_list;
self.range_max_list = range_max_list;
%默認(rèn)為求最大值
self.is_cal_max = true;
end
% 初始化
function init(self)
self.position_best=zeros(1,self.dim);
self.value_best_history=[];
self.position_best_history=[];
%設(shè)置初始最優(yōu)值侥锦,由于是求最大值进栽,所以設(shè)置了最大浮點(diǎn)數(shù)的負(fù)值
self.value_best = -realmax('double');
end
% 開始迭代
function iteration(self)
for iter = 1:self.iter_max
self.update(iter)
end
end
% 處理一次迭代
function update(self,iter)
% 記錄最優(yōu)值
for i = 1:self.size
if(self.unit_list(i).value>self.value_best)
self.value_best = self.unit_list(i).value;
self.position_best = self.unit_list(i).position;
end
% 保存每一代的位置
self.unit_list(i).save();
end
disp(['第' num2str(iter) '代']);
if(self.is_cal_max)
self.value_best_history(end+1) = self.value_best;
disp(['最優(yōu)值=' num2str(self.value_best)]);
else
self.value_best_history(end+1) = -self.value_best;
disp(['最優(yōu)值=' num2str(-self.value_best)]);
end
self.position_best_history = [self.position_best_history;self.position_best];
disp(['最優(yōu)解=' num2str(self.position_best)]);
end
function value = cal_fitfunction(self,position)
if(isempty(self.fitfunction))
value = 0;
else
% 如果適應(yīng)度函數(shù)不為空則返回適應(yīng)度值
if(self.is_cal_max)
value = self.fitfunction(position);
else
value = -self.fitfunction(position);
end
end
self.cal_fit_num = self.cal_fit_num+1;
end
% 越界檢查,超出邊界則停留在邊界上
function s=get_out_bound_value(self,position,min_list,max_list)
if(~exist('min_list','var'))
min_list = self.range_min_list;
end
if(~exist('max_list','var'))
max_list = self.range_max_list;
end
% Apply the lower bound vector
position_tmp=position;
I=position_tmp<min_list;
position_tmp(I)=min_list(I);
% Apply the upper bound vector
J=position_tmp>max_list;
position_tmp(J)=max_list(J);
% Update this new move
s=position_tmp;
end
% 越界檢查,超出邊界則在解空間內(nèi)隨機(jī)初始化
function s=get_out_bound_value_rand(self,position,min_list,max_list)
if(~exist('min_list','var'))
min_list = self.range_min_list;
end
if(~exist('max_list','var'))
max_list = self.range_max_list;
end
position_rand = unifrnd(self.range_min_list,self.range_max_list);
% Apply the lower bound vector
position_tmp=position;
I=position_tmp<min_list;
position_tmp(I)=position_rand(I);
% Apply the upper bound vector
J=position_tmp>max_list;
position_tmp(J)=position_rand(J);
% Update this new move
s=position_tmp;
end
end
events
end
end
4.測(cè)試代碼
使用之前的差分進(jìn)化算法測(cè)試一下動(dòng)態(tài)圖的繪制(需要實(shí)現(xiàn)優(yōu)化算法matlab實(shí)現(xiàn)(七)差分進(jìn)化算法matlab實(shí)現(xiàn)中的相關(guān)代碼)。
注意調(diào)用方法是需要自行決定步長(zhǎng)恭垦,即draw2_gif()和draw3_gif中的step參數(shù)快毛。步長(zhǎng)越小繪制的圖片越多,執(zhí)行的越慢番挺。
測(cè)試F1
文件名:..\optimization algorithm\algorithm_differential_evolution\Test.m
%% 清理之前的數(shù)據(jù)
% 清除所有數(shù)據(jù)
clear all;
% 清除窗口輸出
clc;
%% 添加目錄
% 將上級(jí)目錄中的frame文件夾加入路徑
addpath('../frame')
%% 選擇測(cè)試函數(shù)
Function_name='F1';
%[最小值唠帝,最大值,維度玄柏,測(cè)試函數(shù)]
[lb,ub,dim,fobj]=Get_Functions_details(Function_name);
%% 算法實(shí)例
% 種群數(shù)量
size = 50;
% 最大迭代次數(shù)
iter_max = 1000;
% 取值范圍上界
range_max_list = ones(1,dim)*ub;
% 取值范圍下界
range_min_list = ones(1,dim)*lb;
% 實(shí)例化差分進(jìn)化算法類
base = DE_Base(dim,size,iter_max,range_min_list,range_max_list);
base.is_cal_max = false;
% 確定適應(yīng)度函數(shù)
base.fitfunction = fobj;
% 運(yùn)行
base.run();
disp(base.cal_fit_num);
%% 繪制2維圖像襟衰,每10代繪制一次,且保存gif圖像到本地
%base.draw2_gif(10,true,base.name);
% 繪制3維圖像粪摘,每10代繪制一次瀑晒,且保存gif圖像到本地
base.draw3_gif(10,true,base.name);
%% 繪制圖像
figure('Position',[500 500 660 290])
%Draw search space
subplot(1,2,1);
func_plot(Function_name);
title('Parameter space')
xlabel('x_1');
ylabel('x_2');
zlabel([Function_name,'( x_1 , x_2 )'])
%Draw objective space
subplot(1,2,2);
% 繪制曲線绍坝,由于算法是求最大值,適應(yīng)度函數(shù)為求最小值苔悦,故乘了-1轩褐,此時(shí)去掉-1
semilogy((base.value_best_history),'Color','r')
title('Objective space')
xlabel('Iteration');
ylabel('Best score obtained so far');
% 將坐標(biāo)軸調(diào)整為緊湊型
axis tight
% 添加網(wǎng)格
grid on
% 四邊都顯示刻度
box off
legend(base.name)
display(['The best solution obtained by ',base.name ,' is ', num2str(base.value_best)]);
display(['The best optimal value of the objective funciton found by ',base.name ,' is ', num2str(base.position_best)]);