file jswarm/particle.cpp

[No description available] More…

Namespaces

Name
Gambit
TODO: see if we can use this one:
Gambit::jswarm_1_0_0

Detailed Description

Author: Pat Scott (pat.scott@uq.edu.au)

Date: 2019 Oct

j-Swarm: particle swarm optimisation with meta-optimisation a la jDE.

Implementations of particle class


Authors (add name and date if you modify):


Source code

//   GAMBIT: Global and Modular BSM Inference Tool
//   *********************************************
///  \file
///
///  j-Swarm: particle swarm optimisation with
///  meta-optimisation a la jDE.
///
///  Implementations of particle class
///
///  *********************************************
///
///  Authors (add name and date if you modify):
///
///  \author Pat Scott
///          (pat.scott@uq.edu.au)
///  \date 2019 Oct
///
///  *********************************************

#include "gambit/ScannerBit/scanners/jswarm/jswarm.hpp"


namespace Gambit
{

  namespace jswarm_1_0_0
  {

    /// Constructor
    particle::particle(int nPar, std::vector<double>& lb, std::vector<double>& ub, rng_type& generator)
    : lowerbounds(&lb)
    , upperbounds(&ub)
    , rng(&generator)
    , personal_best_value(-std::numeric_limits<double>::max())
    {
      if (nPar <= 0) Scanner::scan_error().raise(LOCAL_INFO, "You must set nPar positive before creating a particle!");
      x.resize(nPar);
      v.resize(nPar);
      personal_best_x.resize(nPar);
    }

    /// Initialise a particle with a random position and zero/random velocity
    void particle::init(bool zero_vel)
    {
      for (unsigned int i = 0; i < x.size(); i++)
      {
        double extent = upperbounds->at(i) - lowerbounds->at(i);
        // Set position randomly
        x.at(i) = lowerbounds->at(i) + extent * std::generate_canonical<double, 32>(*rng);
        // Reset velocity to either zero or a random number in [-extent,extent].  Velocity is in units of [x] per generation 'timestep'.
        v.at(i) = (zero_vel ? 0.0 : extent * (2.0 * std::generate_canonical<double, 32>(*rng) - 1.0));
      }
    }

    /// Update the particle's personal best fit seen so far
    void particle::update_personal_best()
    {
      if (lnlike > personal_best_value)
      {
        personal_best_value = lnlike;
        personal_best_x = x;
      }
    }

    /// Reflect a particle's position and velocity off the walls of the prior box
    void particle::reflect()
    {
      for (unsigned int i = 0; i < x.size(); i++)
      {
        double bound_violated, other_bound;
        double lb = lowerbounds->at(i);
        double ub = upperbounds->at(i);

        // Work out whether it is the upper, lower, or no bound exceeded for this dimension
        if (x.at(i) < lb)
        {
          bound_violated = lb;
          other_bound = ub;
        }
        else if (x.at(i) > ub)
        {
          bound_violated = ub;
          other_bound = lb;
        }
        else continue;

        // Work out how many prior box lengths the particle has overshot (= how many reflections needed)
        double overshoot_factor = (x.at(i) - bound_violated) / (ub - lb);
        int reflections = (int) overshoot_factor;
        double offset = (overshoot_factor - reflections) *  (ub - lb);

        // Perform the reflections
        if (reflections%2 == 1) // odd number of reflections
        {
          x.at(i) = bound_violated - offset;
          v.at(i) = -v.at(i);
        }
        else x.at(i) = other_bound + offset; //even number of reflections
      }


    }

    /// Return a particle's position vector, discretised at some specified indices
    std::vector<double> particle::discretised_x(const std::vector<int>& indices)
    {
      std::vector<double> x_discrete = x;
      for (int i : indices) x_discrete.at(i) = round(x.at(i));
      return x_discrete;
    }


  }

}

Updated on 2025-02-12 at 15:36:40 +0000