# !/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 copy import deepcopy
from mealpy.optimizer import Optimizer
[docs]class BaseQSA(Optimizer):
"""
My changed version of: Queuing Search Algorithm (QSA)
Notes
~~~~~
All third loop is removed, the global best solution is used in business 3 instead of random solution
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.human_based.QSA import BaseQSA
>>>
>>> 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
>>> model = BaseQSA(problem_dict1, epoch, pop_size)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_fitness}")
"""
def __init__(self, problem, epoch=10000, pop_size=100, **kwargs):
"""
Args:
problem (dict): The problem dictionary
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
"""
super().__init__(problem, kwargs)
self.nfe_per_epoch = 3 * pop_size
self.sort_flag = True
self.epoch = epoch
self.pop_size = pop_size
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
def _update_business_1(self, pop=None, current_epoch=None):
A1, A2, A3 = pop[0][self.ID_POS], pop[1][self.ID_POS], pop[2][self.ID_POS]
t1, t2, t3 = pop[0][self.ID_TAR][self.ID_FIT], pop[1][self.ID_TAR][self.ID_FIT], pop[2][self.ID_TAR][self.ID_FIT]
q1, q2, q3 = self._calculate_queue_length__(t1, t2, t3)
case = None
for i in range(self.pop_size):
if i < q1:
if i == 0:
case = 1
A = deepcopy(A1)
elif q1 <= i < q1 + q2:
if i == q1:
case = 1
A = deepcopy(A2)
else:
if i == q1 + q2:
case = 1
A = deepcopy(A3)
beta = np.power(current_epoch, np.power(current_epoch / self.epoch, 0.5))
alpha = np.random.uniform(-1, 1)
E = np.random.exponential(0.5, self.problem.n_dims)
F1 = beta * alpha * (E * np.abs(A - pop[i][self.ID_POS])) + np.random.exponential(0.5) * (A - pop[i][self.ID_POS])
F2 = beta * alpha * (E * np.abs(A - pop[i][self.ID_POS]))
if case == 1:
pos_new = A + F1
pos_new = self.amend_position(pos_new)
fit_new = self.get_fitness_position(pos_new)
if self.compare_agent([pos_new, fit_new], pop[i]):
pop[i] = [pos_new, fit_new]
else:
case = 2
else:
pos_new = pop[i][self.ID_POS] + F2
pos_new = self.amend_position(pos_new)
fit_new = self.get_fitness_position(pos_new)
if self.compare_agent([pos_new, fit_new], pop[i]):
pop[i] = [pos_new, fit_new]
else:
case = 1
pop, _ = self.get_global_best_solution(pop)
return pop
def _update_business_2(self, pop=None):
A1, A2, A3 = pop[0][self.ID_POS], pop[1][self.ID_POS], pop[2][self.ID_POS]
t1, t2, t3 = pop[0][self.ID_TAR][self.ID_FIT], pop[1][self.ID_TAR][self.ID_FIT], pop[2][self.ID_TAR][self.ID_FIT]
q1, q2, q3 = self._calculate_queue_length__(t1, t2, t3)
pr = [i / self.pop_size for i in range(1, self.pop_size + 1)]
if t1 > 1.0e-005:
cv = t1 / (t2 + t3)
else:
cv = 1.0 / 2
pop_new = []
for i in range(self.pop_size):
if i < q1:
A = deepcopy(A1)
elif q1 <= i < q1 + q2:
A = deepcopy(A2)
else:
A = deepcopy(A3)
if np.random.random() < pr[i]:
i1, i2 = np.random.choice(self.pop_size, 2, replace=False)
if np.random.random() < cv:
X_new = pop[i][self.ID_POS] + np.random.exponential(0.5) * (pop[i1][self.ID_POS] - pop[i2][self.ID_POS])
else:
X_new = pop[i][self.ID_POS] + np.random.exponential(0.5) * (A - pop[i1][self.ID_POS])
else:
X_new = np.random.uniform(self.problem.lb, self.problem.ub)
pos_new = self.amend_position(X_new)
pop_new.append([pos_new, None])
pop_new = self.update_fitness_population(pop_new)
pop = self.greedy_selection_population(pop, pop_new)
pop, _ = self.get_global_best_solution(pop)
return pop
def _update_business_3(self, pop, g_best):
pr = np.array([i / self.pop_size for i in range(1, self.pop_size + 1)])
pop_new = []
for i in range(self.pop_size):
X_new = deepcopy(pop[i][self.ID_POS])
id1 = np.random.choice(self.pop_size)
temp = g_best[self.ID_POS] + np.random.exponential(0.5, self.problem.n_dims) * (pop[id1][self.ID_POS] - pop[i][self.ID_POS])
X_new = np.where(np.random.random(self.problem.n_dims) > pr[i], temp, X_new)
pos_new = self.amend_position(X_new)
pop_new.append([pos_new, None])
pop_new = self.update_fitness_population(pop_new)
pop_new = self.greedy_selection_population(pop, pop_new)
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 + 1)
pop = self._update_business_2(pop)
self.pop = self._update_business_3(pop, self.g_best)
[docs]class OppoQSA(BaseQSA):
"""
My Opposition-based learning version of: Queuing Search Algorithm (OQSA)
Notes
~~~~~
Added the opposition-based learning technique
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.human_based.QSA import OppoQSA
>>>
>>> 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
>>> model = OppoQSA(problem_dict1, epoch, pop_size)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_fitness}")
"""
def __init__(self, problem, epoch=10000, pop_size=100, **kwargs):
"""
Args:
problem (dict): The problem dictionary
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
"""
super().__init__(problem, epoch, pop_size, **kwargs)
self.nfe_per_epoch = 4 * pop_size
self.sort_flag = True
def _opposition_based(self, pop=None, g_best=None):
pop, _ = self.get_global_best_solution(pop)
pop_new = []
for i in range(0, self.pop_size):
X_new = self.create_opposition_position(pop[i], g_best)
pos_new = self.amend_position(X_new)
pop_new.append([pos_new, None])
pop_new = self.update_fitness_population(pop_new)
return self.greedy_selection_population(pop, 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 + 1)
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(BaseQSA):
"""
My Levy-flight version of: Queuing Search Algorithm (LQSA)
Notes
~~~~~
Added the Levy-flight technique to QSA
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.human_based.QSA import LevyQSA
>>>
>>> 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
>>> model = LevyQSA(problem_dict1, epoch, pop_size)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_fitness}")
"""
def __init__(self, problem, epoch=10000, pop_size=100, **kwargs):
"""
Args:
problem (dict): The problem dictionary
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
"""
super().__init__(problem, epoch, pop_size, **kwargs)
self.nfe_per_epoch = 3 * pop_size
self.sort_flag = True
def _update_business_2(self, pop=None, current_epoch=None):
A1, A2, A3 = pop[0][self.ID_POS], pop[1][self.ID_POS], pop[2][self.ID_POS]
t1, t2, t3 = pop[0][self.ID_TAR][self.ID_FIT], pop[1][self.ID_TAR][self.ID_FIT], pop[2][self.ID_TAR][self.ID_FIT]
q1, q2, q3 = self._calculate_queue_length__(t1, t2, t3)
pr = [i / self.pop_size for i in range(1, self.pop_size + 1)]
if t1 > 1.0e-6:
cv = t1 / (t2 + t3)
else:
cv = 1 / 2
pop_new = []
for i in range(self.pop_size):
if i < q1:
A = deepcopy(A1)
elif q1 <= i < q1 + q2:
A = deepcopy(A2)
else:
A = deepcopy(A3)
if np.random.random() < pr[i]:
id1 = np.random.choice(self.pop_size)
if np.random.random() < cv:
levy_step = self.get_levy_flight_step(beta=1.0, multiplier=0.001, case=-1)
X_new = pop[i][self.ID_POS] + np.random.normal(0, 1, self.problem.n_dims) * levy_step
else:
X_new = pop[i][self.ID_POS] + np.random.exponential(0.5) * (A - pop[id1][self.ID_POS])
pos_new = self.amend_position(X_new)
else:
pos_new = np.random.uniform(self.problem.lb, self.problem.ub)
pos_new = self.amend_position(pos_new)
pop_new.append([pos_new, None])
pop_new = self.update_fitness_population(pop_new)
pop_new = self.greedy_selection_population(pop, pop_new)
pop_new, _ = self.get_global_best_solution(pop_new)
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 + 1)
pop = self._update_business_2(pop, epoch + 1)
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.human_based.QSA import ImprovedQSA
>>>
>>> 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
>>> model = ImprovedQSA(problem_dict1, epoch, pop_size)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_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, problem, epoch=10000, pop_size=100, **kwargs):
"""
Args:
problem (dict): The problem dictionary
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
"""
super().__init__(problem, epoch, pop_size, **kwargs)
self.nfe_per_epoch = 4 * pop_size
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 + 1)
pop = self._update_business_2(pop, epoch + 1)
pop = self._update_business_3(pop, self.g_best)
self.pop = self._opposition_based(pop, self.g_best)
[docs]class OriginalQSA(BaseQSA):
"""
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.human_based.QSA import OriginalQSA
>>>
>>> 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
>>> model = OriginalQSA(problem_dict1, epoch, pop_size)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_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, problem, epoch=10000, pop_size=100, **kwargs):
"""
Args:
problem (dict): The problem dictionary
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
"""
super().__init__(problem, epoch, pop_size, **kwargs)
self.nfe_per_epoch = 3 * pop_size
self.sort_flag = True
def _update_business_3(self, pop, g_best):
pr = [i / self.pop_size for i in range(1, self.pop_size + 1)]
pop_new = []
for i in range(self.pop_size):
pos_new = deepcopy(pop[i][self.ID_POS])
for j in range(self.problem.n_dims):
if np.random.random() > pr[i]:
i1, i2 = np.random.choice(self.pop_size, 2, replace=False)
e = np.random.exponential(0.5)
X1 = pop[i1][self.ID_POS]
X2 = pop[i2][self.ID_POS]
pos_new[j] = X1[j] + e * (X2[j] - pop[i][self.ID_POS][j])
pos_new = self.amend_position(pos_new)
pop_new.append([pos_new, None])
pop_new = self.update_fitness_population(pop_new)
return self.greedy_selection_population(pop, 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)