在上一篇文章中讲述了模拟退火的基本原理,以下以一个实际的例子来说明,其中所有的源码已贴出,可以从中了解到很多细节。
使用模拟退火法求函数 f(x,y) = 5sin(xy) + x 2 + y 2 的最小值
解:根据题意,我们设计冷却表进度表为:
即初始温度为 100
衰减参数为 0.95
马可夫链长度为 10000
Metropolis 的步长为 0.02
结束条件为根据上一个最优解与最新的一个最优解的之差小于某个容差。
使用 METROPOLIS 接受准则进行模拟 , 程序如下
/*
模拟退火法求函数f(x,y) = 5sin(xy) + x^2 + y^2的最小值
日期:2004-4-16
作者:ARMYLAU
EMAIL:[email protected]
结束条件为两次最优解之差小于某小量
*/
using System;
namespace SimulateAnnealing
{
class Class1
{
// 要求最优值的目标函数
static double ObjectFunction( double x, double y )
{
double z = 0.0;
z = 5.0 * Math.Sin(xy) + xx + y*y;
return z;
}
[STAThread]
static void Main ( string [] args)
{
// 搜索的最大区间
const double XMAX = 4;
const double YMAX = 4;
// 冷却表参数
int MarkovLength = 10000; // 马可夫链长度
double DecayScale = 0.95; // 衰减参数
double StepFactor = 0.02; // 步长因子
double Temperature = 100; // 初始温度
double Tolerance = 1e-8; // 容差
double PreX,NextX; // prior and next value of x
double PreY,NextY; // prior and next value of y
double PreBestX, PreBestY; // 上一个最优解
double BestX,BestY; // 最终解
double AcceptPoints = 0.0; // Metropolis过程中总接受点
Random rnd = new Random();
// 随机选点
PreX = -XMAX * rnd.NextDouble() ;
PreY = -YMAX * rnd.NextDouble();
PreBestX = BestX = PreX;
PreBestY = BestY = PreY;
// 每迭代一次退火一次(降温), 直到满足迭代条件为止
do
{
Temperature *=DecayScale;
AcceptPoints = 0.0;
// 在当前温度T下迭代loop(即MARKOV链长度)次
for ( int i=0;i
1<markovlength;i++) !(nextx="" (="" +="" 1)="" do="" nextx="PreX" nexty="PreY" stepfactor*xmax*(rnd.nextdouble()-0.5);="" stepfactor*ymax*(rnd.nextdouble()-0.5);="" while="" {="" }="" 在此点附近随机选下一点="">= -XMAX && NextX <= XMAX && NextY >= -YMAX && NextY <= YMAX) );
2
3// 2) 是否全局最优解
4
5if (ObjectFunction(BestX,BestY) > ObjectFunction(NextX,NextY))
6
7{
8
9// 保留上一个最优解
10
11PreBestX =BestX;
12
13PreBestY = BestY;
14
15// 此为新的最优解
16
17BestX=NextX;
18
19BestY=NextY;
20
21}
22
23// 3) Metropolis过程
24
25if ( ObjectFunction(PreX,PreY) - ObjectFunction(NextX,NextY) > 0 )
26
27{
28
29// 接受, 此处lastPoint即下一个迭代的点以新接受的点开始
30
31PreX=NextX;
32
33PreY=NextY;
34
35AcceptPoints++;
36
37}
38
39else
40
41{
42
43double change = -1 * ( ObjectFunction(NextX,NextY) - ObjectFunction(PreX,PreY) ) / Temperature ;
44
45if ( Math.Exp(change) > rnd.NextDouble() )
46
47{
48
49PreX=NextX;
50
51PreY=NextY;
52
53AcceptPoints++;
54
55}
56
57// 不接受, 保存原解
58
59}
60
61}
62
63Console.WriteLine("{0},{1},{2},{3}",PreX, PreY, ObjectFunction ( PreX, PreY ), Temperature);
64
65} while ( Math.Abs( ObjectFunction( BestX,BestY) – ObjectFunction (PreBestX, PreBestY)) > Tolerance );
66
67Console.WriteLine("最小值在点:{0},{1}",BestX, BestY);
68
69Console.WriteLine( "最小值为:{0}",ObjectFunction(BestX, BestY) );
70
71}
72
73}
74
75}
76
77l 结果:
78
79最小值在点 :-1.07678129318956,1.07669421564618
80
81最小值为 :-2.26401670947686
82
83l 后记:
84
85原来想写一系列的文章,介绍如何用 C #解数值问题,这是因为在 CSDN 上很少有数值计算方面的文章,所以希望能有所补充。
86
87一开始在网上搜索模拟退火的资料并想作为 C #数值计算的一个例子,找不到现成的源码。后来自己实验了很久,终于将此程序写出,不敢私藏,拿出来作用模拟退火或者用 C #解数值算法问题的一个入门例子。
88
89本文尽量避免太过学术化,如数学和物理名称和公式,仓促下笔,有很多地方可能讲得不是很清楚,希望各位体谅。任何问题或批评,可 EMAIL 与我: [email protected]
90
91另,模拟退火还可以应用到其它更多更复杂的问题,如“推销员问题”等组合优化问题。本例只是求一个二维函数的最小值问题,而且其冷却表参数的选择也过于简单,只能作用一个初步的入门简介,请读者注意。
92
93l 参考文献:
94
951. http://www.computer-dictionary-online.org/index.asp?q=simulated+annealing 计算机词典
96
972. Numeric Recipes in C
98
993. 计算方法丛书 非数值并行算法 (第一册) 模拟退火算法</markovlength;i++)>