奇迹969

 

连续问题北极熊算法

import matplotlib;
matplotlib.use('TkAgg')
from pylab import *
mpl.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题
import numpy as np
from tqdm import tqdm  # 进度条设置
import random
# 更改了位置更新函数,

class PBO(object):
    """"
     M:种群最大容量
     m:种群当前规模大小
     N:目标函数解的维度
     T:迭代次数
     V:最大视野距离
     P:初始化种群数量百分比
     K:动态调整规模参数
     B:变量限制范围
     X:解集合
     """
    def __init__(self):
        self.M =50
        self.N= 2
        self.T= 200
        self.V= 0.3
        self.P= 0.75
        self.K= 0.25
        self.x_min = -32  #暂时设置每个维度的可移动范围相同,实际需要根据N个维度进行设置
        self.x_max = 32
        self.m = int(np.floor(self.M*self.P)) #随后期的繁衍和死亡会变化


        # 初始化种群

    def init_x(self):
        """
        :return:
        """
        X = np.zeros((self.M, self.N))
        X[:self.m] = np.random.random((self.m, self.N)) * (self.x_max - self.x_min) + self.x_min
        return X

    def fitness(self,X):
        """
        有待更改
        :param X:
        :return:
        """
        # y = X[0]+X[1]+X[2]+X[3]+X[4]+X[5]+X[6]+X[7]+X[8]+X[9]
        y = -1*np.sum(X**2)
        return y

    def up_data(self,index,angle,radius,action,X):
        """
        局部搜索中的位置更新公式  公式看原版文献csdn有误
        :param index:每一只熊的的编号
        :param angle:angles [0,2pi]
        :param X[index][0]:第index只熊的0维
        :param radius:
        :param action:
        :param X:
        :return:
        """
        temp = np.zeros(self.N)
        result = 0
        if "add".__eq__(action):
            x_temp = X[index][0] + radius * np.cos(angle[0])
        else:
            x_temp = X[index][0] - radius * np.cos(angle[0])
        if x_temp>=self.x_min and x_temp<=self.x_max:
            temp[0] = x_temp
        elif x_temp<self.x_min :
            temp[0] = self.x_min
        elif x_temp>self.x_max:
            temp[0] = self.x_max


        #因为从第2到n-1只熊由通用计算工时
        for i in range(self.N-2):
            result += np.sin(angle[i])
            if "add".__eq__(action):
                x_temp = X[index][i+1] + radius * (result+np.cos(angle[i+1]))
            else:
                x_temp = X[index][i+1] - radius * (result+np.cos(angle[i+1]))
            if x_temp >= self.x_min and x_temp <= self.x_max:
                temp[i + 1] = x_temp
            elif x_temp < self.x_min:
                temp[i + 1] = self.x_min
            elif x_temp > self.x_max:
                temp[i + 1] = self.x_max
        if "add".__eq__(action):
            x_temp = X[index][self.N-1] + radius * (result + np.sin(angle[self.N-2]))
        else:
            x_temp = X[index][self.N-1] - radius * (result + np.sin(angle[self.N-2]))
        if x_temp >= self.x_min and x_temp <= self.x_max:
            temp[self.N-1] = x_temp
        elif x_temp < self.x_min:
            temp[self.N-1] = self.x_min
        elif x_temp > self.x_max:
            temp[self.N-1] = self.x_max
        return temp

    def move_local(self,X):
        """
        局部更新 (包含搜索半径 和局部更新)
        :param X:
        :return:
        r=4acos(φ)sin(φ)
        """
        # 对每个北极熊设计随机角度  根据公式计算出搜索半径  r=4acos(φ)sin(φ)
        for i in range(self.m):
            angles = np.random.random(self.N-1) * 2 * np.pi  # [0,2pi]用于局部搜索中的位置更新
            sta = np.random.random() * self.V  # [0,0.3]
            angle0 = np.random.random() * np.pi / 2  # [0,pi/2]
            # 搜索半径
            r = 4 * sta * np.cos(angle0) * np.sin(angle0)
            # using the sign of add
            tmp = self.up_data(i, angles, r, 'add', X)
            if self.fitness(tmp) > self.fitness(X[i]):
                X[i] = tmp
            else:
                tmp = self.up_data(i, angles, r, 'minus', X)
            if self.fitness(tmp) > self.fitness(X[i]):
                X[i] = tmp
        return X

    def move_globle(self,X,xbest):
        """
        浮水漂移,全局搜索
        X:M行N列的二维矩阵 ,每一个子矩阵代表一个多纬度的北极熊
        全局位置更新
        :return:
        """
        for i in range(self.m):
            # 每一只熊的W
            w = np.sqrt(np.sum(xbest - X[i]) ** 2)    #w是n-1个维度的欧氏距离
            alpha = np.random.random()
            gamma = np.random.random() * w  # 0-w之间的随机数
            x_temp = X[i] + np.sign(w) * alpha + gamma

            x_temp[x_temp<self.x_min] = self.x_min
            x_temp[x_temp>self.x_max] = self.x_max
            if self.fitness(x_temp) > self.fitness(X[i]):
                 X[i] = x_temp
        return X


    def fit_best(self,X,f_best,x_best):
        fits = np.zeros(self.m)
        for i in range(self.m):
            #找个体最优
            fits[i] = self.fitness(X[i])
        arg = np.argsort(fits[:self.m])
        if fits[arg[-1]]>=f_best:
            f_best = fits[arg[-1]]
            x_best = X[arg[-1]]
        return f_best,x_best,fits


    def zhongqunfangyan(self,X,x_best,fits):
        k = np.random.random()
        arg = np.argsort(fits[:self.m])
        # 种群繁衍
        if self.m < self.M - 1 and k > 0.75:
            # 从前10%中随机抽取一个 个体与最好个体交配 生成新的个体
            idx = random.randint(1, np.floor(self.m * 0.1) + 1)
            X[self.m] = (x_best + X[arg[self.m-1-idx]]) / 2
            self.m += 1
        # 最弱个体死亡
        if self.m > self.M * 0.5 and k < 0.25:
            # arg中排序最后的为最弱个体
            # 死亡之后 后面的所有个体往前移动一个位置
            X[arg[0]:self.m] = X[arg[0] + 1:self.m + 1]
            self.m -= 1
        return  X

    def main(self):
        fitness_list = []    #画图使用
        x_best_list=[]
        X = self.init_x()
        f_best = -1*np.inf   #表示负无穷
        x_best = 0
        f_best,x_best,fits = self.fit_best(X,f_best,x_best)
        fitness_list.append(f_best)


        #先局部后全局搜索
        for i in tqdm(range(self.T)):
            X = self.move_local(X)
            X = self.move_globle(X,x_best)
            print(i)
            #计算当前适应度
            f_best, x_best,fits= self.fit_best(X, f_best, x_best)
            fitness_list.append(f_best)
            print(x_best)
            #种群动态变化
            X = self.zhongqunfangyan(X,x_best,fits)
            f_best, x_best, fits = self.fit_best(X, f_best, x_best)
        print("最大适应度值:", f_best, '个体为:', x_best)
        plt.plot(fitness_list, "--")
        plt.xlabel('迭代次数', size=15)
        plt.ylabel('fitness', size=15)
        plt.legend()
        plt.show()

if __name__ == '__main__':

       pbo = PBO()
       pbo.main()

 

posted on 2022-04-02 14:21  奇迹969  阅读(113)  评论(0)    收藏  举报

导航