7 ABC算法 的概念衬廷,代碼摇予,小例子

先上代碼

#include<iostream>  
#include<time.h>  
#include<stdlib.h>  
#include<cmath>  
#include<fstream>  
#include<iomanip>  
using namespace std;

const int NP = 40;//種群的規(guī)模,采蜜蜂+觀察蜂  
const int FoodNumber = NP / 2;//食物的數(shù)量吗跋,為采蜜蜂的數(shù)量  
const int limit = 20;//限度侧戴,超過這個(gè)限度沒有更新采蜜蜂變成偵查蜂  
const int maxCycle = 10;//停止條件  
double result[maxCycle] = { 0 };//每輪循環(huán)中的函數(shù)值

/*****函數(shù)的特定參數(shù)*****/
const int D = 2;//函數(shù)的參數(shù)個(gè)數(shù)  
const double lb = -5;//函數(shù)的下界   
const double ub = 5;//函數(shù)的上界  

/*****種群的定義****///定義了輸入輸出結(jié)構(gòu),IO結(jié)構(gòu)
struct BeeGroup
{
    double code[D];//函數(shù)的維數(shù) //估計(jì)是函數(shù)有幾個(gè)參數(shù)小腊,不是幾個(gè)參數(shù)用D就可以定義救鲤。我知道了,是輸入變量的函數(shù)值秩冈。
    double trueFit;//記錄真實(shí)的最小值//估計(jì)是最優(yōu)函數(shù)值  
    double fitness;//把最有函數(shù)值轉(zhuǎn)化為適應(yīng)度
    double rfitness;//相對(duì)適應(yīng)值比例  
    int trail;//表示實(shí)驗(yàn)的次數(shù)本缠,用于與limit作比較//隨機(jī)采樣的次數(shù)。
}Bee[FoodNumber];//FoodNumber表示多少個(gè)采樣點(diǎn)入问。然后再采樣點(diǎn)附近局部采樣丹锹。

BeeGroup NectarSource[FoodNumber];//蜜源,注意:一切的修改都是針對(duì)蜜源而言的  //蜜源應(yīng)該是可行解集合 //芬失?
BeeGroup EmployedBee[FoodNumber];//采蜜蜂  //每個(gè)采樣點(diǎn)都有人在計(jì)算(采蜜/IO)
BeeGroup OnLooker[FoodNumber];//觀察蜂  //楣黍?
BeeGroup BestSource;//記錄最好蜜源  //記錄最有解的input或者output,或者都記錄棱烂∽馄看到initial就是到時(shí)最有xy對(duì)。

/*****函數(shù)的聲明*****/
double random(double, double);//產(chǎn)生區(qū)間上的隨機(jī)數(shù)  
void initilize();//初始化參數(shù)  
double calculationTruefit(BeeGroup);//計(jì)算真實(shí)的函數(shù)值  
double calculationFitness(double);//計(jì)算適應(yīng)值  
void CalculateProbabilities();//計(jì)算輪盤賭的概率  
void evalueSource();//評(píng)價(jià)蜜源  
void sendEmployedBees();//采蜜蜂颊糜,計(jì)算蜂哩治,局部變異蜂
void sendOnlookerBees();//觀察蜂?
void sendScoutBees();//偵察蜂衬鱼?
void MemorizeBestSource();//記錄最有解xy對(duì)的函數(shù)

/*******主函數(shù)*******/
int main()
{
    ofstream output; output.open("dataABC.txt");//寫文件
    srand((unsigned)time(NULL));//生成隨機(jī)數(shù)业筏,隨機(jī)種子是時(shí)間
    
    initilize();//初始化  
    MemorizeBestSource();//保存最好的蜜源  

    int gen = 0;
    while (gen < maxCycle) {
        sendEmployedBees();//體現(xiàn)計(jì)算蜂功能的時(shí)候到了//ok,計(jì)算蜂的功能是在采樣點(diǎn)附近找更優(yōu)的解鸟赫。//這個(gè)函數(shù)只是進(jìn)行了一次局部搜索
        CalculateProbabilities();
        sendOnlookerBees();//Onlook的功能是什么蒜胖?也是進(jìn)行一次局部變異
        MemorizeBestSource();
        sendScoutBees();//局部嘗試若干次,無法找到最優(yōu)解抛蚤,就換個(gè)地方找找
        MemorizeBestSource();
        output << setprecision(10) << BestSource.trueFit << ","<< BestSource.code[0]<<","<< BestSource.code[1] << endl;
        gen++;
    }


    output.close();
    cout << "運(yùn)行結(jié)束!!" << endl;//C++編程語言互換流中的標(biāo)準(zhǔn)輸出流台谢,需要iostream支持。
    system("pause");
    return 0;
}

void initilize()//初始化參數(shù)  
{
    int i, j;
    for (i = 0; i<FoodNumber; i++) //就是隨機(jī)取多少個(gè)可行解岁经。
    {
        for (j = 0; j<D; j++)//如果輸入x是向量的話就要用到D对碌,就是一共有幾個(gè)輸入。
        {
            NectarSource[i].code[j] = random(lb, ub);//cout << NectarSource[i].code[j] << endl;
            //code表示輸入x蒿偎,是隨機(jī)生成的可行解朽们。lb, ub是給定了上下界。NectarSource[i]也是xy對(duì)诉位,但為什么取名Nectar骑脱,和其他類似數(shù)組有何區(qū)別不得而知。
            EmployedBee[i].code[j] = NectarSource[i].code[j];
            //同樣苍糠,計(jì)算蜂也是xy對(duì)叁丧,EmployedBee[i].code[j] = NectarSource[i].code[j];表示蜜源Nectar被計(jì)算了,交給Employ計(jì)算/采蜜了
            OnLooker[i].code[j] = NectarSource[i].code[j];
            //OnLook的功能岳瞭?
            BestSource.code[j] = NectarSource[0].code[j];
            //BestSource是用來存放最有xy對(duì)的拥娄。
        }
        /****蜜源的初始化*****/
        NectarSource[i].trueFit = calculationTruefit(NectarSource[i]);//cout << NectarSource[i].trueFit << endl;
        NectarSource[i].fitness = calculationFitness(NectarSource[i].trueFit); //cout << NectarSource[i].fitness << endl;
        NectarSource[i].rfitness = 0;
        NectarSource[i].trail = 0;
        /****采蜜蜂的初始化*****/
        //采蜜蜂的計(jì)算功能由蜜源承擔(dān)了
        EmployedBee[i].trueFit = NectarSource[i].trueFit;
        EmployedBee[i].fitness = NectarSource[i].fitness;
        EmployedBee[i].rfitness = NectarSource[i].rfitness;
        EmployedBee[i].trail = NectarSource[i].trail;
        /****觀察蜂的初始化****/
        //觀察蜂的功能仍然不清楚
        OnLooker[i].trueFit = NectarSource[i].trueFit;
        OnLooker[i].fitness = NectarSource[i].fitness;
        OnLooker[i].rfitness = NectarSource[i].rfitness;
        OnLooker[i].trail = NectarSource[i].trail;
    }
    /*****最優(yōu)蜜源的初始化*****/
    //隨機(jī)選定一個(gè)最有解/初始最優(yōu)解。
    BestSource.trueFit = NectarSource[0].trueFit;
    BestSource.fitness = NectarSource[0].fitness;
    BestSource.rfitness = NectarSource[0].rfitness;
    BestSource.trail = NectarSource[0].trail;
}
double random(double start, double end)//隨機(jī)產(chǎn)生區(qū)間內(nèi)的隨機(jī)數(shù)  
{
    return start + (end - start)*rand() / (RAND_MAX + 1.0);
}
double calculationTruefit(BeeGroup bee)//計(jì)算真實(shí)的函數(shù)值  //外面?zhèn)魅氲拿墼赐ぃ@里傳入的是的形參是bee稚瘾,bee的功能相當(dāng)于一個(gè)橋梁,傳遞參數(shù)姚炕。
{
    //計(jì)算一下目標(biāo)函數(shù)值摊欠。
    double truefit = 0;
    /******測試函數(shù)1******/
    truefit = bee.code[0] * bee.code[0] + bee.code[1] * bee.code[1]; //bee.code[0]* bee.code[1]*bee.code[0]* bee.code[1];

    return truefit;
}
double calculationFitness(double truefit)//計(jì)算適應(yīng)值  //構(gòu)造了一個(gè)連續(xù)遞減函數(shù)
{
    double fitnessResult = 0;
    if (truefit >= 0)
    {
        fitnessResult = 1 / (truefit + 1);
    }
    else
    {
        fitnessResult = 1 + abs(truefit);
    }
    return fitnessResult;
}
//以上4個(gè)函數(shù)共同完成了initial 操作,下面返回主函數(shù)
//主函數(shù)下一步是保存最好蜜源柱宦,就是最有xy解些椒。
void MemorizeBestSource()//保存最優(yōu)的蜜源  //就是把當(dāng)前最優(yōu)解與第i次循環(huán)中所有采蜜點(diǎn)比較
{
    int i, j;
    for (i = 1; i<FoodNumber; i++)
    {
        if (NectarSource[i].trueFit<BestSource.trueFit)
        {
            for (j = 0; j<D; j++)
            {
                BestSource.code[j] = NectarSource[i].code[j];
            }
            BestSource.trueFit = NectarSource[i].trueFit;
        }
    }
}
void sendEmployedBees()//修改采蜜蜂的函數(shù)  
{
    int i, j, k;
    int param2change;//需要改變的維數(shù)  
    double Rij;//[-1,1]之間的隨機(jī)數(shù)  
    for (i = 0; i<FoodNumber; i++){//對(duì)于每個(gè)采樣點(diǎn)都隨機(jī)局部變換
        //對(duì)每個(gè)采樣點(diǎn)都遍歷一遍
        param2change = (int)random(0, D);//隨機(jī)選取需要改變的維數(shù),取向量輸入x的一個(gè)子集掸刊。 
        /******選取不等于i的k********/
        while (1){
            k = (int)random(0, FoodNumber);
            if (k != i){
                break;
            }
        }
        for (j = 0; j<D; j++){
            EmployedBee[i].code[j] = NectarSource[i].code[j];
        }
        /*******采蜜蜂去更新信息*******/
        Rij = random(-1, 1);
        EmployedBee[i].code[param2change] = (1- Rij)*NectarSource[i].code[param2change] + Rij*(NectarSource[k].code[param2change]);
        //隨機(jī)選擇一個(gè)局部點(diǎn)位code[param2change]免糕,在這個(gè)點(diǎn)位上把采樣點(diǎn)i和k的值進(jìn)行雜交
        /*******判斷是否越界********/
        if (EmployedBee[i].code[param2change]>ub){
            EmployedBee[i].code[param2change] = ub;
        }
        if (EmployedBee[i].code[param2change]<lb){
            EmployedBee[i].code[param2change] = lb;
        }
        EmployedBee[i].trueFit = calculationTruefit(EmployedBee[i]);
        EmployedBee[i].fitness = calculationFitness(EmployedBee[i].trueFit);

        /******貪婪選擇策略*******/
        if (EmployedBee[i].trueFit<NectarSource[i].trueFit){
            for (j = 0; j<D; j++){
                NectarSource[i].code[j] = EmployedBee[i].code[j];
            }
            NectarSource[i].trail = 0;
            NectarSource[i].trueFit = EmployedBee[i].trueFit;
            NectarSource[i].fitness = EmployedBee[i].fitness;
        }
        else{
            NectarSource[i].trail++;
        }
    }
}
void CalculateProbabilities()//計(jì)算輪盤賭的選擇概率  
{
    int i;
    double maxfit;
    maxfit = NectarSource[0].fitness;
    for (i = 1; i<FoodNumber; i++)
    {
        if (NectarSource[i].fitness>maxfit)
            maxfit = NectarSource[i].fitness;
    }

    for (i = 0; i<FoodNumber; i++)
    {
        NectarSource[i].rfitness = (0.9*(NectarSource[i].fitness / maxfit)) + 0.1;
    }
}
void sendOnlookerBees()//采蜜蜂與觀察蜂交流信息,觀察蜂更改信息  
{
    int i, j, t, k;
    double R_choosed;//被選中的概率  
    int param2change;//需要被改變的維數(shù)  
    double Rij;//[-1,1]之間的隨機(jī)數(shù)  
    i = 0;
    t = 0;
    while (t<FoodNumber){
        R_choosed = random(0, 1);
        if (R_choosed<NectarSource[i].rfitness){//根據(jù)被選擇的概率選擇  //對(duì)于每個(gè)采樣點(diǎn)忧侧,都在局部變動(dòng)一次石窑,一定會(huì)被選擇,不選擇t就保持不變苍柏,
            //不出循環(huán)尼斧,t<FoodNumber,說明t和全局采樣點(diǎn)有關(guān)试吁。i是NectarSource中的一點(diǎn)棺棵,說明也與全局采樣點(diǎn)有關(guān)。
            t++;
            param2change = (int)random(0, D);//選擇變異的x分量param2change
            /******選取不等于i的k********/
            while (1){
                k = (int)random(0, FoodNumber);
                if (k != i){
                    break;
                }
            }
            for (j = 0; j<D; j++){
                OnLooker[i].code[j] = NectarSource[i].code[j];
            }
            /****更新******///完成對(duì)param2change的變異熄捍,i=t-1
            Rij = random(-1, 1);
            OnLooker[i].code[param2change] =(1-Rij)*NectarSource[i].code[param2change] + Rij*(NectarSource[k].code[param2change]);

            /*******判斷是否越界*******/
            if (OnLooker[i].code[param2change]<lb){
                OnLooker[i].code[param2change] = lb;
            }
            if (OnLooker[i].code[param2change]>ub){
                OnLooker[i].code[param2change] = ub;
            }
            OnLooker[i].trueFit = calculationTruefit(OnLooker[i]);
            OnLooker[i].fitness = calculationFitness(OnLooker[i].trueFit);

            /****貪婪選擇策略******/
            if (OnLooker[i].trueFit<NectarSource[i].trueFit){
                for (j = 0; j<D; j++)
                {
                    NectarSource[i].code[j] = OnLooker[i].code[j];
                }
                NectarSource[i].trail = 0;
                NectarSource[i].trueFit = OnLooker[i].trueFit;
                NectarSource[i].fitness = OnLooker[i].fitness;
            }
            else
            {
                NectarSource[i].trail++;
            }
        }
        i++;
        if (i == FoodNumber)
        {
            i = 0;
        }
    }
}
/*******只有一只偵查蜂**********/
void sendScoutBees()//判斷是否有偵查蜂的出現(xiàn)烛恤,有則重新生成蜜源  
{
    int maxtrialindex, i, j;
    double R;//[0,1]之間的隨機(jī)數(shù)  
    maxtrialindex = 0;
    for (i = 1; i<FoodNumber; i++)
    {
        if (NectarSource[i].trail>NectarSource[maxtrialindex].trail)
        {
            maxtrialindex = i;
        }
    }
    if (NectarSource[maxtrialindex].trail >= limit)
    {
        /*******重新初始化*********/
        for (j = 0; j<D; j++)
        {
            R = random(0, 1);
            NectarSource[maxtrialindex].code[j] = lb + R*(ub - lb);
        }
        NectarSource[maxtrialindex].trail = 0;
        NectarSource[maxtrialindex].trueFit = calculationTruefit(NectarSource[maxtrialindex]);
        NectarSource[maxtrialindex].fitness = calculationFitness(NectarSource[maxtrialindex].trueFit);
    }
}

這段代碼解決的問題是x12+x22,迭代10次余耽,結(jié)果可以缚柏,如圖所示。

收斂趨勢

還有一個(gè)問題碟贾,Onlooker和Employed的區(qū)別是什么币喧?
EmployedBees:將采蜜蜂與蜜源一一對(duì)應(yīng)轨域,根據(jù)上面第一個(gè)公式更新蜜源信息,同時(shí)確定蜜源的花蜜量杀餐;對(duì)于每個(gè)采礦點(diǎn)干发,先進(jìn)行一次試探性的局部搜索。
OnlookerBees:根據(jù)試探的結(jié)果史翘,有選擇性的進(jìn)一步挖掘枉长。挖掘就是多試幾次。多產(chǎn)生幾次隨機(jī)數(shù)琼讽。利用輪盤賭概率必峰,選中某個(gè)采礦點(diǎn),然后在其附近搜索钻蹬。
ScoutBees:當(dāng)所有的采蜜蜂和觀察蜂都搜索完整個(gè)搜索空間時(shí)吼蚁,如果一個(gè)蜜源的適應(yīng)值在給定的步驟內(nèi)(定義為控制參數(shù)“l(fā)imit”) 沒有被提高, 則丟棄該蜜源,而與該蜜源相對(duì)應(yīng)的采蜜蜂變成偵查蜂脉让,偵查蜂通過已下公式搜索新的可能解桂敛。意思就是說生產(chǎn)全局最優(yōu)解。

俄羅斯輪盤賭的選擇情況如下圖溅潜,但是OnlookerBees不是這么選的术唬。t<=FoodNumber,就是說選中20次滚澜,至于選哪個(gè)粗仓,從0個(gè)開礦點(diǎn)開始,沒被選中设捐,就換下一個(gè)采礦點(diǎn)借浊。選中了t=t+1;然后再對(duì)第i個(gè)采礦點(diǎn)進(jìn)行局部變異搜索萝招。那么ABC里的選擇方法比輪盤賭又高明了一點(diǎn)蚂斤。


Paste_Image.png

case 2


Paste_Image.png

Paste_Image.png

經(jīng)過多次對(duì)照,確實(shí)可以求到近似最優(yōu)解槐沼。
【-1曙蒸,5】,最小值在5附近岗钩,ABC算法求導(dǎo)的最優(yōu)解確實(shí)4.9x纽窟,沒錯(cuò)。


Paste_Image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兼吓,一起剝皮案震驚了整個(gè)濱河市臂港,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖审孽,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件县袱,死亡現(xiàn)場離奇詭異,居然都是意外死亡瓷胧,警方通過查閱死者的電腦和手機(jī)显拳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搓萧,“玉大人,你說我怎么就攤上這事宛畦∪陈澹” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵次和,是天一觀的道長反肋。 經(jīng)常有香客問我,道長踏施,這世上最難降的妖魔是什么石蔗? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮畅形,結(jié)果婚禮上养距,老公的妹妹穿的比我還像新娘。我一直安慰自己日熬,他們只是感情好棍厌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著竖席,像睡著了一般耘纱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毕荐,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天束析,我揣著相機(jī)與錄音,去河邊找鬼憎亚。 笑死员寇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的虽填。 我是一名探鬼主播丁恭,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼斋日!你這毒婦竟也來了牲览?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎第献,沒想到半個(gè)月后贡必,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡庸毫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年仔拟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片飒赃。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡利花,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出载佳,到底是詐尸還是另有隱情炒事,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布蔫慧,位于F島的核電站挠乳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏姑躲。R本人自食惡果不足惜睡扬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望黍析。 院中可真熱鬧卖怜,春花似錦、人聲如沸橄仍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侮繁。三九已至虑粥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宪哩,已是汗流浹背娩贷。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锁孟,地道東北人彬祖。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像品抽,于是被迫代替她去往敵國和親储笑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容