该算法是于2020年提出的一种新型智能优化算法。冠状病毒群免疫优化算法(CHIO)灵感来源于应对冠状病毒大流行(2019冠状病毒疾病)的群体免疫概念。传播冠状病毒的速度取决于感染者如何与其他社会成员直接接触。为了保护社会其他成员免受这种疾病的侵害,健康专家建议社会疏远。群体免疫是当大多数群体具有免疫力时,群体达到的一种状态,这种状态可以防止疾病的传播。
未经允许不得转载。
本专栏除了针对本科、研究生的数学建模比赛以外,有些内容是个人研究,比如本文就是。不会出现在比赛里面的算法,所以如果你对它没有兴趣,可以跳过本篇。尊重劳动成果,每一篇我都是花了很多的时间研究与编写。
这是一种新的受自然启发的基于人类的优化算法,称为冠状病毒群体免疫优化器(CHIO)。CHIO 的灵感源于群体免疫概念,作为应对冠状病毒大流行 (COVID-19) 的一种方式。冠状病毒感染的传播速度取决于感染者与其他社会成员的直接接触方式。
为了保护其他社会成员免受疾病侵害,健康专家建议保持社交距离。群体免疫是当大多数人口具有免疫力时,人口达到的一种状态,可防止疾病传播。这些概念是根据优化概念建模的。CHIO 模仿群体免疫策略以及社会疏离概念
三种类型的个案用于群体免疫:易感、感染和免疫。这是为了确定新生成的解决方案如何通过社交距离策略更新其基因。CHIO 使用 23 个著名的基准函数进行评估。最初,研究了 CHIO 对其参数的敏感性。此后,对七种最先进的方法进行了比较评估。比较分析证实,与其他成熟方法获得的结果相比,CHIO 能够产生极具竞争力的结果。为了进行更多验证,使用了从 IEEE-CEC 2011 中提取的三个实际工程优化问题。CHIO 再次被证明是有效的。总之,CHIO 是一种非常强大的优化算法,可用于解决各种优化领域的许多优化问题
病毒通常在人群中迅速传播和进化。卫生界通常使用疫苗来建立对病毒的免疫力。然而,新病毒需要一段时间才能发现它们。同时,医疗保健组织建议采用以下两种方式之一来治疗病毒:
群体免疫是指人口中有足够多的人对感染具有免疫力,从而能够有效阻止该疾病传播的情况。对于群体免疫,无论免疫是来自疫苗接种还是来自患病者都无关紧要。关键是它们是免疫的。
群体免疫受基本繁殖率的影响,基本繁殖率代表有多少人可能会被传播病例感染。这可以表明疾病在人群中传播的速度。一般来说,当免疫病例数达到人口的很大比例(即大于60%)时,人口将被屏蔽,不会出现更多的感染病例,这个比例称为群体免疫阈值。
传播病例会通过感染,感染者的免疫系统将保留对该疾病的免疫记忆。这将使受感染的人将来能够对该病毒产生免疫力,从而阻止疾病的传播。
对冠状病毒群体免疫概念进行了数学建模,以开发所提出的优化算法。该算法依赖于如何通过将大多数未感染的易感人群转变为免疫人群来最好地保护社区免受疾病侵害的概念。结果,即使是剩余的易感病例也不会被感染,因为免疫人群将不再传播疾病。
群体免疫中个体可分为三种类型:易感、感染和免疫(分为未恢复和恢复)个体。
下图显示了这三种类型的个体是如何分布的。该图表示为一棵树,其中根是受感染的个体,边缘指向接触的人。右图显示,如果根个体被免疫,病毒就不会传播给其接触的个体。因此,它在功能上被用作抵御病毒流行的防火墙。
对于这三类人群,有如下定义
当根据优化上下文设计 CHIO 时,为了表示人口的层次结构,易感个体从人口中占据很大一部分。第二部分人口被标记为感染者,由少数人发起,代表人口中出现的第一批感染者,如果他们不遵循社交距离的规则建议,直到所有受感染的个体要么免疫(即康复),要么死亡。人口的最后一部分是免疫个体。。最后一个过程中,大多数人都免疫了,因此疫情的流行就停止了。
在病毒大流行的情况下,社交距离的概念被用作减少感染传播的策略。通常,政府和医疗机构建议采取此类行动,建议个人在去拥挤的地方时彼此之间保持 2 米(6.5 英尺)的距离。其他一些预防措施可以避开拥挤的地方,如商场、学校和大学。
社交距离的影响如下图所示。疾病的传播将下降,最终可能导致大流行的爆发。病毒的传播链将被打破,从而减缓疾病的传播速度,并以较少的感染病例达到大流行高峰。因此,该国的医疗保健系统将能够继续为较少的感染病例提供服务。
上图显示的两个正态分布图显示了社交距离在控制大流行传播方面的作用。显然,保持社交距离将使感染病例分布的时间更长,从而减少了未满足的需求区域。
在 CHIO 中,社会距离的概念是通过将当前个体与可能易感、感染或免疫的人群中选定的个体之间的差异来实现的。
一些国家(例如,英国和瑞典)使用使用受控群体免疫来控制 COVID-19 的概念。
瑞典对群体免疫采取了一种受控的方法,让学校、餐馆和大多数企业保持开放,并要求其公民自愿保持社交距离。瑞典的群体免疫需要比预期更长的时间。如图所示,它显示了 2020 年 2 月至 2020 年 5 月瑞典的确诊病例和死亡人数。截至 2020 年 6 月 28 日,瑞典有 65,137 例确诊病例和 5,280 人死亡
一些国家(如英国)允许病毒传播以提高人群的群体免疫力,同时保护老年人,因为他们最容易感染这种病毒。英国政府建议使用群体免疫来遏制 COVID-19 ,下图显示了 2020 年 2 月至 2020 年 5 月期间英国确诊病例数和死亡人数随时间的下降情况。截至 2020 年 6 月 28 日,英国有 310,254 例确诊病例和 43,514 例死亡
初始化 CHIO 的参数和优化问题 在这一步中,优化问题在目标函数的上下文中表述如下(l b lblb和u b ubub分别为搜索的上下限)
CHIO 有四个算法参数和两个控制参数。四个算法参数是
CHIO 有两个主要的控制参数需要在这一步初始化:
产生最初群体免疫群体 ,CHIO 随机(或启发式地)产生一组与 HIS 一样多的病例(个人)。生成的案例存储为大小n*HIS的二维矩阵
其中每一行 j 代表一个案例
利用步骤一计算每种情况的目标函数(或免疫率)。
冠状病毒群体免疫进化这是CHIO的主要改进循环。基础繁殖率(BRr)。
式中i 为个体编号,j 为维度,r 为[0,1]内一随机值。现在我们分情况来讨论:
简单来讲即先选出适应度值排名前三的个体作为xc、xm、xv,其状态向量(S)分别为1、0、2,然后根据r 值执行相应的更新。
此时首先采用贪心策略进行位置更新,但是这里有个重要的操作,那就是年龄Age:所有个体的初始年龄均为0,迭代一次后年龄加1,当到达100岁后即认为该个体死亡,所有参数重新初始化。可以看做是一种增加种群多样性的操作。
之后对状态向量S 进行更新
式中is_Corona是一个二进制值,当在群体免疫进化操作中该个体被感染时,该值等于1。
这部分就等于群体适应度平均值。可以看出,当个体的适应度值低于平均值且是易感人群且被感染了,那么他必然成为感染者;而当其适应度值大于平均值且是感染者时,他就会被群体免疫净化了
如果新生成的个体免疫力优于人群的平均免疫力,则人群中的个体免疫力将根据之前计算的社会距离进行更改。这意味着我们开始拥有更好的免疫人口。如果新产生的人口足够强大,可以免疫大流行,那么我们就达到了群体免疫阈值。
(f(xj(t+1)) 当前感染病例 (Sj== 1) 在参数 Max_Age 指定的特定迭代次数内无法改善。那么这个案子就被认为是死了。之后,它使用从头开始重生,使用该公式计算:
此外,Aj和 Sj被设置为零。这有助于使当前人口多样化,从而避免局部最优。
停止标准 CHIO 重复步骤 3 到步骤 6,直到终止标准,这通常取决于是否达到最大迭代次数。在这种情况下,易感和免疫病例的总数在人群中占主导地位。感染病例也消失了。
迭代次数150,000 ,运行次数25,其他参数的设置包括HIS=30,BRr=0.01,Max age=100可以得到最佳结果。
我找到了Matlab官网发布的程序,可官网下载:
https://www.mathworks.com/matlabcentral/fileexchange/103905-coronavirus-herd-immunity-optimizer-chio?s_tid=FX_rc1_behav
也可以通过我的网盘下载:
链接:https://pan.baidu.com/s/1VKTv8z54Ss6Khen3fg0E3Q?pwd=1lti
提取码:1lti
当然,我也希望用python实现一次。
模块编写,文件名:CHIO.py,该文件建议不要修改任何参数:
import numpy as np
from copy import deepcopy
from mealpy.optimizer import Optimizer
class OriginalCHIO(Optimizer):
"""
The original version of: Coronavirus Herd Immunity Optimization (CHIO)
Links:
1. https://link.springer.com/article/10.1007/s00521-020-05296-6
Hyper-parameters should fine-tune in approximate range to get faster convergence toward the global optimum:
+ brr (float): [0.05, 0.2], Basic reproduction rate, default=0.15
+ max_age (int): [5, 20], Maximum infected cases age, default=10
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.human_based.CHIO import OriginalCHIO
>>>
>>> def fitness_function(solution):
>>> return np.sum(solution**2)
>>>
>>> problem_dict1 = {
>>> "fit_func": fitness_function,
>>> "lb": [-10, -15, -4, -2, -8],
>>> "ub": [10, 15, 12, 8, 20],
>>> "minmax": "min",
>>> }
>>>
>>> epoch = 1000
>>> pop_size = 50
>>> brr = 0.15
>>> max_age = 10
>>> model = OriginalCHIO(problem_dict1, epoch, pop_size, brr, max_age)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_fitness}")
References
~~~~~~~~~~
[1] Al-Betar, M.A., Alyasseri, Z.A.A., Awadallah, M.A. et al. Coronavirus herd immunity optimizer (CHIO).
Neural Comput & Applic 33, 5011–5042 (2021). https://doi.org/10.1007/s00521-020-05296-6
"""
def __init__(self, problem, epoch=10000, pop_size=100, brr=0.15, max_age=10, **kwargs):
"""
Args:
problem (dict): The problem dictionary
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
brr (float): Basic reproduction rate, default=0.15
max_age (int): Maximum infected cases age, default=10
"""
super().__init__(problem, kwargs)
self.epoch = self.validator.check_int("epoch", epoch, [1, 100000])
self.pop_size = self.validator.check_int("pop_size", pop_size, [10, 10000])
self.brr = self.validator.check_float("brr", brr, (0, 1.0))
self.max_age = self.validator.check_int("max_age", max_age, [1, 1+int(epoch/5)])
self.nfe_per_epoch = self.pop_size
self.sort_flag = False
def after_initialization(self):
_, self.g_best = self.get_global_best_solution(self.pop)
self.immunity_type_list = np.random.randint(0, 3, self.pop_size) # Randint [0, 1, 2]
self.age_list = np.zeros(self.pop_size) # Control the age of each position
self.finished = False
def evolve(self, epoch):
"""
The main operations (equations) of algorithm. Inherit from Optimizer class
Args:
epoch (int): The current iteration
"""
pop_new = []
is_corona_list = [False, ] * self.pop_size
for i in range(0, self.pop_size):
pos_new = deepcopy(self.pop[i][self.ID_POS])
for j in range(0, self.problem.n_dims):
rand = np.random.uniform()
if rand < (1.0 / 3) * self.brr:
idx_candidates = np.where(self.immunity_type_list == 1) # Infected list
if idx_candidates[0].size == 0:
self.finished = True
# print("Epoch: {}, i: {}, immunity_list: {}".format(epoch, i, self.immunity_type_list))
break
idx_selected = np.random.choice(idx_candidates[0])
pos_new[j] = self.pop[i][self.ID_POS][j] + np.random.uniform() * \
(self.pop[i][self.ID_POS][j] - self.pop[idx_selected][self.ID_POS][j])
is_corona_list[i] = True
elif (1.0 / 3) * self.brr <= rand < (2.0 / 3) * self.brr:
idx_candidates = np.where(self.immunity_type_list == 0) # Susceptible list
idx_selected = np.random.choice(idx_candidates[0])
pos_new[j] = self.pop[i][self.ID_POS][j] + np.random.uniform() * \
(self.pop[i][self.ID_POS][j] - self.pop[idx_selected][self.ID_POS][j])
elif (2.0 / 3) * self.brr <= rand < self.brr:
idx_candidates = np.where(self.immunity_type_list == 2) # Immunity list
fit_list = np.array([self.pop[item][self.ID_TAR][self.ID_FIT] for item in idx_candidates[0]])
idx_selected = idx_candidates[0][np.argmin(fit_list)] # Found the index of best fitness
pos_new[j] = self.pop[i][self.ID_POS][j] + np.random.uniform() * \
(self.pop[i][self.ID_POS][j] - self.pop[idx_selected][self.ID_POS][j])
if self.finished:
break
pos_new = self.amend_position(pos_new, self.problem.lb, self.problem.ub)
pop_new.append([pos_new, None])
if self.mode not in self.AVAILABLE_MODES:
pop_new[-1][self.ID_TAR] = self.get_target_wrapper(pos_new)
pop_new = self.update_target_wrapper_population(pop_new)
if len(pop_new) != self.pop_size:
pop_child = self.create_population(self.pop_size - len(pop_new))
pop_new = pop_new + pop_child
for idx in range(0, self.pop_size):
# Step 4: Update herd immunity population
if self.compare_agent(pop_new[idx], self.pop[idx]):
self.pop[idx] = deepcopy(pop_new[idx])
else:
self.age_list[idx] += 1
## Calculate immunity mean of population
fit_list = np.array([item[self.ID_TAR][self.ID_FIT] for item in self.pop])
delta_fx = np.mean(fit_list)
if (self.compare_agent(pop_new[idx], [None, [delta_fx, None]])) and (self.immunity_type_list[idx] == 0) and is_corona_list[idx]:
self.immunity_type_list[idx] = 1
self.age_list[idx] = 1
if (self.compare_agent([None, [delta_fx, None]], pop_new[idx])) and (self.immunity_type_list[idx] == 1):
self.immunity_type_list[idx] = 2
self.age_list[idx] = 0
# Step 5: Fatality condition
if (self.age_list[idx] >= self.max_age) and (self.immunity_type_list[idx] == 1):
self.pop[idx] = self.create_solution(self.problem.lb, self.problem.ub)
self.immunity_type_list[idx] = 0
self.age_list[idx] = 0
class BaseCHIO(OriginalCHIO):
"""
My changed version of: Coronavirus Herd Immunity Optimization (CHIO)
Hyper-parameters should fine-tune in approximate range to get faster convergence toward the global optimum:
+ brr (float): [0.05, 0.2], Basic reproduction rate, default=0.15
+ max_age (int): [5, 20], Maximum infected cases age, default=10
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.human_based.CHIO import BaseCHIO
>>>
>>> def fitness_function(solution):
>>> return np.sum(solution**2)
>>>
>>> problem_dict1 = {
>>> "fit_func": fitness_function,
>>> "lb": [-10, -15, -4, -2, -8],
>>> "ub": [10, 15, 12, 8, 20],
>>> "minmax": "min",
>>> }
>>>
>>> epoch = 1000
>>> pop_size = 50
>>> brr = 0.15
>>> max_age = 10
>>> model = BaseCHIO(problem_dict1, epoch, pop_size, brr, max_age)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_fitness}")
"""
def __init__(self, problem, epoch=10000, pop_size=100, brr=0.15, max_age=10, **kwargs):
"""
Args:
problem (dict): The problem dictionary
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
brr (float): Basic reproduction rate, default=0.15
max_age (int): Maximum infected cases age, default=10
"""
super().__init__(problem, epoch, pop_size, brr, max_age, **kwargs)
def evolve(self, epoch):
"""
The main operations (equations) of algorithm. Inherit from Optimizer class
Args:
epoch (int): The current iteration
"""
pop_new = []
is_corona_list = [False, ] * self.pop_size
for i in range(0, self.pop_size):
pos_new = deepcopy(self.pop[i][self.ID_POS])
for j in range(0, self.problem.n_dims):
rand = np.random.uniform()
if rand < (1.0 / 3) * self.brr:
idx_candidates = np.where(self.immunity_type_list == 1) # Infected list
if idx_candidates[0].size == 0:
rand_choice = np.random.choice(range(0, self.pop_size), int(0.33 * self.pop_size), replace=False)
self.immunity_type_list[rand_choice] = 1
idx_candidates = np.where(self.immunity_type_list == 1)
idx_selected = np.random.choice(idx_candidates[0])
pos_new[j] = self.pop[i][self.ID_POS][j] + np.random.uniform() * \
(self.pop[i][self.ID_POS][j] - self.pop[idx_selected][self.ID_POS][j])
is_corona_list[i] = True
elif (1.0 / 3) * self.brr <= rand < (2.0 / 3) * self.brr:
idx_candidates = np.where(self.immunity_type_list == 0) # Susceptible list
if idx_candidates[0].size == 0:
rand_choice = np.random.choice(range(0, self.pop_size), int(0.33 * self.pop_size), replace=False)
self.immunity_type_list[rand_choice] = 0
idx_candidates = np.where(self.immunity_type_list == 0)
idx_selected = np.random.choice(idx_candidates[0])
pos_new[j] = self.pop[i][self.ID_POS][j] + np.random.uniform() * \
(self.pop[i][self.ID_POS][j] - self.pop[idx_selected][self.ID_POS][j])
elif (2.0 / 3) * self.brr <= rand < self.brr:
idx_candidates = np.where(self.immunity_type_list == 2) # Immunity list
fit_list = np.array([self.pop[item][self.ID_TAR][self.ID_FIT] for item in idx_candidates[0]])
idx_selected = idx_candidates[0][np.argmin(fit_list)] # Found the index of best fitness
pos_new[j] = self.pop[i][self.ID_POS][j] + np.random.uniform() * \
(self.pop[i][self.ID_POS][j] - self.pop[idx_selected][self.ID_POS][j])
if self.finished:
break
pos_new = self.amend_position(pos_new, self.problem.lb, self.problem.ub)
pop_new.append([pos_new, None])
if self.mode not in self.AVAILABLE_MODES:
pop_new[-1][self.ID_TAR] = self.get_target_wrapper(pos_new)
pop_new = self.update_target_wrapper_population(pop_new)
for idx in range(0, self.pop_size):
# Step 4: Update herd immunity population
if self.compare_agent(pop_new[idx], self.pop[idx]):
self.pop[idx] = deepcopy(pop_new[idx])
else:
self.age_list[idx] += 1
## Calculate immunity mean of population
fit_list = np.array([item[self.ID_TAR][self.ID_FIT] for item in self.pop])
delta_fx = np.mean(fit_list)
if (self.compare_agent(pop_new[idx], [None, [delta_fx, None]])) and (self.immunity_type_list[idx] == 0) and is_corona_list[idx]:
self.immunity_type_list[idx] = 1
self.age_list[idx] = 1
if (self.compare_agent([None, [delta_fx, None]], pop_new[idx])) and (self.immunity_type_list[idx] == 1):
self.immunity_type_list[idx] = 2
self.age_list[idx] = 0
# Step 5: Fatality condition
if (self.age_list[idx] >= self.max_age) and (self.immunity_type_list[idx] == 1):
self.pop[idx] = self.create_solution(self.problem.lb, self.problem.ub)
self.immunity_type_list[idx] = 0
self.age_list[idx] = 0
代码部分严格按照作者原文编写,这是原文:
https://link.springer.com/article/10.1007/s00521-020-05296-6
与CHIO.py的同级目录建立一个目标函数进行测试。这样:
测试代码如下:
from CHIO import OriginalCHIO
import numpy as np
# 目标函数
def fitness_function(solution):
return np.sum(solution ** 2)
# 问题定义
problem_dict1 = {
"fit_func": fitness_function,
"lb": [-10, -15, -4, -2, -8],
"ub": [10, 15, 12, 8, 20],
"minmax": "min",
}
pop_size = 50 # 种群规模
epoch = 1000 # 迭代次数
brr = 0.15 # BRr值
max_age = 10 # 最大年龄
model = OriginalCHIO(problem_dict1, epoch, pop_size, brr, max_age) # 传入参数
best_position, best_fitness = model.solve() # 求解
print(f"Solution: {best_position}, Fitness: {best_fitness}") # 打印最优值
结果如下:
Solution: [-0.37709366 0.08123882 -0.36440879 -0.52289409 1.4873688 ], Fitness: 2.767277305804889
最佳免疫率(目标值)为2.767277305804889。
文中参数BRr的值决定了冠状病毒大流行在人群中传播的速度。较高的BRr值会导致疾病传播率较高,因此勘探规模较大;较小的值会产生低的病毒传播率,使得开发性能增强,但是较低的BRr值又会导致最优个体引导受限。
https://blog.csdn.net/u011835903/article/details/121465952
https://link.springer.com/article/10.1007/s00521-020-05296-6