Source code for mealpy.human_based.QSA

#!/usr/bin/env python
# Created by "Thieu" at 10:21, 18/03/2020 ----------%
#       Email: nguyenthieu2102@gmail.com            %
#       Github: https://github.com/thieu1995        %
# --------------------------------------------------%

import numpy as np
from mealpy.optimizer import Optimizer


[docs]class DevQSA(Optimizer): """ The developed version: Queuing Search Algorithm (QSA) Notes: + The third loops are removed + Global best solution is used in business 3-th instead of random solution Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, QSA >>> >>> 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 = QSA.DevQSA(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}") """ def __init__(self, epoch: int = 10000, pop_size: int = 100, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 """ 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.set_parameters(["epoch", "pop_size"]) self.sort_flag = True
[docs] def calculate_queue_length__(self, t1, t2, t3): """ Calculate length of each queue based on t1, t2,t3 + t1 = t1 * 1.0e+100 + t2 = t2 * 1.0e+100 + t3 = t3 * 1.0e+100 """ if t1 > 1.0e-6: n1 = (1 / t1) / ((1 / t1) + (1 / t2) + (1 / t3)) n2 = (1 / t2) / ((1 / t1) + (1 / t2) + (1 / t3)) else: n1 = 1.0 / 3 n2 = 1.0 / 3 q1 = int(n1 * self.pop_size) q2 = int(n2 * self.pop_size) q3 = self.pop_size - q1 - q2 return q1, q2, q3
[docs] def update_business_1__(self, pop=None, current_epoch=None): A1, A2, A3 = pop[0].solution, pop[1].solution, pop[2].solution t1, t2, t3 = pop[0].target.fitness, pop[1].target.fitness, pop[2].target.fitness q1, q2, q3 = self.calculate_queue_length__(t1, t2, t3) case = None for idx in range(self.pop_size): if idx < q1: if idx == 0: case = 1 A = A1.copy() elif q1 <= idx < q1 + q2: if idx == q1: case = 1 A = A2.copy() else: if idx == q1 + q2: case = 1 A = A3.copy() beta = np.power(current_epoch, np.power(current_epoch / self.epoch, 0.5)) alpha = self.generator.uniform(-1, 1) E = self.generator.exponential(0.5, self.problem.n_dims) F1 = beta * alpha * (E * np.abs(A - pop[idx].solution)) + self.generator.exponential(0.5) * (A - pop[idx].solution) F2 = beta * alpha * (E * np.abs(A - pop[idx].solution)) if case == 1: pos_new = A + F1 pos_new = self.correct_solution(pos_new) agent = self.generate_agent(pos_new) if self.compare_target(agent.target, pop[idx].target, self.problem.minmax): pop[idx] = agent else: case = 2 else: pos_new = pop[idx].solution + F2 pos_new = self.correct_solution(pos_new) agent = self.generate_agent(pos_new) if self.compare_target(agent.target, pop[idx].target, self.problem.minmax): pop[idx] = agent else: case = 1 return self.get_sorted_population(pop, self.problem.minmax)
[docs] def update_business_2__(self, pop=None): A1, A2, A3 = pop[0].solution, pop[1].solution, pop[2].solution t1, t2, t3 = pop[0].target.fitness, pop[1].target.fitness, pop[2].target.fitness q1, q2, q3 = self.calculate_queue_length__(t1, t2, t3) pr = [idx / self.pop_size for idx in range(1, self.pop_size + 1)] if t1 > 1.0e-005: cv = t1 / (t2 + t3) else: cv = 1.0 / 2 pop_new = [] for idx in range(self.pop_size): if idx < q1: A = A1.copy() elif q1 <= idx < q1 + q2: A = A2.copy() else: A = A3.copy() if self.generator.random() < pr[idx]: i1, i2 = self.generator.choice(self.pop_size, 2, replace=False) if self.generator.random() < cv: X_new = pop[idx].solution + self.generator.exponential(0.5) * (pop[i1].solution - pop[i2].solution) else: X_new = pop[idx].solution + self.generator.exponential(0.5) * (A - pop[i1].solution) else: X_new = self.problem.generate_solution() pos_new = self.correct_solution(X_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) if self.mode not in self.AVAILABLE_MODES: agent.target = self.get_target(pos_new) pop_new[-1] = self.get_better_agent(agent, pop[idx], self.problem.minmax) if self.mode in self.AVAILABLE_MODES: pop_new = self.update_target_for_population(pop_new) pop_new = self.greedy_selection_population(pop, pop_new, self.problem.minmax) return self.get_sorted_and_trimmed_population(pop_new, self.pop_size, self.problem.minmax)
[docs] def update_business_3__(self, pop, g_best): pr = np.array([idx / self.pop_size for idx in range(1, self.pop_size + 1)]) pop_new = [] for idx in range(self.pop_size): X_new = pop[idx].solution.copy() id1 = self.generator.choice(self.pop_size) temp = g_best.solution + self.generator.exponential(0.5, self.problem.n_dims) * (pop[id1].solution - pop[idx].solution) X_new = np.where(self.generator.random(self.problem.n_dims) > pr[idx], temp, X_new) pos_new = self.correct_solution(X_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) if self.mode not in self.AVAILABLE_MODES: agent.target = self.get_target(pos_new) pop_new[-1] = self.get_better_agent(agent, pop[idx], self.problem.minmax) if self.mode in self.AVAILABLE_MODES: pop_new = self.update_target_for_population(pop_new) pop_new = self.greedy_selection_population(pop, pop_new, self.problem.minmax) return pop_new
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ pop = self.update_business_1__(self.pop, epoch) pop = self.update_business_2__(pop) self.pop = self.update_business_3__(pop, self.g_best)
[docs]class OppoQSA(DevQSA): """ The opposition-based learning version: Queuing Search Algorithm (OQSA) Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, QSA >>> >>> 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 = QSA.OppoQSA(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}") """ def __init__(self, epoch: int = 10000, pop_size: int = 100, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 """ super().__init__(epoch, pop_size, **kwargs) self.sort_flag = True
[docs] def opposition_based__(self, pop = None, g_best = None): pop = self.get_sorted_population(pop, self.problem.minmax) pop_new = [] for idx in range(0, self.pop_size): pos_new = self.generate_opposition_solution(pop[idx], g_best) 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: agent.target = self.get_target(pos_new) pop_new[-1] = self.get_better_agent(agent, pop[idx], self.problem.minmax) if self.mode in self.AVAILABLE_MODES: pop_new = self.update_target_for_population(pop_new) pop_new = self.greedy_selection_population(pop, pop_new, self.problem.minmax) return pop_new
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ pop = self.update_business_1__(self.pop, epoch) pop = self.update_business_2__(pop) pop = self.update_business_3__(pop, self.g_best) self.pop = self.opposition_based__(pop, self.g_best)
[docs]class LevyQSA(DevQSA): """ The Levy-flight version: Queuing Search Algorithm (LQSA) Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, QSA >>> >>> 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 = QSA.LevyQSA(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}") """ def __init__(self, epoch: int = 10000, pop_size: int = 100, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 """ super().__init__(epoch, pop_size, **kwargs) self.sort_flag = True
[docs] def update_business_2__(self, pop=None, current_epoch=None): A1, A2, A3 = pop[0].solution, pop[1].solution, pop[2].solution t1, t2, t3 = pop[0].target.fitness, pop[1].target.fitness, pop[2].target.fitness q1, q2, q3 = self.calculate_queue_length__(t1, t2, t3) pr = [idx / self.pop_size for idx in range(1, self.pop_size + 1)] if t1 > 1.0e-6: cv = t1 / (t2 + t3) else: cv = 1 / 2 pop_new = [] for idx in range(self.pop_size): if idx < q1: A = A1.copy() elif q1 <= idx < q1 + q2: A = A2.copy() else: A = A3.copy() if self.generator.random() < pr[idx]: id1 = self.generator.choice(self.pop_size) if self.generator.random() < cv: levy_step = self.get_levy_flight_step(beta=1.0, multiplier=0.001, case=-1) X_new = pop[idx].solution + self.generator.normal(0, 1, self.problem.n_dims) * levy_step else: X_new = pop[idx].solution + self.generator.exponential(0.5) * (A - pop[id1].solution) pos_new = self.correct_solution(X_new) else: pos_new = self.problem.generate_solution() 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: agent.target = self.get_target(pos_new) pop_new[-1] = self.get_better_agent(agent, pop[idx], self.problem.minmax) if self.mode in self.AVAILABLE_MODES: pop_new = self.update_target_for_population(pop_new) pop_new = self.greedy_selection_population(pop, pop_new, self.problem.minmax) return self.get_sorted_and_trimmed_population(pop_new, self.pop_size, self.problem.minmax)
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ pop = self.update_business_1__(self.pop, epoch) pop = self.update_business_2__(pop, epoch) self.pop = self.update_business_3__(pop, self.g_best)
[docs]class ImprovedQSA(OppoQSA, LevyQSA): """ The original version of: Improved Queuing Search Algorithm (QSA) Links: 1. https://doi.org/10.1007/s12652-020-02849-4 Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, QSA >>> >>> 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 = QSA.ImprovedQSA(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] Nguyen, B.M., Hoang, B., Nguyen, T. and Nguyen, G., 2021. nQSV-Net: a novel queuing search variant for global space search and workload modeling. Journal of Ambient Intelligence and Humanized Computing, 12(1), pp.27-46. """ def __init__(self, epoch: int = 10000, pop_size: int = 100, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 """ super().__init__(epoch, pop_size, **kwargs) self.sort_flag = True
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ pop = self.update_business_1__(self.pop, epoch) pop = self.update_business_2__(pop, epoch) pop = self.update_business_3__(pop, self.g_best) self.pop = self.opposition_based__(pop, self.g_best)
[docs]class OriginalQSA(DevQSA): """ The original version of: Queuing Search Algorithm (QSA) Links: 1. https://www.sciencedirect.com/science/article/abs/pii/S0307904X18302890 Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, QSA >>> >>> 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 = QSA.OriginalQSA(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] Zhang, J., Xiao, M., Gao, L. and Pan, Q., 2018. Queuing search algorithm: A novel metaheuristic algorithm for solving engineering optimization problems. Applied Mathematical Modelling, 63, pp.464-490. """ def __init__(self, epoch: int = 10000, pop_size: int = 100, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 """ super().__init__(epoch, pop_size, **kwargs) self.sort_flag = True
[docs] def update_business_3__(self, pop, g_best): pr = [idx / self.pop_size for idx in range(1, self.pop_size + 1)] pop_new = [] for idx in range(self.pop_size): pos_new = pop[idx].solution.copy() for jdx in range(self.problem.n_dims): if self.generator.random() > pr[idx]: i1, i2 = self.generator.choice(self.pop_size, 2, replace=False) e = self.generator.exponential(0.5) X1 = pop[i1].solution X2 = pop[i2].solution pos_new[jdx] = X1[jdx] + e * (X2[jdx] - pop[idx].solution[jdx]) 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: agent.target = self.get_target(pos_new) pop_new[-1] = self.get_better_agent(agent, pop[idx], self.problem.minmax) if self.mode in self.AVAILABLE_MODES: pop_new = self.update_target_for_population(pop_new) pop_new = self.greedy_selection_population(pop, pop_new, self.problem.minmax) return pop_new
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ pop = self.update_business_1__(self.pop, epoch) pop = self.update_business_2__(pop) self.pop = self.update_business_3__(pop, self.g_best)