2018.09.28 模拟退火算法研究日志
本周研究模拟退火算法,这也是一个启发式求最优解的方法。这个算法可以被优化,比如结合遗传算法减少迭代次数。
模拟退火算法
百度百科对模拟退火算法的解释是:
模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,即在局部最优解能概率性地跳出并最终趋于全局最优。
它的基本思想是:
模拟退火其实也是一种贪心算法,但是它的搜索过程引入了随机因素。在迭代更新可行解时,以一定的概率来接受一个比当前解要差的解,因此有可能会跳出这个局部的最优解,达到全局的最优解。
如上图,模拟退火算法从A点出发,快速定位到B点,这是一个局部最优点而不是全局最优,根据算法,它按概率(刚开始时概率较大,而后逐步减小)接收劣于B的点,模拟退火算法会逐步搜索到C点(该点也是局部最优),再用同样的方法搜索到D点。此时,由于接受该点为最优的概率远高于跳出概率(接受劣于D的点的概率),且迭代次数逐渐接近最初定义的次数最大值,所以会有极大概率接受D为全局最优解,算法停止。
有关接受劣等数据的概率,同时应用退火过程的热力学公式如下:
p ( d E ) = e d E k T p(dE)=e^{\frac{dE}{kT}} p(dE)=ekTdE
其中,k是波尔兹曼常数,但是在算法中通常简化为k=1
,而初始化温度充分大,温度下限充分小,能够更快得到全剧最优点。
能量差计算公式入下:
d E = Δ f = f ( x n e w ) − f ( x ) dE=\Delta f=f(x_{new})-f(x) dE=Δf=f(xnew)−f(x)
x_new为迭代更新后的点。
模拟退火算法描述
过程如下:
–
- 初始化:初始温度 T T T(充分大),温度下限 T m i n T_{min} Tmin(充分小),初始化解状态 x x x(是算法迭代的起点),每一个 T T T值的迭代次数 L L L;
- 对
l
=
1
,
2
,
⋯
 
,
L
l=1,2,\cdots,L
l=1,2,⋯,L做以下步骤:
2.1 产生新解 x n e w x_{new} xnew:( x n e w = x + Δ x x_{new}=x+\Delta x xnew=x+Δx);
2.2 计算能量增量 Δ f = f ( x n e w ) − f ( x ) \Delta f=f(x_{new})-f(x) Δf=f(xnew)−f(x),其中 f ( x ) f(x) f(x)为优化目标;
2.3 若 Δ f < 0 \Delta f<0 Δf<0(若寻找最大值, Δ f > 0 \Delta f>0 Δf>0)则接受 x n e w x_{new} xnew作为新的当前解,否则以概率 e − Δ f k T e^{\frac{-\Delta f}{kT}} ekT−Δf接受 x n e w x_{new} xnew作为新的当前解;
2.4 如果满足终止条件则输出当前解作为最优解,结束程序。(终止条件通常取为连续若干个新解都没有被接受时终止算法) - T逐渐减少,且 T > T m i n T>T_{min} T>Tmin,然后转到第二步;否则退出算法。
–
2018.10.21模拟退火算法研究日志
很久没有研究算法啦,这几天接了一个项目,蛮忙的,现在总算完成了。从今天开始,继续研究拖到现在的算法。
模拟退火算法实例——以求最小值为例
设函数 f ( x ) = ( x − 2 ) × ( x + 3 ) × ( x + 8 ) × ( x − 9 ) f(x)=(x-2)\times(x+3)\times(x+8)\times(x-9) f(x)=(x−2)×(x+3)×(x+8)×(x−9),求其最小值。
首先,我们先了解一下该函数图形的模样:
用Java实现该算法过程:
import java.math.BigDecimal;
import java.util.Random;
import static java.lang.Math.exp;
public class Main {
public static void main(String[] args) {
double initT=1000.0; //初识温度
double minT=1.0; //温度下限
int iterL=1000; //每个T值的迭代次数
double delta=0.95; //温度衰减系数
int k=1; //波尔兹曼常数
Funcion func = new Funcion();
double x = func.randomDouble();
System.out.println("初始解为: "+x);
double T = initT; //当前温度为初始温度
Random random = new Random();
while(T>minT){
for(int times=0;times<iterL;times++){
//产生新值
double delta_x=-1+random.nextDouble()*2;
double x_new = x+delta_x;
if(x_new>=-10&&x_new<=10){
if(func.function_value(x)<func.function_value(x_new)){
double difference = func.function_value(x_new)-func.function_value(x); //delta f(x)两函数的差
double probability = random.nextDouble(); //以概率接受值
if(probability<exp(-(difference/(k*T)))){
x=x_new;
}
}else {
x=x_new;
}
}
}
T = T*delta; //减小T;
}
//输出
BigDecimal decimal=new BigDecimal(func.function_value(x));
double out=decimal.setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue();
BigDecimal decimal_x=new BigDecimal(x);
double out_x=decimal_x.setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue();
System.out.println("经过多次迭代");
System.out.println("最优解:"+out_x);
System.out.println("函数最小值:"+out);
}
}
class Funcion{
//函数值
public double function_value(double x){
return (x-2)*(x+3)*(x+8)*(x-9);
}
//最大温度和最小温度之间产生一个随机浮点数,精确到小数点后4位
public double randomDouble(){
Random random = new Random();
double x = -10+random.nextDouble()+random.nextInt(19); //[-10,10]
// 新建格式化器,设置格式
BigDecimal decimal=new BigDecimal(x);
// 将数据四舍五入为4位小数的double值
double out=decimal.setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue();
return out;
}
}