智能算法之模拟退火算法
1.起源
模拟退火算法来源于热力学中固体物质的退火冷却过程 (退火是一种金属热处理工艺,指的是将金属缓慢加热到一定温度,保持足够时间,然后以适宜速度冷却)。
2.物理退火流程
模拟退火的算法思想是参考物理退火的过程而来,物理退火的过程为:加温过程 -> 等温过程 -> 冷却过程。
2.1 加温过程
通过加温,增强粒子的热运动,让各部分变得均匀。当温度足够高时,固体将熔解为液体,从而消除原先系统中可能存在的非均匀状态,保证后续进行的过程是从平衡态开始,由于是加温过程温度上升,所以该过程系统能量增加。
2.2 等温过程
对于与周围环境交换热量而温度保持不变的封闭系统,系统状态的自发变化总是朝着自由能减少的方向进行,当自由能达到最小时,系统达到平衡态。
2.3 冷却过程
通过一定速率对液体进行冷却,减弱粒子的热运动并趋于有序,在每个温度都达到平衡态,最后在常温时达到基态,能量减为最小,从而得到低能态的晶体结构。
2.4 组合优化与物理退化
3.原理
模拟退火算法的基本原理:对于目标函数 f ( X ) f(X) f(X)、自变量为 X X X 的 n n n 维极小化问题(极大化问题乘以 − 1 -1 −1转化为极小化问题),初值 X 0 X_0 X0 可以随机化或者自己设置。
3.1 算法核心迭代
设 f k , f k + 1 f_k,f_{k+1} fk,fk+1 分别为目标函数在第 k k k 次和第 k + 1 k+1 k+1 次迭代值,即 f k = f ( X k ) , f k + 1 = f ( X k + 1 ) f_k=f(X_k),f_{k+1}=f(X_{k+1}) fk=f(Xk),fk+1=f(Xk+1)。
若 f k > f k + 1 f_k>f_{k+1} fk>fk+1,则接受 X k + 1 X_{k+1} Xk+1 作为下一次迭代的初值继续进行运算,直至满足终止条件(收敛或者迭代次数耗尽);
若 f k < f k + 1 f_k<f_{k+1} fk<fk+1,则接受 X k + 1 X_{k+1} Xk+1 的概率为 p p p,拒绝的概率为 1 − p 1-p 1−p,其中接受概率公式如下: p = e x p ( − f k + 1 − f k T ) p=exp(-\frac{f_{k+1}-f_k}{T}) p=exp(−Tfk+1−fk) 其中 T T T 为控制参数,在模拟退火算法中, T T T 必须缓慢减少,避免变化过快,导致优化陷入极值点。
3.2 具体流程
以求解极小值问题为例:
( 1 ) (1) (1)设定初始温度 T T T,迭代次数 L L L,误差 ϵ \epsilon ϵ,初始解 X 0 X_0 X0,得到目标函数 f ( X 0 ) f(X_0) f(X0);
( 2 ) (2) (2)循环进行迭代, k = 1 , ⋯ , L k=1,\cdots,L k=1,⋯,L;
( 3 ) (3) (3)根据当前温度得到新解 X ′ X' X′(第一个可以随机生成), 代入 f ( X ) f(X) f(X) 得到 f ( X ′ ) f(X') f(X′);
( 4 ) (4) (4)若 f ( X ) > f ( X ′ ) f(X)>f(X') f(X)>f(X′),则接受 X ′ X' X′ 作为下一次迭代的初值,若 f ( X ) < f ( X ′ ) f(X)<f(X') f(X)<f(X′),则以概率 e x p ( − f ( X ′ ) − f ( X ) T ) exp(-\frac{f(X')-f(X)}{T}) exp(−Tf(X′)−f(X)) 接受 X ′ X' X′ 作为下一次迭代的初值;
( 5 ) (5) (5)若满足终止条件,则输出当前最优解 X ′ X' X′,终止条件;
( 6 ) (6) (6) T T T 减小,然后回到流程 ( 2 ) (2) (2),在当前温度下继续循环迭代,执行步骤 ( 3 , 4 , 5 ) (3,4,5) (3,4,5);
( 7 ) (7) (7)注意,这里的终止条件可以有多个,比如:迭代次数耗尽、满足最优解、温度降低到一定值、新目标函数与原先目标函数的误差小于 ϵ \epsilon ϵ。
4.案例
4.1 求解n元函数的极小值
例1:求解函数 f ( X ) = X 2 f(X)=X^2 f(X)=X2 的最小值,其中 X 2 = ∑ i = 1 10 x 2 X^2=\sum_{i=1}^{10}x^2 X2=∑i=110x2, − 10 ≤ x ≤ 10 -10\leq x\leq 10 −10≤x≤10。
下面通过matlab进行求解:
目标函数:
%--------目标函数f(x)---------
function result = func1(x)
result = sum(x.^2);
end
模拟退火算法:
clear; clc;
%---------------------模拟退火核心-------------------------------
L = 200; % 每个温度的迭代次数
epsilon = 1e-10; % 新目标函数与原先目标函数的误差
T0 = 200; % 初始温度
T1 = 0.00001; % 终止温度
s = 0.01; % 自变量更新的步长,相当于学习率
K = 0.998; % 温度衰减参数
P = 0; % Metropolis 过程中总接受点
%---------------------根据题目所写--------------------------------
opt_minmax = 1; % 求解极小值问题为1,极大值问题为-1
n = 10; % 自变量维度
up = 10; % 自变量上限
sup = -10; % 自变量下限
x0 = rand(n, 1)*(up-sup)-up; % 随机生成在范围内的初始自变量
x1 = rand(n, 1)*(up-sup)-up; % 随机生成在范围内的 x1 自变量进行第一步
PreBest = x0;
NowBest = x1;
%---------------------进行迭代----------------------------------
delta = abs(func1(NowBest) - func1(PreBest));
while (delta > epsilon) && (T0 > T1)
T0 = K*T0;
for i = 1:L
x2 = x1 + s*(rand(n, 1)*(up-sup)-up);
%-----下面这个循环是写题目的条件的,这里没啥好些,就重复了边界条件
for j = 1:n
while (x2(j) > up) || (x2(j) < sup)
x2(j) = x1(j) + s*(rand*(up-sup)-up);
end
end
%--------------查看解是否是全局最优解----------------
if opt_minmax*func1(NowBest) > opt_minmax*func1(x2)
PreBest = NowBest; % 保留上一个最优解
NowBest = x2; % 保留新的最优解
end
%---------------- Metropolis过程--------------------
if opt_minmax*func1(x1) > opt_minmax*func1(x2)
x1 = x2;
P = P + 1;
else
p = exp(-(func1(x2)-func1(x1))/T0);
if p > rand(1)
x1 = x2;
P = P + 1;
end
end
Y(P) = func1(NowBest);
end
delta = abs(func1(NowBest) - func1(PreBest));
end
得到结果为:
X = [ − 0.0114 , − 0.0002 , 0.0020 , 0.0101 , 0.0074 , − 0.0003 , − 0.0084 , 0.0112 , − 0.0252 , 0.0052 ] X=[-0.0114,-0.0002,0.0020,0.0101,0.0074,-0.0003,-0.0084,0.0112,-0.0252,0.0052] X=[−0.0114,−0.0002,0.0020,0.0101,0.0074,−0.0003,−0.0084,0.0112,−0.0252,0.0052]
f ( X ) = 0.0011 f(X)=0.0011 f(X)=0.0011
绘制适应度进化曲线:
%----------------------------画图--------------------------------
plot(Y, 'r');
hold on
scatter(length(Y), Y(end), 'bo', 'MarkerFaceColor', 'b')
text(length(Y), Y(end), ' 最优点')
xlabel('迭代次数'); ylabel('目标函数值'); title('适应度进化曲线');
4.2 求解二元函数的极小值
例2:求解函数 f ( x , y ) = 5 c o s ( x y ) + x y + y 3 f(x,y) = 5cos(xy)+xy+y^3 f(x,y)=5cos(xy)+xy+y3 的最小值,其中 − 5 ≤ x ≤ 5 , − 5 ≤ y ≤ 5 -5\leq x\leq 5,-5\leq y\leq 5 −5≤x≤5,−5≤y≤5。
下面通过matlab进行求解:
目标函数:
%--------目标函数f(x)---------------
function result = func1(x)
result = 5*cos(x(1).*x(2))+x(1).*x(2)+x(2).^3;
end
可以看看 f ( x , y ) f(x,y) f(x,y) 的图像:
clear;clc;
x = linspace(-5, 5);
y = linspace(-5, 5);
[x, y] = meshgrid(x, y);
f = 5*cos(x.*y)+x.*y+y.^3;
mesh(x, y, f);
xlabel('x'); ylabel('y'); zlabel('f');
第二种方法适合小白,不过和meshgrid画出来的图相比较发现是翻转过的,所以可以自行选择。
x1 = linspace(-5, 5);
y1 = linspace(-5, 5);
N = size(x1, 2);
for i = 1:N
for j = 1:N
z(i, j)=5*cos(x1(i)*y1(j))+x1(i)*y1(j)+y1(j)^3;
end
end
mesh(x1, y1, z);
xlabel('x1'); ylabel('y1'); zlabel('z');
模拟退火算法:
clear; clc;
%---------------------模拟退火核心------------------------------------------
L = 200; % 每个温度的迭代次数
epsilon = 1e-8; % 新目标函数与原先目标函数的误差
T0 = 200; % 初始温度
T1 = 0.00001; % 终止温度
s = 0.01; % 自变量更新的步长,相当于学习率
K = 0.998; % 温度衰减参数
P = 0; % Metropolis 过程中总接受点
%---------------------根据题目所写------------------------------------------
opt_minmax = 1; % 求解极小值问题为1,极大值问题为-1
n = 2; % 自变量维度
up = [5; 5]; % 自变量x,y上限
sup = [-5; -5]; % 自变量x,y下限
x0 = rand(2, 1).*(up-sup)-up; % 随机生成在范围内的初始自变量x0,y0
x1 = rand(2, 1).*(up-sup)-up; % 随机生成在范围内的 x1, y1 自变量进行第一步
PreBest = x0;
NowBest = x1;
%---------------------进行迭代----------------------------------------------
delta = abs(func1(NowBest) - func1(PreBest));
while (delta > epsilon) && (T0 > T1)
T0 = K*T0;
for i = 1:L
x2 = x1 + s*(rand(n, 1).*(up-sup)-up);
%-----下面这个循环是写题目的条件的,这里没啥好些,就重复了边界条件
for j = 1:n
while (x2(j) > up(j)) || (x2(j) < sup(j))
x2(j) = x1(j) + s*(rand*(up(j)-sup(j))-up(j));
end
end
%--------------查看解是否是全局最优解----------------
if opt_minmax*func1(NowBest) > opt_minmax*func1(x2)
PreBest = NowBest; % 保留上一个最优解
NowBest = x2; % 保留新的最优解
end
%---------------- Metropolis过程--------------------
if opt_minmax*func1(x1) > opt_minmax*func1(x2)
x1 = x2;
P = P + 1;
else
p = exp(-(func1(x2)-func1(x1))/T0);
if p > rand(1)
x1 = x2;
P = P + 1;
end
end
Y(P) = func1(NowBest);
end
delta = abs(func1(NowBest) - func1(PreBest));
end
得到结果为:
f ( x , y ) = f ( 4.4394 , − 5.0000 ) = − 152.0912 f(x,y)=f(4.4394,-5.0000)=-152.0912 f(x,y)=f(4.4394,−5.0000)=−152.0912
绘制适应度进化曲线:
%----------------------------画图--------------------------------
plot(Y, 'r');
hold on
scatter(length(Y), Y(end), 'bo', 'MarkerFaceColor', 'b')
text(length(Y), Y(end), ' 最优点')
xlabel('迭代次数'); ylabel('目标函数值'); title('适应度进化曲线');
4.3 货物配送规划
例3:根据下面的所给的条件,给此地的生鲜配送路线进行规划,让生鲜被高效率送到各销售市场中,使得资源达到最大的利用。
n n n :销售市场数量;
q i q_i qi:每个市场需求量 ( i = 1 , 2 , ⋯ , n ) (i=1,2,\cdots,n) (i=1,2,⋯,n);
m m m:配送车数量(每辆车都型号都一致);
Q Q Q:配送车最大装载量;
d i j d_{ij} dij:市场 i i i 到市场 j j j 的距离;
t i j t_{ij} tij:从市场 i i i 到市场 j j j 所需时间;
d o i d_{oi} doi:配送中心 o o o 到市场 i i i 的距离;
c 0 c_0 c0 :每次配送固定成本;
c v c_v cv:单位里程行驶费用;
v v v:配送车匀速行驶速度;
T T T:生鲜装卸时间;
β 1 \beta_1 β1:单位时间配送运输损耗比例;
β 2 \beta_2 β2:单位时间配送装卸损耗比例;
u i j k u_{ijk} uijk:配送车辆 k k k 在 i i i 到 j j j 路径上行驶时的载重量;
p p p:单位重量货物的货损价格;
f 0 f_0 f0:单次配送任务中,配送中心派出的送货车辆总数;
f v f_v fv:单次配送任务中,所有配送车辆行驶里程数之和;
f b f_b fb:单次配送任务中,所有配送线路上产生的货损量之和。
4.3.1 分析
决策变量:
X i j k = { 1 , 配 送 车 k 从 市 场 ( 或 配 送 中 心 ) i 到 市 场 j 0 , 其 他 X_{ijk}=\left\{ \begin{aligned} 1, \quad 配送车 k 从市场(或配送中心) i 到市场 j \\ 0, \quad \quad \quad \quad \quad \quad \quad \quad其他 \quad \quad \quad\quad \quad \quad \quad \end{aligned} \right. Xijk={1,配送车k从市场(或配送中心)i到市场j0,其他 Y i k = { 1 , 市 场 i 的 货 物 由 配 送 车 k 配 送 0 , 其 他 Y_{ik}=\left\{ \begin{aligned} 1, \quad 市场 i 的货物由配送车k配送 \\ 0, \quad \quad \quad \quad \quad其他\quad \quad \quad \quad\quad \quad \end{aligned} \right. Yik={1,市场i的货物由配送车k配送0,其他 目标函数 m i n Z = m i n ( f 0 c 0 + f v c v + f b p ) min Z = min(f_0c_0+f_vc_v+f_bp) minZ=min(f0c0+fvcv+fbp) m i n Z = m i n [ k c 0 + ∑ i = 0 n ∑ j = 0 n ∑ k = 1 m d i j X i j k c v + ( ∑ i = 0 n ∑ j = 0 n ∑ k = 1 m β 1 t i j u i j k X i j k + ∑ i = 0 n ∑ k = 1 m β 2 T q i Y i k ) p ] minZ=min[kc_0+\sum_{i=0}^n\sum_{j=0}^n\sum_{k=1}^md_{ij}X_{ijk}c_v \\ + (\sum_{i=0}^n\sum_{j=0}^n\sum_{k=1}^m\beta_1t_{ij}u_{ijk}X_{ijk}+\sum_{i=0}^n\sum_{k=1}^m\beta_2Tq_{i}Y_{ik})p] minZ=min[kc0+i=0∑nj=0∑nk=1∑mdijXijkcv+(i=0∑nj=0∑nk=1∑mβ1tijuijkXijk+i=0∑nk=1∑mβ2TqiYik)p] 约束条件
每条路线的生鲜需求量之和不超过配送车最大装载量 Q Q Q: ∑ i = 1 n q i Y i k ≤ Q ( k = 1 , 2 , ⋯ , m ) \sum_{i=1}^nq_{i}Y_{ik} \leq Q \quad(k=1,2,\cdots,m) i=1∑nqiYik≤Q(k=1,2,⋯,m) 每辆车不可能同时去两个市场: ∑ i = 1 n X o i k = ∑ i = 1 n X i o k ≤ 1 ( k = 1 , 2 , ⋯ , m ) \sum_{i=1}^nX_{oik}=\sum_{i=1}^nX_{iok}\leq1 \quad(k=1,2,\cdots,m) i=1∑nXoik=i=1∑nXiok≤1(k=1,2,⋯,m) 每个市场只有一辆配送车送货: ∑ k = 1 m Y i k = 1 ( i = 1 , 2 , ⋯ , n ) \sum_{k=1}^mY_{ik}=1\quad (i=1,2,\cdots,n) k=1∑mYik=1(i=1,2,⋯,n) 这里假设市场需求量之和为配送车最大装载量之和: ∑ i = 1 n q i = ∑ k = 1 m Q \sum_{i=1}^{n}q_i=\sum_{k=1}^mQ i=1∑nqi=k=1∑mQ
编写程序,进行计算
5.优缺点及可改进方向
6.参考文献
[1] 周佳莉. 模拟退火算法的应用[J]. 西部皮革,2019,41(20):82.
[2] 包子阳,余继周,杨杉. 智能优化算法及其MATLAB实例(第3版)
[3] 康雯轩. 基于模拟退火算法的共享单车城市配送路径规划[J]. 科技与创新,2022(13):104-106,109. DOI:10.15913/j.cnki.kjycx.2022.13.032.