Source code for mealpy.evolutionary_based.EP

#!/usr/bin/env python
# Created by "Thieu" at 19:27, 10/04/2020 ----------%
#       Email: nguyenthieu2102@gmail.com            %
#       Github: https://github.com/thieu1995        %
# --------------------------------------------------%

import numpy as np
from mealpy.optimizer import Optimizer
from mealpy.utils.agent import Agent


[docs]class OriginalEP(Optimizer): """ The original version of: Evolutionary Programming (EP) Links: 1. https://www.cleveralgorithms.com/nature-inspired/evolution/evolutionary_programming.html 2. https://github.com/clever-algorithms/CleverAlgorithms Hyper-parameters should fine-tune in approximate range to get faster convergence toward the global optimum: + bout_size (float): [0.05, 0.2], percentage of child agents implement tournament selection Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, EP >>> >>> 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 = EP.OriginalEP(epoch=1000, pop_size=50, bout_size = 0.05) >>> 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] Yao, X., Liu, Y. and Lin, G., 1999. Evolutionary programming made faster. IEEE Transactions on Evolutionary computation, 3(2), pp.82-102. """ def __init__(self, epoch: int = 10000, pop_size: int = 100, bout_size: float = 0.05, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size (miu in the paper), default = 100 bout_size (float): percentage of child agents implement tournament selection """ 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.bout_size = self.validator.check_float("bout_size", bout_size, (0, 1.0)) self.set_parameters(["epoch", "pop_size", "bout_size"]) self.sort_flag = True
[docs] def initialize_variables(self): self.n_bout_size = int(self.bout_size * self.pop_size) self.distance = 0.05 * (self.problem.ub - self.problem.lb)
[docs] def generate_empty_agent(self, solution: np.ndarray = None) -> Agent: if solution is None: solution = self.problem.generate_solution(encoded=True) strategy = self.generator.uniform(0, self.distance, self.problem.n_dims) times_win = 0 return Agent(solution=solution, strategy=strategy, win=times_win)
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ child = [] for idx in range(0, self.pop_size): pos_new = self.pop[idx].solution + self.pop[idx].strategy * self.generator.normal(0, 1.0, self.problem.n_dims) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) s_old = self.pop[idx].strategy + self.generator.normal(0, 1.0, self.problem.n_dims) * np.abs(self.pop[idx].strategy) ** 0.5 agent.update(solution=pos_new, strategy=s_old, win=0) child.append(agent) if self.mode not in self.AVAILABLE_MODES: child[-1].target = self.get_target(pos_new) child = self.update_target_for_population(child) # Update the global best children = self.get_sorted_population(child, self.problem.minmax) pop = children + self.pop for i in range(0, len(pop)): ## Tournament winner (Tried with bout_size times) for idx in range(0, self.n_bout_size): rand_idx = self.generator.integers(0, len(pop)) if self.compare_target(pop[i].target, pop[rand_idx].target, self.problem.minmax): pop[i].win += 1 else: pop[rand_idx].win += 1 pop = sorted(pop, key=lambda agent: agent.win, reverse=True) self.pop = pop[:self.pop_size]
[docs]class LevyEP(OriginalEP): """ The developed Levy-flight version: Evolutionary Programming (LevyEP) Notes: + Levy-flight is applied to EP, flow and some equations is changed. Hyper-parameters should fine-tune in approximate range to get faster convergence toward the global optimum: + bout_size (float): [0.05, 0.2], percentage of child agents implement tournament selection Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, EP >>> >>> 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 = EP.LevyEP(epoch=1000, pop_size=50, bout_size = 0.05) >>> 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}") """ def __init__(self, epoch: int = 10000, pop_size: int = 100, bout_size: float = 0.05, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size (miu in the paper), default = 100 bout_size (float): percentage of child agents implement tournament selection """ super().__init__(epoch, pop_size, bout_size, **kwargs) self.sort_flag = True
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ child = [] for idx in range(0, self.pop_size): pos_new = self.pop[idx].solution + self.pop[idx].strategy * self.generator.normal(0, 1.0, self.problem.n_dims) pos_new = self.correct_solution(pos_new) s_old = self.pop[idx].strategy + self.generator.normal(0, 1.0, self.problem.n_dims) * np.abs(self.pop[idx].strategy) ** 0.5 agent = self.generate_empty_agent(pos_new) agent.update(solution=pos_new, strategy=s_old, win=0) child.append(agent) if self.mode not in self.AVAILABLE_MODES: child[-1].target = self.get_target(pos_new) child = self.update_target_for_population(child) # Update the global best children = self.get_sorted_population(child, self.problem.minmax) pop = children + self.pop for i in range(0, len(pop)): ## Tournament winner (Tried with bout_size times) for idx in range(0, self.n_bout_size): rand_idx = self.generator.integers(0, len(pop)) if self.compare_target(pop[i].target, pop[rand_idx].target, self.problem.minmax): pop[i].win += 1 else: pop[rand_idx].win += 1 ## Keep the top population, but 50% of left population will make a comeback an take the good position pop = sorted(pop, key=lambda agent: agent.win, reverse=True) pop_new = pop[:self.pop_size] pop_left = pop[self.pop_size:] ## Choice random 50% of population left pop_comeback = [] idx_list = self.generator.choice(range(0, len(pop_left)), int(0.5 * len(pop_left)), replace=False) for idx in idx_list: pos_new = pop_left[idx].solution + self.get_levy_flight_step(multiplier=0.01, size=self.problem.n_dims, case=0) pos_new = self.correct_solution(pos_new) strategy = self.distance = 0.05 * (self.problem.ub - self.problem.lb) agent = self.generate_empty_agent(pos_new) agent.update(solution=pos_new, strategy=strategy, win=0) pop_comeback.append(agent) if self.mode not in self.AVAILABLE_MODES: pop_comeback[-1].target = self.get_target(pos_new) pop_comeback = self.update_target_for_population(pop_comeback) self.pop = self.get_sorted_and_trimmed_population(pop_new + pop_comeback, self.pop_size, self.problem.minmax)