Source code for mealpy.human_based.GSKA

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

import numpy as np
from mealpy.optimizer import Optimizer


[docs]class DevGSKA(Optimizer): """ The developed version: Gaining Sharing Knowledge-based Algorithm (GSKA) Notes: + Third loop is removed, 2 parameters is removed + Solution represent junior or senior instead of dimension of solution + Equations is based vector, can handle large-scale problem + Apply the ideas of levy-flight and global best + Keep the better one after updating process Hyper-parameters should fine-tune in approximate range to get faster convergence toward the global optimum: + pb (float): [0.1, 0.5], percent of the best (p in the paper), default = 0.1 + kr (float): [0.5, 0.9], knowledge ratio, default = 0.7 Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, GSKA >>> >>> 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 = GSKA.DevGSKA(epoch=1000, pop_size=50, pb = 0.1, kr = 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}") """ def __init__(self, epoch: int = 10000, pop_size: int = 100, pb: float = 0.1, kr: float = 0.7, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100, n: pop_size, m: clusters pb (float): percent of the best 0.1%, 0.8%, 0.1% (p in the paper), default = 0.1 kr (float): knowledge ratio, default = 0.7 """ 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.pb = self.validator.check_float("pb", pb, (0, 1.0)) self.kr = self.validator.check_float("kr", kr, (0, 1.0)) self.set_parameters(["epoch", "pop_size", "pb", "kr"]) 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 """ dd = int(np.ceil(self.pop_size * (1. - epoch / self.epoch))) pop_new = [] for idx in range(0, self.pop_size): # If it is the best it chooses best+2, best+1 if idx == 0: previ, nexti = idx + 2, idx + 1 # If it is the worse it chooses worst-2, worst-1 elif idx == self.pop_size - 1: previ, nexti = idx - 2, idx - 1 # Other case it chooses i-1, i+1 else: previ, nexti = idx - 1, idx + 1 if idx < dd: # senior gaining and sharing if self.generator.uniform() <= self.kr: rand_idx = self.generator.choice(list(set(range(0, self.pop_size)) - {previ, idx, nexti})) if self.compare_target(self.pop[rand_idx].target, self.pop[idx].target, self.problem.minmax): pos_new = self.pop[idx].solution + self.generator.uniform(0, 1, self.problem.n_dims) * \ (self.pop[previ].solution - self.pop[nexti].solution + self.pop[rand_idx].solution - self.pop[idx].solution) else: pos_new = self.g_best.solution + self.generator.uniform(0, 1, self.problem.n_dims) * \ (self.pop[rand_idx].solution - self.pop[idx].solution) else: pos_new = self.generator.uniform(self.problem.lb, self.problem.ub) else: # junior gaining and sharing if self.generator.uniform() <= self.kr: id1 = int(self.pb * self.pop_size) id2 = id1 + int(self.pop_size - 2 * 100 * self.pb) rand_best = self.generator.choice(list(set(range(0, id1)) - {idx})) rand_worst = self.generator.choice(list(set(range(id2, self.pop_size)) - {idx})) rand_mid = self.generator.choice(list(set(range(id1, id2)) - {idx})) if self.compare_target(self.pop[rand_mid].target, self.pop[idx].target, self.problem.minmax): pos_new = self.pop[idx].solution + self.generator.uniform(0, 1, self.problem.n_dims) * \ (self.pop[rand_best].solution - self.pop[rand_worst].solution + self.pop[rand_mid].solution - self.pop[idx].solution) else: pos_new = self.g_best.solution + self.generator.uniform(0, 1, self.problem.n_dims) * \ (self.pop[rand_mid].solution - self.pop[idx].solution) else: pos_new = self.generator.uniform(self.problem.lb, self.problem.ub) 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: 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.greedy_selection_population(self.pop, pop_new, self.problem.minmax)
[docs]class OriginalGSKA(Optimizer): """ The original version of: Gaining Sharing Knowledge-based Algorithm (GSKA) Links: 1. https://doi.org/10.1007/s13042-019-01053-x Hyper-parameters should fine-tune in approximate range to get faster convergence toward the global optimum: + pb (float): [0.1, 0.5], percent of the best (p in the paper), default = 0.1 + kf (float): [0.3, 0.8], knowledge factor that controls the total amount of gained and shared knowledge added from others to the current individual during generations, default = 0.5 + kr (float): [0.5, 0.95], knowledge ratio, default = 0.9 + kg (int): [3, 20], number of generations effect to D-dimension, default = 5 Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, GSKA >>> >>> 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 = GSKA.OriginalGSKA(epoch=1000, pop_size=50, pb = 0.1, kf = 0.5, kr = 0.9, kg = 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] Mohamed, A.W., Hadi, A.A. and Mohamed, A.K., 2020. Gaining-sharing knowledge based algorithm for solving optimization problems: a novel nature-inspired algorithm. International Journal of Machine Learning and Cybernetics, 11(7), pp.1501-1529. """ def __init__(self, epoch: int = 10000, pop_size: int = 100, pb: float = 0.1, kf: float = 0.5, kr: float = 0.9, kg: int = 5, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100, n: pop_size, m: clusters pb (float): percent of the best 0.1%, 0.8%, 0.1% (p in the paper), default = 0.1 kf (float): knowledge factor that controls the total amount of gained and shared knowledge added from others to the current individual during generations, default = 0.5 kr (float): knowledge ratio, default = 0.9 kg (int): Number of generations effect to D-dimension, default = 5 """ 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.pb = self.validator.check_float("pb", pb, (0, 1.0)) self.kf = self.validator.check_float("kf", kf, (0, 1.0)) self.kr = self.validator.check_float("kr", kr, (0, 1.0)) self.kg = self.validator.check_int("kg", kg, [1, 1 + int(epoch / 2)]) self.set_parameters(["epoch", "pop_size", "pb", "kf", "kr", "kg"]) 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 """ dd = int(self.problem.n_dims * (1 - epoch / self.epoch) ** self.kg) pop_new = [] for idx in range(0, self.pop_size): # If it is the best it chooses best+2, best+1 if idx == 0: previ, nexti = idx + 2, idx + 1 # If it is the worse it chooses worst-2, worst-1 elif idx == self.pop_size - 1: previ, nexti = idx - 2, idx - 1 # Other case it chooses i-1, i+1 else: previ, nexti = idx - 1, idx + 1 # The random individual is for all dimension values rand_idx = self.generator.choice(list(set(range(0, self.pop_size)) - {previ, idx, nexti})) pos_new = self.pop[idx].solution.copy() for j in range(0, self.problem.n_dims): if j < dd: # junior gaining and sharing if self.generator.uniform() <= self.kr: if self.compare_target(self.pop[rand_idx].target, self.pop[idx].target, self.problem.minmax): pos_new[j] = self.pop[idx].solution[j] + self.kf * \ (self.pop[previ].solution[j] - self.pop[nexti].solution[j] + self.pop[rand_idx].solution[j] - self.pop[idx].solution[j]) else: pos_new[j] = self.pop[idx].solution[j] + self.kf * \ (self.pop[previ].solution[j] - self.pop[nexti].solution[j] + self.pop[idx].solution[j] - self.pop[rand_idx].solution[j]) else: # senior gaining and sharing if self.generator.uniform() <= self.kr: id1 = int(self.pb * self.pop_size) id2 = id1 + int(self.pop_size - 2 * 100 * self.pb) rand_best = self.generator.choice(list(set(range(0, id1)) - {idx})) rand_worst = self.generator.choice(list(set(range(id2, self.pop_size)) - {idx})) rand_mid = self.generator.choice(list(set(range(id1, id2)) - {idx})) if self.compare_target(self.pop[rand_mid].target, self.pop[idx].target, self.problem.minmax): pos_new[j] = self.pop[idx].solution[j] + self.kf * \ (self.pop[rand_best].solution[j] - self.pop[rand_worst].solution[j] + self.pop[rand_mid].solution[j] - self.pop[idx].solution[j]) else: pos_new[j] = self.pop[idx].solution[j] + self.kf * \ (self.pop[rand_best].solution[j] - self.pop[rand_worst].solution[j] + self.pop[idx].solution[j] - self.pop[rand_mid].solution[j]) 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: 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.greedy_selection_population(self.pop, pop_new, self.problem.minmax)