class MHL::ChargedSwarm

Constants

DEFAULT_CHARGED_TO_NEUTRAL_RATIO

default composition is half charged, i.e., QPSO, and half neutral, i.e., traditional PSO (with inertia), swarms

Public Class Methods

new(size:, initial_positions:, initial_velocities:, charged_to_neutral_ratio: nil, alpha: nil, c1: nil, c2: nil, chi: nil, constraints: nil, logger: nil) click to toggle source
# File lib/mhl/charged_swarm.rb, line 11
def initialize(size:, initial_positions:, initial_velocities:,
               charged_to_neutral_ratio: nil, alpha: nil, c1: nil, c2: nil,
               chi: nil, constraints: nil, logger: nil)
  @size = size

  # retrieve ratio between charged (QPSO) and neutral (constrained PSO) particles
  ratio = (charged_to_neutral_ratio || DEFAULT_CHARGED_TO_NEUTRAL_RATIO).to_f
  unless ratio > 0.0
    raise ArgumentError, 'Parameter :charged_to_neutral_ratio should be a real greater than zero!'
  end

  num_charged_particles = (@size * ratio).round
  @num_neutral_particles = @size - num_charged_particles

  # the particles are ordered, with neutral (PSO w/ inertia) particles
  # first and charged (QPSO) particles later
  @particles = Array.new(@size) do |index|
    if index < @num_neutral_particles
      Particle.new(initial_positions[index], initial_velocities[index])
    else
      QuantumParticle.new(initial_positions[index])
    end
  end

  # find problem dimension
  @dimension  = initial_positions[0].size

  @iteration = 1

  # define procedure to get dynamic value for alpha
  @get_alpha = if alpha and alpha.respond_to? :call
    alpha
  else
    ->(it) { (alpha || DEFAULT_ALPHA).to_f }
  end

  # get values for parameters C1 and C2
  @c1 = (c1 || DEFAULT_C1).to_f
  @c2 = (c2 || DEFAULT_C2).to_f

  # define procedure to get dynamic value for chi
  @get_chi = if chi and chi.respond_to? :call
    chi
  else
    ->(it) { (chi || DEFAULT_CHI).to_f }
  end

  @constraints = constraints
  @logger = logger

  if @constraints and @logger
    @logger.info "ChargedSwarm called w/ constraints: #{@constraints}"
  end
end

Public Instance Methods

mutate() click to toggle source
# File lib/mhl/charged_swarm.rb, line 66
def mutate
  # get alpha parameter
  alpha = @get_alpha.call(@iteration)

  # get chi parameter
  chi = @get_chi.call(@iteration)

  # this calculates the C_n parameter (the centroid of the set of all the
  # particle attractors) as defined in equations 4.81 and 4.82 of [SUN11].
  #
  # Note: we consider ALL the particles here, not just the charged (QPSO)
  # ones. As a result, the neutral particles influence the behavior of the
  # charged ones not only by defining the swarm attractor, but also the
  # centroid.
  attractors = @particles.map {|p| p.attractor[:position] }
  c_n = 0.upto(@dimension-1).map do |j|
    attractors.inject(0.0) {|s,attr| s += attr[j] } / @size.to_f
  end

  @particles.each_with_index do |p,i|
    # remember: the particles are kept in a PSO-first and QPSO-last order
    if i < @num_neutral_particles
      p.move(chi, @c1, @c2, @swarm_attractor)
    else
      p.move(alpha, c_n, @swarm_attractor)
    end
    if @constraints
      p.remain_within(@constraints)
    end
  end

  @iteration += 1
end