智能优化算法(四):模拟退火算法

1.算法简介

\quad 模拟退火算法(Simulated Annealing,SA)的思想最早由N. Metropolis等人在1953年提出,1983年,S. Kirkpatrick等人成功地将退火思想引入到组合优化领域,该算法基于Monte-Carlo迭代求解策略,是一种随机寻优算法,其核心思想是物理中固体物质的退火过程与组合优化问题之间的相似性。
\quad 模拟退火算法是一种基于概率的随机优化算法,它尽管也是一种贪心算法,但其搜索过程引入了随机因素,使得算法在一定程度上能够接受较差的解,从而有可能跳出局部最优解,最终达到全局最优解。模拟退火算法通过以一定概率接受一个比当前解更差的解,避免陷入局部最优解。
\quad 在退火算法中,算法在找到局部最优解E后,可能会以一定的概率接受到F的移动,经过几次这样的非最优移动后,可能会到达G点,并进一步上升到H点,从而跳出局部最大值E。模拟退火算法来源于固体退火的原理,固体退火过程是将固体加热至高温,然后逐渐冷却,在加热过程中,固体内部的粒子变得无序,内能增大;在逐渐冷却的过程中,粒子趋于有序,并在每个温度下达到平衡态,最终在常温下达到基态,内能最小。
在这里插入图片描述

2.算法推导

2.1.Bolzman方程

\quad 设热力学系统S中有n个状态(有限且离散的),其中状态i的能量为 E i E_{i} Ei ,在温度 T k T_{k} Tk下,经一段时间达到热平衡,此时处在状态i的概率为:
P i ( T k ) = C k exp ⁡ ( − E i T k ) P_i\left(T_k\right)=C_k\exp\begin{pmatrix}-E_i\\T_k\end{pmatrix} Pi(Tk)=Ckexp(EiTk)
\quad 那么对于系数 C k C_{k} Ck我们应该如何确定?确定方法如下所示:
∑ j = 1 n P j ( T k ) = 1 ⇒ ∑ j = 1 n C k ⋅ exp ⁡ ( − E j T k ) = 1 ⇒ C k ⋅ ∑ j = 1 n exp ⁡ ( − E j T k ) = 1 ⟹ C k = 1 ∑ j = 1 n exp ⁡ ( − E j T k ) \begin{aligned}&\sum_{j=1}^nP_j(T_k)=1\Rightarrow\sum_{j=1}^nC_k\cdot\exp\begin{pmatrix}-E_j\\T_k\end{pmatrix}=1\\&\Rightarrow C_k\cdot\sum_{j=1}^n\exp\begin{pmatrix}-E_j\\T_k\end{pmatrix}=1\Longrightarrow C_k=\frac1{\sum_{j=1}^n\exp\begin{pmatrix}-E_j\\T_k\end{pmatrix}}\end{aligned} j=1nPj(Tk)=1j=1nCkexp(EjTk)=1Ckj=1nexp(EjTk)=1Ck=j=1nexp(EjTk)1
\quad 通过求 C k C_{k} Ck, 获得Bolzman方程:
P i ( T k ) = exp ⁡ ( − E i T k ) ∑ j = 1 n exp ⁡ ( − E j T k ) P_i\left(T_k\right)=\frac{\exp\begin{pmatrix}-E_i\\T_k\end{pmatrix}}{\sum_{j=1}^n\exp\begin{pmatrix}-E_j\\T_k\end{pmatrix}} Pi(Tk)=j=1nexp(EjTk)exp(EiTk)

2.2.Metropolis准则

\quad 本质思想为以概率接受新状态:
\quad 若在温度 T k T_k Tk , 当前状态 i i i →新状态 j j j,若 E j E_j Ej< E i E_i Ei, 则接受 j j j为当前状态.
\quad 否则, 若概率 p = e x p [ − ( E j − E i ) / T k ] p=exp[-(Ej-Ei)/ Tk ] p=exp[(EjEi)/Tk]大于[0,1)区间的随机数, 则仍接受状态 j j j为当前状态; 若不成立则保留状态 i i i为当前状态.

2.3.算法要素

\quad ∙ \bullet 初始温度 T 0 T_{0} T0
\quad ①均匀抽样一组状态,以各状态目标值的方差为初温。
\quad ② 随机产生一组状态,确定两两状态间的最大目标值差,根据差值,利用一定的函数确定初温。
\quad ③ 利用经验公式。
实验表明:初温越大,获得高质量解的机率越大,但花费较多的计算时间!!
\quad ∙ \bullet 降温函数
\quad T k + 1 = T k ⋅ r T_{k+1}=T_{k}\cdot r Tk+1=Tkr \quad r ∈ ( 0.950.99 ) r\in(0.95 0.99) r(0.950.99)
\quad T k + 1 = T k − Δ T T_{k+1}=T_k-\Delta T Tk+1=TkΔT
\quad ∙ \bullet 热平衡条件
\quad Metropolis抽样稳定准则:
\quad ①设置内循环迭代次数
\quad ②检验目标函数的均值是否稳定
\quad ③连续若干步的目标值变化较小
\quad 停止准则:
\quad ①设置外循环迭代次数
\quad ②设置终止温度的阈值
\quad ③算法搜索到的最优值连续若干步保持不变

2.4.算法流程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.算法实现

3.1.算法MTALAB实现

%%%%%%%%%%%%%%%%%%%%%%模拟退火算法解决 TSP 问题%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%初始化%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear all; %清除所有变量
close all; %清图
clc; %清屏
tic
%成绩坐标点
C=[1304 2312;3639 1315;4177 2244;3712 1399;3488 1535;3326 1556;...
3238 1229;4196 1044;4312 790;4386 570;3007 1970;2562 1756;...
2788 1491;2381 1676;1332 695;3715 1678;3918 2179;4061 2370;...
3780 2212;3676 2578;4029 2838;4263 2931;3429 1908;3507 2376;...
3394 2643;3439 3201;2935 3240;3140 3550;2545 2357;2778 2826;...
2370 2975]; %31 个省会城市坐标
n=size(C,1); %TSP 问题的规模,即城市数目
T=100*n; %初始温度
L=100; %马可夫链长度
K=0.8; %衰减参数
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%城市坐标结构体%%%%%%%%%%%%%%%%%%%%%%%%%%
city=struct([]);
for i=1:n
    city(i).x=C(i,1);
    city(i).y=C(i,2);
end
l=1; %统计迭代次数
len(l)=func3(city,n); %每次迭代后的路线长度
figure(1);
while T>0.001 %停止迭代温度
%%%%%%%%%%%%%%%%多次迭代扰动,温度降低之前多次实验%%%%%%%%%%%%%%%
    for i=1:L
        %%%%%%%%%%%%%%%%%%%计算原路线总距离%%%%%%%%%%%%%%%%%%%%%%%%%
        len1=func3(city,n);
        %%%%%%%%%%%%%%%%%%%%%%%%%产生随机扰动%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%随机置换两个不同的城市的坐标%%%%%%%%%%%%%%%%%
        p1=floor(1+n*rand());
        p2=floor(1+n*rand());
        while p1==p2
            p1=floor(1+n*rand());
            p2=floor(1+n*rand());
        end
        tmp_city=city;
        tmp=tmp_city(p1);
        tmp_city(p1)=tmp_city(p2);
        tmp_city(p2)=tmp;
        %%%%%%%%%%%%%%%%%%%%%%%%计算新路线总距离%%%%%%%%%%%%%%%%%%%%
        len2=func3(tmp_city,n);
        %%%%%%%%%%%%%%%%%%新老距离的差值,相当于能量%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%新路线好于旧路线,用新路线代替旧路线%%%%%%%%%%%%%%
        delta_e=len2-len1;
        if delta_e<0
            city=tmp_city;
        else
        %%%%%%%%%%%%%%%%%%以概率选择是否接受新解%%%%%%%%%%%%%%%%%
        if exp(-delta_e/T)>rand()
            city=tmp_city;
        end
        end
    end
    l=l+1;
    %%%%%%%%%%%%%%%%%%%%%%%%%计算新路线距离%%%%%%%%%%%%%%%%%%%%%%%%%%
    len(l)=func3(city,n);
    %%%%%%%%%%%%%%%%%%%%%%%%%%%温度不断下降%%%%%%%%%%%%%%%%%%%%%%%%%%
    T=T*K;
    for i=1:n-1
        plot([city(i).x,city(i+1).x],[city(i).y,city(i+1).y],'bo-');
        hold on;
    end
    plot([city(n).x,city(1).x],[city(n).y,city(1).y],'ro-');
    
    title(['优化最短距离(K=0.8):',num2str(len(l))]);
    hold off;
    pause(0.005);
end
%print(gcf,'C:\Users\Zeng Zhong Yan\Desktop\SA_result','-dpng','-r600')

figure(2);
plot(len)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')
print(gcf,'C:\Users\Zeng Zhong Yan\Desktop\SA','-dpng','-r600')

在这里插入图片描述
在这里插入图片描述

3.2.算法PYTHON实现

import numpy as np
import matplotlib.pyplot as plt
import math
import random
import time

# Function to calculate the total distance of the tour
def calculate_total_distance(city, n):
    total_distance = 0
    for i in range(n - 1):
        total_distance += np.linalg.norm(np.array([city[i]['x'], city[i]['y']]) - np.array([city[i + 1]['x'], city[i + 1]['y']]))
    total_distance += np.linalg.norm(np.array([city[n - 1]['x'], city[n - 1]['y']]) - np.array([city[0]['x'], city[0]['y']]))
    return total_distance

# Initialize coordinates
C = np.array([
    [1304, 2312], [3639, 1315], [4177, 2244], [3712, 1399], [3488, 1535], [3326, 1556],
    [3238, 1229], [4196, 1044], [4312, 790], [4386, 570], [3007, 1970], [2562, 1756],
    [2788, 1491], [2381, 1676], [1332, 695], [3715, 1678], [3918, 2179], [4061, 2370],
    [3780, 2212], [3676, 2578], [4029, 2838], [4263, 2931], [3429, 1908], [3507, 2376],
    [3394, 2643], [3439, 3201], [2935, 3240], [3140, 3550], [2545, 2357], [2778, 2826],
    [2370, 2975]
])

n = len(C)  # Number of cities
T = 100 * n  # Initial temperature
L = 100  # Length of the Markov chain
K = 0.8  # Decay parameter

# City coordinates as a list of dictionaries
city = [{'x': C[i, 0], 'y': C[i, 1]} for i in range(n)]

# Initialize variables for iteration
iteration = 1
len_list = [calculate_total_distance(city, n)]

plt.figure(1)
start_time = time.time()

while T > 0.001:  # Stop iteration when temperature is low enough
    for _ in range(L):
        len1 = calculate_total_distance(city, n)
        p1, p2 = random.sample(range(n), 2)
        tmp_city = city.copy()
        tmp_city[p1], tmp_city[p2] = tmp_city[p2], tmp_city[p1]
        len2 = calculate_total_distance(tmp_city, n)
        delta_e = len2 - len1
        if delta_e < 0 or math.exp(-delta_e / T) > random.random():
            city = tmp_city

    iteration += 1
    len_list.append(calculate_total_distance(city, n))
    T *= K

    for i in range(n - 1):
        plt.plot([city[i]['x'], city[i + 1]['x']], [city[i]['y'], city[i + 1]['y']], 'bo-')
    plt.plot([city[n - 1]['x'], city[0]['x']], [city[n - 1]['y'], city[0]['y']], 'ro-')

    plt.title(f'Optimized Shortest Distance (K=0.8): {len_list[-1]}')
    plt.pause(0.005)
    plt.clf()

print(f"Execution Time: {time.time() - start_time:.2f} seconds")

# Save the final result plot
plt.figure(1)
for i in range(n - 1):
    plt.plot([city[i]['x'], city[i + 1]['x']], [city[i]['y'], city[i + 1]['y']], 'bo-')
plt.plot([city[n - 1]['x'], city[0]['x']], [city[n - 1]['y'], city[0]['y']], 'ro-')
plt.title(f'Optimized Shortest Distance (K=0.8): {len_list[-1]}')
plt.savefig('SA_result.png', dpi=600)

# Plot the evolution of the objective function value
plt.figure(2)
plt.plot(len_list)
plt.xlabel('Iteration')
plt.ylabel('Objective Function Value')
plt.title('Fitness Evolution Curve')
plt.savefig('SA.png', dpi=600)
plt.show()

在这里插入图片描述

在这里插入图片描述

4.参考文献

[1]https://blog.csdn.net/bingokunkun/article/details/118583729
[2]https://www.cnblogs.com/dion-90/articles/8469351.html
[3]https://chatgpt.com/
  • 28
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温柔济沧海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值