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 OriginalCRO(Optimizer): """ The original version of: Coral Reefs Optimization (CRO) Links: 1. https://downloads.hindawi.com/journals/tswj/2014/739768.pdf Hyper-parameters should fine-tune in approximate range to get faster convergence 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.1, 0.7], Probability of depredation + GCR (float): [0.05, 0.2], probability for mutation process + gamma_min (float): [0.01, 0.1] factor for mutation process + gamma_max (float): [0.1, 0.5] factor 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 import FloatVar, CRO >>> >>> 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 = CRO.OriginalCRO(epoch=1000, pop_size=50, po = 0.4, Fb = 0.9, Fa = 0.1, Fd = 0.1, Pd = 0.5, GCR = 0.1, gamma_min = 0.02, gamma_max = 0.2, n_trials = 5) >>> 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] 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, epoch: int = 10000, pop_size: int = 100, po: float = 0.4, Fb: float = 0.9, Fa: float = 0.1, Fd: float = 0.1, Pd: float = 0.5, GCR: float = 0.1, gamma_min: float = 0.02, gamma_max: float = 0.2, n_trials: int = 3, **kwargs: object) -> None: """ Args: 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): the maximum of probability of depredation GCR (float): probability for mutation process gamma_min (float): factor for mutation process gamma_max (float): factor for mutation process n_trials (int): number of attempts for a larva to set in the reef. """ 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]) # ~ number of space self.po = self.validator.check_float("po", po, (0, 1.0)) self.Fb = self.validator.check_float("Fb", Fb, (0, 1.0)) self.Fa = self.validator.check_float("Fa", Fa, (0, 1.0)) self.Fd = self.validator.check_float("Fd", Fd, (0, 1.0)) self.Pd = self.validator.check_float("Pd", Pd, (0, 1.0)) self.GCR = self.validator.check_float("GCR", GCR, (0, 1.0)) self.gamma_min = self.validator.check_float("gamma_min", gamma_min, (0, 0.15)) self.gamma_max = self.validator.check_float("gamma_max", gamma_max, (0.15, 1.0)) self.n_trials = self.validator.check_int("n_trials", n_trials, [2, int(self.pop_size / 2)]) self.set_parameters(["epoch", "pop_size", "po", "Fb", "Fa", "Fd", "Pd", "GCR", "gamma_min", "gamma_max", "n_trials"]) self.sort_flag = False
[docs] def initialization(self): if self.pop is None: self.pop = self.generate_population(self.pop_size) self.reef = np.array([]) self.occupied_position = [] # after a gen, you should update the occupied_position self.G1 = self.gamma_max self.alpha = 10 * self.Pd / self.epoch self.gama = 10 * (self.gamma_max - self.gamma_min) / self.epoch self.num_occupied = int(self.pop_size / (1 + self.po)) self.dyn_Pd = 0 self.occupied_list = np.zeros(self.pop_size) self.occupied_idx_list = self.generator.choice(list(range(self.pop_size)), self.num_occupied, replace=False) self.occupied_list[self.occupied_idx_list] = 1
[docs] def gaussian_mutation__(self, position): random_pos = position + self.G1 * (self.problem.ub - self.problem.lb) * self.generator.normal(0, 1, self.problem.n_dims) condition =self.generator.random(self.problem.n_dims) < self.GCR pos_new = np.where(condition, random_pos, position) return self.correct_solution(pos_new)
### Crossover
[docs] def multi_point_cross__(self, pos1, pos2): p1, p2 = self.generator.choice(list(range(len(pos1))), 2, replace=False) start, end = min(p1, p2), max(p1, p2) pos_new = np.concatenate((pos1[:start], pos2[start:end], pos1[end:]), axis=0) return self.correct_solution(pos_new)
[docs] def larvae_setting__(self, larvae): # Trial to land on a square of reefs for larva in larvae: for idx in range(self.n_trials): pdx = self.generator.integers(0, self.pop_size - 1) if self.occupied_list[pdx] == 0: self.pop[pdx] = larva self.occupied_idx_list = np.append(self.occupied_idx_list, pdx) # Update occupied id self.occupied_list[pdx] = 1 # Update occupied list break else: if self.compare_target(larva.target, self.pop[pdx].target, self.problem.minmax): self.pop[pdx] = larva break
[docs] def sort_occupied_reef__(self): def reef_fitness(idx): return self.pop[idx].target.fitness return sorted(self.occupied_idx_list, key=reef_fitness)
[docs] def broadcast_spawning_brooding__(self): # Step 1a larvae = [] selected_corals = self.generator.choice(self.occupied_idx_list, int(len(self.occupied_idx_list) * self.Fb), replace=False) for idx in self.occupied_idx_list: if idx not in selected_corals: pos_new = self.gaussian_mutation__(self.pop[idx].solution) agent = self.generate_empty_agent(pos_new) larvae.append(agent) if self.mode not in self.AVAILABLE_MODES: larvae[-1].target = self.get_target(pos_new) # Step 1b while len(selected_corals) >= 2: id1, id2 = self.generator.choice(range(len(selected_corals)), 2, replace=False) pos_new = self.multi_point_cross__(self.pop[selected_corals[id1]].solution, self.pop[selected_corals[id2]].solution) agent = self.generate_empty_agent(pos_new) larvae.append(agent) if self.mode not in self.AVAILABLE_MODES: larvae[-1].target = self.get_target(pos_new) selected_corals = np.delete(selected_corals, [id1, id2]) return self.update_target_for_population(larvae)
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ ## Broadcast Spawning Brooding larvae = self.broadcast_spawning_brooding__() self.larvae_setting__(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_and_trimmed_population(pop_best, num_duplicate, self.problem.minmax) self.larvae_setting__(pop_best) ## Depredation if self.generator.random() < self.dyn_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__:] self.occupied_idx_list = np.setdiff1d(self.occupied_idx_list, selected_depredator) for idx in selected_depredator: self.occupied_list[idx] = 0 if self.dyn_Pd <= self.Pd: self.dyn_Pd += self.alpha if self.G1 >= self.gamma_min: self.G1 -= self.gama
[docs]class OCRO(OriginalCRO): """ 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-tune in approximate range to get faster convergence 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.1, 0.7], the maximum of probability of depredation + GCR (float): [0.05, 0.2], probability for mutation process + gamma_min (float): [0.01, 0.1] factor for mutation process + gamma_max (float): [0.1, 0.5] factor 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 import FloatVar, CRO >>> >>> 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 = CRO.OCRO(epoch=1000, pop_size=50, po = 0.4, Fb = 0.9, Fa = 0.1, Fd = 0.1, Pd = 0.5, GCR = 0.1, gamma_min = 0.02, gamma_max = 0.2, n_trials = 5, restart_count = 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, 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, epoch: int = 10000, pop_size: int = 100, po: float = 0.4, Fb: float = 0.9, Fa: float = 0.1, Fd: float = 0.1, Pd: float = 0.5, GCR: float = 0.1, gamma_min: float = 0.02, gamma_max: float = 0.2, n_trials: int = 3, restart_count: int = 20, **kwargs: object) -> None: """ Args: 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 GCR (float): probability for mutation process gamma_min (float): [0.01, 0.1] factor for mutation process gamma_max (float): [0.1, 0.5] factor 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__(epoch, pop_size, po, Fb, Fa, Fd, Pd, GCR, gamma_min, gamma_max, n_trials, **kwargs) self.restart_count = self.validator.check_int("restart_count", restart_count, [2, int(epoch / 2)]) self.set_parameters(["epoch", "pop_size", "po", "Fb", "Fa", "Fd", "Pd", "GCR", "gamma_min", "gamma_max", "n_trials", "restart_count"]) self.sort_flag = False
[docs] def initialize_variables(self): self.reset_count = 0
[docs] def local_search__(self, pop=None): pop_new = [] for idx in range(0, len(pop)): random_pos = self.generator.uniform(self.problem.lb, self.problem.ub) condition = self.generator.random(self.problem.n_dims) < 0.5 pos_new = np.where(condition, self.g_best.solution, random_pos) 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: pop_new[-1].target = self.get_target(pos_new) return self.update_target_for_population(pop_new)
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ ## Broadcast Spawning Brooding larvae = self.broadcast_spawning_brooding__() self.larvae_setting__(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_and_trimmed_population(pop_best, num_duplicate, self.problem.minmax) pop_local_search = self.local_search__(pop_best) self.larvae_setting__(pop_local_search) ## Depredation if self.generator.random() < self.dyn_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: ### Using opposition-based leanring pos_oppo = self.generate_opposition_solution(self.pop[idx], self.g_best) agent = self.generate_agent(pos_oppo) if self.compare_target(agent.target, self.pop[idx].target, self.problem.minmax): self.pop[idx] = agent else: self.occupied_idx_list = self.occupied_idx_list[~np.isin(self.occupied_idx_list, [idx])] self.occupied_list[idx] = 0 if self.dyn_Pd <= self.Pd: self.dyn_Pd += self.alpha if self.G1 >= self.gamma_min: self.G1 -= self.gama self.reset_count += 1 local_best = self.get_best_agent(self.pop, self.problem.minmax) if self.compare_target(local_best.target, self.g_best.target, self.problem.minmax): self.reset_count = 0 if self.reset_count == self.restart_count: self.pop = self.generate_population(self.pop_size) self.occupied_list = np.zeros(self.pop_size) self.occupied_idx_list = self.generator.choice(range(self.pop_size), self.num_occupied, replace=False) self.occupied_list[self.occupied_idx_list] = 1 self.reset_count = 0