一 算法背景
1. 算法解决的问题
求给定范围内函数最值问题。
2.物理背景
退火算法:退火概念来源于物理概念。当温度高时,分子能量大,使得分子空间位置处于无序状态;当温度降低,分子能量减少,分子的空间状态趋于有序(类比水的气态,液态和固态)。
此时当温度足够低时,分子排列出现一个相对最优值,这个最优值就是我们所得的最优解。
二 策略简介
特点:贪婪算法的升级版。
贪婪算法:适合求函数只有一个极值(数学概念,就是一定范围内的最小(大)值)的情况,此时极值即最值。以求函数最大值为例,当起始点是A时,它会贪婪的求出局部最大值B;当起始点是C时,它会贪婪的求出局部最大值D。但它不能求出函数最大值是D。对于简单的,只有一个极值的函数,用贪婪算法足矣。
退火算法:可以求函数的最值(数学概念,所有函数极值的最大值)。同贪婪算法,但它求出函数的极值点后,并不会停止计算,而是以一定的概率跳过该值继续计算(Metropolis接受准则),从而保证在全域(给定的)内求函数的值,从而保证求出函数的最值。
三 代码实现
本人代码实现主要参考:https://cloud.tencent.com/developer/article/1064344
1.流程图
本程序通过退火算法求出适宜的自变量的值,在通过比较各个自变量对应函数值的大小,从而得到函数的最值。
程序实现流程图如下:
2.代码使用函数
本次使用函数为:,
其中,0≤x≤100,任意输入y值,求f(z)的最值。
注:严格意义上讲,本函数在定义域内并不是多极值函数。如上图。因为怎eclipse里实现多极值函数是在太难(MATLAB就容易多了),已超出本小白的知识范围,但退火原理的基本思想仍适用。
3.代码实现
/** * 实现模拟退火算法 */
public class tuihuo {
public static final int T = 100;// 初始化温度
public static final double Tmin = 1e-8;// 温度的下界
public static final int k = 100;// 迭代的次数
public static final double delta = 0.98;// 温度的下降率
//产生一个0~100之间的随机double数
public static double getX() {
return Math.random() * 100; //math.random默认产生一个[0.0~1.0]之间的数。
}
/**求得函数的值*/
public static double getFuncResult(double x, double y) {
double result = 6 * Math.pow(x, 7) + 8 * Math.pow(x, 6) + 7
* Math.pow(x, 3) + 5 * Math.pow(x, 2) - x * y;
return result;
}
/**模拟退火算法的过程*/
public static double getSA(double y) {
//因为求函数的最小值,所以初始化为最大,同理,如果求函数最大值,初始化为最小值。
double result = Double.MAX_VALUE;// 初始化最终的结果,64位双精度值能表示的最大正数
double t = T;
double x[] = new double[k];
// 初始化初始解。将数组X初始化为0~100的随机数。
for (int i = 0; i < k; i++) {
x[i] = getX();
}
// 迭代的过程
while (t > Tmin) {
for (int i = 0; i < k; i++) {
// 计算此时的函数结果
double funTmp = getFuncResult(x[i], y);
// 在邻域内产生新的解
double x_new = x[i] + (Math.random() * 2 - 1) * t;
// 判断新的x不能超出界
if (x_new >= 0 && x_new <= 100) {
double funTmp_new = getFuncResult(x_new, y);
//如果新的函数值比之前的函数值要小,则用新的x值替换原来的x值。否则,
if (funTmp_new - funTmp < 0) {
// 替换
x[i] = x_new;
} else {
// 以概率替换
double p = 1 / (1 + Math
.exp(-(funTmp_new - funTmp) / T));
if (Math.random() < p) {
x[i] = x_new;
}
}
}
}
t = t * delta;
}
//结果与各个函数值作比较,得出最小值。
for (int i = 0; i < k; i++) {
result = Math.min(result, getFuncResult(x[i], y));
}
return result;
}
public static void main(String args[]) {
// 设置y的值
int y = 0;
System.out.println("最优解为:" + getSA(y));
}
}
希望可以帮助到大家,如果不妥,可以及时联系本小白呦。