Source code for mealpy.swarm_based.OSA

#!/usr/bin/env python
# Created by "Furkan Buyukyozgat" at 15:25, 05/01/2026-------%
#       Email: furkanbuyuky@gmail.com                        %
#       Github: https://github.com/furkanbuyuky              %
# -----------------------------------------------------------%

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


[docs]class OriginalOSA(Optimizer): """ The original version: Owl Search Algorithm (OSA) Parameters ---------- epoch : int Maximum number of iterations, in range [1, 100000]. Default is 10000. pop_size : int Number of population size, in range [5, 100000]. Default is 100. alpha_max : float Maximum value of alpha, in range (0.0, 10.0). Default is 0.5. beta_max : float Maximum value of beta, in range (0.0, 10.0). Default is 1.9. Warnings -------- There are two MATLAB versions of this algorithm available. However, neither is from the original authors, and their implementations do not accurately reflect the original paper. This algorithm was published in a low-tier journal, lacks any unique update operators, and does not provide pseudocode, which explains why it hasn't gained traction since its publication in 2018. Links ----- 1. https://www.mathworks.com/matlabcentral/fileexchange/181126-owl-search-algorithm-osa 2. https://www.mathworks.com/matlabcentral/fileexchange/162356-owl-search-algorithm-osa References ---------- 1. Jain, M., Maurya, S., Rani, A., & Singh, V. (2018). Owl search algorithm: a novel nature-inspired heuristic paradigm for global optimization. Journal of Intelligent & Fuzzy Systems, 34(3), 1573-1582. https://doi.org/10.3233/JIFS-169452 Examples ~~~~~~~~ >>> import numpy as np >>> from mealpy import FloatVar, OSA >>> >>> 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 = OSA.OriginalOSA(epoch=1000, pop_size=50, alpha_max = 0.5, beta_max = 1.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}") """ OPT_INFO = OptInfo(name="Owl Search Algorithm", year=2018, difficulty="easy", kind="original", scientific_status="questionable", concerns=( ScientificConcern.LACK_OF_NOVELTY, ScientificConcern.QUESTIONABLE_MATH, ScientificConcern.POOR_REPRODUCIBILITY, ScientificConcern.FABRICATED_RESULTS, )) def __init__(self, epoch: int = 10000, pop_size: int = 100, alpha_max: float = 0.5, beta_max: float = 1.9, **kwargs: object) -> None: 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, 100000]) self.alpha_max = self.validator.check_float("alpha_max", alpha_max, (0.0, 10.0)) self.beta_max = self.validator.check_float("beta_max", beta_max, (0.0, 10.0)) self.set_parameters(["epoch", "pop_size", "beta_max", "alpha_max"]) self.sort_flag = False
[docs] def evolve(self, epoch: int) -> None: """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ alpha = self.generator.random() * self.alpha_max beta = self.beta_max * (1.0 - epoch / self.epoch) fits = np.array([agent.target.fitness for agent in self.pop]) fmax = np.max(fits) fmin = np.min(fits) if self.problem.minmax == "min": best_fit, worst_fit = fmin, fmax else: best_fit, worst_fit = fmax, fmin if abs(best_fit - worst_fit) < self.EPSILON: I_i = np.ones(self.pop_size) else: I_i = (fits - worst_fit) / (best_fit - worst_fit) # Equation (7): Distance calculation R_i = ||O_i, V||_2 # Epsilon (1e-9) is added to prevent division by zero for the best owl owls = np.array([agent.solution for agent in self.pop]) R_i = np.linalg.norm(owls - self.g_best.solution, axis=1) + self.EPSILON # Equation (8): Change in intensity Ic_i obeying inverse square law Ic_i = (I_i / (R_i ** 2)) + self.generator.random(self.pop_size) for idx in range(self.pop_size): p_vm = self.generator.random() # Step size magnitude step = beta * Ic_i[idx] * (alpha * self.g_best.solution - owls[idx]) # Prey movement probability trigger if p_vm < 0.5: pos_new = owls[idx] + step else: pos_new = owls[idx] - step # Apply boundary constraints pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) self.pop[idx] = agent # Update fitness in single mode if self.mode not in self.AVAILABLE_MODES: self.pop[idx].target = self.get_target(pos_new) # Update fitness in parallel modes if self.mode in self.AVAILABLE_MODES: self.pop = self.update_target_for_population(self.pop)