这是一篇关于模拟退火算法的总结博客,包括算法思想,算法步骤,Python实现,MATLAB实现,算法进阶等。
look这个函数,我们要求它的最小值。
模拟退火算法是这么做的:
r<P
时把当前值更新为新值,否则不更新。可以发现,当前温度 T 0 T_0 T0越大,指数函数括号里的值越大,接受这个新值的概率P越大。随着迭代次数的增加, T 0 T_0 T0会越来越小,接受新值的概率P也会越来越小,相当于渐渐冷却了下来,趋于稳定的状态。伪代码:
求函数f(x)的最小值
T0: 系统的初始温度(高温状态)
Tf: 温度的下限
rate: 控制降温的速率
f(now): 系统当前状态的评价函数值
f(new): 系统新状态的评价函数值
while (T0 > Tf)
{
if f(new) - f(now) < 0
f(now) = f(new)
else if (exp(f(new) - f(now) / T0) > random(0,1))
f(now) = f(new)
else
不更新f(now)
T0 = T0 * rate;
更新状态new
}
循环结束,得到模拟退火求得的最小值f(now)
求下列函数的最小值:
f ( x ) = x 3 − 60 x 2 − 4 x + 6 f(x)= x^3-60x^2-4x+6 f(x)=x3−60x2−4x+6
定义域为 [ 0 , 100 ] [0,100] [0,100]
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import math
# define aim function
def aimFunction(x):
y = x ** 3 - 60 * x ** 2 - 4 * x + 6
return y
x = [i / 10 for i in range(1000)]
y = [0 for i in range(1000)]
for i in range(1000):
y[i] = aimFunction(x[i])
plt.plot(x, y)
T = 1000 # initiate temperature
Tmin = 10 # minimum value of terperature
x = np.random.uniform(low=0, high=100) # initiate x
k = 50 # times of internal circulation
y = 0 # initiate result
t = 0 # time
while T >= Tmin:
for i in range(k):
# calculate y
y = aimFunction(x)
# generate a new x in the neighboorhood of x by transform function
xNew = x + np.random.uniform(low=-0.055, high=0.055) * T
if (0 <= xNew and xNew <= 100):
yNew = aimFunction(xNew)
if yNew - y < 0:
x = xNew
else:
# metropolis principle
p = math.exp(-(yNew - y) / T)
r = np.random.uniform(low=0, high=1)
if r < p:
x = xNew
t += 1
print(t)
T = 1000 / (1 + t) #降温函数,也可使用T=0.9T
print(x, aimFunction(x))
通过求导计算得到的精确最小值为 40.033,运行求得的最小值为40.072。
代码来源
%% I. 清空环境变量
clear all
clc
%% II. 导入城市位置数据
X = [16.4700 96.1000
16.4700 94.4400
20.0900 92.5400
22.3900 93.3700
25.2300 97.2400
22.0000 96.0500
20.4700 97.0200
17.2000 96.2900
16.3000 97.3800
14.0500 98.1200
16.5300 97.3800
21.5200 95.5900
19.4100 97.1300
20.0900 92.5500];
%% III. 计算距离矩阵
D = Distance(X); %计算距离矩阵
n = size(D,1); %城市的个数
%% IV. 初始化参数
T0 = 1e10; % 初始温度
Tf = 1e-30; % 终止温度
q = 0.9; % 降温速率
Time = ceil(double(solve([num2str(T0) '*(0.9)^x = ', num2str(Tf)]))); % 计算迭代的次数 T0 * (0.9)^x = Tf
count = 0; % 初始化迭代计数
Obj = zeros(Time, 1); % 目标值矩阵初始化
path = zeros(Time, n); % 每代的最优路线矩阵初始化
%% V. 随机产生一个初始路线
S1 = randperm(n);
DrawPath(S1, X) % 画出初始路线
disp('初始种群中的一个随机值:')
OutputPath(S1); % 用箭头的形式表述初始路线
rlength = PathLength(D, S1); % 计算初始路线的总长度
disp(['总距离:', num2str(rlength)]);
%% VI. 迭代优化
while T0 > Tf
count = count + 1; % 更新迭代次数
%temp = zeros(L,n+1);
% 1. 产生新解
S2 = NewAnswer(S1);
% 2. Metropolis法则判断是否接受新解
[S1, R] = Metropolis(S1, S2, D, T0); % Metropolis 抽样算法
% 3. 记录每次迭代过程的最优路线
if count == 1 || R < Obj(count-1) % 如果当前温度下的距离小于上个温度的距离,记录当前距离
Obj(count) = R;
else
Obj(count) = Obj(count-1);
end
path(count,:) = S1; % 记录每次迭代的路线
T0 = q * T0; % 以q的速率降温
end
%% VII. 优化过程迭代图
figure
plot(1: count, Obj)
xlabel('迭代次数')
ylabel('距离')
title('优化过程')
grid on
%% VIII. 绘制最优路径图
DrawPath(path(end, :), X) % path矩阵的最后一行一定是最优路线
%% IX. 输出最优解的路线和总距离
disp('最优解:')
S = path(end, :);
p = OutputPath(S);
disp(['总距离:', num2str(PathLength(D, S))]);
function [S,R] = Metropolis(S1, S2, D, T)
%% 输入
% S1: 当前解
% S2: 新解
% D: 距离矩阵(两两城市的之间的距离)
% T: 当前温度
%% 输出
% S: 更新后的当前解
% R: 更新后的路线距离
R1 = PathLength(D, S1); % 计算S1路线长度
n = length(S1); % 城市的个数
R2 = PathLength(D,S2); % 计算S2路线长度
dC = R2 - R1; % 计算能力之差
if dC < 0 % 如果能力降低 接受新路线
S = S2; % 接受新解
R = R2;
elseif exp(-dC/T) >= rand % 以exp(-dC/T)概率接受新路线
S = S2;
R = R2;
else % 不接受新路线
S = S1;
R = R1;
end
end
function S2 = NewAnswer(S1)
% 输入:当前解S1
% 输出:新解S2
n = length(S1);
S2 = S1;
a = round(rand(1, 2) * (n - 1) + 1); %产生两个随机位置,用于交换
W = S2(a(1));
S2(a(1)) = S1(a(2));
S2(a(2)) = W;
function D = Distance(citys)
% 输入:各城市的位置坐标(citys)
% 输出:两两城市之间的距离(D)
n = size(citys, 1);
D = zeros(n, n);
for i = 1: n
for j = i + 1: n
D(i, j) = sqrt((citys(i, 1) - citys(j, 1))^2 + (citys(i, 2) - citys(j, 2))^2);
D(j, i) = D(i, j);
end
end
function DrawPath(Route, citys)
%% 画路径函数
% 输入
% Route 待画路径
% citys 各城市坐标位置
%画出初始路线
figure
plot([citys(Route, 1); citys(Route(1), 1)], [citys(Route, 2); citys(Route(1), 2)], 'o-');
grid on
%给每个地点标上序号
for i = 1: size(citys, 1)
text(citys(i, 1), citys(i, 2), [' ' num2str(i)]);
end
text(citys(Route(1), 1), citys(Route(1), 2), ' 起点');
text(citys(Route(end), 1), citys(Route(end), 2), ' 终点');
function p = OutputPath(Route)
% 输入: 路径Route
% 输出: 路径函数
%给R末端添加起点即R(1)
Route = [Route, Route(1)];
n = length(Route);
p = num2str(Route(1));
for i = 2: n
p = [p, ' —> ', num2str(Route(i))];
end
disp(p)
function Length = PathLength(D, Route)
%% 输入
% D 两两城市之间的距离
% Route 路线
%% 输出
起点与终点之间的路径长度Length
Length = 0;
n = length(Route);
for i = 1: (n - 1)
Length = Length + D(Route(i), Route(i + 1));
end
Length = Length + D(Route(n), Route(1));
运行了上述代码后,得到的结果如下:
初始解:
11 —> 10 —> 14 —> 9 —> 5 —> 3 —> 7 —> 4 —> 8 —> 1 —> 2 —> 13 —> 12 —> 6 —> 11
总距离:62.7207
SA求得的最优解:
9 —> 11 —> 8 —> 13 —> 7 —> 12 —> 6 —> 5 —> 4 —> 3 —> 14 —> 2 —> 1 —> 10 —> 9
总距离:29.3405
随着迭代次数的增加,SA找到的最短路径变化图如下:
可以看出,随着不断的迭代,距离是一直在不断下降的。我们不能保证最终的答案一定是最短的,迭代的次数越多,得到的结果就越接近正确答案。但是迭代次数过多就会需要很长的计算时间,所以要适当选择迭代次数。
1 算法特点:
2 改进的可行方案:
3 改进的方式:
4 改进的思路:
5 改进的退火过程
6 改进的抽样过程
时间不变的噪声算法(TINA Time-invariant noise algorithm)
状态产生函数中扰动强度不随时间改变,而是和能量大小相关,能量大的扰动大,能量小的扰动小,能量为零,扰动也为零,算法停止。
单调升温(Monotonic temperature rising) SA
在算法退火后期,温度很低且陷入局部极小解的时,算法很难跳出。因此,可以适当重新提高温度,促使算法跳出。
记忆指导SA(Simulated Annealing with Memmory Guidance ,简记为SAMG)
增加一个记忆装置,存储算法计算过程产生的最好的解,以这个解为最终解。
自适应SA算法
根据邻域搜索进展的反馈信息, 自适应确定温度变化和邻域搜索强度特点:
退火过程中温度参数变化符合幅值递减的下降总趋势, 但不排除局部升温的可能, 以保证寻求到合适的温度序列, 避免陷入局部最优;
算法的终止条件依据退火温度和邻域搜索进展状态设计;
每一温度下算法的迭代次数随温度下降而递增, 邻域搜索强度依其对目标函数的贡献动态分配;
温度变化、邻域搜索和终止条件的控制机制由算法过程自动触发。
并行性
操作并行性:各个环节同时处理;
进程并行性:同时多个算法运行;
空间并行性:解空间分解分别处理,最终组合。
传统优化算法与全局优化算法的对比:
全局优化算法:
传统优化算法: