Source code for metaheuristic_designer.strategies.swarm.PSO

"""
Particle Swarm Optimization strategy.
"""

from __future__ import annotations
import logging
from typing import Optional
import numpy as np

from ...objective_function import ObjectiveFunc
from ...constraint_handlers.extended_constraint import ExtendedConstraintHandler
from ...encodings.composite_encoding import CompositeEncoding
from ...encodings.special.PSO_encoding import PSOEncoding
from ...initializer import Initializer
from ...constraint_handlers.bounce_bound_constraint import BounceBoundConstraint
from ...initializers import UniformInitializer, ExtendedInitializer
from ...operators import create_swarm_operator
from ...encodings import ParameterExtendingEncoding
from ..static_population import StaticPopulation
from ...utils import RNGLike

logger = logging.getLogger(__name__)


[docs] class PSO(StaticPopulation): """ Particle Swarm Optimization (PSO). Each individual (particle) has a position and a velocity. The velocity is updated using personal and global bests, and the position is moved accordingly. This requires a :class:`ParameterExtendingEncoding` that stores a speed vector; if not supplied, a default :class:`PSOEncoding` is created. Parameters ---------- initializer : Initializer Initializer for the solution part. An :class:`ExtendedInitializer` is automatically created to handle the velocity parameter. lower_bound : float, optional Lower bound of the search space (default -100). upper_bound : float, optional Upper bound of the search space (default 100). name : str, optional Display name (default ``"PSO"``). 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). encoding : ParameterExtendingEncoding, optional Encoding that includes a ``"speed"`` parameter. If ``None``, a :class:`PSOEncoding` is used. random_state : RNGLike, optional Random number generator. **kwargs Forwarded to :class:`StaticPopulation`. """ def __init__( self, initializer: Initializer, lower_bound: float = -100, upper_bound: float = 100, name: str = "PSO", w=0.7, c1=1.5, c2=1.5, encoding: Optional[ParameterExtendingEncoding] = None, random_state: Optional[RNGLike] = None, **kwargs, ): if encoding is None: encoding = PSOEncoding(initializer.dimension) elif not isinstance(encoding, ParameterExtendingEncoding): encoding = CompositeEncoding([PSOEncoding(initializer.dimension), encoding]) self.abs_upper_bound = np.maximum(np.abs(lower_bound), np.abs(upper_bound)) if not isinstance(initializer.encoding, ParameterExtendingEncoding): logger.info("Overwritten initializer's encoding with PSO encoding.") initializer.encoding = encoding if not isinstance(initializer, ExtendedInitializer): initializer = ExtendedInitializer( solution_init=initializer, param_init_dict={ "speed": UniformInitializer(encoding.dimension, -self.abs_upper_bound, self.abs_upper_bound, random_state=random_state) }, random_state=random_state, encoding=encoding, ) self.encoding = encoding pso_op = create_swarm_operator("PSO", encoding=encoding, w=w, c1=c1, c2=c2, random_state=random_state) super().__init__(initializer, operator=pso_op, name=name, **kwargs)
[docs] def initialize(self, objfunc: ObjectiveFunc): """Set up the initial population and attach velocity constraints. Parameters ---------- objfunc : ObjectiveFunc The objective function. Its constraint handler is extended with a :class:`BounceBoundConstraint` for the velocity so that speeds stay within the feasible range. .. warning:: There is a known bug: the objective function **does not** automatically remove the extended constraint handler after a PSO run finishes. Reusing the same objective function instance for other algorithms may cause unexpected behaviour. This will be resolved in a future release. Returns ------- Population The initialised and evaluated population. """ if not isinstance(objfunc.constraint_handler, ExtendedConstraintHandler): objfunc.add_parameter_constraints( self.encoding, {"speed": BounceBoundConstraint(self.encoding.dimension, -self.abs_upper_bound, self.abs_upper_bound)} ) logger.info("Overwritten constraint's encoding with custom extended encoding. The objective must be reloaded for use with other algorithms.") return super().initialize(objfunc)