ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

启发式算法/人工蜂群算法

2022-03-19 10:02:57  阅读:154  来源: 互联网

标签:蜂群 蜜源 get self np 算法 蜜蜂 启发式 role


原理

在这里插入图片描述
介绍:

  • limit:采蜜蜂蜜源被跟随蜂选择一定次数后蜜源质量仍然低于跟随蜂蜜源把这些采蜜蜂变成工蜂
  • num:固定保留+随机保留采蜜蜂之后剩余的采蜜蜂数量

分工:

  • 工蜂负责采蜜
  • 侦查蜂负责在田野里寻找蜜源(全局搜索)
  • 采蜜蜂负责保留蜜源信息和招募跟随蜂
  • 跟随蜂负责在它选择的采蜜蜂周围寻找新蜜源(局部搜索)

过程

  • 开始大家都是工蜂
  • 派出一部分工蜂作为侦查蜂,在田野里寻找蜜源
  • 蜜源平均质量以上的侦查蜂变采蜜蜂,平均质量一下的侦查蜂变工蜂
  • 采蜜蜂跳舞招募跟随蜂(从工蜂中派出一部分工蜂作为跟随蜂)在采蜜蜂蜜源周围寻找新蜜源
  • 如果跟随蜂找到的新蜜源质量比采蜜蜂好,跟随蜂变成采蜜蜂,后面可以去招募跟随蜂;跟随蜂蜜源质量好于原采蜜蜂,采蜜蜂蜜源被跟随蜂选择一定次数后蜜源质量仍然低于跟随蜂蜜源把这些采蜜蜂变成工蜂

轮盘赌算法:
在这里插入图片描述

代码

采蜜步骤:

  1. 初始化种群,全部是工蜂
  2. 开始迭代
  3. 派出侦查蜂,侦查蜂占工蜂10%~20%
  4. 蜜源平均质量以上的侦查蜂变采蜜蜂,平均质量一下的侦查蜂变工蜂
  5. 采蜜蜂招募跟随蜂,跟随蜂占工蜂10%~20%
  6. 跟随蜂轮盘赌选择采蜜蜂蜜源,在选择的采蜜蜂蜜源周围寻找新蜜源
  7. 如果跟随蜂找到的新蜜源质量比采蜜蜂好,跟随蜂变成采蜜蜂,后面可以去招募跟随蜂;跟随蜂蜜源质量好于原采蜜蜂,采蜜蜂蜜源被跟随蜂选择一定次数后蜜源质量仍然低于跟随蜂找到的新蜜源把这些采蜜蜂变成工蜂
  8. 保存此次迭代结果
  9. 固定保留(%20到50%)最好采蜜蜂,随机保留剩下(10%到20%)采蜜蜂,其余蜜蜂变工蜂
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from enum import Enum

matplotlib.rcParams['font.family'] = 'STSong'
matplotlib.rcParams['font.size'] = 10


def fitness_F1(x):
    """
    F1函数
    :param x: 粒子当前位置 一个解4维
    :return: 适应度
    """
    return -np.sum(x ** 2) + 900


class Role(Enum):
    """
    角色枚举
    """
    WORKER = 0
    SCOUT = 1
    PICKER = 2
    FOLLOWER = 3


class BeeWorker(object):
    """
    工蜂
    """

    def __init__(self, id, x=None, role=Role.WORKER):
        """
        初始化方法
        :param: id: 唯一标识
        :param: x: 蜜源位置
        :param: role: 工蜂角色(工蜂,侦查蜂,采蜜蜂,跟随蜂)
        """
        self.__id = id
        self.__x = x
        self.__role = role

    def set_id(self, id):
        """
        setter id
        :return:
        """
        self.__id = id

    def get_id(self):
        """
        getter id
        :return:
        """
        return self.__id

    def set_role(self, role):
        """
        设置角色
        :param role:
        :return: self
        """
        self.__role = role
        return self

    def get_role(self):
        """
        getter
        :return:
        """
        return self.__role

    def set_x(self, x):
        """
        setter x
        :return:
        """
        self.__x = x

    def get_x(self):
        """
        获取x
        :return:
        """
        return self.__x


class ArtificialBeeColonyAlgorithm(object):
    """
    算法
    """

    def __init__(self, iter_num, fitness_end, x_min, x_max, NP, D, limit):
        """
        初始化方法
        :param iter_num: 迭代次数
        :param fitness_end: 截止适应度
        :param x_min: 下界
        :param x_max: 上界
        :param NP: 工蜂数量
        :param D: 蜜源位置维度
        :param limit: 蜜源保留次数
        """
        # 截止条件
        self.iter_num = iter_num
        self.fitness_end = fitness_end
        # 解空间
        self.x_min = x_min
        self.x_max = x_max
        # 求解者
        self.NP = NP
        self.D = D
        self.beeWorkers = None
        # 算法参数
        self.limit = limit
        # 蜂巢保存最好蜜源
        self.fitness_list = []

    def initilize_pop(self):
        """
        种群初始化
        :return:
        """
        # 初始化种群
        # todo bee  worker
        self.beeWorkers = [BeeWorker(i, role=Role.WORKER) for i in range(self.NP)]

    def gather(self):
        """
        采蜜
        :param: beeWorker 工蜂
        :return:
        """
        workers = [bee for bee in self.beeWorkers if bee.get_role() == Role.WORKER]
        beeid_limit = {worker.get_id(): 0 for worker in workers}  # dict生成式
        for it in range(self.iter_num):
            # 侦查蜂
            ## 侦查蜂占工蜂10%~20%
            workers = [bee for bee in self.beeWorkers if bee.get_role() == Role.WORKER]
            num_worker = len(workers)
            rs = np.random.uniform(0.1, 0.2, 1)  # 范围随机数
            num_scout = int(num_worker * rs)
            ## 工蜂变成侦查蜂
            scouts = [bee.set_role(Role.SCOUT) for bee in workers[:num_scout]]
            ## 侦查蜂全局搜索蜜源
            pop_scout = np.random.uniform(self.x_min, self.x_max, (num_scout, self.D))
            for i in range(0, num_scout):
                scouts[i].set_x(pop_scout[i])
            ## 侦查蜂适应度好于平均适应度变采蜜蜂,坏于变工蜂
            fit_scouts = np.array([fitness_F1(scout.get_x()) for scout in scouts])
            fit_avg = np.average(fit_scouts)
            for scout in scouts:
                if fitness_F1(scout.get_x()) >= fit_avg:
                    scout.set_role(Role.PICKER)
                else:
                    scout.set_role(Role.WORKER)
            # 跟随蜂
            workers = [bee for bee in self.beeWorkers if bee.get_role() == Role.WORKER]
            num_worker = len(workers)
            ## 跟随蜂占工蜂10%~20%
            rf = np.random.uniform(0.1, 0.2, 1)  # 范围随机数
            num_follower = int(num_worker * rf)
            followers = [worker.set_role(Role.FOLLOWER) for worker in workers[:num_follower]]
            pickers = [bee for bee in self.beeWorkers if bee.get_role() == Role.PICKER]
            ## 跟随蜂 局部搜索蜜源
            for i in range(num_follower):
                ## 轮盘赌选择跟随采蜜蜂
                sum_fit = np.sum([fitness_F1(one.get_x()) for one in pickers])
                p_fits = [fitness_F1(one.get_x()) / sum_fit for one in pickers]
                p_cumsum = np.array(p_fits).cumsum()  # np累计求和
                p_cumsum_1 = np.copy(p_cumsum)  # 深拷贝
                r1 = np.random.random()
                p_cumsum_1 -= r1
                picker1 = pickers[list(p_cumsum_1 > 0).index(True)]  # 返回第1个大于0的索引
                p_cumsum_2 = np.copy(p_cumsum)
                r2 = np.random.random()
                p_cumsum_2 -= r2
                picker2 = pickers[list(p_cumsum_2 > 0).index(True)]
                rr = np.random.random((self.D,))
                follower_x_temp = np.array(picker1.get_x()) + (
                        np.array(picker1.get_x()) - np.array(picker2.get_x())) * rr
                ## 防止越界
                follower_x = np.clip(follower_x_temp, self.x_min, self.x_max)
                ## 跟随蜂蜜源 好于 采蜜蜂蜜源,跟随蜂变采蜜蜂,采蜜蜂变工蜂;跟随蜂蜜源 坏于 采蜜蜂蜜源,跟随蜂变工蜂;
                if fitness_F1(follower_x) <= fitness_F1(picker1.get_x()):
                    followers[i].set_role(Role.WORKER)
                    num_follower -= 1
                    continue
                if fitness_F1(follower_x) <= fitness_F1(picker2.get_x()):
                    followers[i].set_role(Role.WORKER)
                    num_follower -= 1
                    continue
                followers[i].set_role(Role.PICKER)
                followers[i].set_x(follower_x)
                num_follower -= 1
                # 跟随蜂蜜源好于采蜜蜂蜜源limit次 采蜜蜂变为工蜂(丢弃蜜源)
                if beeid_limit[picker1.get_id()] > self.limit:
                    picker1.set_role(Role.WORKER)
                else:
                    beeid_limit[picker1.get_id()] = beeid_limit[picker1.get_id()] + 1
                pass
                if beeid_limit[picker2.get_id()] > self.limit:
                    picker2.set_role(Role.WORKER)
                else:
                    beeid_limit[picker2.get_id()] = beeid_limit[picker2.get_id()] + 1
                pass

            # 保存结果
            pickers = [bee for bee in self.beeWorkers if bee.get_role() == Role.PICKER]
            x_pickers = np.array([picker.get_x() for picker in pickers])
            fit_pickers = np.array([fitness_F1(picker.get_x()) for picker in pickers])
            fit_max_picker = np.max(fit_pickers)
            x_max_picker = x_pickers[np.argmax(fit_pickers)]
            self.fitness_list.append(fit_max_picker)
            print('第', it + 1, '迭代', ',蜜源位置:', x_max_picker, ',最佳适应度:', self.fitness_list[-1])
            # 截止条件
            if self.fitness_end < fit_max_picker:
                break
            pass
            # 固定保留(%20~50%)最好采蜜蜂,随机保留剩下(10%~20%)采蜜蜂,其余蜜蜂变工蜂
            pickers.sort(key=lambda picker: fitness_F1(picker.get_x()))  # lambda param: return expression
            len_p = len(pickers)
            rp = np.random.uniform(0.2, 0.5, 1)
            num_fix = int(len_p * rp)
            pickers_rest = pickers[:-int(num_fix)]
            np.random.shuffle(pickers_rest)
            len_pr = len(pickers_rest)
            rpr = np.random.uniform(0.1, 0.2, 1)
            num_retain = int(len_pr * rpr)
            picker_workers = pickers_rest[num_retain:]
            for pw in picker_workers: pw.set_role(Role.WORKER)
            pickers = [bee for bee in self.beeWorkers if bee.get_role() == Role.PICKER]
            np.random.shuffle(pickers)
            print("采蜜蜂数量:", len(pickers))
        pass
        return x_max_picker, self.fitness_list

    def show(self, x_best, fitness_list):
        """
        展示迭代过程
        :param x_best: 最优解
        :param fitness_list: 每次迭代适应度值
        :return:
        """
        print("最优解:", str(x_best))
        print("最优适应度:", str(fitness_list[-1]))

        plt.title("迭代过程")
        plt.xlabel("迭代次数")
        plt.ylabel("适应度")
        x = range(1, len(fitness_list) + 1)
        y = fitness_list
        plt.plot(x, y, label="ABC")
        plt.legend()
        plt.show()


if __name__ == "__main__":
    abc = ArtificialBeeColonyAlgorithm(100, 900, -30, 30, 1000, 3, 6)
    abc.initilize_pop()
    x_best, fitness_list = abc.gather()
    abc.show(x_best, fitness_list)

标签:蜂群,蜜源,get,self,np,算法,蜜蜂,启发式,role
来源: https://blog.csdn.net/baidu_35805755/article/details/123588580

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有