# !/usr/bin/env python
# Created by "Thieu" at 21:18, 17/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 BaseTWO(Optimizer):
"""
The original version of: Tug of War Optimization (TWO)
Links:
1. https://www.researchgate.net/publication/332088054_Tug_of_War_Optimization_Algorithm
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.physics_based.TWO import BaseTWO
>>>
>>> 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 = BaseTWO(problem_dict1, epoch, pop_size)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_fitness}")
References
~~~~~~~~~~
[1] Kaveh, A., 2017. Tug of war optimization. In Advances in metaheuristic algorithms for
optimal design of structures (pp. 451-487). Springer, Cham.
"""
ID_POS = 0
ID_TAR = 1
ID_WEIGHT = 2
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 = pop_size
self.sort_flag = False
self.epoch = epoch
self.pop_size = pop_size
self.muy_s = 1
self.muy_k = 1
self.delta_t = 1
self.alpha = 0.99
self.beta = 0.1
[docs] def create_solution(self, minmax=0):
"""
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, ...]], weight]
"""
position = np.random.uniform(self.problem.lb, self.problem.ub)
position = self.amend_position(position)
fitness = self.get_fitness_position(position=position)
weight = 0.0
return [position, fitness, weight]
def _update_weight(self, teams):
_, best, worst = self.get_special_solutions(teams, best=1, worst=1)
best_fit = best[0][self.ID_TAR][self.ID_FIT]
worst_fit = worst[0][self.ID_TAR][self.ID_FIT]
if best_fit == worst_fit:
for i in range(self.pop_size):
teams[i][self.ID_WEIGHT] = np.random.uniform(0.5, 1.5)
else:
for i in range(self.pop_size):
teams[i][self.ID_WEIGHT] = (teams[i][self.ID_TAR][self.ID_FIT] - worst_fit) / (best_fit - worst_fit + self.EPSILON) + 1
return teams
[docs] def initialization(self):
self.pop = self.create_population(self.pop_size)
_, self.g_best = self.get_global_best_solution(self.pop)
self.pop = self._update_weight(self.pop)
[docs] def evolve(self, epoch):
"""
The main operations (equations) of algorithm. Inherit from Optimizer class
Args:
epoch (int): The current iteration
"""
pop_new = deepcopy(self.pop)
for i in range(self.pop_size):
pos_new = pop_new[i][self.ID_POS].astype(float)
for j in range(self.pop_size):
if self.pop[i][self.ID_WEIGHT] < self.pop[j][self.ID_WEIGHT]:
force = max(self.pop[i][self.ID_WEIGHT] * self.muy_s, self.pop[j][self.ID_WEIGHT] * self.muy_s)
resultant_force = force - self.pop[i][self.ID_WEIGHT] * self.muy_k
g = self.pop[j][self.ID_POS] - self.pop[i][self.ID_POS]
acceleration = resultant_force * g / (self.pop[i][self.ID_WEIGHT] * self.muy_k)
delta_x = 1 / 2 * acceleration + np.power(self.alpha, epoch + 1) * self.beta * \
(self.problem.ub - self.problem.lb) * np.random.randn(self.problem.n_dims)
pos_new += delta_x
pop_new[i][self.ID_POS] = self.amend_position(pos_new)
for i in range(self.pop_size):
pos_new = pop_new[i][self.ID_POS].astype(float)
for j in range(self.problem.n_dims):
if pos_new[j] < self.problem.lb[j] or pos_new[j] > self.problem.ub[j]:
if np.random.random() <= 0.5:
pos_new[j] = self.g_best[self.ID_POS][j] + np.random.randn() / (epoch + 1) * \
(self.g_best[self.ID_POS][j] - pos_new[j])
if pos_new[j] < self.problem.lb[j] or pos_new[j] > self.problem.ub[j]:
pos_new[j] = self.pop[i][self.ID_POS][j]
else:
if pos_new[j] < self.problem.lb[j]:
pos_new[j] = self.problem.lb[j]
if pos_new[j] > self.problem.ub[j]:
pos_new[j] = self.problem.ub[j]
pop_new[i][self.ID_POS] = self.amend_position(pos_new)
pop_new = self.update_fitness_population(pop_new)
self.pop = self.greedy_selection_population(self.pop, pop_new)
self.pop = self._update_weight(pop_new)
[docs]class OppoTWO(BaseTWO):
"""
The opossition-based learning version of: Tug of War Optimization (OTWO)
Notes
~~~~~
+ Applied the idea of Opposition-based learning technique
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.physics_based.TWO import OppoTWO
>>>
>>> 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 = OppoTWO(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 = pop_size
self.sort_flag = False
[docs] def initialization(self):
pop_temp = self.create_population(int(self.pop_size / 2))
pop_oppo = []
for i in range(len(pop_temp)):
pos_opposite = self.problem.ub + self.problem.lb - pop_temp[i][self.ID_POS]
pos_opposite = self.amend_position(pos_opposite)
pop_oppo.append([pos_opposite, None, 0.0])
pop_oppo = self.update_fitness_population(pop_oppo)
self.pop = pop_temp + pop_oppo
self.pop = self._update_weight(self.pop)
_, self.g_best = self.get_global_best_solution(self.pop)
[docs] def evolve(self, epoch):
"""
The main operations (equations) of algorithm. Inherit from Optimizer class
Args:
epoch (int): The current iteration
"""
## Apply force of others solution on each individual solution
pop_new = deepcopy(self.pop)
for i in range(self.pop_size):
pos_new = pop_new[i][self.ID_POS].astype(float)
for j in range(self.pop_size):
if self.pop[i][self.ID_WEIGHT] < self.pop[j][self.ID_WEIGHT]:
force = max(self.pop[i][self.ID_WEIGHT] * self.muy_s, self.pop[j][self.ID_WEIGHT] * self.muy_s)
resultant_force = force - self.pop[i][self.ID_WEIGHT] * self.muy_k
g = self.pop[j][self.ID_POS] - self.pop[i][self.ID_POS]
acceleration = resultant_force * g / (self.pop[i][self.ID_WEIGHT] * self.muy_k)
delta_x = 1 / 2 * acceleration + np.power(self.alpha, epoch + 1) * self.beta * \
(self.problem.ub - self.problem.lb) * np.random.randn(self.problem.n_dims)
pos_new += delta_x
self.pop[i][self.ID_POS] = self.amend_position(pos_new)
## Amend solution and update fitness value
for i in range(self.pop_size):
pos_new = self.g_best[self.ID_POS] + np.random.normal(0, 1, self.problem.n_dims) / (epoch + 1) * \
(self.g_best[self.ID_POS] - pop_new[i][self.ID_POS])
conditions = np.logical_or(pop_new[i][self.ID_POS] < self.problem.lb, pop_new[i][self.ID_POS] > self.problem.ub)
conditions = np.logical_and(conditions, np.random.uniform(0, 1, self.problem.n_dims) < 0.5)
pos_new = np.where(conditions, pos_new, self.pop[i][self.ID_POS])
pop_new[i][self.ID_POS] = self.amend_position(pos_new)
pop_new = self.update_fitness_population(pop_new)
## Opposition-based here
for i in range(self.pop_size):
if self.compare_agent(pop_new[i], self.pop[i]):
self.pop[i] = deepcopy(pop_new[i])
else:
C_op = self.create_opposition_position(self.pop[i][self.ID_POS], self.g_best[self.ID_POS])
C_op = self.amend_position(C_op)
fit_op = self.get_fitness_position(C_op)
if self.compare_agent([C_op, fit_op], self.pop[i]):
self.pop[i] = [C_op, fit_op, 0.0]
self.pop = self._update_weight(self.pop)
[docs]class LevyTWO(BaseTWO):
"""
The Levy-flight version of: Tug of War Optimization (LTWO)
Notes
~~~~~
+ Applied the idea of Levy-flight technique
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.physics_based.TWO import LevyTWO
>>>
>>> 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 = LevyTWO(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 = pop_size
self.sort_flag = False
[docs] def evolve(self, epoch):
"""
The main operations (equations) of algorithm. Inherit from Optimizer class
Args:
epoch (int): The current iteration
"""
pop_new = deepcopy(self.pop)
for i in range(self.pop_size):
pos_new = self.pop[i][self.ID_POS].astype(float)
for k in range(self.pop_size):
if self.pop[i][self.ID_WEIGHT] < self.pop[k][self.ID_WEIGHT]:
force = max(self.pop[i][self.ID_WEIGHT] * self.muy_s, self.pop[k][self.ID_WEIGHT] * self.muy_s)
resultant_force = force - self.pop[i][self.ID_WEIGHT] * self.muy_k
g = self.pop[k][self.ID_POS] - self.pop[i][self.ID_POS]
acceleration = resultant_force * g / (self.pop[i][self.ID_WEIGHT] * self.muy_k)
delta_x = 1 / 2 * acceleration + np.power(self.alpha, epoch + 1) * self.beta * \
(self.problem.ub - self.problem.lb) * np.random.randn(self.problem.n_dims)
pos_new +=delta_x
pop_new[i][self.ID_POS] = self.amend_position(pos_new)
for i in range(self.pop_size):
pos_new = self.pop[i][self.ID_POS].astype(float)
for j in range(self.problem.n_dims):
if pos_new[j] < self.problem.lb[j] or pos_new[j] > self.problem.ub[j]:
if np.random.random() <= 0.5:
pos_new[j] = self.g_best[self.ID_POS][j] + np.random.randn() / (epoch + 1) * \
(self.g_best[self.ID_POS][j] - pos_new[j])
if pos_new[j] < self.problem.lb[j] or pos_new[j] > self.problem.ub[j]:
pos_new[j] = self.pop[i][self.ID_POS][j]
else:
if pos_new[j] < self.problem.lb[j]:
pos_new[j] = self.problem.lb[j]
if pos_new[j] > self.problem.ub[j]:
pos_new[j] = self.problem.ub[j]
pop_new[i][self.ID_POS] = self.amend_position(pos_new)
pop_new = self.update_fitness_population(pop_new)
self.pop = self.greedy_selection_population(self.pop, pop_new)
self.pop = self._update_weight(pop_new)
### Apply levy-flight here
for i in range(self.pop_size):
if self.compare_agent(pop_new[i], self.pop[i]):
self.pop[i] = deepcopy(pop_new[i])
else:
levy_step = self.get_levy_flight_step(beta=1.0, multiplier=0.001, case=-1)
pos_new = pop_new[i][self.ID_POS] + 1.0 / np.sqrt(epoch + 1) * np.sign(np.random.random() - 0.5) * levy_step
pos_new = self.amend_position(pos_new)
fit_new = self.get_fitness_position(pos_new)
self.pop[i] = [pos_new, fit_new, 0.0]
self.pop = self._update_weight(pop_new)
[docs]class EnhancedTWO(OppoTWO, LevyTWO):
"""
The original version of: Enhenced Tug of War Optimization (ETWO)
Links:
1. https://doi.org/10.1016/j.procs.2020.03.063
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.physics_based.TWO import EnhancedTWO
>>>
>>> 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
>>> r_rate = 0.3
>>> ps_rate = 0.85
>>> p_field = 0.1
>>> n_field = 0.45
>>> model = EnhancedTWO(problem_dict1, epoch, pop_size, r_rate, ps_rate, p_field, n_field)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_fitness}")
References
~~~~~~~~~~
[1] Nguyen, T., Hoang, B., Nguyen, G. and Nguyen, B.M., 2020. A new workload prediction model using
extreme learning machine and enhanced tug of war optimization. Procedia Computer Science, 170, pp.362-369.
"""
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 = pop_size
self.sort_flag = False
[docs] def initialization(self):
pop_temp = self.create_population(self.pop_size)
pop_oppo = deepcopy(pop_temp)
for i in range(self.pop_size):
pos_opposite = self.problem.ub + self.problem.lb - pop_temp[i][self.ID_POS]
pop_oppo[i][self.ID_POS] = self.amend_position(pos_opposite)
pop_oppo = self.update_fitness_population(pop_oppo)
self.pop = self.get_sorted_strim_population(pop_temp + pop_oppo, self.pop_size)
self.pop = self._update_weight(self.pop)
self.g_best = deepcopy(self.pop[0])
[docs] def evolve(self, epoch):
"""
The main operations (equations) of algorithm. Inherit from Optimizer class
Args:
epoch (int): The current iteration
"""
pop_new = deepcopy(self.pop)
for i in range(self.pop_size):
pos_new = self.pop[i][self.ID_POS].astype(float)
for k in range(self.pop_size):
if self.pop[i][self.ID_WEIGHT] < self.pop[k][self.ID_WEIGHT]:
force = max(self.pop[i][self.ID_WEIGHT] * self.muy_s, self.pop[k][self.ID_WEIGHT] * self.muy_s)
resultant_force = force - self.pop[i][self.ID_WEIGHT] * self.muy_k
g = self.pop[k][self.ID_POS] - self.pop[i][self.ID_POS]
acceleration = resultant_force * g / (self.pop[i][self.ID_WEIGHT] * self.muy_k)
delta_x = 1 / 2 * acceleration + np.power(self.alpha, epoch + 1) * self.beta * \
(self.problem.ub - self.problem.lb) * np.random.randn(self.problem.n_dims)
pos_new += delta_x
pop_new[i][self.ID_POS] = self.amend_position(pos_new)
for i in range(self.pop_size):
pos_new = self.pop[i][self.ID_POS].astype(float)
for j in range(self.problem.n_dims):
if pos_new[j] < self.problem.lb[j] or pos_new[j] > self.problem.ub[j]:
if np.random.random() <= 0.5:
pos_new[j] = self.g_best[self.ID_POS][j] + np.random.randn() / (epoch + 1) * \
(self.g_best[self.ID_POS][j] - pos_new[j])
if pos_new[j] < self.problem.lb[j] or pos_new[j] > self.problem.ub[j]:
pos_new[j] = self.pop[i][self.ID_POS][j]
else:
if pos_new[j] < self.problem.lb[j]:
pos_new[j] = self.problem.lb[j]
if pos_new[j] > self.problem.ub[j]:
pos_new[j] = self.problem.ub[j]
pop_new[i][self.ID_POS] = self.amend_position(pos_new)
pop_new = self.update_fitness_population(pop_new)
self.pop = self.greedy_selection_population(self.pop, pop_new)
self.pop = self._update_weight(pop_new)
for i in range(self.pop_size):
if self.compare_agent(pop_new[i], self.pop[i]):
self.pop[i] = deepcopy(pop_new[i])
else:
C_op = self.create_opposition_position(self.pop[i][self.ID_POS], self.g_best[self.ID_POS])
C_op = self.amend_position(C_op)
fit_op = self.get_fitness_position(C_op)
if self.compare_agent([C_op, fit_op], self.pop[i]):
self.pop[i] = [C_op, fit_op, 0.0]
else:
levy_step = self.get_levy_flight_step(beta=1.0, multiplier=0.001, case=-1)
pos_new = pop_new[i][self.ID_POS] + 1.0 / np.sqrt(epoch + 1) * np.sign(np.random.random() - 0.5) * levy_step
pos_new = self.amend_position(pos_new)
fit_new = self.get_fitness_position(pos_new)
self.pop[i] = [pos_new, fit_new, 0.0]
self.pop = self._update_weight(pop_new)