模拟退火算法

1. 就是求函数最值,求出来近似值,近似值(与代码有很大关系);

2. 基于物理原型:一个固体温度高,内能大,内部粒子在运动,温度慢慢降低,粒子趋于有序,达到常温后,粒子稳定运动,内能减小;

通过模拟这个操作,使得答案区域有序,也就是最靠近需要的值。

3. 退火有温度,慢慢降温,每次降当前温度的1%,降到什么时候为止:eps = 1e-14, 也是迭代的循环算法;

double T = 2000; //代表开始的温度
double dT = 0.99; //代表系数delta T
double eps = 1e-14; //相当于0.0000000000000001
while(T > eps) {
    //--------------
    //这里是每一次退火的操作
	//--------------
    T = T * dT; //温度每次下降一点点, T * 0.99
}

温度下降越慢,结果越精细;

4. 代码段中“退火操作”

        随机找一点x_0 (不超过定义域就可),对应找到函数值f(x_0)x_0 相当于是粒子,相当于无序运动,向左或向右随机运动,移动幅度与当前温度有关,温度高,运动幅度大,温度低,运动幅度小;

        随机移动到另外一个地方,得到x_1, 得到f(x_1),若比f(x_0)好,就直接替换 x_0f(x_0)

        但是,该方法会有一定的概率接受更差的状态;

                因为温度在越来越小,运动的幅度也在越来越小,如果粒子一直在右侧移动,随着幅度的变小,它就不可能找到函数的最大值,但若以一定概率接受较差的状态,粒子就可能会跳到左边,在运动幅度减小之前,可能会找到函数的最优解。

                 概率大小:e^{\triangle f/kT}

                kT,这里的k代表一个超参,代码中可以当作1来使用,T是温度,上述代码第一可以看到T>0

                \triangle f在这里应该是负值,这是由于概率值在[0,1]范围内,又由于e^x的图像为:

 

        所以   \triangle f在这里应该是负值,其是一个差值,\triangle f = -|f(x_0) - f(x_1)|

        但是具体情况要具体分析,因为当函数值变好了,是一定接受的,函数值变差了,是以一定概率接受的,所以只有当f(x_0) < f(x_1)时,才使用令\triangle f = -(f(x_0) - f(x_1))

5. 具体要定义的函数:

(1)要进行模拟退火的函数;

(2)定义好初始值x_0

(3)定义好每次运动的幅度\triangle x (让选取的新值,要落在定义域中,若没在要重新运算);

        \triangle x = (2 * rand() - RANDMAX) *T

        T越大,运动幅度越大;

        对rand()解释:

                可以默认拿到[0,32767]内的随机整数;

                RANDMAX = 32767,可以看作常量。本质是宏定义: #define RANDMAX 32767;

                rand() * 2 的范围是[0,32767 * 2];

                rand() * 2 - RAND_MAX 的范围是[-32767, 32767];

(4)求出新的函数值,若变大直接接受,变小以一定概率接受

                e^{f(x_1) - f(x_0)/T} * RANDMAX > rand()

        目的是要一定概率接受,但是e^{\frac{f(x_1 - f(x_0)}{T}}是个准确值,所以从理论上可以生成一个(0,1)的随机数,如果e^{\frac{f(x_1 - f(x_0)}{T}}比(0,1)这个随机数要大,那么我们就接受;

        但是由于rand()只能产生[0,32767]内的随机整数,化成小数太过麻烦。所以可以把左边乘以RANDMAX(也就是把概率同时扩大32767倍),效果就等同于e^{\frac{f(x_1 - f(x_0)}{T}}在(0,1)了.

6. 伪代码

double T = 2000; //代表开始的温度
double dT = 0.99; //代表系数delta T
double eps = 1e-14; //相当于0.0000000000000001
 
//用自变量计算函数值,这里可能存在多个自变量对应一个函数值的情况,比如f(x,y)
double func(int x, ... ) {
    //这里是对函数值进行计算
    double ans = .......
    return ans;
}
//原始值
double x = rand(); //x0取随机值
double f = func(x,...); //通过自变量算出f(x0)的值
while(T > eps) {
    //--------------
    //这里是每一次退火的操作
    
    //x1可以左右随机移动,幅度和温度T正相关,所以*T
    //注意这里移动可以左右移动,但是也可以单向移动
    //关于rand()详细见开头注的①
    double dx = (2*rand() - RAND_MAX) * T; 
    
    //让x落在定义域内,如果没在里面,就重新随机。题目有要求需要写,否则不用写
    // ================
    while(x > ? || x < ? ...) {
        double dx = (2*rand() - RAND_MAX) * T; 
    }
    // ================
    
    //求出f(x1)的值
    double df = func(dx);
    //这里需要具体问题具体分析,我们要接受更加优秀的情况。可能是df < f(比如求最小值)
    if(f < df) {
        f = df; x = dx;  [...,y = dy;] // 接受,替换值,如果多个自变量,那么都替换
    }
    //否则概率接受,注意这里df-f也要具体问题具体分析。
    //详细见开头注的②③
    else if(exp((df - f) / T) * RAND_MAX > rand()) {
        f = df; x = dx;  [...y = dy;] // 接受,替换值,如果多个自变量,那么都替换
    }
	//--------------
    T = T * dT; //温度每次下降一点点, T * 0.99
}
//最后输出靠近最优的自变量x值,和函数值f(x)
cout << x << " " << f << endl;

 

 参考: B站视频:大学生速通模拟退火算法_哔哩哔哩_bilibili

                博客:速通模拟退火 - Don't Cry!

m .\anneal.m .\berkeley.m .\COPYRIGHT.txt .\dispEh.m .\dispEt.m .\dispMat.m .\ensembleInit.m .\examples .\........\chemcluster .\........\...........\clusterdistances.m .\........\...........\clusterplot.m .\........\...........\cluster_cost.m .\........\...........\cluster_init.m .\........\...........\cluster_new.m .\........\...........\cluster_perturb.m .\........\...........\test_all.m .\........\...........\try_me.m .\........\graphbipart .\........\...........\bipart_cost.m .\........\...........\bipart_init.m .\........\...........\bipart_new.m .\........\...........\bipart_perturb.m .\........\...........\try_me.m .\........\proteinfold .\........\...........\sequence_cost.m .\........\...........\sequence_init.m .\........\...........\sequence_new.m .\........\...........\sequence_perturb.m .\........\...........\try_me.m .\........\README.txt .\........\seismicdecon .\........\............\decon_cost.m .\........\............\decon_init.m .\........\............\decon_new.m .\........\............\decon_perturb.m .\........\............\eventparts.m .\........\............\eventplot.m .\........\............\modelparts.m .\........\............\modelplot.m .\........\............\modelsignal.m .\........\............\README.txt .\........\............\try_me.m .\........\spinglass .\........\.........\Jcoord.m .\........\.........\spin_cost.m .\........\.........\spin_init.m .\........\.........\spin_new.m .\........\.........\spin_perturb.m .\........\.........\try_me.m .\........\tsp .\........\...\route_cost.m .\........\...\route_init.m .\........\...\route_new.m .\........\...\route_perturb.m .\........\...\try_me.m .\franz.m .\geman.m .\geometric.m .\hartley.m .\historyupdate.m .\hoffmann.m .\metropolis.m .\metropoliswalk.m .\mktemplate.m .\nextstate.m .\plotBins.m .\randomwalk.m .\README.txt .\retrospect.m .\satools.m .\satoolsversion.m .\stillinger3Dpoints.m .\szu.m .\template_cost.txt .\template_init.txt .\template_new.txt .\template_perturb.txt .\template_try_me.txt .\TfinalNstop.m .\thermospeedHC.m .\thermospeedR.m .\threshold.m .\TinitAccept.m .\TinitT0.m .\TinitWhite.m .\TM.m .\tsallis.m
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值