Exploring Particle Swarm Optimization with Dart: A Beginner's Guide

Adam StirtanAdam Stirtan
7 min read

Particle Swarm Optimization (PSO) is an efficient and intuitive optimization technique inspired by social behaviour of animals. Developed in 1995 by Eberhart and Kennedy, PSO has gained popularity in various fields, including engineering, computer science, and economics. By simulating the movement of a swarm of particles, PSO searches for optimal solutions in complex problem spaces.

Think about the last time you saw a large flock of birds, or a swarm of flying bugs. As they move around in their 3D space, each of them occupies a vector at position <x, y, z>. Their world space may be a field, like the image below, or maybe its the swarm of bugs seemingly flying directly around your head driving you insane like a warm summer night in Ontario.

The position vector of every particle/bird/bug is input to the fitness function of our optimization. The function below evaluates a candidate solution in an n-dimensional space and returns a scalar fitness value y, indicating its quality for optimization.

$$f: \mathbb{R}^n \to \mathbb{R}, \quad f(\mathbf{x}) = y$$

Once the swarm is initialized with random positions and velocities, the PSO algorithm enters its iterative loop. In each step, every particle evaluates its current position using the fitness function, updating its personal best position if it discovers a better one. The swarm also keeps track of the global best position found by any particle. Guided by these best positions, each particle updates its velocity by combining three components: inertia (how much it retains its previous motion), cognitive influence (how strongly it moves toward its own best position), and social influence (how strongly it is drawn toward the swarm's global best). These components are scaled by adjustable weights and random factors, simulating the unpredictable yet purposeful nature of a swarm. The updated velocity is then used to calculate the particle's new position, pushing it closer to optimal solutions with each iteration.

The velocity update method drives particle movement by balancing three forces: inertia (maintaining current motion), a pull toward its personal best position, and a pull toward the swarm's best position. Weighted and randomized, these forces help particles explore the search space while converging toward optimal solutions.

$$\mathbf{v}_i(t+1) = w \cdot \mathbf{v}_i(t) + c_1 \cdot r_1 \cdot (\mathbf{p}_i - \mathbf{x}_i(t)) + c_2 \cdot r_2 \cdot (\mathbf{g} - \mathbf{x}_i(t))$$

In the PSO algorithm, each particle’s velocity is updated based on three main components: inertia, cognitive influence, and social influence. The inertia term, represented by the weight w, helps the particle maintain its current velocity, allowing it to continue moving in the same direction. The cognitive influence is scaled by the coefficient c1 and pulls the particle toward its personal best position, p_i, encouraging it to exploit areas it has already discovered. The social influence is scaled by the coefficient c2 and pulls the particle toward the global best position, g, found by the entire swarm, helping the particle explore new regions of the search space. Both the cognitive and social influences are further randomized by the factors r1 and r2, which are random values between 0 and 1, introducing stochasticity to the particle’s movement. The resulting velocity, v_i(t+1), is a combination of these influences and guides the particle’s next position, x_i(t+1), balancing exploration and exploitation to find the optimal solution.

Particle Swarm Optimization in Dart

This Dart implementation of the Particle Swarm Optimization (PSO) algorithm simulates a swarm of particles searching for an optimal solution in a 2-dimensional space. The algorithm starts by randomly initializing particles' positions and velocities, then iteratively updates these values based on their personal best positions pBest and the global best position found by the swarm gBest. The particles' velocities are updated using a combination of their current velocity, cognitive influence (attraction to their personal best), and social influence (attraction to the global best). The algorithm aims to minimize a problem function, which, in this case, is the sum of the squares of the particle's position values. The algorithm returns the global best position found during the iterations as the optimal solution.

import 'dart:math';

// Define the PSO parameters
const numParticles = 30;
const numDimensions = 2;
const maxIterations = 100;

// Define the problem function
double problemFunction(List<double> x) {
  return pow(x[0], 2) + pow(x[1], 2);
}

// Define the PSO algorithm
List<double> particleSwarmOptimization() {
  // Initialize the particles and velocities
  List<List<double>> particles = [];
  List<List<double>> velocities = [];
  Random random = Random();

  for (int i = 0; i < numParticles; i++) {
    List<double> particle = [];
    List<double> velocity = [];

    for (int j = 0; j < numDimensions; j++) {
      particle.add(random.nextDouble() * 10);
      velocity.add(random.nextDouble());
    }

    particles.add(particle);
    velocities.add(velocity);
  }

  // Initialize the best positions
  List<List<double>> pBest = particles.map((particle) => List.from(particle)).toList();
  List<double> gBest = List.from(pBest[0]);

  // Perform iterations
  for (int iteration = 0; iteration < maxIterations; iteration++) {
    for (int i = 0; i < numParticles; i++) {
      List<double> particle = particles[i];
      List<double> velocity = velocities[i];
      List<double> pBestParticle = pBest[i];

      for (int j = 0; j < numDimensions; j++) {
        velocity[j] = velocity[j] +
            random.nextDouble() * (pBestParticle[j] - particle[j]) +
            random.nextDouble() * (gBest[j] - particle[j]);
        particle[j] = particle[j] + velocity[j];
      }

      // Update pBest and gBest
      if (problemFunction(particle) < problemFunction(pBestParticle)) {
        pBest[i] = List.from(particle);
      }

      if (problemFunction(particle) < problemFunction(gBest)) {
        gBest = List.from(particle);
      }
    }
  }

  return gBest;
}

// Usage
void main() {
  List<double> solution = particleSwarmOptimization();
  print("Optimal solution: $solution");
}

Particle Swarm Optimization (PSO) is a surprisingly simple yet powerful algorithm that mimics the way flocks of birds or schools of fish find their way to optimal locations. By updating particles' positions based on their own experiences and the experiences of the swarm, PSO explores the search space in a smart, dynamic way. Whether you're optimizing an engineering problem or diving into machine learning, PSO offers a flexible, efficient approach that can quickly adapt to many challenges. With its combination of randomness and guided movement, PSO provides a great way to solve tough problems while keeping things intuitive and easy to implement.

Frequently asked questions

How are particles in PSO initialized?

In the Particle Swarm Optimization (PSO) algorithm, particles are initialized with random positions and velocities. The position of each particle is typically selected within a defined search space—often a random value within a specified range (e.g., between 0 and 10 for each dimension). Similarly, the velocity of each particle is initialized as a random value, typically between 0 and 1. This random initialization allows the swarm to explore a wide area of the search space initially. As the algorithm progresses, the particles update their positions and velocities based on their own best-found positions and the global best position found by the swarm, gradually converging toward the optimal solution.

What is the role of the global best and personal best in PSO?

The global best (gBest) represents the best solution found by any particle in the swarm. The personal best (pBest) is the best solution found by each individual particle. Both of these play crucial roles in guiding the particles’ movement: particles are attracted toward their personal best and the global best, balancing exploration of the search space with exploitation of known good solutions.

How does the inertia weight affect the PSO algorithm?

The inertia weight (w) controls the influence of the particle’s previous velocity on its current velocity. A higher inertia weight encourages exploration of new areas in the search space, while a lower inertia weight helps the particle converge more quickly to a solution. Tuning the inertia weight is key to balancing exploration and exploitation in PSO.

Why are random numbers used in PSO?

Random numbers are used in PSO to introduce variability into the particle's movements, ensuring that the swarm does not get stuck in local optima. These random factors are applied to the cognitive and social components of the velocity update, allowing particles to explore different parts of the search space and avoid predictable paths that could lead to suboptimal solutions.

How do you choose the optimal values for the parameters in PSO?

The performance of PSO depends on the correct choice of parameters, such as the number of particles, the number of iterations, the inertia weight, and the cognitive and social coefficients. These values are typically chosen through experimentation or by running the algorithm on known benchmark problems. In some cases, they can be fine-tuned using techniques like grid search or sensitivity analysis to achieve better performance.

0
Subscribe to my newsletter

Read articles from Adam Stirtan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Adam Stirtan
Adam Stirtan