# !/usr/bin/env python
# Created by "Thieu" at 16:44, 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 BaseGCO(Optimizer):
"""
My changed version of: Germinal Center Optimization (GCO)
Notes
~~~~~
+ The global best solution and 2 random solutions are used instead of randomizing 3 solutions
Hyper-parameters should fine tuned in approximate range to get faster convergen toward the global optimum:
+ cr (float): [0.5, 0.95], crossover rate, default = 0.7 (Same as DE algorithm)
+ wf (float): [1.0, 2.0], weighting factor (f in the paper), default = 1.25 (Same as DE algorithm)
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.system_based.GCO import BaseGCO
>>>
>>> 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
>>> cr = 0.7
>>> wf = 1.25
>>> model = BaseGCO(problem_dict1, epoch, pop_size, cr, wf)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_fitness}")
"""
def __init__(self, problem, epoch=10000, pop_size=100, cr=0.7, wf=1.25, **kwargs):
"""
Args:
problem (dict): The problem dictionary
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
cr (float): crossover rate, default = 0.7 (Same as DE algorithm)
wf (float): weighting factor (f in the paper), default = 1.25 (Same as DE algorithm)
"""
super().__init__(problem, kwargs)
self.nfe_per_epoch = pop_size
self.sort_flag = False
self.epoch = epoch
self.pop_size = pop_size
self.cr = cr
self.wf = wf
## Dynamic variables
self.dyn_list_cell_counter = np.ones(self.pop_size) # CEll Counter
self.dyn_list_life_signal = 70 * np.ones(self.pop_size) # 70% to duplicate, and 30% to die # LIfe-Signal
[docs] def evolve(self, epoch):
"""
The main operations (equations) of algorithm. Inherit from Optimizer class
Args:
epoch (int): The current iteration
"""
## Dark-zone process (can be parallelization)
pop_new = []
for idx in range(0, self.pop_size):
if np.random.uniform(0, 100) < self.dyn_list_life_signal[idx]:
self.dyn_list_cell_counter[idx] += 1
else:
self.dyn_list_cell_counter[idx] = 1
# Mutate process
r1, r2 = np.random.choice(list(set(range(0, self.pop_size)) - {idx}), 2, replace=False)
pos_new = self.g_best[self.ID_POS] + self.wf * (self.pop[r2][self.ID_POS] - self.pop[r1][self.ID_POS])
pos_new = np.where(np.random.uniform(0, 1, self.problem.n_dims) < self.cr, pos_new, self.pop[idx][self.ID_POS])
pos_new = self.amend_position(pos_new)
pop_new.append([pos_new, None])
pop_new = self.update_fitness_population(pop_new)
for idx in range(0, self.pop_size):
if self.compare_agent(pop_new[idx], self.pop[idx]):
self.dyn_list_cell_counter[idx] += 10
self.pop[idx] = deepcopy(pop_new[idx])
## Light-zone process (no needs parallelization)
for i in range(0, self.pop_size):
self.dyn_list_cell_counter[i] = 10
fit_list = np.array([item[self.ID_TAR][self.ID_FIT] for item in pop_new])
fit_max = max(fit_list)
fit_min = min(fit_list)
self.dyn_list_cell_counter[i] += 10 * (self.pop[i][self.ID_TAR][self.ID_FIT] - fit_max) / (fit_min - fit_max + self.EPSILON)
[docs]class OriginalGCO(BaseGCO):
"""
The original version of: Germinal Center Optimization (GCO)
Links:
1. https://doi.org/10.2991/ijcis.2018.25905179
2. https://www.atlantis-press.com/journals/ijcis/25905179/view
Hyper-parameters should fine tuned in approximate range to get faster convergen toward the global optimum:
+ cr (float): [0.5, 0.95], crossover rate, default = 0.7 (Same as DE algorithm)
+ wf (float): [1.0, 2.0], weighting factor (f in the paper), default = 1.25 (Same as DE algorithm)
Examples
~~~~~~~~
>>> import numpy as np
>>> from mealpy.system_based.GCO import OriginalGCO
>>>
>>> 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
>>> cr = 0.7
>>> wf = 1.25
>>> model = OriginalGCO(problem_dict1, epoch, pop_size, cr, wf)
>>> best_position, best_fitness = model.solve()
>>> print(f"Solution: {best_position}, Fitness: {best_fitness}")
References
~~~~~~~~~~
[1] Villaseñor, C., Arana-Daniel, N., Alanis, A.Y., López-Franco, C. and Hernandez-Vargas, E.A., 2018.
Germinal center optimization algorithm. International Journal of Computational Intelligence Systems, 12(1), p.13.
"""
def __init__(self, problem, epoch=10000, pop_size=100, cr=0.7, wf=1.25, **kwargs):
"""
Args:
problem (dict): The problem dictionary
epoch (int): maximum number of iterations, default = 10000
pop_size (int): number of population size, default = 100
cr (float): crossover rate, default = 0.7 (Same as DE algorithm)
wf (float): weighting factor (f in the paper), default = 1.25 (Same as DE algorithm)
"""
super().__init__(problem, epoch, pop_size, cr, wf, **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 = []
for idx in range(0, self.pop_size):
if np.random.uniform(0, 100) < self.dyn_list_life_signal[idx]:
self.dyn_list_cell_counter[idx] += 1
else:
self.dyn_list_cell_counter[idx] = 1
# Mutate process
r1, r2, r3 = np.random.choice(list(set(range(0, self.pop_size)) - {idx}), 3, replace=False)
pos_new = self.pop[r1][self.ID_POS] + self.wf * (self.pop[r2][self.ID_POS] - self.pop[r3][self.ID_POS])
pos_new = np.where(np.random.uniform(0, 1, self.problem.n_dims) < self.cr, pos_new, self.pop[idx][self.ID_POS])
pos_new = self.amend_position(pos_new)
pop_new.append([pos_new, None])
pop_new = self.update_fitness_population(pop_new)
for idx in range(0, self.pop_size):
if self.compare_agent(pop_new[idx], self.pop[idx]):
self.dyn_list_cell_counter[idx] += 10
self.pop[idx] = deepcopy(pop_new[idx])