Source code for mealpy.swarm_based.HGS

# !/usr/bin/env python
# Created by "Thieu" at 15:37, 19/03/2021 ----------%
#       Email: nguyenthieu2102@gmail.com            %
#       Github: https://github.com/thieu1995        %
# --------------------------------------------------%

import numpy as np
from copy import deepcopy
from mealpy.optimizer import Optimizer


[docs]class OriginalHGS(Optimizer): """ The original version of: Hunger Games Search (HGS) Links: https://aliasgharheidari.com/HGS.html Hyper-parameters should fine tuned in approximate range to get faster convergen toward the global optimum: + PUP (float): [0.01, 0.2], The probability of updating position (L in the paper), default = 0.08 + LH (float): [1000, 20000], Largest hunger / threshold, default = 10000 Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy.swarm_based.HGS import OriginalHGS >>> >>> 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", >>> "verbose": True, >>> } >>> >>> epoch = 1000 >>> pop_size = 50 >>> PUP = 0.08 >>> LH = 10000 >>> model = OriginalHGS(problem_dict1, epoch, pop_size, PUP, LH) >>> best_position, best_fitness = model.solve() >>> print(f"Solution: {best_position}, Fitness: {best_fitness}") References ~~~~~~~~~~ [1] Yang, Y., Chen, H., Heidari, A.A. and Gandomi, A.H., 2021. Hunger games search: Visions, conception, implementation, deep analysis, perspectives, and towards performance shifts. Expert Systems with Applications, 177, p.114864. """ ID_HUN = 2 # ID for Hunger value def __init__(self, problem, epoch=10000, pop_size=100, PUP=0.08, LH=10000, **kwargs): """ Args: problem (dict): The problem dictionary epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 PUP (float): The probability of updating position (L in the paper), default = 0.08 LH (float): Largest hunger / threshold, default = 10000 """ super().__init__(problem, kwargs) self.nfe_per_epoch = pop_size self.sort_flag = False self.epoch = epoch self.pop_size = pop_size self.PUP = PUP self.LH = LH
[docs] def create_solution(self): """ To get the position, fitness wrapper, target and obj list + A[self.ID_POS] --> Return: position + A[self.ID_TAR] --> Return: [target, [obj1, obj2, ...]] + A[self.ID_TAR][self.ID_FIT] --> Return: target + A[self.ID_TAR][self.ID_OBJ] --> Return: [obj1, obj2, ...] Returns: list: wrapper of solution with format [position, [target, [obj1, obj2, ...]], hunger] """ position = np.random.uniform(self.problem.lb, self.problem.ub) position = self.amend_position(position) fitness = self.get_fitness_position(position=position) hunger = 1.0 return [position, fitness, hunger]
[docs] def sech(self, x): if np.abs(x) > 50: return 0.5 return 2 / (np.exp(x) + np.exp(-x))
[docs] def update_hunger_value(self, pop=None, g_best=None, g_worst=None): # min_index = pop.index(min(pop, key=lambda x: x[self.ID_TAR][self.ID_FIT])) # Eq (2.8) and (2.9) for i in range(0, self.pop_size): r = np.random.rand() # space: since we pass lower bound and upper bound as list. Better take the np.mean of them. space = np.mean(self.problem.ub - self.problem.lb) H = (pop[i][self.ID_TAR][self.ID_FIT] - g_best[self.ID_TAR][self.ID_FIT]) / \ (g_worst[self.ID_TAR][self.ID_FIT] - g_best[self.ID_TAR][self.ID_FIT] + self.EPSILON) * r * 2 * space if H < self.LH: H = self.LH * (1 + r) pop[i][self.ID_HUN] += H if g_best[self.ID_TAR][self.ID_FIT] == pop[i][self.ID_TAR][self.ID_FIT]: pop[i][self.ID_HUN] = 0 return pop
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ ## Eq. (2.2) ### Find the current best and current worst g_best, g_worst = self.get_global_best_global_worst_solution(self.pop) pop = self.update_hunger_value(self.pop, g_best, g_worst) ## Eq. (2.4) shrink = 2 * (1 - (epoch + 1) / self.epoch) total_hunger = np.sum([pop[idx][self.ID_HUN] for idx in range(0, self.pop_size)]) pop_new = [] for idx in range(0, self.pop_size): current_agent = deepcopy(self.pop[idx]) #### Variation control E = self.sech(current_agent[self.ID_TAR][self.ID_FIT] - g_best[self.ID_TAR][self.ID_FIT]) # R is a ranging controller added to limit the range of activity, in which the range of R is gradually reduced to 0 R = 2 * shrink * np.random.rand() - shrink # Eq. (2.3) ## Calculate the hungry weight of each position if np.random.rand() < self.PUP: W1 = current_agent[self.ID_HUN] * self.pop_size / (total_hunger + self.EPSILON) * np.random.rand() else: W1 = 1 W2 = (1 - np.exp(-abs(current_agent[self.ID_HUN] - total_hunger))) * np.random.rand() * 2 ### Udpate position of individual Eq. (2.1) r1 = np.random.rand() r2 = np.random.rand() if r1 < self.PUP: pos_new = current_agent[self.ID_POS] * (1 + np.random.normal(0, 1)) else: if r2 > E: pos_new = W1 * g_best[self.ID_POS] + R * W2 * abs(g_best[self.ID_POS] - current_agent[self.ID_POS]) else: pos_new = W1 * g_best[self.ID_POS] - R * W2 * abs(g_best[self.ID_POS] - current_agent[self.ID_POS]) current_agent[self.ID_POS] = self.amend_position(pos_new) pop_new.append(current_agent) self.pop = self.update_fitness_population(pop_new)