Source code for mealpy.evolutionary_based.CRO

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

import numpy as np
from mealpy.optimizer import Optimizer


[docs]class BaseCRO(Optimizer): """ The original version of: Coral Reefs Optimization (CRO) Links: 1. http://downloads.hindawi.com/journals/tswj/2014/739768.pdf Hyper-parameters should fine tuned in approximate range to get faster convergen toward the global optimum: + po (float): [0.2, 0.5], the rate between free/occupied at the beginning + Fb (float): [0.6, 0.9], BroadcastSpawner/ExistingCorals rate + Fa (float): [0.05, 0.3], fraction of corals duplicates its self and tries to settle in a different part of the reef + Fd (float): [0.05, 0.5], fraction of the worse health corals in reef will be applied depredation + Pd (float): [0.05, 0.3], Probability of depredation + G (list): (gamma_min, gamma_max) -> ([0.01, 0.1], [0.1, 0.5]), factor for mutation process + GCR (float): [0.05, 0.2], probability for mutation process + n_trials (int): [2, 10], number of attempts for a larvar to set in the reef. Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy.evolutionary_based.CRO import BaseCRO >>> >>> 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 >>> po = 0.4 >>> Fb = 0.9 >>> Fa = 0.1 >>> Fd = 0.1 >>> Pd = 0.1 >>> G = [0.02, 0.2] >>> GCR = 0.1 >>> n_trials = 5 >>> model = BaseCRO(problem_dict1, epoch, pop_size, po, Fb, Fa, Fd, Pd, G, GCR, n_trials) >>> best_position, best_fitness = model.solve() >>> print(f"Solution: {best_position}, Fitness: {best_fitness}") References ~~~~~~~~~~ [1] Salcedo-Sanz, S., Del Ser, J., Landa-Torres, I., Gil-López, S. and Portilla-Figueras, J.A., 2014. The coral reefs optimization algorithm: a novel metaheuristic for efficiently solving optimization problems. The Scientific World Journal, 2014. """ def __init__(self, problem, epoch=10000, pop_size=100, po=0.4, Fb=0.9, Fa=0.1, Fd=0.1, Pd=0.1, G=(0.02, 0.2), GCR=0.1, n_trials=3, **kwargs): """ Args: problem (dict): The problem dictionary epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 po (float): the rate between free/occupied at the beginning Fb (float): BroadcastSpawner/ExistingCorals rate Fa (float): fraction of corals duplicates its self and tries to settle in a different part of the reef Fd (float): fraction of the worse health corals in reef will be applied depredation Pd (float): Probability of depredation G (list): (gamma_min, gamma_max), factor for mutation process GCR (float): probability for mutation process n_trials (int): number of attempts for a larva to set in the reef. """ super().__init__(problem, kwargs) self.nfe_per_epoch = pop_size self.sort_flag = False self.epoch = epoch self.pop_size = pop_size # ~ number of space self.po = po self.Fb = Fb self.Fa = Fa self.Fd = Fd self.Pd_threshold = Pd self.Pd = 0 self.n_trials = n_trials self.G = G self.GCR = GCR self.G1 = G[1] self.reef = np.array([]) self.occupied_position = [] # after a gen, you should update the occupied_position self.alpha = 10 * self.Pd / self.epoch self.gama = 10 * (self.G[1] - self.G[0]) / self.epoch self.num_occupied = int(self.pop_size / (1 + self.po)) self.occupied_list = np.zeros(self.pop_size) self.occupied_idx_list = np.random.choice(list(range(self.pop_size)), self.num_occupied, replace=False) self.occupied_list[self.occupied_idx_list] = 1 def _gaussian_mutation(self, position): temp = position + self.G1 * (self.problem.ub - self.problem.lb) * np.random.normal(0, 1, self.problem.n_dims) pos_new = np.where(np.random.uniform(0, 1, self.problem.n_dims) < self.GCR, temp, position) return self.amend_position(pos_new) ### Crossover def _multi_point_cross(self, pos1, pos2): p1, p2 = np.random.choice(list(range(len(pos1))), 2, replace=False) start = min(p1, p2) end = max(p1, p2) return np.concatenate((pos1[:start], pos2[start:end], pos1[end:]), axis=0) def _larvae_setting(self, larvae): # Trial to land on a square of reefs for larva in larvae: for i in range(self.n_trials): p = np.random.randint(0, self.pop_size - 1) if self.occupied_list[p] == 0: self.pop[p] = larva self.occupied_idx_list = np.append(self.occupied_idx_list, p) # Update occupied id self.occupied_list[p] = 1 # Update occupied list break else: if self.compare_agent(larva, self.pop[p]): self.pop[p] = larva break def _sort_occupied_reef(self): def reef_fitness(idx): return self.pop[idx][self.ID_TAR][self.ID_FIT] idx_list_sorted = sorted(self.occupied_idx_list, key=reef_fitness) return idx_list_sorted
[docs] def broadcast_spawning_brooding(self): # Step 1a larvae = [] selected_corals = np.random.choice(self.occupied_idx_list, int(len(self.occupied_idx_list) * self.Fb), replace=False) for i in self.occupied_idx_list: if i not in selected_corals: pos_new = self._gaussian_mutation(self.pop[i][self.ID_POS]) larvae.append([pos_new, None]) # Step 1b while len(selected_corals) >= 2: id1, id2 = np.random.choice(range(len(selected_corals)), 2, replace=False) pos_new = self._multi_point_cross(self.pop[selected_corals[id1]][self.ID_POS], self.pop[selected_corals[id2]][self.ID_POS]) larvae.append([pos_new, None]) selected_corals = np.delete(selected_corals, [id1, id2]) return self.update_fitness_population(larvae)
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ nfe_epoch = 0 ## Broadcast Spawning Brooding larvae = self.broadcast_spawning_brooding() self._larvae_setting(larvae) nfe_epoch += len(larvae) ## Asexual Reproduction num_duplicate = int(len(self.occupied_idx_list) * self.Fa) pop_best = [self.pop[idx] for idx in self.occupied_idx_list] pop_best = self.get_sorted_strim_population(pop_best, num_duplicate) self._larvae_setting(pop_best) ## Depredation if np.random.random() < self.Pd: num__depredation__ = int(len(self.occupied_idx_list) * self.Fd) idx_list_sorted = self._sort_occupied_reef() selected_depredator = idx_list_sorted[-num__depredation__:] for idx in selected_depredator: del self.occupied_idx_list[idx] self.occupied_list[idx] = 0 if self.Pd <= self.Pd_threshold: self.Pd += self.alpha if self.G1 >= self.G[0]: self.G1 -= self.gama self.nfe_per_epoch = nfe_epoch
[docs]class OCRO(BaseCRO): """ The original version of: Opposition-based Coral Reefs Optimization (OCRO) Links: 1. https://dx.doi.org/10.2991/ijcis.d.190930.003 Hyper-parameters should fine tuned in approximate range to get faster convergen toward the global optimum: + po (float): [0.2, 0.5], the rate between free/occupied at the beginning + Fb (float): [0.6, 0.9], BroadcastSpawner/ExistingCorals rate + Fa (float): [0.05, 0.3], fraction of corals duplicates its self and tries to settle in a different part of the reef + Fd (float): [0.05, 0.5], fraction of the worse health corals in reef will be applied depredation + Pd (float): [0.05, 0.3], Probability of depredation + G (list): (gamma_min, gamma_max) -> ([0.01, 0.1], [0.1, 0.5]), factor for mutation process + GCR (float): [0.05, 0.2], probability for mutation process + n_trials (int): [2, 10], number of attempts for a larvar to set in the reef + restart_count (int): [10, 100], reset the whole population after global best solution is not improved after restart_count times Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy.evolutionary_based.CRO import OCRO >>> >>> 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 >>> po = 0.4 >>> Fb = 0.9 >>> Fa = 0.1 >>> Fd = 0.1 >>> Pd = 0.1 >>> G = [0.02, 0.2] >>> GCR = 0.1 >>> n_trials = 5 >>> restart_count = 50 >>> model = OCRO(problem_dict1, epoch, pop_size, po, Fb, Fa, Fd, Pd, G, GCR, n_trials, restart_count) >>> best_position, best_fitness = model.solve() >>> print(f"Solution: {best_position}, Fitness: {best_fitness}") References ~~~~~~~~~~ [1] Nguyen, T., Nguyen, T., Nguyen, B.M. and Nguyen, G., 2019. Efficient time-series forecasting using neural network and opposition-based coral reefs optimization. International Journal of Computational Intelligence Systems, 12(2), p.1144. """ def __init__(self, problem, epoch=10000, pop_size=100, po=0.4, Fb=0.9, Fa=0.1, Fd=0.1, Pd=0.1, G=(0.02, 0.2), GCR=0.1, n_trials=3, restart_count=55, **kwargs): """ Args: problem (dict): The problem dictionary epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 po (float): the rate between free/occupied at the beginning Fb (float): BroadcastSpawner/ExistingCorals rate Fa (float): fraction of corals duplicates its self and tries to settle in a different part of the reef Fd (float): fraction of the worse health corals in reef will be applied depredation Pd (float): Probability of depredation G (list): (gamma_min, gamma_max), factor for mutation process GCR (float): probability for mutation process n_trials (int): number of attempts for a larva to set in the reef. restart_count (int): reset the whole population after global best solution is not improved after restart_count times """ super().__init__(problem, epoch, pop_size, po, Fb, Fa, Fd, Pd, G, GCR, n_trials, **kwargs) self.nfe_per_epoch = pop_size self.sort_flag = False self.restart_count = restart_count self.reset_count = 0 def _local_search(self, pop=None): pop_new = [] for idx in range(0, len(pop)): temp = np.random.uniform(self.problem.lb, self.problem.ub) pos_new = np.where(np.random.uniform(0, 1, self.problem.n_dims) < 0.5, self.g_best[self.ID_POS], temp) pos_new = self.amend_position(pos_new) pop_new.append([pos_new, None]) return self.update_fitness_population(pop_new) def _opposition_based_position(self, reef, g_best): pos_new = self.problem.ub + self.problem.lb - g_best[self.ID_POS] + np.random.uniform() * (g_best[self.ID_POS] - reef[self.ID_POS]) pos_new = self.amend_position(pos_new) fit_new = self.get_fitness_position(pos_new) return [pos_new, fit_new]
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ nfe_epoch = 0 ## Broadcast Spawning Brooding larvae = self.broadcast_spawning_brooding() self._larvae_setting(larvae) nfe_epoch += len(larvae) ## Asexual Reproduction num_duplicate = int(len(self.occupied_idx_list) * self.Fa) pop_best = [self.pop[idx] for idx in self.occupied_idx_list] pop_best = self.get_sorted_strim_population(pop_best, num_duplicate) pop_local_search = self._local_search(pop_best) self._larvae_setting(pop_local_search) ## Depredation if np.random.random() < self.Pd: num__depredation__ = int(len(self.occupied_idx_list) * self.Fd) idx_list_sorted = self._sort_occupied_reef() selected_depredator = idx_list_sorted[-num__depredation__:] for idx in selected_depredator: opposite_reef = self._opposition_based_position(self.pop[idx], self.g_best) if self.compare_agent(opposite_reef, self.pop[idx]): self.pop[idx] = opposite_reef else: del self.occupied_idx_list[idx] self.occupied_list[idx] = 0 if self.Pd <= self.Pd_threshold: self.Pd += self.alpha if self.G1 >= self.G[0]: self.G1 -= self.gama self.reset_count += 1 _, local_best = self.get_global_best_solution(self.pop) if self.compare_agent(local_best, self.g_best): self.reset_count = 0 if self.reset_count == self.restart_count: nfe_epoch += self.pop_size self.pop = self.create_population(self.pop_size) self.occupied_list = np.zeros(self.pop_size) self.occupied_idx_list = np.random.choice(range(self.pop_size), self.num_occupied, replace=False) self.occupied_list[self.occupied_idx_list] = 1 self.reset_count = 0 self.nfe_per_epoch = nfe_epoch