Source code for mealpy.physics_based.FLA

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

import numpy as np
from mealpy.optimizer import Optimizer
from mealpy.utils.opt_info import OptInfo


[docs]class OriginalFLA(Optimizer): """ The original version of: Fick's Law Algorithm (FLA) Parameters ---------- epoch : int Maximum number of iterations, in range [1, 100000]. Default is 10000. pop_size : int Number of population size, in range [10, 10000]. Default is 100. C1 : float Factor C1, in range (-100.0, 100.0). Default is 0.5. C2 : float Factor C2, in range (-100.0, 100.0). Default is 2.0. C3 : float Factor C3, in range (-100.0, 100.0). Default is 0.1. C4 : float Factor C4, in range (-100.0, 100.0). Default is 0.2. C5 : float Factor C5, in range (-100.0, 100.0). Default is 2.0. DD : float Factor D in the paper, in range (-100.0, 100.0). Default is 0.01. Note ---- 1. The algorithm contains a high number of parameters, some of which may be unnecessary. 2. Despite the complexity of the algorithms, they may not perform optimally and could potentially become trapped in local optima. 3. Division by the fitness value may cause overflow issues to arise. 4. https://www.mathworks.com/matlabcentral/fileexchange/121033-fick-s-law-algorithm-fla References ~~~~~~~~~~ 1. Hashim, F. A., Mostafa, R. R., Hussien, A. G., Mirjalili, S., & Sallam, K. M. (2023). Fick’s Law Algorithm: A physical law-based algorithm for numerical optimization. Knowledge-Based Systems, 260, 110146. https://doi.org/10.1016/j.knosys.2022.110146 Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, FLA >>> >>> def objective_function(solution): >>> return np.sum(solution**2) >>> >>> problem_dict = { >>> "bounds": FloatVar(lb=(-10.,) * 30, ub=(10.,) * 30, name="delta"), >>> "minmax": "min", >>> "obj_func": objective_function >>> } >>> >>> model = FLA.OriginalFLA(epoch=1000, pop_size=50, C1 = 0.5, C2 = 2.0, C3 = 0.1, C4 = 0.2, C5 = 2.0, DD = 0.01) >>> 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}") """ OPT_INFO = OptInfo(name="Fick's Law Algorithm", year=2023, difficulty="nightmare", kind="original") def __init__(self, epoch: int = 10000, pop_size: int = 100, C1: float = 0.5, C2: float = 2.0, C3: float = 0.1, C4: float = 0.2, C5: float = 2.0, DD: float = 0.01, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 C1 (float): factor C1, default=0.5 C2 (float): factor C2, default=2.0 C3 (float): factor C3, default=0.1 C4 (float): factor C4, default=0.2 C5 (float): factor C5, default=2.0 DD (float): factor D in the paper, default=0.01 """ super().__init__(**kwargs) self.epoch = self.validator.check_int("epoch", epoch, [1, 100000]) self.pop_size = self.validator.check_int("pop_size", pop_size, [10, 10000]) self.C1 = self.validator.check_float("C1", C1, (-100., 100.)) self.C2 = self.validator.check_float("C2", C2, (-100., 100.)) self.C3 = self.validator.check_float("C3", C3, (-100., 100.)) self.C4 = self.validator.check_float("C4", C4, (-100., 100.)) self.C5 = self.validator.check_float("C5", C5, (-100., 100.)) self.DD = self.validator.check_float("DD", DD, (-100., 100.)) self.set_parameters(["epoch", "pop_size", "C1", "C2", "C3", "C4", "C5", "DD"]) self.sort_flag = False
[docs] def before_main_loop(self): self.xss, _ = self.get_sorted_population(self.pop, self.problem.minmax) self.g_best = self.xss[0].copy() self.n1 = int(np.round(self.pop_size/2)) self.n2 = self.pop_size - self.n1 self.pop1 = self.pop[:self.n1].copy() self.pop2 = self.pop[self.n1:].copy() self.best1, _ = self.get_best_agent(self.pop1, self.problem.minmax) self.best2, _ = self.get_best_agent(self.pop2, self.problem.minmax) if self.compare_target(self.best1.target, self.best2.target, self.problem.minmax): self.fsss = self.best1.target.fitness else: self.fsss = self.best2.target.fitness
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ pos_list = np.array([agent.solution for agent in self.pop]) pos1_list = np.array([agent.solution for agent in self.pop1]) pos2_list = np.array([agent.solution for agent in self.pop2]) xm1 = np.mean(pos1_list, axis=0) xm2 = np.mean(pos2_list, axis=0) xm = np.mean(pos_list, axis=0) tf = np.sinh(epoch/ self.epoch)**self.C1 pop_new = [] if tf < 0.9: dof = np.exp(-(self.C2 * tf - self.generator.random()))**self.C2 tdo = self.C5 * tf - self.generator.random() if tdo < self.generator.random(): m1n, m2n = self.C3*self.n1, self.C4*self.n1 nt12 = int(np.round((m2n - m1n)*self.generator.random() + m1n)) for idx in range(0, nt12): dfg = self.generator.integers(1, 3) jj = -self.DD * (xm2 - xm1) / (np.linalg.norm(self.best2.solution - self.pop1[idx].solution) + self.EPSILON) pos_new = self.best2.solution + dfg*dof*self.generator.random(self.problem.n_dims)*(jj*self.best2.solution - self.pop1[idx].solution) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) for idx in range(nt12, self.n1): tt = self.pop1[idx].solution + dof * (self.generator.random(self.problem.n_dims) * (self.problem.ub - self.problem.lb) + self.problem.lb) pp = self.generator.random(self.problem.n_dims) pos_new = np.where(pp < 0.8, self.best1.solution, np.where(pp >= 0.9, self.pop1[idx].solution, tt)) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) for idx in range(0, self.n2): pos_new = self.best2.solution + dof * (self.generator.random(self.problem.n_dims) * (self.problem.ub - self.problem.lb) + self.problem.lb) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) else: m1n, m2n = 0.1 * self.n2, 0.2 * self.n2 nt12 = int(np.round((m2n - m1n) * self.generator.random() + m1n)) for idx in range(0, nt12): dfg = self.generator.integers(1, 3) jj = -self.DD*(xm1-xm2) / (np.linalg.norm(self.best1.solution - self.pop2[idx].solution) + self.EPSILON) pos_new = self.best1.solution + dfg * dof * self.generator.random(self.problem.n_dims) * (jj * self.best1.solution - self.pop2[idx].solution) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) for idx in range(nt12, self.n2): tt = self.pop2[idx].solution + dof * (self.generator.random(self.problem.n_dims) * (self.problem.ub - self.problem.lb) + self.problem.lb) pp = self.generator.random(self.problem.n_dims) pos_new = np.where(pp < 0.8, self.best2.solution, np.where(pp >= 0.9, self.pop2[idx].solution, tt)) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) for idx in range(0, self.n1): pos_new = self.best1.solution + dof * (self.generator.random(self.problem.n_dims) * (self.problem.ub - self.problem.lb) + self.problem.lb) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) else: # Equilibrium operator (EO) if tf <= 1: for idx in range(0, self.n1): dfg = self.generator.integers(1, 3) tttt = np.linalg.norm(self.best1.solution - self.pop1[idx].solution) if tttt == 0: jj = 0 else: jj = -self.DD*(self.best1.solution - xm1) / tttt drf = np.exp(-jj / tf) ms = np.exp(-self.best1.target.fitness / (self.pop1[idx].target.fitness + self.EPSILON)) qeo = dfg * drf * self.generator.random(self.problem.n_dims) pos_new = self.best1.solution + qeo*self.pop1[idx].solution + qeo *(ms * self.best1.solution - self.pop1[idx].solution) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) for idx in range(0, self.n2): dfg = self.generator.integers(1, 3) tttt = np.linalg.norm(self.best2.solution - self.pop2[idx].solution) if tttt == 0: jj = 0 else: jj = -self.DD * (self.best2.solution - xm2) / tttt drf = np.exp(-jj / tf) ms = np.exp(-self.best2.target.fitness / (self.pop2[idx].target.fitness + self.EPSILON)) qeo = dfg * drf * self.generator.random(self.problem.n_dims) pos_new = self.best2.solution + qeo * self.pop2[idx].solution + qeo * (ms * self.best2.solution - self.pop2[idx].solution) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) else: # Steady state operator (SSO) for idx in range(0, self.n1): dfg = self.generator.integers(1, 3) tttt = np.linalg.norm(self.g_best.solution - self.pop1[idx].solution) if tttt == 0: jj = 0 else: jj = -self.DD * (xm - xm1) / tttt drf = np.exp(-jj / tf) ms = np.exp(-self.fsss / (self.pop1[idx].target.fitness + self.EPSILON)) qg = dfg * drf * self.generator.random(self.problem.n_dims) pos_new = self.g_best.solution + qg * self.pop1[idx].solution + qg * (ms * self.best1.solution - self.pop1[idx].solution) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new.append(agent) for idx in range(0, self.n2): dfg = self.generator.integers(1, 3) tttt = np.linalg.norm(self.g_best.solution - self.pop2[idx].solution) if tttt == 0: jj = 0 else: jj = -self.DD * (xm - xm2) / tttt drf = np.exp(-jj / tf) ms = np.exp(-self.fsss / (self.pop2[idx].target.fitness + self.EPSILON)) qg = dfg * drf * self.generator.random(self.problem.n_dims) pos_new = self.g_best.solution + qg * self.pop2[idx].solution + qg * (ms * self.g_best.solution - self.pop2[idx].solution) 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: for idx in range(0, self.pop_size): pop_new[idx].target = self.get_target(pop_new[idx].solution) else: pop_new = self.update_target_for_population(pop_new) for idx in range(0, self.pop_size): if self.compare_target(pop_new[idx].target, self.pop[idx].target, self.problem.minmax): self.pop[idx] = pop_new[idx] self.pop1 = self.pop[:self.n1].copy() self.pop2 = self.pop[self.n1:].copy() self.best1, _ = self.get_best_agent(self.pop1, self.problem.minmax) self.best2, _ = self.get_best_agent(self.pop2, self.problem.minmax) if self.compare_target(self.best1.target, self.best2.target, self.problem.minmax): self.fsss = self.best1.target.fitness else: self.fsss = self.best2.target.fitness