Source code for mealpy.bio_based.EOA

#!/usr/bin/env python
# Created by "Thieu" at 14:52, 17/03/2020 ----------%
#       Email: nguyenthieu2102@gmail.com            %
#       Github: https://github.com/thieu1995        %
# --------------------------------------------------%

import numpy as np
from mealpy.optimizer import Optimizer


[docs]class OriginalEOA(Optimizer): """ The developed version: Earthworm Optimisation Algorithm (EOA) Links: 1. http://doi.org/10.1504/IJBIC.2015.10004283 2. https://www.mathworks.com/matlabcentral/fileexchange/53479-earthworm-optimization-algorithm-ewa Notes: The original version from matlab code above will not work well, even with small dimensions. I change updating process, change cauchy process using x_mean, use global best solution Hyper-parameters should fine-tune in approximate range to get faster convergence toward the global optimum: + p_c (float): (0, 1) -> better [0.5, 0.95], crossover probability + p_m (float): (0, 1) -> better [0.01, 0.2], initial mutation probability + n_best (int): (2, pop_size/2) -> better [2, 5], how many of the best earthworm to keep from one generation to the next + alpha (float): (0, 1) -> better [0.8, 0.99], similarity factor + beta (float): (0, 1) -> better [0.8, 1.0], the initial proportional factor + gama (float): (0, 1) -> better [0.8, 0.99], a constant that is similar to cooling factor of a cooling schedule in the simulated annealing. Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, EOA >>> >>> 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 = EOA.OriginalEOA(epoch=1000, pop_size=50, p_c = 0.9, p_m = 0.01, n_best = 2, alpha = 0.98, beta = 0.9, gama = 0.9) >>> 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] Wang, G.G., Deb, S. and Coelho, L.D.S., 2018. Earthworm optimisation algorithm: a bio-inspired metaheuristic algorithm for global optimisation problems. International journal of bio-inspired computation, 12(1), pp.1-22. """ def __init__(self, epoch: int = 10000, pop_size: int = 100, p_c: float = 0.9, p_m: float = 0.01, n_best: int = 2, alpha: float = 0.98, beta: float = 0.9, gama: float = 0.9, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 p_c (float): default = 0.9, crossover probability p_m (float): default = 0.01 initial mutation probability n_best (int): default = 2, how many of the best earthworm to keep from one generation to the next alpha (float): default = 0.98, similarity factor beta (float): default = 0.9, the initial proportional factor gama (float): default = 0.9, a constant that is similar to cooling factor of a cooling schedule in the simulated annealing. """ 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]) self.p_c = self.validator.check_float("p_c", p_c, (0, 1.0)) self.p_m = self.validator.check_float("p_m", p_m, (0, 1.0)) self.n_best = self.validator.check_int("n_best", n_best, [2, int(self.pop_size / 2)]) self.alpha = self.validator.check_float("alpha", alpha, (0, 1.0)) self.beta = self.validator.check_float("beta", beta, (0, 1.0)) self.gama = self.validator.check_float("gama", gama, (0, 1.0)) self.set_parameters(["epoch", "pop_size", "p_c", "p_m", "n_best", "alpha", "beta", "gama"]) self.sort_flag = False
[docs] def initialize_variables(self): self.dyn_beta = self.beta
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ ## Update the pop best pop_elites, _, _ = self.get_special_agents(self.pop, n_best=1, minmax=self.problem.minmax) pop = [] for idx in range(0, self.pop_size): ### Reproduction 1: the first way of reproducing x_t1 = self.problem.lb + self.problem.ub - self.alpha * self.pop[idx].solution ### Reproduction 2: the second way of reproducing if idx >= self.n_best: ### Select two parents to mate and create two children idx = int(self.pop_size * 0.2) if self.generator.uniform() < 0.5: ## 80% parents selected from best population idx1, idx2 = self.generator.choice(range(0, idx), 2, replace=False) else: ## 20% left parents selected from worst population (make more diversity) idx1, idx2 = self.generator.choice(range(idx, self.pop_size), 2, replace=False) r = self.generator.uniform() x_child = r * self.pop[idx2].solution + (1 - r) * self.pop[idx1].solution else: r1 = self.generator.integers(0, self.pop_size) x_child = self.pop[r1].solution x_t1 = self.dyn_beta * x_t1 + (1.0 - self.dyn_beta) * x_child pos_new = self.correct_solution(x_t1) agent = self.generate_empty_agent(pos_new) pop.append(agent) if self.mode not in self.AVAILABLE_MODES: agent.target = self.get_target(pos_new) self.pop[idx] = self.get_better_agent(agent, self.pop[idx], self.problem.minmax) if self.mode in self.AVAILABLE_MODES: pop = self.update_target_for_population(pop) self.pop = self.greedy_selection_population(self.pop, pop, self.problem.minmax) self.dyn_beta = self.gama * self.beta self.pop = self.get_sorted_and_trimmed_population(self.pop, self.pop_size, self.problem.minmax) pos_list = np.array([agent.solution for agent in self.pop]) x_mean = np.mean(pos_list, axis=0) ## Cauchy mutation (CM) cauchy_w = self.g_best.solution.copy() pop_new = [] for idx in range(self.n_best, self.pop_size): # Don't allow the elites to be mutated condition = self.generator.random(self.problem.n_dims) < self.p_m cauchy_w = np.where(condition, x_mean, cauchy_w) x_t1 = (cauchy_w + self.g_best.solution) / 2 pos_new = self.correct_solution(x_t1) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) if self.mode not in self.AVAILABLE_MODES: agent.target = self.get_target(pos_new) self.pop[idx] = self.get_better_agent(agent, self.pop[idx], self.problem.minmax) if self.mode in self.AVAILABLE_MODES: pop_new = self.update_target_for_population(pop_new) self.pop[self.n_best:] = self.greedy_selection_population(pop_new, self.pop[self.n_best:], self.problem.minmax) ## Elitism Strategy: Replace the worst with the previous generation's elites. self.pop, _, _ = self.get_special_agents(self.pop, minmax=self.problem.minmax) for idx in range(0, self.n_best): self.pop[self.pop_size - idx - 1] = pop_elites[idx].copy() ## Make sure the population does not have duplicates. new_set = set() for idx, agent in enumerate(self.pop): if tuple(agent.solution.tolist()) in new_set: self.pop[idx] = self.generate_agent() else: new_set.add(tuple(agent.solution.tolist()))