目錄
基本概念
布穀鳥搜索算法(Cuckoo Search,縮寫 CS)是由劍橋大學楊新社教授和S.戴佈於2009年提出的一種新興啓發算法。根據昆蟲學家的長期觀察研究發現,一部分佈谷鳥以寄生的方式養育幼鳥,它們不築巢,而是將自己的卵產在其他鳥的巢中(通常爲黃鶯、雲雀等),由其他鳥(義親)代爲孵化和育雛。然而,如果這些外來鳥蛋被宿主發現,宿主便會拋棄這些鳥蛋或新築鳥巢。
通俗理解就是,布穀鳥蛋找到能成功在其他鳥巢成功孵化這個過程就是尋優過程。布穀鳥算法源於對布穀鳥繁育行爲的模擬,爲了簡化自然界中布穀鳥的繁衍習性,Yang 等將布穀鳥的產卵行爲假設爲3個理想狀態。
- 布穀鳥一次只產一個卵,並隨機選擇鳥窩位置來孵化它。
- 在隨機選擇的一組鳥窩中,最好的鳥窩將會被保留到下一代。
- 可選擇的寄生巢的數量是固定的,寄生巢主人發現外來鳥蛋的概率爲pa,其中 。
基於這 3 個理想狀態,Yang 等採用式(1)對下代鳥巢位置進行更新:
(1)
式中: 表示第個鳥巢在第t代的位置; 表示點對點乘法; 表示步長控制量,用來控制步長大小,通常情況下,取 。 爲Levy隨機搜索路徑,屬於隨機行走,採用萊維飛行機制,其行走的步長滿足一個重尾的穩定分佈,而隨機步長爲levy分佈:
(2)
基本布穀鳥搜索算法先按照式(1)對下一代的鳥巢位置進行更新,並且計算目標函數的適應度值,如果該值優於上一代的目標函數值,則更新鳥巢位置,否則保持原來位置不變。通過位置更新後,用隨機產生的服從 0 到 1 均勻分佈的數值𝑅與鳥巢主人發現外來鳥蛋的概率pa相比較,若R>pa,則對進行隨機改變,反之不變。最後保留測試值較好的一組鳥窩位置 ,記爲 。判斷算法是否滿足設置的最大迭代次數:若滿足,結束迭代尋優,輸出全局最優值fmin ;否則,繼續迭代尋優。該算法具有全局探索和局部開發性能的平衡以及種羣的多樣性。
算法具體流程
Step 1(初始化)確定目標函數初始化羣體,隨機產生n個鳥窩的初始位置。設置算法參數:種羣規模N、維度D、發現概率pa、界值大小L、最大迭代次數MaxN、最優鳥窩位置和最優解 。
Step 2(循環體)按式(1)、(2)更新當代鳥窩的位置;將當代鳥窩與上一代鳥窩位置進行對比,用適應度值較好的鳥窩位置替換適應度值較差的鳥窩位置:。
Step 3(循環體)用隨機數𝑅作爲鳥窩主人發現外來鳥蛋的可能性,將其與鳥被淘汰的概率pa進行比較。若𝑅 >pa則隨機改變 中的鳥窩位置,得到一組新的鳥窩位置。再更新鳥窩位置,得到一組較好的鳥窩位置:。更新最優鳥窩位置和最優解。
Step 4 判斷算法是否滿足設置的最大迭代次數:若滿足,結束搜索過程,輸出全局最優值,否則,重複step2進行迭代尋優。
算法流程圖
測試函數
優化變量:
約束條件:
目標函數:
式中, Goldstein-Price函數f(x)是一個二元八次多項式,作爲常見的算法測試函數,許多科研人員利用它研究其局部最小值。上式爲該優化問題的數學優化模型,該函數的理論結果爲在(0,-1)處取得最小值3。
優化結果
從上圖可以看出,布穀鳥搜索算法優化最小值爲3.02573,迭代400次用時2.119s。
visual studio2017C++代碼
頭文件:
//布穀鳥搜索算法
//開發人員:chenshuai 開發日期:2019.11.25 郵箱:[email protected]
//************************************************************************************//
//布穀鳥算法參數設定
//************************************************************************************//
#ifndef PCH_H
#define PCH_H
#include <iostream>
# include <fstream>
#include <iomanip>
#include <math.h>
#include <cstdlib> // 標準庫
#include <ctime> // 時間庫
#include <vector> //容器頭文件
#include<random>
#define PI 3.1415926535897 //π值
using namespace std;
//產生隨機小數或整數
class RandomNumber {
public:
RandomNumber() {
srand((unsigned)time(NULL)); //析構函數,在對象創建時數據成員執行初始化操作
}
int integer(int begin, int end)
{
return rand() % (end - begin + 1) + begin;
}
double decimal(double a, double b)
{
return double(rand() % 10000) / 10000 * (b - a) + a;
}
};
class cs {
private:
int N_nest;//種羣(布穀鳥巢總數)
int Max_iteration;//最大迭代次數,
int D_egg;//變量個數(布穀鳥蛋維數)
double pa;//布穀鳥蛋被發現的概率
double cs_alpha;//步長控制量
double R; //隨機數R
public:
double lambda;
vector<double>fmin; //最優解
vector<vector<double>>f_nest; //鳥窩的適應度值
vector<vector<double>>p_t; //與上一代比較後最優的鳥窩種羣
vector<vector<double>>g_t; //被發現之後,更新的最優鳥窩種羣
vector<double>nest_best; //最好的鳥窩
vector<double>nest_low = { -2,-2 }; //儲存變量上限值 (鳥窩的上限)
vector<double>nest_high = { 2,2 }; //儲存變量下限值 (鳥窩的下限)
//*******************************************//
//定義函數
//*******************************************//
void setParameters();//設置算法參數int N_nest,int Max_iteration,int D_egg,double cs_alpha
void initialize(); //初始化
double select_optimal(vector<vector<double>>x); //選擇最優的鳥巢
double fit_function(vector<double> x); //目標函數
vector<vector<double>> update_Levyflight(vector<vector<double>>x, int t);//萊維飛行更新鳥窩位置
vector<vector<double>> update_Rrandomnumber(vector<vector<double>>x);//隨機數R更新鳥窩位置
};
#endif //PCH_H
函數文件:
#include "pch.h"
//***********************************************
//設置布穀鳥算法參數
//**********************************************
void cs::setParameters()
{
N_nest = 100; //種羣(布穀鳥巢總數)
Max_iteration = 400;//最大迭代次數,
D_egg = 2;//變量個數(布穀鳥蛋維數)
pa = 0.25;//布穀鳥蛋被發現的概率
cs_alpha = 1.0;//步長控制量
}
//**********************************************
//初始化羣體,N個鳥窩的初始位置
//**********************************************
void cs::initialize()
{
extern RandomNumber r; //定義隨機數
fmin.resize(Max_iteration);
p_t.resize(N_nest, vector<double>(D_egg));
g_t.resize(N_nest, vector<double>(D_egg));
f_nest.resize(Max_iteration, vector<double>(N_nest));
nest_best.resize(D_egg);
for (int i = 0; i < N_nest; i++)
{
for (int j = 0; j < D_egg; j++)
{
p_t[i][j] = r.decimal(nest_low[j], nest_high[j]);//初始化鳥窩的值
}
}
}
//***********************************************
//鳥窩位置的適應度
//**********************************************
double cs::fit_function(vector<double>x)
{
double fx = 0;
//Rastrigin函數
/*for (int i = 0; i < 2; i++)
{
fx = fx + x[i] * x[i] - 10 * cos(2 * PI*x[i]) + 10;
}*/
//Goldstein -Price函數
fx = (1 + pow((1 + x[0] + x[1]), 2)*(19 - 14 * x[0] + 3 * x[0] * x[0] - 14 * x[1] + 6 * x[0] * x[1] + 3 * x[1] * x[1]))*(30 + pow((2 * x[0] - 3 * x[1]), 2)*(18 - 32 * x[0] + 12 * x[0] * x[0] + 48 * x[1] - 36 * x[0] * x[1] + 27 * x[1] * x[1]));
//SiX-Hump Camel函數
//fx = 4 * x[0] * x[0] - 2.1*pow(x[0], 4) + 1.0 / 3.0*pow(x[0], 6) + x[0] * x[1] - 4 * x[1] * x[1] + 4 * pow(x[1], 4);
return fx;
}
//**********************************************
//計算每個鳥窩的目標函數值並記錄當前的最優解
//**********************************************
double cs::select_optimal(vector<vector<double>>x)
{
double fmin = 0;
fmin = fit_function(x[0]);
for (int i = 1; i < N_nest; i++)
{
if (fmin > fit_function(x[i]))
{
fmin = fit_function(x[i]);
for (int j = 0; j < D_egg; j++)
{
nest_best[j] = x[i][j];
}
}
}
return fmin;
}
//**********************************************
//隨機數R更新鳥窩位置
//**********************************************
vector<vector<double>> cs::update_Rrandomnumber(vector<vector<double>>x)
{
extern RandomNumber r; //聲明全局隨機數
for (int j = 0; j < N_nest; j++)
{
for (int k = 0; k < D_egg; k++)
{
R = r.decimal(0, 1);
if (R > pa)
{
x[j][k] = r.decimal(nest_low[k], nest_high[k]);
}
}
}
return x;
}
//**********************************************
//萊維飛行更新每個鳥窩的位置
//**********************************************
vector<vector<double>> cs::update_Levyflight(vector<vector<double>>x, int t)
{
extern RandomNumber r; //聲明全局隨機數
for (int j = 0; j < N_nest; j++)
{
for (int k = 0; k < D_egg; k++)
{
lambda = r.decimal(1, 3);
x[j][k] = x[j][k] + cs_alpha * pow(t, -1 * lambda);
if (x[j][k]< nest_low[k] || x[j][k] > nest_high[k])
{
x[j][k] = r.decimal(nest_low[k], nest_high[k]);
}
}
}
return x;
}
主函數:
#include "pch.h"
#include <iostream>
RandomNumber r; //隨機數
int main()
{
clock_t startTime, endTime; //定義程序開始運行時間和結束時間
startTime = clock(); //計時開始
cs CS; //定義布穀鳥種羣
CS.setParameters();//設置算法參數
CS.initialize(); //初始化
CS.fmin[0] = CS.select_optimal(CS.p_t);//選擇初代最優個體
cout << CS.fmin[0] << endl;
//循環體
ofstream out("布穀鳥算法優化結果.txt");
for (int i = 1; i < size(CS.fmin); i++)
{
CS.p_t = CS.update_Levyflight(CS.p_t, i); //萊維飛行更新鳥窩的位置
CS.fmin[i] = CS.select_optimal(CS.p_t);
if (CS.fmin[i] > CS.fmin[i - 1])
{
CS.fmin[i] = CS.fmin[i - 1];
}
CS.p_t = CS.update_Rrandomnumber(CS.p_t);//隨機數R發現更新鳥窩的位置
if (CS.fmin[i] > CS.select_optimal(CS.p_t))
{
CS.fmin[i] = CS.select_optimal(CS.p_t);
}
out << i << fixed << setw(12) << setprecision(5) << CS.fmin[i] << endl;
}
out << "最優變量:" << endl;
for (int ii = 0; ii < size(CS.nest_best); ii++)
{
out << "x" << ii << "=" << fixed << setw(12) << setprecision(5) << CS.nest_best[ii] << endl;//輸出最優變量
}
out << "最優值=" << fixed << setw(12) << setprecision(5) << CS.fmin[size(CS.fmin) - 1] << endl;
endTime = clock();//計時結束
out << "run time:" << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
}
各位閱讀文章的朋友覺得文章可以給個好評或者點贊,大家覺得有問題可以指出來或者發郵箱[email protected]聯繫我!如需要轉載請附上鍊接,謝謝各位朋友!