Source code for pyswarms.backend.generators

# -*- coding: utf-8 -*-

"""
Swarm Generation Backend

This module abstracts how a swarm is generated. You can see its
implementation in our base classes. In addition, you can use all the methods
here to dictate how a swarm is initialized for your custom PSO.

"""

# Import standard library
import logging

# Import modules
import numpy as np

from ..utils.reporter import Reporter
from .swarms import Swarm

rep = Reporter(logger=logging.getLogger(__name__))


[docs]def generate_swarm( n_particles, dimensions, bounds=None, center=1.00, init_pos=None ): """Generate a swarm Parameters ---------- n_particles : int number of particles to be generated in the swarm. dimensions: int number of dimensions to be generated in the swarm bounds : tuple of numpy.ndarray or list, optional a tuple of size 2 where the first entry is the minimum bound while the second entry is the maximum bound. Each array must be of shape :code:`(dimensions,)`. Default is :code:`None` center : numpy.ndarray or float, optional controls the mean or center whenever the swarm is generated randomly. Default is :code:`1` init_pos : numpy.ndarray, optional option to explicitly set the particles' initial positions. Set to :code:`None` if you wish to generate the particles randomly. Default is :code:`None`. Returns ------- numpy.ndarray swarm matrix of shape (n_particles, n_dimensions) Raises ------ ValueError When the shapes and values of bounds, dimensions, and init_pos are inconsistent. TypeError When the argument passed to bounds is not an iterable. """ try: if (init_pos is not None) and (bounds is None): pos = init_pos elif (init_pos is not None) and (bounds is not None): if not ( np.all(bounds[0] <= init_pos) and np.all(init_pos <= bounds[1]) ): raise ValueError("User-defined init_pos is out of bounds.") pos = init_pos elif (init_pos is None) and (bounds is None): pos = center * np.random.uniform( low=0.0, high=1.0, size=(n_particles, dimensions) ) else: lb, ub = bounds min_bounds = np.repeat( np.array(lb)[np.newaxis, :], n_particles, axis=0 ) max_bounds = np.repeat( np.array(ub)[np.newaxis, :], n_particles, axis=0 ) pos = center * np.random.uniform( low=min_bounds, high=max_bounds, size=(n_particles, dimensions) ) except ValueError: msg = "Bounds and/or init_pos should be of size ({},)" rep.logger.exception(msg.format(dimensions)) raise except TypeError: msg = "generate_swarm() takes an int for n_particles and dimensions and an array for bounds" rep.logger.exception(msg) raise else: return pos
[docs]def generate_discrete_swarm( n_particles, dimensions, binary=False, init_pos=None ): """Generate a discrete swarm Parameters ---------- n_particles : int number of particles to be generated in the swarm. dimensions: int number of dimensions to be generated in the swarm. binary : bool generate a binary matrix. Default is :code:`False` init_pos : numpy.ndarray, optional option to explicitly set the particles' initial positions. Set to :code:`None` if you wish to generate the particles randomly. Default is :code:`None` Returns ------- numpy.ndarray swarm matrix of shape (n_particles, n_dimensions) Raises ------ ValueError When init_pos during binary=True does not contain two unique values. TypeError When the argument passed to n_particles or dimensions is incorrect. """ try: if (init_pos is not None) and binary: if not len(np.unique(init_pos)) <= 2: raise ValueError("User-defined init_pos is not binary!") # init_pos maybe ones pos = init_pos elif (init_pos is not None) and not binary: pos = init_pos elif (init_pos is None) and binary: pos = np.random.randint(2, size=(n_particles, dimensions)) else: pos = np.random.random_sample( size=(n_particles, dimensions) ).argsort(axis=1) except ValueError: rep.logger.exception("Please check the size and value of dimensions") raise except TypeError: msg = "generate_discrete_swarm() takes an int for n_particles and dimensions" rep.logger.exception(msg) raise else: return pos
[docs]def generate_velocity(n_particles, dimensions, clamp=None): """Initialize a velocity vector Parameters ---------- n_particles : int number of particles to be generated in the swarm. dimensions: int number of dimensions to be generated in the swarm. clamp : tuple of floats, optional a tuple of size 2 where the first entry is the minimum velocity and the second entry is the maximum velocity. It sets the limits for velocity clamping. Default is :code:`None` Returns ------- numpy.ndarray velocity matrix of shape (n_particles, dimensions) """ try: min_velocity, max_velocity = (0, 1) if clamp is None else clamp velocity = (max_velocity - min_velocity) * np.random.random_sample( size=(n_particles, dimensions) ) + min_velocity except ValueError: msg = "Please check clamp shape: {} != {}" rep.logger.exception(msg.format(len(clamp), dimensions)) raise except TypeError: msg = "generate_velocity() takes an int for n_particles and dimensions and an array for clamp" rep.logger.exception(msg) raise else: return velocity
[docs]def create_swarm( n_particles, dimensions, discrete=False, binary=False, options={}, bounds=None, center=1.0, init_pos=None, clamp=None, ): """Abstract the generate_swarm() and generate_velocity() methods Parameters ---------- n_particles : int number of particles to be generated in the swarm. dimensions: int number of dimensions to be generated in the swarm discrete : bool Creates a discrete swarm. Default is `False` options : dict, optional Swarm options, for example, c1, c2, etc. binary : bool generate a binary matrix, Default is `False` bounds : tuple of np.ndarray or list a tuple of size 2 where the first entry is the minimum bound while the second entry is the maximum bound. Each array must be of shape :code:`(dimensions,)`. Default is `None` center : numpy.ndarray, optional a list of initial positions for generating the swarm. Default is `1` init_pos : numpy.ndarray, optional option to explicitly set the particles' initial positions. Set to :code:`None` if you wish to generate the particles randomly. clamp : tuple of floats, optional a tuple of size 2 where the first entry is the minimum velocity and the second entry is the maximum velocity. It sets the limits for velocity clamping. Returns ------- pyswarms.backend.swarms.Swarm a Swarm class """ if discrete: position = generate_discrete_swarm( n_particles, dimensions, binary=binary, init_pos=init_pos ) else: position = generate_swarm( n_particles, dimensions, bounds=bounds, center=center, init_pos=init_pos, ) velocity = generate_velocity(n_particles, dimensions, clamp=clamp) return Swarm(position, velocity, options=options)