启发式算法/人工蜂群算法
作者:互联网
原理
介绍:
- limit:采蜜蜂蜜源被跟随蜂选择一定次数后蜜源质量仍然低于跟随蜂蜜源把这些采蜜蜂变成工蜂
- num:固定保留+随机保留采蜜蜂之后剩余的采蜜蜂数量
分工:
- 工蜂负责采蜜
- 侦查蜂负责在田野里寻找蜜源(全局搜索)
- 采蜜蜂负责保留蜜源信息和招募跟随蜂
- 跟随蜂负责在它选择的采蜜蜂周围寻找新蜜源(局部搜索)
过程
- 开始大家都是工蜂
- 派出一部分工蜂作为侦查蜂,在田野里寻找蜜源
- 蜜源平均质量以上的侦查蜂变采蜜蜂,平均质量一下的侦查蜂变工蜂
- 采蜜蜂跳舞招募跟随蜂(从工蜂中派出一部分工蜂作为跟随蜂)在采蜜蜂蜜源周围寻找新蜜源
- 如果跟随蜂找到的新蜜源质量比采蜜蜂好,跟随蜂变成采蜜蜂,后面可以去招募跟随蜂;跟随蜂蜜源质量好于原采蜜蜂,采蜜蜂蜜源被跟随蜂选择一定次数后蜜源质量仍然低于跟随蜂蜜源把这些采蜜蜂变成工蜂
轮盘赌算法:
代码
采蜜步骤:
- 初始化种群,全部是工蜂
- 开始迭代
- 派出侦查蜂,侦查蜂占工蜂10%~20%
- 蜜源平均质量以上的侦查蜂变采蜜蜂,平均质量一下的侦查蜂变工蜂
- 采蜜蜂招募跟随蜂,跟随蜂占工蜂10%~20%
- 跟随蜂轮盘赌选择采蜜蜂蜜源,在选择的采蜜蜂蜜源周围寻找新蜜源
- 如果跟随蜂找到的新蜜源质量比采蜜蜂好,跟随蜂变成采蜜蜂,后面可以去招募跟随蜂;跟随蜂蜜源质量好于原采蜜蜂,采蜜蜂蜜源被跟随蜂选择一定次数后蜜源质量仍然低于跟随蜂找到的新蜜源把这些采蜜蜂变成工蜂
- 保存此次迭代结果
- 固定保留(%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