模拟退火算法_模拟退火算法学习笔记

本文详细介绍了模拟退火算法的基本原理,包括算法简介、实现过程和重点讲解,并给出了MATLAB编程的实现思路及代码示例,旨在解决寻找最优化问题的解决方案。
摘要由CSDN通过智能技术生成

参考文章:https://zhuanlan.zhihu.com/p/33184423

参考文件:《Matlab数学建模算法全收录》

2019.8.12更新:由于本人输入地过于仓促,文中出现了严重的错误,在此对之前的读者表示歉意。

2020.1.21更新

一,算法简介

1.1 内容简介

对于某个问题而言,没有很好的办法可以直接求得它的最优解,又或是直接求解太复杂。此时,我们尝试随机带入一些值,想要试一下,撞一下大运,看看能不能撞出比较好的解出来。

1.2 算法实现的过程

第一步,我们将根据可控变量的取值范围,来随机选取初始值,这是初次试值

第二步,接下来的试值中,我们会给每一个变量,产生一个微小的变化量delta=

(delta具体是多少,可以由用户决定。
代表变化后的可控变量,
代表变化前的可控变量),当然变化后的每一个变量要求在取值范围以内。注意,这个微小变化量是随机取值的,但是要保证它的取值范围关于原点对称。

注意,可控变量可能不是一维的,可能是二维或者更高维度。此时

为一个存储多个可控变量的向量。

第三步,我们自定义了的函数关系,这个函数是针对当前问题的,是变量到结果的映射。这个函数的输入端是向量

,输出端是映射后的结果
。假设
映射后的结果是
映射后的结果是

对于

我们提出如下要求:

1)如果新的结果更接近我们想要的结果(一般我们想要找到的是最值),我们就直接接受当前得到的

2)如果新的结果

远离或者等于原来的结果,我们以一定概率 P 的去接受当前状态下的变量。假设 函数值的变化量
,温度为 T (这是用户自己设置的一个量,用于调控算法在起始及过程当中的概率大小)。则 P 满足如下关系:

并且,我们要求,如果你是以概率的方式接受了当前状态下的结果,那么在每次接受以后,温度将会下降,即

=
*
。注意,T 的初始值是人为设定的,
也是人为设定的。

3)当 P 过于小的时候,或长时间找不到更优的解,那么结束算法。

1.3 重点讲解

1)不难发现,对于 P 而言,由于指数的分子恒为正,当指数分母趋于无穷大的时候,概率趋于1。这意味我们选择远离或者等于原来的结果的可能性会比较高。刚开始的时候,我们需要接触更多的区域,来试探解的结果,所以温度会设定的很高。随着算法的进行,温度逐渐降下来后,P 会逐渐变小。最后,我们能够得到一个尽可能接近最优解的解。

2)如何实现求解最大值呢?首先,使得

,那么由于我们要求
,所以当
,此时的
是我们不想要的解,也就是我们想要更大的解。其次,写下一个判断函数 judge(dE,t),传入
和 t ,其中,dE =
。当dE < 0 时,返回值1,代表接受结果;当dE ≥ 0 时,进行概率选择,依照概率返回值 1 或 0 。

该算法计算的就是最大值。如果我们使得

,就可以通过输入的extreme值来修改计算的最值了,当 extreme=1 时,计算最大值;当 extreme=-1 时,计算最小值。(注意,下面编程当中的
,所以和这里刚好相反。)

二,算法的matlab编程

首先考虑一下算法的整体结构:输入端,循环处理的过程,输出端

输入端:

包括温度 T 、温度最小值 Tm 、温度下降系数 alpha 、变量矩阵 X 及其取值范围、自定义的函数 val()

变量矩阵 X 用于存储已知条件,它是一个 m*n 的矩阵,其中 m 代表已知点的个数,而 n 代表每个点的维度。

循环处理过程:

包括这几个部分,初始图像的绘制、初始值的求解、随机扰动的求解、是否采纳解的判断、绘图。

输出端:

主要需要最终的温度T,和最后得到的状态下的变量及其函数值


matlab编程

(原代码来源于https://zhuanlan.zhihu.com/p/33184423中的第二例,但是我将算法改进了一下,目的是使其更具有普遍性)

使用模拟退火算法求解到点集直线距离之和最短的点

5dde24b1c66878ebcf13ccc341c3953b.png
%{
名称:模拟退火算法
用途:用于求某个函数的最值
输入:温度、温度最小值、温度下降系数、变量矩阵及其取值范围、自定义的函数val
输出:函数图像,以及最终得到的值y
注意:
%}
clc, clear
%用户输入参数
disp('请修改关于变量矩阵的自定义函数,初始及初始图像函数,还有循环过程中的绘图部分');
T_input=input('请以向量的形式依次输入tmp,tmp_min,alpha:');
tmp=T_input(1);tmp_min=T_input(2);alpha=T_input(3);
varied_data=input('请输入变量矩阵,每一列代表不同维度,每一行代表不同元素:');
extreme=input('需要计算最大值请输入-1,计算最小值请输入1:')
%实验参数,可以将上面内容注释掉,把这里取消注释进行实验
%tmp = 1000;
%tmp_min = 0.001;
%alpha = 0.98;
%extreme=-1;
%varied_data=[0 0;1.5 10;1.5 12; -2 11; -4 -8;-5  2;2 -1.5;4 -2.5;5 1;-2 -2;-3 8;3 6;-1.5 0;-2.5 0;0.1 0.2];

draw_dist(varied_data);
[varied_data_new,tmp,counter]=tuihuo(tmp,tmp_min,alpha,varied_data,extreme);

%%
%此为自定义函数,不同题目需要有不同的自定义函数,用户需要自行修改
function [result] = val(varied_data,varied_single_data)
x=varied_data(:,1);
y=varied_data(:,2);
xx=varied_single_data(1);
yy=varied_single_data(2);
result = 0;
num_of_dots = length(x);
for i = 1:num_of_dots
    result = result + sqrt((xx - x(i))^2 + (yy - y(i))^2);
end
end

%%
%此为绘制初始图像的函数,针对不同的情况,用户需要自行更改
function []=draw_dist(varied_data)
x=varied_data(:,1);
y=varied_data(:,2);

x_min = floor(min(x));
y_min = floor(min(y));
x_max = ceil(max(x));
y_max = ceil(max(y));


resol = 10;
dx = x_min: 1/resol : x_max;
dy = y_min: 1/resol : y_max;

[xx, yy] = meshgrid(dx, dy);
zz = zeros(length(dy), length(dx));

for ii = 1:length(dx)
    for jj = 1:length(dy)
        zz(jj, ii) = val(varied_data,[dx(ii), dy(jj)]);
    end
end

contour(xx, yy, zz);
hold on;
scatter(x, y, 'MarkerFaceColor','blue');hold on;
end

%%
%退火的主体函数
function [varied_data_new,tmp,counter]=tuihuo(tmp,tmp_min,alpha,varied_data,extreme)
%判断变量维度及个数
[m,n]=size(varied_data);

%自动生成初始值并判断
for i=1:1:n
    varied_data_max(i)=max(varied_data(:,i));
    varied_data_min(i)=min(varied_data(:,i));
    varied_data_old(i) = (varied_data_max(i)-varied_data_min(i))*rand()+min(varied_data(:,i));%生成初始值
end

s_old = val(varied_data,varied_data_old);
s_new = s_old;

text_lt = text(0, 0, 'Init');

%计数器
counter = 0;

%退火的主体部分,一个循环
while(tmp > tmp_min)
    %随机扰动,需要保证扰动后的变量处于定义域内
    varied_new_mark=1;
    while(sum(varied_new_mark))
        for i=1:1:n
            delta(i) = rand() - 0.5;%此处可以自行更改大小
            varied_data_new(i)=varied_data_old(i) + delta(i);
            if(varied_data_new(i)<varied_data_min(i) || varied_data_new(i)>varied_data_max(i))
                varied_new_mark(i) = 1;%变量不能超出上下限
                break
            else
                varied_new_mark(i) = 0;
            end
        end
    end
    
    s_new = val(varied_data,varied_data_new);
    
    %求差值,extreme=1时,求最小值;=-1时,求最大值
    dE = (s_new - s_old)*extreme;
    
    %判断
    j = judge(dE, tmp);
    if(j)
        s_old = s_new;
        varied_data_old = varied_data_new;
    end
    
    %只有当dE < 0的情况下才降温
    if(dE < 0)
        %这里时循环过程中的绘图部分,请依照具体情况修改
        delete(text_lt);
        text_lt = text(-4, 6, {['Dist: ',num2str(s_old)];['Tmp: ', num2str(tmp)]});
        scatter(varied_data_old(1), varied_data_old(2), '.');%这里可以修改字符出现的位置
        pause(0.001);
        tmp = tmp * alpha;
    else
        counter = counter + 1;
    end
    
    %当接受更差的解的概率太小时,若又长时间找不到更优的解,那么退出循环,结束算法
    if(counter > 10000)%这里可以修改计数器的最大值
        break;
    end
end
end

%%
%{
名称:judge
用途:用于在随机扰动以后,判断是否选择这组数据
输入:扰动前后的变化量dE,退火温度t
输出:状态y,若y=1,为选择;y=0,为不选择
注意:
%}
function [y] = judge(dE, t)
  if(dE < 0)
    y = 1;
  else
    d = exp(-(dE / t));
    if(d > rand)
      y = 1;
    else
      y = 0;
    end
  end
end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值