数学建模(三):模拟退火算法(SA)

news2024/12/26 20:50:53

文章目录

  • 模拟退火算法(SA)
    • 一、 概述
      • 1、 算法简介
      • 2、 核心思想
      • 3、 数学原理
      • 4、 模拟退火的流程
    • 二、 实例分析
      • 1、 初始化参数
      • 2、 Metrospolis 准则
      • 3、 生成新的值
      • 4、 获取最优值
      • 5、 主程序
      • 6、 总代码

模拟退火算法(SA)

一、 概述

1、 算法简介

模拟退火算法(simulated annealing,SA)来源于固体退火原理,是一种基于概率的算法。

模拟退火算法(SA)来源于固体退火原理,是一种基于概率的算法。将固体加温至充分高的温度,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,分子和原子越不稳定。而徐徐冷却时粒子渐趋有序,能量减少,原子越稳定。在冷却(降温)过程中,固体在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。

模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,即在局部最优解能概率性地跳出并最终趋于全局最优。模拟退火算法是通过赋予搜索过程一种时变且最终趋于零的概率突跳性,从而可有效避免陷入局部极小并最终趋于全局最优的串行结构的优化算法。

2、 核心思想

模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合一定的概率突跳特性在解空间中随机寻找目标函数的全局最优解,即在局部最优解能概率性地跳出并最终趋于全局最优。

这里的 “一定的概率” 的计算参考了金属冶炼的退火过程,这也是模拟退火算法名称的由来。将温度 T 当作控制参数,目标函数值 f 视为内能 E ,而固体在某温度 T 时的一个状态对应一个解 x i x_i xi,然后算法试图随着控制参数 T 的降低,使目标函数 f (内能 E )也逐渐降低,直至趋于全局最小值(退火中低温时的最低能量状态),就像金属退火过程一样。

关于爬山算法与模拟退火,有一个有趣的比喻:

  • 爬山算法:兔子朝着比现在高的地方跳去。它找到了不远处的最高山峰。但是这座山不一定是珠穆朗玛峰。这就是爬山算法,它不能保证局部最优值就是全局最优值。

  • 模拟退火:兔子喝醉了。它随机地跳了很长时间。这期间,它可能走向高处,也可能踏入平地。但是,它渐渐清醒了并朝最高方向跳去。这就是模拟退火。

3、 数学原理

从上面我们知道,会结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,那么具体的更新解的机制是什么呢?如果新解比当前解更优,则接受新解,否则基于Metropolis准则判断是否接受新解。接受概率为:

假设开始状态在A,随着迭代次数更新到B局部最优解,这时发现更新到B时,能量比A要低,则说明接近最优解了,因此百分百转移,状态到达B后,发现下一步能量上升了,如果是梯度下降则是不允许继续向前的,而这里会以一定的概率跳出这个坑,这个概率和当前的状态、能量等都有关系,如果B最终跳出来了到达C,又会继续以一定的概率跳出来,直到到达D后,就会稳定下来。

4、 模拟退火的流程

(1) 初始化:初始温度 T (充分大),初始解状态S(是算法迭代的起点),每个 T 值的迭代次数 L

(2) 对 k=1, …, L 做第(3)至第(6)步:

(3) 产生新解 S′

(4) 计算增量 ΔT = C(S′)-C(S),其中 C(S) 为目标函数, C(S) 相当于能量

(5) 若 ΔT<0 则接受 S′ 作为新的当前解,否则以概率 exp(-ΔT/T) 接受S′作为新的当前解.

(6) 如果满足终止条件则输出当前解作为最优解,结束程序。

(7) T 逐渐减少,且 T->0 ,然后转第2步。

其中有几个需要注意的点:

  • 初始点的选取对算法结果有一定的影响,最好是多次运行对结果进行综合判断。
  • 在算法运行初期,温度下降快,避免接受过多的差结果。当运行时间增加,温度下降减缓,以便于更快稳定结果。
  • 当迭代次数增加到一定次数时,结果可能已经达到稳定,但是距离算法结束还有一段时间。在设计程序时应该加入适当的输出条件,满足输出条件即可结束程序。

可以大概分为这四个步骤:

  1. 第一步是由一个产生函数从当前解产生一个位于解空间的新解;为便于后续的计算和接受,减少算法耗时,通常选择由当前新解经过简单地变换即可产生新解的方法,如对构成新解的全部或部分元素进行置换、互换等,注意到产生新解的变换方法决定了当前新解的邻域结构,因而对冷却进度表的选取有一定的影响。
  2. 第二步是计算与新解所对应的目标函数差。因为目标函数差仅由变换部分产生,所以目标函数差的计算最好按增量计算。事实表明,对大多数应用而言,这是计算目标函数差的最快方法。
  3. 第三步是判断新解是否被接受,判断的依据是一个接受准则,最常用的接受准则是 Metropolis 准则: 若 ΔT < 0 则接受 S′ 作为新的当前解 S,否则以概率 P 接受 S′ 作为新的当前解 S。
  4. 第四步是当新解被确定接受时,用新解代替当前解,这只需将当前解中对应于产生新解时的变换部分予以实现,同时修正目标函数值即可。此时,当前解实现了一次迭代。可在此基础上开始下一轮试验。而当新解被判定为舍弃时,则在原当前解的基础上继续下一轮试验。

二、 实例分析

1、 初始化参数

# -*- coding: utf-8 -*-
"""
Created on Mon Apr  3 19:17:28 2023

@author: steve
"""
from random import random
import math
import matplotlib.pyplot as plt


max_iter = 100  # 每一次温度降低的迭代次数
alpha = 0.99  # 降温系数
T_f = 0.01  # 温度的终值
T_n = 100  # 当前的温度,也是初始温度
x, y = [random() * 10 - 5 for i in range(max_iter)], [random() * 10 - 5 for i in range(max_iter)] # 进行数据的初始化
f = lambda x, y : (4 * x ** 2 - 2.1 * x ** 4 + x ** 6 / 3 + x * y - 4 * y ** 2 + 4 * y ** 4)  # 我们需要求的函数
result = {
    "f": [], 
    "t": []
    }  # 用来存放每一次下降的最优解

2、 Metrospolis 准则

def metrospolis(T_n, old, new):
    """
    进行 Metrospolis 准则的判断

    Parameters
    ----------
    T_n : int
        当前的温度.  
    old : double
        函数扰动之前的值.
    new : double
        函数扰动之后的值.

    Returns
    -------
    int
        是否需要重新寻找值.
    """
    if old >= new:
        return 1
    else:
        p = math.exp((old - new) / T_n)
        if random() < p:
            return 1
        else:
            return 0

3、 生成新的值

def generate_new(T_n, x, y):
    """
    其为扰动的过程

    Parameters
    ----------
    T_n : int
        当前的温度.
    x : double
        DESCRIPTION.
    y : double
        DESCRIPTION.

    Returns
    -------
    list
        返回生成的新值.
    """
    while True:
        x_new = x + T_n * (random() - random())
        y_new = y + T_n * (random() - random())
        if (-5 <= x_new <= 5) & (-5 <= y_new <= 5):  
            break                                  #重复得到新解,直到产生的新解满足约束条件
    return x_new, y_new 

4、 获取最优值

def best(max_iter, f, x, y):
    """
    计算这个温度下的最优值

    Parameters
    ----------
    max_iter : int
        最大的迭代次数.
    f : function
        我们需要求的函数.
    x : double
        DESCRIPTION.
    y : double
        DESCRIPTION.

    Returns
    -------
    list
        返回最优值,以及它的索引.

    """
    min_val, min_inx = f(x[0], y[0]), 0
    for i in range(max_iter):
        val = f(x[i], y[i])
        if min_val > val:
            min_val, min_inx = val, i
            
    return [min_val, min_inx]

5、 主程序

def plot(result):
    plt.plot(result['t'], result['f'])
    plt.title('SA')
    plt.xlabel('t')
    plt.ylabel('f')
    plt.gca().invert_xaxis()
    plt.show()


def main(max_iter, alpha, T_f, T_n, x, y, f, result):
    count = 0  # 统计迭代了多少次
    while T_n > T_f:  # 外层循环,当前温度小于最低温度时,终止循环
        for i in range(max_iter):  # 内层循环
            x_new, y_new = generate_new(T_n, x[i], y[i])  # 产生新值
            if metrospolis(T_n, f(x[i], y[i]), f(x_new, y_new)):  # 将原值与新产生的值进行比较
                x[i] = x_new  # 如果接收新值,则存入数组中
                y[i] = y_new
        # 迭代 max_iter 后,记录该温度下的最优解
        [ft, _] = best(max_iter, f, x, y)
        result["f"].append(ft)
        result["t"].append(T_n)
        T_n = T_n * alpha  # 进行降温操作
        count += 1
        
    # 得到最优解
    [f_best, inx] = best(max_iter, f, x, y)
    print(f"F={f_best}, x_1={x[inx]}, x_2={y[inx]}")
    # 进行图像表示
    plot(result)

6、 总代码

# -*- coding: utf-8 -*-
"""
Created on Mon Apr  3 19:17:28 2023

@author: steve
"""
from random import random
import math
import matplotlib.pyplot as plt


def metrospolis(T_n, old, new):
    """
    进行 Metrospolis 准则的判断

    Parameters
    ----------
    T_n : int
        当前的温度.  
    old : double
        函数扰动之前的值.
    new : double
        函数扰动之后的值.

    Returns
    -------
    int
        是否需要重新寻找值.
    """
    if old >= new:
        return 1
    else:
        p = math.exp((old - new) / T_n)
        if random() < p:
            return 1
        else:
            return 0
        
        
def generate_new(T_n, x, y):
    """
    其为扰动的过程

    Parameters
    ----------
    T_n : int
        当前的温度.
    x : double
        DESCRIPTION.
    y : double
        DESCRIPTION.

    Returns
    -------
    list
        返回生成的新值.
    """
    while True:
        x_new = x + T_n * (random() - random())
        y_new = y + T_n * (random() - random())
        if (-5 <= x_new <= 5) & (-5 <= y_new <= 5):  
            break                                  #重复得到新解,直到产生的新解满足约束条件
    return x_new, y_new 
    
def best(max_iter, f, x, y):
    """
    计算这个温度下的最优值

    Parameters
    ----------
    max_iter : int
        最大的迭代次数.
    f : function
        我们需要求的函数.
    x : double
        DESCRIPTION.
    y : double
        DESCRIPTION.

    Returns
    -------
    list
        返回最优值,以及它的索引.

    """
    min_val, min_inx = f(x[0], y[0]), 0
    for i in range(max_iter):
        val = f(x[i], y[i])
        if min_val > val:
            min_val, min_inx = val, i
            
    return [min_val, min_inx]


def plot(result):
    plt.plot(result['t'], result['f'])
    plt.title('SA')
    plt.xlabel('t')
    plt.ylabel('f')
    plt.gca().invert_xaxis()
    plt.show()



def main(max_iter, alpha, T_f, T_n, x, y, f, result):
    count = 0  # 统计迭代了多少次
    while T_n > T_f:  # 外层循环,当前温度小于最低温度时,终止循环
        for i in range(max_iter):  # 内层循环
            x_new, y_new = generate_new(T_n, x[i], y[i])  # 产生新值
            if metrospolis(T_n, f(x[i], y[i]), f(x_new, y_new)):  # 将原值与新产生的值进行比较
                x[i] = x_new  # 如果接收新值,则存入数组中
                y[i] = y_new
        # 迭代 max_iter 后,记录该温度下的最优解
        [ft, _] = best(max_iter, f, x, y)
        result["f"].append(ft)
        result["t"].append(T_n)
        T_n = T_n * alpha  # 进行降温操作
        count += 1
        
    # 得到最优解
    [f_best, inx] = best(max_iter, f, x, y)
    print(f"F={f_best}, x_1={x[inx]}, x_2={y[inx]}")
    # 进行图像表示
    plot(result)
    


max_iter = 100  # 每一次温度降低的迭代次数
alpha = 0.99  # 降温系数
T_f = 0.01  # 温度的终值
T_n = 100  # 当前的温度,也是初始温度
x, y = [random() * 10 - 5 for i in range(max_iter)], [random() * 10 - 5 for i in range(max_iter)] # 进行数据的初始化
f = lambda x, y : (4 * x ** 2 - 2.1 * x ** 4 + x ** 6 / 3 + x * y - 4 * y ** 2 + 4 * y ** 4)  # 我们需要求的函数
result = {
    "f": [], 
    "t": []
    }  # 用来存放每一次下降的最优解

main(max_iter, alpha, T_f, T_n, x, y, f, result)

最后的运行结果为:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/422222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

折叠屏市场起风,华为、OPPO“你追我赶”

配图来自Canva可画 现如今&#xff0c;智能手机已经成为了人们生活中不可或缺的重要工具&#xff0c;无论是出行&#xff0c;还是社交&#xff0c;亦或是支付&#xff0c;只需要一部智能手机就可以通通搞定。因此&#xff0c;在消费者多样化需求的助推下&#xff0c;智能手机行…

【Spring】—Spring中Bean的配置、作用域

一、Bean的配置 Spring用于生产和管理Spring容器中的Bean&#xff0c;需要开发者对Spring的配置文件进行配置。在实际开发中&#xff0c;最常采用XML格式的配置方式&#xff0c;即通过XML文件来注册并管理Bean之间的依赖关系。 在Spring中&#xff0c;XML配置文件的根元素是…

易基因:全基因组CpG密度和DNA甲基化分析方法比较(MeDIP、RRBS和WGBS)| 研究综述

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 CpG密度&#xff08;CpG density&#xff09;与各种组织中的DNA甲基化相关。基因组按CpG密度分为&#xff1a;CpG岛&#xff08;CpG island&#xff0c;CGI&#xff09;、CpG岛上下游2kb…

FFMPEG VCL Pack Crack显示位置支持或光标

FFMPEG VCL Pack Crack显示位置支持或光标 FFMPEG VCL Pack是一个组合解决方案和平台&#xff0c;用于在Delphi中录制、转换和传播音频和视频&#xff0c;其中包括音频/视频库中的前一个libavcodec。 FFMPEG VCL Pack功能和选项&#xff1a; 新的Live555公司基于Rtsp Media Ser…

基于深度学习的安全帽检测系统(YOLOv5清新界面版,Python代码)

摘要&#xff1a;安全帽检测系统用于自动化监测安全帽佩戴情况&#xff0c;在需要佩戴安全帽的场合自动安全提醒&#xff0c;实现图片、视频和摄像头等多种形式监测。在介绍算法原理的同时&#xff0c;给出Python的实现代码、训练数据集&#xff0c;以及PyQt的UI界面。安全帽检…

设计模式之迭代器模式(C++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、迭代器模式是什么&#xff1f; 迭代器模式是一种行为型的软件设计模式&#xff0c;提供一种方法能顺序访问聚合对象中的各个元…

如何做好缓存设计?

大家好&#xff0c;我是易安&#xff01;今天我们来谈一谈缓存应该如何设计。 什么是缓存 缓存是一种临时储存数据的方式。当用户查询数据时&#xff0c;系统会首先在缓存中查找&#xff0c;如果数据已经存在于缓存中&#xff0c;则直接使用&#xff0c;否则系统会到数据的原始…

研报精选230410

目录 【行业230410西南证券】医药行业2023年4月投资月报&#xff1a;看好创新药和中药行情【行业230410国信证券】汽车行业4月投资策略&#xff1a;3月新能源乘用车批发销量预计同比增长32%&#xff0c;持续关注板块年报季报行情【行业230410西南证券】医药行业周报&#xff1a…

【集成架构】探索3种顶级「集成框架」Apache、Spring和Mule

正确的集成框架是绑定应用程序架构构建块的粘合剂。应用程序组件必须不断交换关键数据&#xff0c;以方便用户操作、服务扩展、威胁监视、后端操作、事件触发等。如果没有可靠的集成过程&#xff0c;应用程序和服务故障将淹没软件环境。正确的集成框架是绑定应用程序架构构建块…

【JAVA】#详细介绍!!! synchronized 加锁 详解(1)!

本文分以下几点来介绍synchronized&#xff08;根据JDK1.8&#xff09; 1. 介绍synchronized 2. synchronized 为什么能保证线程安全 3. synchronized 的 用法 4. synchronized 的锁特性 目录 1. 介绍synchronized 2. synchronized的用法 2.1 synchronized修饰指定代码块 2…

如何定位Spark数据倾斜问题,解决方案

文章目录前言一、数据倾斜和数据过量二、 数据倾斜的表现三、定位数据倾斜问题定位思路&#xff1a;查看任务-》查看Stage-》查看代码四、7种典型的数据倾斜场景解决方案一&#xff1a;聚合元数据解决方案二&#xff1a;过滤导致倾斜的key解决方案三&#xff1a;提高shuffle操作…

谁才是天下第一关?

什么是关&#xff0c;中华大地有多少关&#xff1f; 关是往来必由之要处。“山川扼要&#xff0c;是设关津。表封藏&#xff0c;以达道路&#xff0c;天险既呈&#xff0c;人力并济”。 关可分为&#xff1a; 关防&#xff0c;驻兵防守的要塞&#xff1b;关津&#xff0c;水陆…

python笔记:qgrid

在Jupyter Notebook中像在Excel一样操作pandas的DataFrames&#xff0c;如sort/filter&#xff0c;并轻松把操作后的数据用于后续分析。 0 安装 pip install qgrid jupyter nbextension enable --py --sys-prefix qgrid 1 基本使用方法 1.1 数据 import numpy as np import…

Carla 保姆级安装教程

一&#xff1a;电脑配置 carla支持windows,Linux系统构建&#xff0c;官方对于安装电脑的最低配置要求是拥有6G显存的GPU&#xff0c;推荐8G显存的GPU&#xff0c;至少需要20G的存储空间&#xff0c;所有对电脑的配置要求是不小的挑战。 我所使用电脑的硬件配置&#xff1a;3…

3.7 曲率

学习目标&#xff1a; 如果我要学习高等数学中的曲率&#xff0c;我会遵循以下步骤&#xff1a; 1.熟悉相关的数学概念&#xff1a;在学习曲率之前&#xff0c;我们需要了解曲线、切线和曲率半径等相关的数学概念。因此&#xff0c;我会复习这些概念&#xff0c;以便更好地理…

网卡别名的设置

文章目录1. 网卡别名是什么2. 工作原理3. 设置3.1 临时添加&#xff0c;重启失效3.1.1 使用ipconfig命令来设置网卡别名3.1.2 使用ip addr命令来设置网卡别名3.2 永久性添加3.3 查看参考1. 网卡别名是什么 IP别名就是一张物理网卡上配置多个IP&#xff0c;实现类似子接口之类的…

制作PassMarkMemTest86启动U盘

制作PassMarkMemTest86启动U盘1. 概述2.制作 PassMarkMemTest86 启动U盘结束语1. 概述 PassMarkMenTest86 是一款免费、开源且强大的内存检测工具&#xff0c;能测试电脑内存的稳定性、存储大小和隐性问题&#xff0c;它还拥有 13 种不同的 RAM 测试算法&#xff0c;在主菜单中…

洛丽运动会 NFT 作品集第一弹

欢迎来到 2036 年洛丽运动会&#xff0c;这是一个以史前世界为背景的体育小游戏体验。为了庆祝这场伟大比赛的开始&#xff0c;结合了史前和运动配件的 NFT 系列将于北 The Sandbox 市场平台发布。 运动和格斗设备将提高你在运动会上的技能&#xff1b;而史前配件将使你与体育场…

Linux高并发服务器(webserver)

一.有限状态机 它的转移函数表示系统从一个状态转移到另一个状态的条件 二.EPOLL 在内核中创建一个数据&#xff0c;这个数据有两个比较重要的数据&#xff0c;一个是需要检测的文件描述符的信息&#xff08;红黑树&#xff09;&#xff0c;一个双向链表&#xff0c;存放检测到…

Java类加载机制介绍

类加载机制的简单介绍 类加载机制是指将.class字节码文件读入到内存中。在运行时数据区中的方法区保留类的数据结构&#xff0c;在堆中创建一个与之对应的Class对象。 类的生命周期主要经历7个阶段&#xff1a;加载、验证、准备、解析、初始化、使用、卸载 其中从加载到初始化…