1、算法简介
模拟退火算法来源于固体退火原理,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。需要注意的是一定要徐徐冷却,也就是物体和外界温度相差越低,退火时间越长退火的效果就越好。这也就是这算法名字的由来。
2、基本步骤
(1)生成初始解T0
(2)生成新解Tn+1
(3)使用评价函数评价新解Tn+1,
(4)如果新解Tn+1更优秀则接受新解。
(5)否则以一定概率p接受Tn+1
(6)重复2-5步骤,直到解足够优秀。
3、关键点
算法中有4个部分是对算法质量有显著影响的。初始解,产生新解的方法,接受差解的概率p,以及评价函数。
通常要求初始解比较差,也就是被加热的温度很高。如果初始解就比较好,很容易坠入局部最优解。
产生的新解与原来的解差距比较要,也就是要徐徐的降温,降温过快就会成淬火了。
接受差解的概率p,概率不能过高也不能过低,过低会导致很容易坠入局部最优解,过高会导致收敛速度大幅下降。
通常取p=exp(-Δt′/T)。
评价函数,显而易见的评价函数能否有效表示解的优秀程度直接关系解的质量。
4、举个例子
下面以求非线性方程组的解为例,展示如何使用模拟退火算法(虽然通常解非线性方程通常不用模拟退火算法,但是用这个举例比较适合,毕竟简单)
(1)方程
funs.Add((double i,double j) => { return (Math.Sin(i) * j); }); funs.Add((double i, double j) => { return (Math.Exp(i)-j); });
这里我用一个List保存方程组的各个函数。这里有两个函数,分别是
f1(x,y)=ysinx=0;
f2(x,y)=e^x-y=0;
(2)产生初始解,这里为-50 ~ 50中的随机数。
double a, b;Random rd = new Random();a = rd.NextDouble()*100-50;b = rd.NextDouble()*100-50;
(3)迭代过程。
while(true){ t++; doublet1=funs[0](a,b); doublet2=funs[1](a,b); //接受新解 if(Ack(t1,t2)
其中评价函数直接去了两个函数计算结果的模长。
5、总结
模拟退火算法是一种通过随机搜索寻求最优解的方法,所以其不一定能够收敛的最优解,是存在一定概率收敛在局部最优解中的。并且解的质量与计算时间有关,不过只要参数设置得当,会取得高质量解,并且速度十分迅速。