其他文章:

通过0-1背包问题看穷举法、贪心算法、启发式算法(JAVA)

模拟退火(SA)算法实例介绍(JAVA)

遗传算法(GA)实例介绍(JAVA)

java集成Cplex:Cplex下载、IDEA环境搭建、docker部署

CPLEX求解器入门案例

cplex的下载、安装、IDE编程及相关问题解决


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

模拟退火算法(Simulated Annealing,SA)最早的思想是由N. Metropolis 等人于1953年提出。1983 年,S. Kirkpatrick 等成功地将退火思想引入到组合优化领域。它是基于Monte-Carlo迭代求解策略的一种随机寻优算法,其出发点是基于物理中固体物质的退火过程与一般组合优化问题之间的相似性。模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,即在局部最优解能概率性地跳出并最终趋于全局最优。模拟退火算法是一种通用的优化算法,理论上算法具有概率的全局优化性能,目前已在工程中得到了广泛应用,诸如VLSI、生产调度、控制工程、机器学习、神经网络、信号处理等领域。

模拟退火算法有如下特点:

  • 不仅能处理连续优化问题,还能很方便的处理组合优化问题,并且编程容易实现,目标函数的收敛速度较快。
  • 参数的选择至关重要,初始参数的合理选择是保证算法的全局收敛和效率的关键,选择不当得到的结果可能会很差。
  • 面对不用的问题,可以设计不同的退火过程,不同过程得到到准确度和效率可能差别较大,因此需要一定的经验。

一、注意点

1.1. 算法框架

    public static void main(String[] args) {// 定义初始温度、温度衰减系数double initT=1000;double decreaseRate = 0.95;// 生成初始解initX, 及该解对应的函数值initY(评价函数可以直接使用目标函数)initX = generateInitSolve();initY = targetFun(initX);// 初始解作为当前最优解bestX = initX;bestY = initY;for(i=0; i<1000; i++){ // 外层for循环 每次循环温度降低// 计算当前的迭代温度currT = initT * decreaseRate^i;for(j=0; j<200; j++){ // 在当前温度下循环多次// 在当前最优解附近产生一个新解,并计算新解的函数值tmpX = getNewX(bestX, currT);tmpY = targetFun(tmpX);// 评价新解和当前最优解,决定取舍if(tmpY>bestY){ // 新解更优,则接受新解为当前最优解bestY = tmpY;bestX = tmpX;}else {         // 新解更差,则以一定的概率接受新解为当前最优解// 根据当前温度和两个解的差值生成接受概率p = Math.exp(-(bestY - tmpY)/currentTemp);// 生成一个均匀分布的概率randomP = random(0.0, 1.0);// 比较两个概率,决定是否接受if(p > randomP){bestY = tmpY;bestX = tmpX;}}}}// 当前最优解就是全局最优解System.out.println("最优解:"+bestX, "最优解对应的函数值:"+bestX);}

1.2. 温度

退火是一种金属热处理工艺,先把金属加热到一个很高的温度,然后以适宜的速度冷却,冷却后金属就可以获得一些之前没有的特性。在算法中也是模拟了这个过程。算法开始时,给一个很高的初始温度initT,每次外层循环使温度以一个固定的衰减速率decreaseRate降低(通常在0.5-0.99之间);但是在每个温度下(currT = initT * decreaseRate^i),内层循环在同一个温度下多次寻找当前最优解附近的新解,并决定接受更好的新解,同时决定要不要接受一个更差的新解。

1.3. 初始解生成

在启发式算法中,初始解的生成也是关键的一步,特别是对应爬山算法,如果初始解选择有问题就容易陷入局部最优的情况。因为模拟退火算法会以一定的概率接受更差的解,可以很大程度上避免陷入局部最优的情况,通常初始解的生成只要满足约束条件即可。

1.4.新解的生成

怎样在当前解的附近生成一个新解,也是模拟退火算法的关键一步。对应新解的生成,在学术上没有统一的规定,具体问题具体分析。

比如:

1.给定函数求最大值最小值问题

目标函数:minf(X)=−x2+3x+6;约束条件:x>=−30并且x<=30目标函数:min f(X) = -x^2 + 3x + 6 ; 约束条件:x>= -30 并且x<=30 目标函数:minf(X)=−x2+3x+6;约束条件:x>=−30并且x<=30

当前解是x1,当前温度是t1,解的下限xMin=-30,解的上限xMax=30,r1是在区间[0,1]之间的服从N(0,1)分布的随机数,r2是在区间[0,1]之间的均匀分布的随机数。新解生成的方法可以简单写成:

    public double getNewX(x1,t1,xMin,xMax,r1,r2){newX = x1 + t1 * r1;if(newX < xMin){newX = r2 * xMin + (1 -r2) * x1;}if(newX > xMax){newX = r2 * xMax + (1 -r2) * x1;}return newX;}

这种方式参考Matlab的内置函数。

2.TSP问题

给定一组城市以及每个城市之间的距离,从一个城市出发,每个城市经过一次,回到出发的城市,走过的最小路径问题。产生新解的三种方法:

参考:《旅行商问题(TSP)的改进模拟退火算法》苗卉,杨韬 ,2007。

3.书店买书问题

有15个书店,每个书店都有各种书籍,每个书店的运费是不一样的。现在需要买20本书,如何买花费最少。

产生新解的方法(参考):

4.背包问题

参考《一种改进的模拟退火算法求解0-1背包问题》 梁国宏,张生,黄辉,何尚录 2007

1.5. 更差解的接受概率

模拟退火算法中,当遇到更差的解时,还是有一定的概率接受这个更差的解,而不是100%拒绝更差的解,从而克服了陷入局部最优的缺陷。

模拟退火算法的关键点就是如何定义接受一个更差解的概率。这个概率有几个比较重要点,1.这个概率函数的值在[0-1]之间;2.当前解的目标函数值f(A)与新解的目标函数值f(B)的差越大,说明新解和当前解差的越多,那么接受新解的概率就越小,反之越大;2.当前温度和概率的关系是,温度越高(搜索的前期),接受更差解的可能越大,这样可以在更大的范围搜索;温度越低(搜索的后期),接受更差解的可能性越小,这样就在小范围搜索。

根据上面的描述,这个概率函数p应该相关的几个部分参数 , 1.两个解的目标函数值之差 f =|f(B)-f(A)|, p与f成反比; 2. 当前温度Tc和时间t(迭代次数)成反比,通常每次迭代温度变成之前的95%,初始温度为Ti时,则 Tc = Ti * 0.95^t; 3.概率p和当前温度的关系是当前温度越高,概率越大。

根据上面的特点,这个概率函数可以构建成:
p=e−∣f(A)−f(B)∣/Tcp=e^{-|f(A)-f(B)|/Tc} p=e−∣f(A)−f(B)∣/Tc

1.6.退出搜索的条件

退出搜索的条件可以是:1.达到指定的搜索次数,比如1000次;2.达到指定的温度,比如0.000001;3.找到的连续最优解M在多次(比如50次)迭代后都没有发生变化。

二、数学模型

求解函数y = 11*sin(x) + 7*cos(5*x)在[-3,3]内的最大值

三、代码实现

3.1.定义参数

package com.wuxiaolong.algorithm.simulatedAnnealing;public class Constants {// 初始温度public static final Double INIT_TEMPERATURE = 100.0;// 最大迭代次数public static final Integer ITERATION_TIMES = 2000;// 每个温度下的迭代次数public static final Integer CURRENT_TEMP_ITERATION_TIMES = 50;// 温度衰减系数public static final Double TEMP_DECREASE_RATE = 0.95;// x的上、下界public static final Double MIN_X = -3.0;public static final Double MAX_X = 3.0;}

3.2.定义工具类

package com.wuxiaolong.algorithm.simulatedAnnealing;import java.util.Random;public class Util {/*** 获取随机值          min   <=    返回值x    <=   max* @return*/public static Double random(Double min,Double max) {Random rand = new Random();double result=0;for(int i=0; i<10; i++){result = min + (rand.nextDouble() * (max - min));result = (double) Math.round(result * 100) / 100;// System.out.println(result);}return result;}/***  随机数 服从N(0,1)**  若随机变量X服从一个数学期望为μ、方差为σ^2的正态分布,记为X~N(μ,σ^2)。** 其概率密度函数为正态分布的期望值μ决定了其位置,其标准差σ决定了分布的幅度。当μ = 0,σ = 1时的正态分布是标准正态分布。*/public static Double random(){Random r = new Random();return r.nextGaussian();}
}

3.3.定义主方法

package com.wuxiaolong.algorithm.simulatedAnnealing;import java.util.HashMap;
import java.util.Map;import static com.wuxiaolong.algorithm.simulatedAnnealing.Constants.*;/*** 模拟退火算法*  // SA 模拟退火: 求解函数y = 11*sin(x) + 7*cos(5*x)在[-3,3]内的最大值*/
public class SA {public static void main(String[] args) {// 迭代中温度会发生改变,第一次迭代时温度就是T0Double currentTemp = INIT_TEMPERATURE;// 随机生成一个初始解 并计算当前解的函数值Double initX = Util.random(-3.0,3.0);Double initY = targetFun(initX);System.out.println("初始解:"+initX +"  初始函数值:"+initY);// 全局最优解Double bestX = initX;Double bestY = initY;// 模拟退火过程// 外循环, 我这里采用的是指定最大迭代次数for(int iter=1; iter<=ITERATION_TIMES; iter++){//System.out.println("-----------------"+iter+"------------------------");// 本次迭代(当前温度)最优解Double currTempBestX = bestX;Double currTempBestY = bestY;// 循环,在每个温度下开始迭代for(int i=1; i<CURRENT_TEMP_ITERATION_TIMES; i++){//找一个当前解附近的x, 计算新解的函数值Double tmpX = getNewX(initX, currentTemp, MIN_X, MAX_X);Double tmpY = targetFun(tmpX);// 如果新解函数值大于当前解的函数值 更新当前解为新解if(tmpY > currTempBestY) {currTempBestX = tmpX;currTempBestY = tmpY;}else{//根据Metropolis准则计算一个概率Double p = Math.exp(-(currTempBestY - tmpY)/currentTemp);// 生成一个随机数和这个概率比较,如果该随机数小于这个概率Double random = Util.random(0.0, 1.0);if(random < p) {// 更新当前解为新解currTempBestX = tmpX;currTempBestY = tmpY;}}}// 判断是否要更新找到的最佳的解 如果当前解更好,则对其进行更新if(currTempBestY > bestY ) {bestY = currTempBestY;  // 更新最大的ybestX = currTempBestX;  // 更新找到的最好的x}System.out.println("iter:" + iter +"  新解:"+bestX +"  新函数值:"+bestY +"  当前温度"+currentTemp);// 温度下降currentTemp = TEMP_DECREASE_RATE * currentTemp;}System.out.println("最终:"+bestX+"------------"+bestY);}public static Double targetFun(Double x){return 11 * Math.sin(x) + 7*Math.cos(5*x);}public static Double getNewX(Double x0,Double T,Double x_lb,Double x_ub){Double y =Util.random(); // 为变量生成N(0,1)随机数Double x_new = x0 + y*T; // 根据新解的产生规则计算x_new的值// 如果这个新解的位置超出了定义域,就对其进行调整if (x_new < x_lb){Double r = Util.random(0.0,1.0);x_new = r*x_lb + (1-r)*x0;}else if(x_new > x_ub){Double r = Util.random(0.0,1.0);x_new = r*x_ub+(1-r)*x0;}//  System.out.println("x0:"+ x0 + "---------------x_new:"+x_new);return x_new;}
}

四、结果

由于目前每次运行的结果还不一样,可能陷入了局部最优,还需要优化。

五、后记

  • 在以上的讨论中都没有涉及到一个核心问题:模拟退火算法一定能找到最优解吗?可以利用随机过程中的马尔科夫过程证明,在一定条件下,当温度降为0时,最后的状态一定是全局最优解。这样就能够为模拟退火算法在求解最优化问题提供理论支持。参考《非数值并行算法(第一册)模拟退火算法》康立山等 1994。
  • 对参数的选择(如初始温度)以及退火流程的设置需要经验,参数设置的不恰当得到的解可能会很差。因此我们可以多次尝试不同的参数,观察求解时间和求解结果,以此来对参数进行修改。
  • 新解的生成至关重要,新解不能距离旧解“太远”,否则旧解的信息不能被新解反应;同时新解也不能距离旧解“太近”,否则容易陷入局部最优。在实际应用中,我们可以先去知网搜索没有有类似问题,看看别人是如何构造新解的,如果实在是没有相关研究,我们再自己去构建新解。
  • 如果优化问题中的约束非常多,那么这个时候构造新解就有很大的技巧性。如果构造的新解不在约束条件内,虽然我们可以重新构造新解,但是这样会增加计算量。
  • 模拟退火算法可以和其他的只能算法混合使用,比如粒子群、遗传等。

模拟退火(SA)算法实例介绍(JAVA)相关推荐

  1. 经典算法:模拟退火(SA)算法

    一.概念 模拟退火算法(SA) 来源于固体退火原理,是一种基于概率的算法. 模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,即在局部最优 ...

  2. java hanlp分词_Hanlp分词实例:Java实现TFIDF算法

    算法介绍 最近要做领域概念的提取,TFIDF作为一个很经典的算法可以作为其中的一步处理. 关于TFIDF算法的介绍可以参考这篇博客http://www.ruanyifeng.com/blog/2013 ...

  3. 模拟退火(SA, Simulated Annealing)算法解决旅行商TSP问题

    01 什么是旅行商问题(TSP)? TSP问题(Traveling Salesman Problem,旅行商问题),由威廉哈密顿爵士和英国数学家克克曼T.P.Kirkman于19世纪初提出.问题描述如 ...

  4. 爬山算法 ( Hill Climbing )/模拟退火(SA,Simulated Annealing)

    一. 爬山算法 ( Hill Climbing ) 爬山算法是一种简单的贪心搜索算法,该算法每次从当前解的临近解空间中选择一个最优解作为当前解,直到达到一个局部最优解.爬山算法实现很简单,其主要缺点是 ...

  5. Hanlp分词实例:Java实现TFIDF算法

    2019独角兽企业重金招聘Python工程师标准>>> 算法介绍 最近要做领域概念的提取,TFIDF作为一个很经典的算法可以作为其中的一步处理. 关于TFIDF算法的介绍可以参考这篇 ...

  6. 异或加密的java算法_Java使用异或运算实现简单的加密解密算法实例代码

    Java简单的加密解密算法,使用异或运算 实例1: package cn.std.util; import java.nio.charset.Charset; public class DeEnCod ...

  7. Java 程序连接 Informix 数据库方法实例介绍

    Java 程序连接 Informix 数据库方法实例介绍 Informix 是一种应用广泛的关系型数据库服务器,支持多种类型的客户端连接程序,包括 .Net.Java.PHP 等.对于 Java 程序 ...

  8. JAVA中几种循环结构的表示_本文通过实例讲解给大家介绍Java中for、while、do while三种循环语句的区别,具体详情如下所示:第一种:for循环 循环结构for语句的格式...

    本文通过实例讲解给大家介绍Java中for.while.do while三种循环语句的区别,具体详情如下所示: 第一种:for循环 循环结构for语句的格式: for(初始化表达式;条件表达式;循环后 ...

  9. 红黑树 原理和算法详细介绍(Java)

    R-B Tree简介 R-B Tree,全称是Red-Black Tree,又称为"红黑树",它一种特殊的二叉查找树.红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red) ...

  10. 模拟退火(Simulated Annealing, SA)算法简介与MATLAB实现

    目录 模拟退火算法概述 算法步骤 算法特点 模拟退火算法MATLAB实现 [例1]一元/多元函数优化 [例2]TSP问题 模拟退火算法概述 模拟退火算法(Simulated Annealing,简称S ...

最新文章

  1. 超融合刚刚好——蓝色光标成功应用联想超融合解决方案
  2. 【Android 应用开发】 Application 使用分析
  3. 2017年如何在移动端优雅的使用flex
  4. 重磅发布|新一代云原生数据仓库AnalyticDB「SQL智能诊断」功能详解
  5. 现在做Android开发有前途吗?附面试题答案
  6. Salesforce宣布5.82亿美元收购文件编辑公司Quip
  7. CSS content 属性 CSS counter-increment 属性 CSS counter-reset 属性
  8. Atitit.js获取上传文件全路径
  9. stm32f103c8t6开发版点亮oled屏幕工程文件_OLED液晶屏如何显示中文呢
  10. Win7扫雷的H5完整复刻实现(一) / js扫雷算法的初次鉴定与地图初始化实现
  11. 什么叫手机android密码,手机这个密码必须设,99%的人不知道!
  12. linux中如何分割字符串数组中,Linux教程——Shell中字符串与数组操作实例
  13. C语言常见问题(7):Remove this redundant cast
  14. STP生成树协议(超详细小白也能看懂)
  15. 医咖会stata 笔记(自己能看懂版
  16. mybatis大于小于等于的写法
  17. uniapp 解决phoneX原生tabbar 安全区域问题
  18. android小红书框架
  19. 识破贷后资金归集——关联网络
  20. 淘宝网-接口测试白皮书V0.1

热门文章

  1. 阿里巴巴(容器镜像服务)docker+springboot实践
  2. Duplicate Cleaner Pro v5.0.13 电脑重复文件查找清理工具
  3. XSS进阶二 ——合天网安实验室学习笔记
  4. 【环境配置】octopus + dirt--ubuntu18.04
  5. AMiner会议论文推荐第七十五期
  6. Python制作安卓游戏外挂
  7. 如何开通支付宝小程序助手?
  8. 【STM32Cube笔记】4-STM32Cube配置时钟设置
  9. 学习“基于深度学习的故障诊断”开源
  10. SWF游戏软件逆向基础知识1