一、原理介紹
模擬退火算法(Simulated Annealing)是一種通用的優(yōu)化算法,最初由Kirkpatrick于1983年提出,靈感來(lái)源于固體物理學(xué)中原子的退火過(guò)程。簡(jiǎn)單來(lái)說(shuō),模擬退火算法是模擬金屬?gòu)母邷貭顟B(tài)到低溫狀態(tài)冷卻過(guò)程中的微觀(guān)行為,使得金屬的內(nèi)部結(jié)構(gòu)由無(wú)序轉(zhuǎn)變?yōu)橛行虻倪^(guò)程。在優(yōu)化問(wèn)題中,可以將最優(yōu)解看作一個(gè)結(jié)構(gòu)有序的狀態(tài),而將優(yōu)化過(guò)程看作從初始狀態(tài)到最優(yōu)狀態(tài)迭代過(guò)程的退火過(guò)程。
模擬退火算法的核心思想是利用概率跳出局部最優(yōu)解,以期望更好的全局解。模擬退火算法按照一定的比例降低溫度,從而使搜索范圍減小,最終找到全局最優(yōu)解的概率逐漸增大,隨著時(shí)間的推移,概率逐漸趨近于1。
二、優(yōu)點(diǎn)分析
三、缺點(diǎn)分析
四、代碼示例
算法核心代碼
/**
* 模擬退火算法
* @param func 目標(biāo)函數(shù)
* @param neighbor 鄰域函數(shù)
* @param t0 初始溫度
* @param tn 最小溫度
* @param alpha 降溫速率
* @param maxIter 最大迭代次數(shù)
*/
double simulatedAnnealing(function)> func, function(vector)> neighbor,
double t0 = 1e4, double tn = 1e-4, double alpha = 0.99, int maxIter = 10000) {
double t = t0; // 當(dāng)前溫度
vector c = {0, 0}; // 初始解
double best = func(c); // 初始解的目標(biāo)函數(shù)值
for (int i = 0; i < maxIter; i++) {
vector nc = neighbor(c); // 產(chǎn)生新解
double delta = func(nc) - best; // 計(jì)算目標(biāo)函數(shù)的值差
if (delta < 0) { // 新解更優(yōu)
c = nc;
best = func(nc);
} else { // 根據(jù)一定概率接受劣解
double p = exp(-delta / t); // 接受概率
double r = ((double) rand() / RAND_MAX); // 隨機(jī)數(shù)
if (r < p) {
c = nc;
}
}
t *= alpha; // 降溫
if (t < tn) {
break; // 溫度達(dá)到最小值,退出迭代
}
}
return best;
}
一個(gè)簡(jiǎn)單的例子
/**
* 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的例子:在二維平面上尋找離原點(diǎn)最遠(yuǎn)的點(diǎn)
*/
double distance(vector p) { // 目標(biāo)函數(shù):點(diǎn)到原點(diǎn)的距離
return sqrt(p[0] * p[0] + p[1] * p[1]);
}
vector perturb(vector p) { // 鄰域函數(shù):隨機(jī)擾動(dòng)點(diǎn)的坐標(biāo)
return {p[0] + ((double) rand() / RAND_MAX - 0.5) * 2.0, p[1] + ((double) rand() / RAND_MAX - 0.5) * 2.0};
}
int main() {
srand(time(NULL)); // 初始化隨機(jī)數(shù)生成器
double ans = simulatedAnnealing(distance, perturb, 1e3, 1e-3, 0.99, 1000);
cout << ans << endl;
return 0;
}