#!/usr/bin/env python
# Created by "Thieu" at 08:57, 12/03/2023 ----------%
# Email: nguyenthieu2102@gmail.com %
# Github: https://github.com/thieu1995 %
# --------------------------------------------------%
import numpy as np
from mealpy.optimizer import Optimizer
[docs]class OriginalHCO(Optimizer):
"""
The original version of: Human Conception Optimizer (HCO)
Links:
1. https://www.mathworks.com/matlabcentral/fileexchange/124200-human-conception-optimizer-hco
2. https://www.nature.com/articles/s41598-022-25031-6
Notes:
1. This algorithm shares some similarities with the PSO algorithm (equations)
2. The implementation of Matlab code is kinda different to the paper
Hyper-parameters should fine-tune in approximate range to get faster convergence toward the global optimum:
+ wfp (float): (0, 1.) - weight factor for probability of fitness selection, default=0.65
+ wfv (float): (0, 1.0) - weight factor for velocity update stage, default=0.05
+ c1 (float): (0., 3.0) - acceleration coefficient, same as PSO, default=1.4
+ c2 (float): (0., 3.0) - acceleration coefficient, same as PSO, default=1.4
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy import FloatVar, HCO
>>>
>>> def objective_function(solution):
>>> return np.sum(solution**2)
>>>
>>> problem_dict = {
>>> "bounds": FloatVar(n_vars=30, lb=(-10.,) * 30, ub=(10.,) * 30, name="delta"),
>>> "minmax": "min",
>>> "obj_func": objective_function
>>> }
>>>
>>> model = HCO.OriginalHCO(epoch=1000, pop_size=50)
>>> g_best = model.solve(problem_dict)
>>> print(f"Solution: {g_best.solution}, Fitness: {g_best.target.fitness}")
>>> print(f"Solution: {model.g_best.solution}, Fitness: {model.g_best.target.fitness}")
References
~~~~~~~~~~
[1] Acharya, D., & Das, D. K. (2022). A novel Human Conception Optimizer for solving optimization problems. Scientific Reports, 12(1), 21631.
"""
def __init__(self, epoch: int = 10000, pop_size: int = 100, wfp: float = 0.65,
wfv: float = 0.05, c1: float = 1.4, c2: float = 1.4, **kwargs: object) -> None:
"""
Args:
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
wfp (float): weight factor for probability of fitness selection, default=0.65
wfv (float): weight factor for velocity update stage, default=0.05
c1 (float): acceleration coefficient, same as PSO, default=1.4
c2 (float): acceleration coefficient, same as PSO, default=1.4
"""
super().__init__(**kwargs)
self.epoch = self.validator.check_int("epoch", epoch, [1, 100000])
self.pop_size = self.validator.check_int("pop_size", pop_size, [5, 10000])
self.wfp = self.validator.check_float("wfp", wfp, [0, 1.0])
self.wfv = self.validator.check_float("wfv", wfv, [0, 1.0])
self.c1 = self.validator.check_float("c1", c1, [0., 100.])
self.c2 = self.validator.check_float("c2", c2, [1., 100.])
self.set_parameters(["epoch", "pop_size", "wfp", "wfv", "c1", "c2"])
self.sort_flag = False
[docs] def initialization(self):
if self.pop is None:
self.pop = self.generate_population(self.pop_size)
pop_op = []
for idx in range(0, self.pop_size):
pos_new = self.problem.ub + self.problem.lb - self.pop[idx].solution
pos_new = self.correct_solution(pos_new)
agent = self.generate_empty_agent(pos_new)
pop_op.append(agent)
if self.mode not in self.AVAILABLE_MODES:
agent.target = self.get_target(pos_new)
self.pop[idx] = self.get_better_agent(agent, self.pop[idx], self.problem.minmax)
if self.mode in self.AVAILABLE_MODES:
pop_op = self.update_target_for_population(pop_op)
self.pop = self.greedy_selection_population(self.pop, pop_op, self.problem.minmax)
_, (best,), (worst,) = self.get_special_agents(self.pop, n_best=1, n_worst=1, minmax=self.problem.minmax)
pfit = (worst.target.fitness - best.target.fitness) * self.wfp + best.target.fitness
for idx in range(0, self.pop_size):
if self.compare_fitness(pfit, self.pop[idx].target.fitness, self.problem.minmax):
while True:
agent = self.generate_agent()
if self.compare_fitness(agent.target.fitness, pfit, self.problem.minmax):
self.pop[idx] = agent
break
self.vec = self.generator.uniform(self.problem.lb, self.problem.ub, (self.pop_size, self.problem.n_dims))
self.pop_p = [agent.copy() for agent in self.pop]
[docs] def evolve(self, epoch):
"""
The main operations (equations) of algorithm. Inherit from Optimizer class
Args:
epoch (int): The current iteration
"""
lamda = self.generator.random()
neu = 2
fits = np.array([agent.target.fitness for agent in self.pop])
fit_mean = np.mean(fits)
RR = (self.g_best.target.fitness - fits) ** 2
rr = (fit_mean - fits) ** 2
ll = RR - rr
LL = (self.g_best.target.fitness - fit_mean)
VV = lamda * (ll / (4 * neu * LL))
pop_new = []
for idx in range(0, self.pop_size):
a1 = self.pop_p[idx].solution - self.pop[idx].solution
a2 = self.g_best.solution - self.pop[idx].solution
self.vec[idx] = self.wfv * (VV[idx] + self.vec[idx]) + self.c1 * a1*np.sin(2*np.pi*epoch/self.epoch) + self.c2*a2*np.sin(2*np.pi*epoch/self.epoch)
pos_new = self.pop[idx].solution + self.vec[idx]
pos_new = self.correct_solution(pos_new)
agent = self.generate_empty_agent(pos_new)
pop_new.append(agent)
if self.mode not in self.AVAILABLE_MODES:
pop_new[-1].target = self.get_target(pos_new)
if self.mode in self.AVAILABLE_MODES:
pop_new = self.update_target_for_population(pop_new)
for idx in range(0, self.pop_size):
if self.compare_target(pop_new[idx].target, self.pop[idx].target, self.problem.minmax):
self.pop[idx] = pop_new[idx].copy()
if self.compare_target(pop_new[idx].target, self.pop_p[idx].target, self.problem.minmax):
self.pop_p[idx] = pop_new[idx].copy()