Source code for metaheuristic_designer.operators.operator_functions.swarm

"""
Swarm intelligence operator implementations.
"""

from typing import Optional
import numpy as np
from ...population import Population
from ...initializer import Initializer
from ...encodings import ParameterExtendingEncoding
from ...utils import MatrixLike, check_random_state, RNGLike


[docs] def pso_operator( population_matrix: MatrixLike, population_speed: MatrixLike, historical_best: MatrixLike, global_best: MatrixLike, random_state: Optional[RNGLike] = None, w: float = 0.7, c1: float = 1.5, c2: float = 1.5, ) -> tuple[MatrixLike, MatrixLike]: """ Perform a single step of the standard Particle Swarm Optimisation (PSO). Velocity is updated as: .. math:: v_{i} = w v_{i} + c_1 r_1 (p_{i} - x_{i}) + c_2 r_2 (g - x_{i}) where :math:`p_{i}` is the historical best of particle *i*, :math:`g` is the global best, and :math:`r_1`, :math:`r_2` are uniform random numbers in [0, 1]. The new position is :math:`x_{i} + v_{i}`. Parameters ---------- population_matrix : MatrixLike Current positions, shape ``(N, D)``. population_speed : MatrixLike Current velocities, shape ``(N, D)``. historical_best : MatrixLike Personal best positions, shape ``(N, D)``. global_best : MatrixLike Global best position, shape ``(D,)`` (broadcast to ``(N, D)``). random_state : RNGLike, optional Random number generator. w : float, optional Inertia weight (default 0.7). c1 : float, optional Cognitive acceleration coefficient (default 1.5). c2 : float, optional Social acceleration coefficient (default 1.5). Returns ------- tuple[MatrixLike, MatrixLike] The new positions and the new velocities, both shape ``(N, D)``. """ random_state = check_random_state(random_state) c1 = c1 * random_state.random(population_matrix.shape) c2 = c2 * random_state.random(population_matrix.shape) speed = w * population_speed + c1 * (historical_best - population_matrix) + c2 * (global_best - population_matrix) return population_matrix + speed, speed
[docs] def pso_operator_wrapper( population: Population, initializer: Initializer, random_state: Optional[RNGLike] = None, w: float = 0.7, c1: float = 1.5, c2: float = 1.5, ) -> Population: """ Wrapper that integrates the PSO operator with the library's Population API. Extracts the solution and velocity parts from the population (which must use a :class:`ParameterExtendingEncoding` with a ``"speed"`` parameter), applies the standard PSO update, and encodes the result back into the population's genotype matrix. Parameters ---------- population : Population Current population. Its encoding must be a :class:`~metaheuristic_designer.encodings.ParameterExtendingEncoding` that includes a ``"speed"`` parameter. _initializer : Initializer Initializer (unused; kept for interface compatibility). random_state : RNGLike, optional Random number generator. w : float, optional Inertia weight (default 0.7). c1 : float, optional Cognitive coefficient (default 1.5). c2 : float, optional Social coefficient (default 1.5). Returns ------- Population The updated population with new positions and velocities. """ population_encoding = population.encoding if (not isinstance(population_encoding, ParameterExtendingEncoding)) or ("speed" not in population_encoding.extended_parameters): raise ValueError('Encoding of the population must be a ParameterExtendingEncoding with a "speed" parameter') population_genotype = population_encoding.extract_solution(population.genotype_matrix) population_params = population_encoding.decode_params(population.genotype_matrix) historical_best_solution = population_encoding.extract_solution(population.historical_best_matrix) global_best_solution = population_encoding.extract_solution(population.best[None, :])[0] population_solutions, population_params["speed"] = pso_operator( population_genotype, population_params["speed"], historical_best_solution, global_best_solution, random_state=random_state, w=w, c1=c1, c2=c2 ) population_matrix = population.encoding.encode(population_solutions, population_params) return population.update_genotype(population_matrix)