1.修改框架的目的
之前有不少问如下动态图是怎么绘制的?
这个是使用java编写的代码实现的,方式较为复杂,把每一代的位置画在一张图中,然后按顺序合成gif动态图。用java实现这种方式非常复杂,需要自己去实现绘制代码,然后保存成图片再合成。单绘制图像的代码就有几百行,而且有不少未解决的bug,比如一些位置的点只能用黑色或者白色才会在动态图中显示。
将代码用matlab实现之后,发现使用matlab绘制动态图要比java容易一万倍,其效果如图。
所以在这里对优化算法框架进行一个小小的更新,让每个算法都能绘制群体位置动态图。
2.算法框架的修改
使用matlab绘制动态图的原理和使用java绘制的原理一样:即将每一代的所有个体的位置保存下来,然后每一代绘制成一张图,最后按顺序合成动态图。
这里我们需要修改的部分由两点:
1.保存所有个体的位置;
2.绘制群体的位置。
图像的显示以及动态图gif的生成,matlab已经帮我们完成,不需要单独去编码实现。
需要修改的代码文件列表:
优化算法matlab实现(二)框架编写中的框架。
文件名 | 描述 |
---|---|
..\optimization algorithm\frame\Unit.m | 个体 |
..\optimization algorithm\frame\Algorithm_Impl.m | 算法主体 |
只需要修改这两个文件即可,不需要修改其他文件。
文件..\optimization algorithm\frame\Unit.m中需要添加个体的历史位置及保存历史位置的方法,其实现如下:
% 个体基类
classdef Unit< handle
properties
% 个体的位置
position;
% 个体的适应度值
value;
% 记录所有的位置,画图用
position_history_list;
end
methods
function self = Unit()
end
% 将当前位置保存到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中每一代都需要调用上面的save方法来保存图像,其实现如下:
% 记录最优值
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中需要绘制群体位置的方法,其实现如下:
% 绘制动态图,2维图像:step为步长(几代绘制一张图像),is_save用来判断是否保存gif动态图
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
% 如果不满足步长,则跳过
if mod(i,step) > 0 && i>1
% 必须要绘制第一代,否则matlab会报错,原因未知
continue
end
% 遍历每一个个体
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);
% 绘制显示区域
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;
% 固定横纵坐标轴
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则设置is_save = true
if is_save
%下面是保存为GIF的程序
frame=getframe(gcf);
% 返回单帧颜色图像
imind=frame2im(frame);
% 颜色转换
[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
% 绘制完成关闭窗口
close(f1);
end
上面绘制的是2维动态图,我们可以将其类推至3维,来绘制3维动态图。当然图像最多只能绘制到3维,毕竟我们生活在3维空间,只能直观看到3维。
% 绘制动态图,3维图像:step为步长(几代绘制一张图像),is_save用来判断是否保存gif动态图
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
% 如果不满足步长,则跳过
if mod(i,step) > 0 && i>1
% 必须要绘制第一代,否则matlab会报错,原因未知
continue
end
% 遍历每一个个体
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);
% 绘制显示区域
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;
% 固定横纵坐标轴
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则设置is_save = true
if is_save
%下面是保存为GIF的程序
frame=getframe(gcf);
% 返回单帧颜色图像
imind=frame2im(frame);
% 颜色转换
[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
% 绘制完成关闭窗口
close(f1);
end
3维图像效果如图:
3.完整框架代码
总目录:..\optimization algorithm
框架目录:..\optimization algorithm/frame
框架文件:
文件名 | 描述 |
---|---|
..\optimization algorithm\frame\Unit.m | 个体 |
..\optimization algorithm\frame\Algorithm_Impl.m | 算法主体 |
文件内容:
Unit.m
% 个体基类
classdef Unit< handle
properties
% 个体的位置
position;
% 个体的适应度值
value;
% 记录所有的位置,画图用
position_history_list;
end
methods
function self = Unit()
end
% 将当前位置保存到position_history_list中
function save(self)
self.position_history_list=[self.position_history_list;self.position];
end
end
end
Algorithm_Impl.m
% 优化算法基类
classdef Algorithm_Impl < handle
properties
%当前最优位置
position_best;
%当前最优适应度
value_best;
%历史最优适应度
value_best_history;
%历史最优位置
position_best_history;
%是否为求最大值,默认为是
is_cal_max;
%适应度函数,需要单独传入
fitfunction;
% 调用适应度函数次数
cal_fit_num = 0;
end
properties(Access = protected)
%维度
dim;
%种群中个体的数量
size;
%最大迭代次数
iter_max;
%解空间下界
range_min_list;
%解空间上界
range_max_list;
%种群列表
unit_list;
end
methods
% 运行,调用入口
function run(self)
tic
self.init()
self.iteration()
toc
disp(['运行时间: ',num2str(toc)]);
end
% 绘制动态图,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
% 如果不满足步长,则跳过
if mod(i,step) > 0 && i>1
% 必须要绘制第一代,否则matlab会报错,原因未知
continue
end
% 遍历每一个个体
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);
% 绘制显示区域
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;
% 固定横纵坐标轴
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则设置is_save = true
if is_save
%下面是保存为GIF的程序
frame=getframe(gcf);
% 返回单帧颜色图像
imind=frame2im(frame);
% 颜色转换
[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
% 绘制完成关闭窗口
close(f1);
end
% 绘制动态图,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
% 如果不满足步长,则跳过
if mod(i,step) > 0 && i>1
% 必须要绘制第一代,否则matlab会报错,原因未知
continue
end
% 遍历每一个个体
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);
% 绘制显示区域
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;
% 固定横纵坐标轴
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则设置is_save = true
if is_save
%下面是保存为GIF的程序
frame=getframe(gcf);
% 返回单帧颜色图像
imind=frame2im(frame);
% 颜色转换
[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
% 绘制完成关闭窗口
close(f1);
end
end
methods (Access = protected)
% 构造函数
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;
%默认为求最大值
self.is_cal_max = true;
end
% 初始化
function init(self)
self.position_best=zeros(1,self.dim);
self.value_best_history=[];
self.position_best_history=[];
%设置初始最优值,由于是求最大值,所以设置了最大浮点数的负值
self.value_best = -realmax('double');
end
% 开始迭代
function iteration(self)
for iter = 1:self.iter_max
self.update(iter)
end
end
% 处理一次迭代
function update(self,iter)
% 记录最优值
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(['最优值=' num2str(self.value_best)]);
else
self.value_best_history(end+1) = -self.value_best;
disp(['最优值=' num2str(-self.value_best)]);
end
self.position_best_history = [self.position_best_history;self.position_best];
disp(['最优解=' num2str(self.position_best)]);
end
function value = cal_fitfunction(self,position)
if(isempty(self.fitfunction))
value = 0;
else
% 如果适应度函数不为空则返回适应度值
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
% 越界检查,超出边界则在解空间内随机初始化
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.测试代码
使用之前的差分进化算法测试一下动态图的绘制(需要实现优化算法matlab实现(七)差分进化算法matlab实现中的相关代码)。
注意调用方法是需要自行决定步长,即draw2_gif()和draw3_gif中的step参数。步长越小绘制的图片越多,执行的越慢。
测试F1
文件名:..\optimization algorithm\algorithm_differential_evolution\Test.m
%% 清理之前的数据
% 清除所有数据
clear all;
% 清除窗口输出
clc;
%% 添加目录
% 将上级目录中的frame文件夹加入路径
addpath('../frame')
%% 选择测试函数
Function_name='F1';
%[最小值,最大值,维度,测试函数]
[lb,ub,dim,fobj]=Get_Functions_details(Function_name);
%% 算法实例
% 种群数量
size = 50;
% 最大迭代次数
iter_max = 1000;
% 取值范围上界
range_max_list = ones(1,dim)*ub;
% 取值范围下界
range_min_list = ones(1,dim)*lb;
% 实例化差分进化算法类
base = DE_Base(dim,size,iter_max,range_min_list,range_max_list);
base.is_cal_max = false;
% 确定适应度函数
base.fitfunction = fobj;
% 运行
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);
% 绘制曲线,由于算法是求最大值,适应度函数为求最小值,故乘了-1,此时去掉-1
semilogy((base.value_best_history),'Color','r')
title('Objective space')
xlabel('Iteration');
ylabel('Best score obtained so far');
% 将坐标轴调整为紧凑型
axis tight
% 添加网格
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)]);