天天看點

python 實作布谷鳥算法(CS)

在網上搜尋沒有發現比較完整用Python寫的CS算法,隻能自己動手編寫一個。

CS算法注意事項:

1.執行流程是,初始化 -> levy飛行變換巢穴位置 -> 與之前的巢穴對比保留好的巢穴 -> 按照發現機率值丢棄部分巢穴重新生成 ->

-> 再與之前的巢穴對比保留好的巢穴 ->判斷循環是否結束 ->  ............

2.levy飛行步長的計算通常是使用Mantegna方法模拟二維平面萊維飛行

3.疊代公式中大量涉及随機數,需要注意的是一部分是服從均勻分布,還有部分是服從正态分布

4.編寫可以參照yang的matlab代碼源代碼(參考的連結中包含源代碼)

Python代碼如下:

公式就不寫了,可以參考連結。

from random import uniform
from random import randint
import math
import numpy as np
import matplotlib.pyplot as plt
'''
根據levy飛行計算新的巢穴位置
'''
def GetNewNestViaLevy(Xt,Xbest,Lb,Ub,lamuda):
    beta = 1.5
    sigma_u = (math.gamma(1 + beta) * math.sin(math.pi * beta / 2) / (
                math.gamma((1 + beta) / 2) * beta * (2 ** ((beta - 1) / 2)))) ** (1 / beta)
    sigma_v = 1
    for i in range(Xt.shape[0]):
        s = Xt[i,:]
        u = np.random.normal(0, sigma_u, 1)
        v = np.random.normal(0, sigma_v, 1)
        Ls = u / ((abs(v)) ** (1 / beta))
        stepsize = lamuda*Ls*(s-Xbest)   #lamuda的設定關系到點的活力程度  方向是由最佳位置确定的  有點類似PSO算法  但是步長不一樣
        s = s + stepsize * np.random.randn(1, len(s))  #産生滿足正态分布的序列
        Xt[i, :] = s
        Xt[i,:] = simplebounds(s,Lb,Ub)
    return Xt
'''
按pa抛棄部分巢穴
'''
def empty_nests(nest,Lb,Ub,pa):
    n = nest.shape[0]
    nest1 = nest.copy()
    nest2 = nest.copy()
    rand_m =pa - np.random.rand(n,nest.shape[1])
    rand_m = np.heaviside(rand_m,0)
    np.random.shuffle(nest1)
    np.random.shuffle(nest2)
    # stepsize = np.random.rand(1,1) * (nest1 - nest)
    stepsize = np.random.rand(1,1) * (nest1 - nest2)
    new_nest = nest + stepsize * rand_m
    nest = simplebounds(new_nest,Lb,Ub)
    return nest
'''
獲得目前最優解
'''
def get_best_nest(nest, newnest,Nbest,nest_best):
    fitall = 0
    for i in range (nest.shape[0]):
        temp1 = fitness(nest[i,:])
        temp2 = fitness(newnest[i,:])
        if temp1 > temp2:
            nest[i, :] = newnest[i,:]
            if temp2 < Nbest :
                Nbest = temp2
                nest_best = nest[i,:]
            fitall = fitall + temp2
        else:
            fitall = fitall + temp1
    meanfit = fitall/nest.shape[0]
    return  nest , Nbest , nest_best ,meanfit

'''
進行适應度計算
'''
def fitness(nest_n):
    X = nest_n[0]
    Y = nest_n[1]
    # rastrigin函數
    A = 10
    Z = 2 * A + X ** 2 - A * np.cos(2 * np.pi * X) + Y ** 2 - A * np.cos(2 * np.pi * Y)


    return Z
'''
進行全部适應度計算
'''
def fit_function(X,Y):
    # rastrigin函數
    A = 10
    Z = 2 * A + X ** 2 - A * np.cos(2 * np.pi * X) + Y ** 2 - A * np.cos(2 * np.pi * Y)
    return Z
'''
限制疊代結果
'''
def simplebounds(s,Lb,Ub):
    for i in range(s.shape[0]):
        for j in range(s.shape[1]):
            if s[i][j] < Lb[j]:
                s[i][j] = Lb[j]
            if s[i][j] > Ub[j]:
                s[i][j] = Ub[j]
    return s

def Get_CS(lamuda = 1,pa =0.25):
    Lb=[-5,-5] #下界
    Ub=[5,5]   #上界
    population_size = 20
    dim = 2
    nest= np.random.uniform(Lb[0], Ub[0],(population_size,dim))  # 初始化位置
    nest_best = nest[0,:]
    Nbest =fitness(nest_best)
    nest ,Nbest, nest_best ,fitmean = get_best_nest(nest,nest,Nbest,nest_best)
    for i in range (30):
        nest_c = nest.copy()
        newnest = GetNewNestViaLevy(nest_c, nest_best, Lb, Ub,lamuda) # 根據萊維飛行産生新的位置

        nest,Nbest, nest_best ,fitmean = get_best_nest(nest, newnest,Nbest, nest_best) # 判斷新的位置優劣進行替換

        nest_e = nest.copy()
        newnest = empty_nests(nest_e,Lb,Ub,pa) #丢棄部分巢穴

        nest,Nbest, nest_best ,fitmean = get_best_nest(nest,newnest, Nbest, nest_best)  # 再次判斷新的位置優劣進行替換

    print("最優解的适應度函數值",Nbest)
    return  Nbest
Get_CS()
           

代碼如果需要使用的話,建議仔細檢查,雖然我檢查沒有發現問題。有不對的地方歡迎指正。

參考:

https://blog.csdn.net/zyqblog/article/details/80905019

https://vlight.me/2017/12/17/Cuckoo-Search/

文獻:動态适應布谷鳥搜尋算法  《控制與政策》 2014年