Source code for mealpy.bio_based.SBOA

#!/usr/bin/env python
# Created by "ozgurk33" on 05/01/2026
# Github: https://github.com/ozgurk33
# --------------------------------------------------%
# Updated by "Thieu" on 16/07/2026
# Github: https://github.com/thieu1995
# --------------------------------------------------%

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


[docs]class OriginalSBOA(Optimizer): """ The original version of: Secretary Bird Optimization Algorithm (SBOA) Parameters ---------- epoch : int Maximum number of iterations, in range [1, 100000]. Default is 10000. pop_size : int Number of population size, in range [5, 10000]. Default is 100. Links ----- 1. https://doi.org/10.1007/s10462-024-10729-y 2. https://www.mathworks.com/matlabcentral/fileexchange/164456-secretary-bird-optimization-algorithm-sboa References ---------- 1. Fu, Y., Liu, D., Chen, J., & He, L. (2024). Secretary bird optimization algorithm: a new metaheuristic for solving global optimization problems. Artificial Intelligence Review, 57(5), 123. Examples -------- >>> import numpy as np >>> from mealpy import FloatVar, SBOA >>> >>> def objective_function(solution): >>> return np.sum(solution**2) >>> >>> problem_dict = { >>> "bounds": FloatVar(lb=(-10.,) * 30, ub=(10.,) * 30, name="delta"), >>> "obj_func": objective_function, >>> "minmax": "min", >>> } >>> >>> model = SBOA.OriginalSBOA(epoch=1000, pop_size=50) >>> 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="Secretary Bird Optimization Algorithm", year=2024, difficulty="easy", kind="original") def __init__(self, epoch: int = 10000, pop_size: int = 100, **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, 10000]) self.set_parameters(["epoch", "pop_size"]) self.sort_flag = False
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ # Calculate Convergence Factor (Eq. 9) CF = (1.0 - epoch/self.epoch) ** (2.0 * epoch/self.epoch) pop_new = [] # Hunting Strategies (Exploration Phase) for idx in range(0, self.pop_size): if epoch < self.epoch / 3: # Stage 1: Secretary bird search prey (Eq. 4-5) r1, r2 = self.sample_indexes_exclude_one(self.generator, self.pop_size, idx, n_samples=2, replace=True) R1 = self.generator.random(self.problem.n_dims) pos_new = self.pop[idx].solution + (self.pop[r1].solution - self.pop[r2].solution) * R1 elif epoch < 2 * self.epoch / 3: # Stage 2: Secretary bird approaching prey (Eq. 7-8) RB = self.generator.normal(0, 1, self.problem.n_dims) term = np.exp((epoch / self.epoch)**4) pos_new = self.g_best.solution + term * (RB - 0.5) * (self.g_best.solution - self.pop[idx].solution) else: # Stage 3: Secretary bird attacks prey (Eq. 9-10) RL = self.get_levy_flight_step(beta=1.5, multiplier=0.5, size=self.problem.n_dims, case=-1) pos_new = self.g_best.solution + CF * self.pop[idx].solution * RL 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) # Update population in parallel mode 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) # Escaping Strategies (Exploitation Phase) r = self.generator.random() k = self.generator.integers(0, self.pop_size) x_random_global = self.pop[k].solution pop_new_escape = [] for idx in range(0, self.pop_size): if r < 0.5: # C1: Secretary birds use their environment to hide (Eq. 14) RB = self.generator.random(self.problem.n_dims) factor = (1 - epoch/self.epoch) ** 2 pos_new = self.g_best.solution + factor * (2 * RB - 1) * self.pop[idx].solution else: # C2: Secretary birds fly or run away (Eq. 14, 16) K = int(round(1 + self.generator.random())) R2 = self.generator.random(self.problem.n_dims) pos_new = self.pop[idx].solution + R2 * (x_random_global - K * self.pop[idx].solution) pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) pop_new_escape.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) # Update population after exploitation if self.mode in self.AVAILABLE_MODES: pop_new_escape = self.update_target_for_population(pop_new_escape) self.pop = self.greedy_selection_population(self.pop, pop_new_escape, self.problem.minmax)