Why Particle Swarm Optimization Matters
Imagine tuning two real-valued settings when evaluating the system is possible but differentiating it is difficult. A single search point can forget useful locations after moving away. Particle swarm optimization, or PSO, instead moves a collection of candidate points while remembering each particle's best visit and the best visit found by the entire swarm.
Each particle has a position and a velocity. Its next velocity combines momentum, attraction toward its own remembered success, and attraction toward a shared success. The particle then moves and is evaluated. Its current position may become worse; the best memories are preserved separately. These memories guide exploration without providing a proof that the global optimum has been found.
This lesson implements a specific synchronous global-best PSO for bounded continuous vectors, with inertia weight, separate per-coordinate random factors, velocity caps, and a defined boundary rule. A shifted sphere supplies an analytic reference solution. You will trace motion, memories, random draws, clipping, and objective calls, then run equivalent Python, C++, and Java programs.
Particle swarm optimization explores a continuous domain by combining velocity inertia with attraction toward each particle's best-ever position and the swarm's best-ever position. Keep current motion separate from those historical memories: preserving the best evaluated solution is a useful invariant, but it is not a global optimality certificate.
Core Concepts and Terminology
Let particle $i$ at iteration $t$ have position $\mathbf x_i^t\in\mathbb R^d$ and velocity $\mathbf v_i^t$. Its personal best $\mathbf p_i^t$ is the first position attaining the smallest objective it has evaluated so far. The swarm best $\mathbf g^t$ is the first position attaining the smallest objective evaluated by any particle. We minimize a deterministic $f$ inside a box $\ell_j\le x_j\le h_j$.
Before velocity and boundary handling, the inertia-weight update for coordinate $j$ is
$$v_{ij}^{\mathrm{raw}}=w v_{ij}^t+c_1r_{1,ij}^t(p_{ij}^t-x_{ij}^t)+c_2r_{2,ij}^t(g_j^t-x_{ij}^t).$$
The inertia weight $w$ retains momentum; $c_1$ controls personal or cognitive attraction; $c_2$ controls social attraction. The random multipliers are sampled separately for every particle, coordinate, and iteration. In an idealized PSO description they are independent uniforms on $[0,1)$; the reproducible teaching programs use the explicitly defined finite grid $\{0,1/1024,\ldots,1023/1024\}$.
The proposed position uses the new velocity, not the previous one:
$$\mathbf x_i^{\mathrm{raw}}=\mathbf x_i^t+\widehat{\mathbf v}_i,$$
where $\widehat{\mathbf v}_i$ is the component-wise capped velocity. Boundary handling may then modify both position and stored velocity. There is no fixed search step size: velocity depends on momentum, remembered points, random factors, and repair.
The worked objective is $f(x,y)=(x-1)^2+(y+1)^2$ on $[-5,5]^2$, with unique minimum $f(1,-1)=0$. The diagram follows particle $2$ through its first two moves. Its current objective worsens from $1$ to $8.5$, while its personal best remains $1$. That distinction is central to PSO.
| Term | Worked value or example | Role |
|---|---|---|
| Position | $\mathbf x_2^1=(0,-1)$ | Current candidate, which may later become worse |
| Velocity | $\mathbf v_2^1=(-3,-3)$ | Momentum used for the next motion |
| Current objective | $f(\mathbf x_2^2)=8.5$ | Quality of the particle's present location |
| Personal best | $\mathbf p_2^2=(0,-1)$ with score $1$ | Best evaluated visit of particle $2$ |
| Swarm best | Approximately $(0.09460449,-1)$ with score $0.81974103$ | Best evaluated visit across all particles |
| Inertia weight | $w=0.5$ | Halves the previous velocity before attractions |
| Cognitive / social coefficients | $c_1=c_2=1.5$ | Scale pulls toward personal and shared memories |
| Random multipliers | Draw $q\in\{0,\ldots,1023\}$, use $r=q/1024$ | Reproducible finite-grid variation |
| Velocity cap | $V_j=3$ | Limits each velocity coordinate before moving |
| Boundary rule | Clip an outside position; set that velocity coordinate to $0$ | Keeps evaluated points feasible and stops outward motion |
| Synchronous guide | Freeze $\mathbf g^t$ throughout iteration $t+1$ | Makes all particles use the same completed-iteration social memory |
How Particle Swarm Optimization Works, Step by Step
The inputs provide initial positions and velocities, box bounds, objective center, per-coordinate velocity caps, seed, iteration limit $K$, coefficients $w,c_1,c_2$, and objective-evaluation budget $B$. The evaluator is the shifted sphere
$$f(\mathbf x)=\sum_{j=0}^{d-1}(x_j-c_j)^2.$$
- Validate and initialize memories. Copy the input arrays. Require budget for all $N$ initial evaluations; otherwise return
EVAL_LIMITwith no evaluated solution and no random draws. Evaluate all initial positions, initialize each personal best with an independent position copy, and choose the earliest minimum as the swarm archive. Record iteration $0$. - Check complete-iteration limits. If $K$ iterations are complete, stop with
ITER_LIMIT. Otherwise require another $N$ evaluations; if unavailable, stop withEVAL_LIMITbefore generating any new motion or random draw. - Freeze the social guide. Copy the current swarm archive into a guide shared by every particle in this iteration. All calculations read old positions, velocities, and personal memories. Store next states separately. Improvements found early in the sweep affect the guide only in the next iteration.
- Draw and compute velocity. For each particle, visit coordinates in increasing order. Draw cognitive multiplier first, then social multiplier. Consume both draws even when a coefficient or attraction difference is zero. Compute inertia, cognitive attraction, and social attraction, then add the first two terms and finally the third.
- Limit velocity. For a nonnegative cap $V_j$, set
$$\widehat v_{ij}=\min\bigl(V_j,\max(-V_j,v_{ij}^{\mathrm{raw}})\bigr).$$
- Move and handle the box. Form $z_{ij}=x_{ij}^t+\widehat v_{ij}$. If $z_{ij}$ is strictly outside its interval, clip it to the nearest bound and store velocity $0$ for that coordinate. Otherwise store position $z_{ij}$ and velocity $\widehat v_{ij}$. Landing exactly on a bound is not counted as crossing it; outward velocity is reset only if a later proposal goes outside.
- Evaluate and update memories. Evaluate the final feasible position once, even if it equals the previous position. Always keep the new current state. Replace a personal best only for a strictly smaller objective; similarly replace the swarm archive only for a strictly smaller objective. Equal scores retain the older memory. Never overwrite a good memory just because the current particle moved.
- Commit and record. After all particles have moved and been evaluated, commit positions, velocities, scores, and personal memories together, increment the iteration, and store a snapshot. The archive may accumulate records during the sweep, but the already-frozen social guide remains unchanged.
The personal and swarm bests are positions with objective values, not just numeric thresholds. Independent copies keep the stored point consistent with its cached score. Unlike differential evolution's target-wise greedy replacement, this PSO accepts current motion that worsens the objective; only its historical memories have monotonic best scores.
flowchart TD
A["Validate and copy swarm state"] --> B{"Budget covers initialization?"}
B -->|No| Z["Return no evaluated point"]
B -->|Yes| C["Evaluate positions and initialize best memories"]
C --> D{"Iteration limit reached?"}
D -->|Yes| Y["Return archive and completed swarm"]
D -->|No| E{"Budget covers N new evaluations?"}
E -->|No| Y
E -->|Yes| F["Freeze social guide and start next state"]
F --> G["Draw per-coordinate factors and compute velocity"]
G --> H["Cap velocity, move, and repair box crossings"]
H --> I["Evaluate current point and retain strict memory improvements"]
I --> J{"More particles?"}
J -->|Yes| G
J -->|No| L["Commit iteration and record snapshot"]
L --> D
Worked Example with a Full Trace
Use $N=3$ particles in two dimensions, bounds $[-5,5]^2$, center $(1,-1)$, caps $(3,3)$, seed $43$, $K=3$, $w=0.5$, $c_1=c_2=1.5$, and $B=100$. Initial state is:
| Particle | Position | Velocity | Objective / initial personal score |
|---|---|---|---|
| $0$ | $(-4,4)$ | $(-3,3)$ | $50$ |
| $1$ | $(-1,-4)$ | $(0.5,0)$ | $13$ |
| $2$ | $(3,2)$ | $(0,-1)$ | $13$ |
Particle $1$ wins the initial objective tie because it appears first. All initial personal-best coordinates equal their particle's initial position, so the first iteration has zero cognitive attraction.
The seeded generator uses
$$z_{k+1}=48271z_k\bmod2147483647,\qquad z_0=43.$$
Let $R=2147483646$. For each mapped draw, compute $v=z-1$, reject and retry if $v\ge R-(R\bmod1024)$, and otherwise return $q=v\bmod1024$. Use $r=q/1024$. This rejection mapping balances residue classes under a uniform raw-input model; the seeded generator itself is deterministic, not independent mathematical randomness. The first raw state is $2075653$, so the first mapped draw is $(2075653-1)\bmod1024=4$.
For each particle the draw order is cognitive $x$, social $x$, cognitive $y$, social $y$. The next table gives every mapped draw and every raw/capped velocity. Coordinates, velocities, and scores in the trace tables are rounded to eight decimal places for readability; calculations use the unrounded state recorded by the programs.
| Iteration / particle | Cognitive q vector | Social q vector | Raw velocity | Capped velocity |
|---|---|---|---|---|
| $1/0$ | 4,218 | 760,36 | (1.83984375,1.07812500) | (1.83984375,1.07812500) |
| $1/1$ | 163,944 | 232,771 | (0.25000000,0.00000000) | (0.25000000,0.00000000) |
| $1/2$ | 203,227 | 883,956 | (-5.17382812,-8.90234375) | (-3.00000000,-3.00000000) |
| $2/0$ | 209,635 | 16,150 | (0.97055054,-1.31835938) | (0.97055054,-1.31835938) |
| $2/1$ | 263,803 | 655,1005 | (0.84460449,4.41650391) | (0.84460449,3.00000000) |
| $2/2$ | 87,337 | 860,184 | (-1.50000000,-1.50000000) | (-1.50000000,-1.50000000) |
| $3/0$ | 568,452 | 580,159 | (1.57635230,-1.74958134) | (1.57635230,-1.74958134) |
| $3/1$ | 470,638 | 660,428 | (0.42230225,1.50000000) | (0.42230225,1.50000000) |
| $3/2$ | 21,120 | 511,61 | (0.48976010,-0.35229492) | (0.48976010,-0.35229492) |
For iteration $1$, particle $0$, the frozen guide is $(-1,-4)$. Inertia is $(-1.5,1.5)$ and cognitive attraction is zero. Social attraction is $(1.5(760/1024)3,\;1.5(36/1024)(-8))=(3.33984375,-0.421875)$. Thus raw velocity is $(1.83984375,1.078125)$. Its proposed position has second coordinate $5.078125$, so repair sets that coordinate to $5$ and its stored velocity to $0$.
For particle $2$ in the same iteration, raw velocity $(-5.173828125,-8.90234375)$ is capped to $(-3,-3)$, producing $(0,-1)$ with score $1$. At iteration $2$, that particle still has its personal best and frozen social guide at its current point, so both attractions vanish. Inertia alone moves it to $(-1.5,-2.5)$ with score $8.5$; its personal memory stays at $(0,-1)$ with score $1$.
Here are the proposed positions, feasible positions, stored velocities after boundary handling, and memory decisions for every update:
| Iteration / particle | Proposed position | Feasible position | Stored next velocity | Current objective | New personal record? |
|---|---|---|---|---|---|
| $1/0$ | (-2.16015625,5.07812500) | (-2.16015625,5.00000000) | (1.83984375,0.00000000) | $45.98658752$ | Yes |
| $1/1$ | (-0.75000000,-4.00000000) | (-0.75000000,-4.00000000) | (0.25000000,0.00000000) | $12.06250000$ | Yes |
| $1/2$ | (0.00000000,-1.00000000) | (0.00000000,-1.00000000) | (-3.00000000,-3.00000000) | $1.00000000$ | Yes |
| $2/0$ | (-1.18960571,3.68164062) | (-1.18960571,3.68164062) | (0.97055054,-1.31835938) | $26.71213212$ | Yes |
| $2/1$ | (0.09460449,-1.00000000) | (0.09460449,-1.00000000) | (0.84460449,3.00000000) | $0.81974103$ | Yes |
| $2/2$ | (-1.50000000,-2.50000000) | (-1.50000000,-2.50000000) | (-1.50000000,-1.50000000) | $8.50000000$ | No |
| $3/0$ | (0.38674659,1.93205929) | (0.38674659,1.93205929) | (1.57635230,-1.74958134) | $8.97305142$ | Yes |
| $3/1$ | (0.51690674,0.50000000) | (0.51690674,0.50000000) | (0.42230225,1.50000000) | $2.48337910$ | No |
| $3/2$ | (-1.01023990,-2.85229492) | (-1.01023990,-2.85229492) | (0.48976010,-0.35229492) | $7.47206093$ | No |
Each accepted personal record stores an independent copy of that row's feasible point. Iteration $3$ also demonstrates nonzero cognitive attraction for particle $2$: its current point is $(-1.5,-2.5)$, while its personal memory is $(0,-1)$ and its social guide is $(0.0946044921875,-1)$. The inertia, cognitive, and social terms are respectively
$$(-0.75,-0.75),\qquad(0.046142578125,0.263671875),$$
and approximately $(1.1936175227165222,0.134033203125)$. The resulting velocity is approximately $(0.4897601008415222,-0.352294921875)$. Its new current score improves relative to its previous current score $8.5$, but remains worse than personal record $1$; that record is therefore preserved.
The completed-iteration summary is:
| Iteration | Personal-best objectives by particle | Swarm archive position | Swarm record objective | Current minimum | Evaluations / raw draws |
|---|---|---|---|---|---|
| $0$ | 50.00000000,13.00000000,13.00000000 | (-1.00000000,-4.00000000) | $13.00000000$ | $13.00000000$ | $3/0$ |
| $1$ | 45.98658752,12.06250000,1.00000000 | (0.00000000,-1.00000000) | $1.00000000$ | $1.00000000$ | $6/12$ |
| $2$ | 26.71213212,0.81974103,1.00000000 | (0.09460449,-1.00000000) | $0.81974103$ | $0.81974103$ | $9/24$ |
| $3$ | 8.97305142,0.81974103,1.00000000 | (0.09460449,-1.00000000) | $0.81974103$ | $2.48337910$ | $12/36$ |
At iteration $3$, all current particles are worse than the historical swarm archive. The final best is approximately $(0.09460449,-1)$ with objective $0.81974103$, while the best current objective is $2.48337910$. Returning only the current minimum would discard a better evaluated solution. The analytic optimum remains $(1,-1)$ with value $0$.
For exact generator accounting, these are the end states after each particle and cumulative raw draw counts:
| Iteration / particle | End generator state | Cumulative raw draws |
|---|---|---|
| $1/0$ | $728608805$ | $4$ |
| $1/1$ | $245587716$ | $8$ |
| $1/2$ | $207805373$ | $12$ |
| $2/0$ | $7816343$ | $16$ |
| $2/1$ | $1211800558$ | $20$ |
| $2/2$ | $169533625$ | $24$ |
| $3/0$ | $1918681248$ | $28$ |
| $3/1$ | $1781803437$ | $32$ |
| $3/2$ | $2063162430$ | $36$ |
No rejection occurs in this sample: each particle update consumes four raw draws, each iteration consumes twelve, and the run consumes $36$. Final status is ITER_LIMIT, with $12$ objective evaluations, $9$ updates, $9$ moved particles, $6$ strict personal records, $3$ strict swarm records, $3$ velocity-coordinate clips, and $1$ box-coordinate crossing. Swarm records can occur more than once within an iteration; the counter excludes initialization.
Trace It by Hand
At the start of iteration $2$, particle $2$ is at $(0,-1)$ with velocity $(-3,-3)$, personal best $(0,-1)$, and frozen social guide $(0,-1)$. Use $w=0.5$, $c_1=c_2=1.5$, caps $(3,3)$, and bounds $[-5,5]^2$. Predict its next velocity, position, current objective, and personal memory.
Reveal: both attraction differences are zero, so velocity becomes $(-1.5,-1.5)$. The new position $(-1.5,-2.5)$ is feasible and has objective $6.25+2.25=8.5$. The particle keeps that current position, but its personal memory remains $(0,-1)$ with score $1$. Particle $1$'s earlier archive improvement in the same sweep cannot change this already-frozen social guide.
Implementation in Python, C++, and Java
Each panel is a complete program with the same inputs, random stream, arithmetic order, boundary rule, and printed output. Use Python $3.10+$, C++17, or Java $17+$. For C++, compile with g++ -std=c++17 -O2 -ffp-contract=off main.cpp -o pso and avoid fast-math transformations. Save the Java panel as Main.java.
Inputs require $1\le N\le32$, $1\le d\le16$, a seed in $1,\ldots,2147483646$, $0\le K\le200$, and $0\le B\le10^6$. Coefficients must be finite with $0\le w\le1$ and $0\le c_1,c_2\le2$. Bounds and center coordinates must be finite and have magnitude at most $10^6$, bounds must be ordered, and every initial position must be inside its box. Velocity caps are finite values in $[0,10^6]$; every initial velocity coordinate must have magnitude at most its cap. Equal position bounds and zero velocity caps are allowed. The center may lie outside the box.
Python accepts bounded integer or float numeric data but rejects booleans; seed, iteration limit, and budget must be actual integers. Inputs must be ordinary finite sequences; Java arrays and rows must be non-null. Invalid parameters raise an exception before searching. The finite ranges keep this sphere's squared differences and the velocity arithmetic finite. Underflow and rounding can still erase tiny steps or distinguishable real-valued objectives.
The search uses binary64 arithmetic, with separate subtraction, multiplication, and addition operations. Each attraction computes coefficient times random multiplier, then multiplies the position difference; inertia plus cognitive attraction is added before social attraction. The objective subtracts, squares, and accumulates coordinates left to right. Java's BigDecimal helper is used only to print the exact double rounded to eight decimal places with half-even rounding; the optimizer itself uses double. Display rounding does not change decisions.
Result contains status, has_value, swarm archive and score, final positions and velocities, current scores, personal-best positions and scores, completed iterations, evaluation/update/move/record/clip/hit counts, generator state/draw/retry counts, snapshots, and per-particle events. A moved particle means at least one position value changed numerically. Clip and boundary counters count coordinates; a strict personal record and a swarm record count particle evaluations, not iterations.
When $B\lt N$, the returned arrays and histories are empty and has_value=false; the zero objective field is a dummy value. With enough initialization budget, a zero-iteration request still evaluates the initial swarm. After initialization, ITER_LIMIT is checked before EVAL_LIMIT. Budget $5$ evaluates the initial three positions but cannot fund another three evaluations; it returns the initial archive without consuming randomness. Repeated and unchanged positions are evaluated again; the program does not silently reuse current evaluations.
The shifted sphere is a teaching evaluator with an independently known minimizer. To use a general deterministic objective, replace sphere and check every returned score is finite before updating memories. Constraints, failed simulations, noise, and changing objectives need explicit policies. The collapsed sample uses three identical positions $(4,4)$ and zero velocities: personal and social differences stay zero forever, preserving objective $34$ even though a feasible point with objective $0$ exists.
Expected standard output, identical in all three languages:
spheret=0 best=(-1.00000000,-4.00000000) f=13.00000000 current_min=13.00000000 eval=3 draws=0t=1 best=(0.00000000,-1.00000000) f=1.00000000 current_min=1.00000000 eval=6 draws=12t=2 best=(0.09460449,-1.00000000) f=0.81974103 current_min=0.81974103 eval=9 draws=24t=3 best=(0.09460449,-1.00000000) f=0.81974103 current_min=2.48337910 eval=12 draws=36status=ITER_LIMIT best=(0.09460449,-1.00000000):0.81974103 iterations=3 eval=12 updates=9 moved=9 personal=6 global=3 vclips=3 hits=1 draws=36 rejections=0 rng=2063162430budgett=0 best=(-1.00000000,-4.00000000) f=13.00000000 current_min=13.00000000 eval=3 draws=0status=EVAL_LIMIT best=(-1.00000000,-4.00000000):13.00000000 iterations=0 eval=3 updates=0 moved=0 personal=0 global=0 vclips=0 hits=0 draws=0 rejections=0 rng=43zero-budgetstatus=EVAL_LIMIT best=NONE iterations=0 eval=0 updates=0 moved=0 personal=0 global=0 vclips=0 hits=0 draws=0 rejections=0 rng=43collapsedt=0 best=(4.00000000,4.00000000) f=34.00000000 current_min=34.00000000 eval=3 draws=0t=1 best=(4.00000000,4.00000000) f=34.00000000 current_min=34.00000000 eval=6 draws=12t=2 best=(4.00000000,4.00000000) f=34.00000000 current_min=34.00000000 eval=9 draws=24status=ITER_LIMIT best=(4.00000000,4.00000000):34.00000000 iterations=2 eval=9 updates=6 moved=0 personal=0 global=0 vclips=0 hits=0 draws=24 rejections=0 rng=1226194021
Complexity, Correctness, and Invariants
Let $k$ be the number of completed iterations. For an initialized run,
$$k=\min\left(K,\left\lfloor\frac{B-N}{N}\right\rfloor\right),\qquad E=N(k+1),\qquad U=kN,$$
where $E$ is objective evaluations and $U$ is particle updates. If $B\lt N$, no objective is evaluated. This implementation has no early convergence exit, so best, average, and worst objective landscapes use the same evaluation count at fixed $N,K,B$. Quality at that budget can differ greatly; no generic bound on iterations to a global optimum follows.
Every particle-coordinate consumes two mapped random draws. If $J$ raw draws are rejected, total raw draws are $Q=2dU+J$. For this particular generator and bound $1024$, each rejected state is followed by an accepted one: it has form $2147483647-a$ with $1\le a\le1023$, whose successor is $2147483647-48271a$, outside the rejection interval. Thus at most two raw draws are needed per mapped value. Together with $\Theta(d)$ sphere evaluation and state copying, the bounded implementation has best-, average-, and worst-case runtime $\Theta((k+1)Nd)$, including input validation.
With an external evaluator costing $C_f$ and an ordinary expected-constant-cost random source, search work is $O(NC_f+kN(d+C_f))$, plus input preparation. Population size, dimensionality, and evaluation cost all matter; increasing particles can improve coverage while reducing the number of iterations affordable under a fixed budget. A convergence-to-quality analysis requires assumptions about the objective and the exact PSO variant.
Live positions, velocities, personal memories, and the shared archive need $O(Nd)$ space. These programs retain full history, including raw/capped velocities, proposed/repaired positions, random draws, and copied memories, so actual auxiliary storage is $\Theta((k+1)Nd)$ words. Dropping traces reduces it to $O(Nd)$ plus evaluator state. Detailed output also has a cost proportional to the values printed.
The useful correctness proof is an induction over evaluated visits. Each initial memory is paired with the score computed at that position. Motion caps velocity, then repairs position, so evaluated current positions stay feasible and stored velocity magnitudes stay within their caps. Strict personal updates preserve the best visited score of each particle:
$$f(\mathbf p_i^t)=\min_{0\le s\le t}f(\mathbf x_i^s).$$
Strict swarm updates preserve the minimum across all those visits:
$$f(\mathbf g^t)=\min_i f(\mathbf p_i^t)=\min_{i,\,0\le s\le t}f(\mathbf x_i^s).$$
These equalities refer to the deterministic computed objective, with fixed arithmetic and coherent position/score pairs. Therefore personal-best and swarm-best scores never increase, and the archive's score is no greater than any current score. Current scores, the current minimum, and current mean need not improve. The archive point may be absent from the current swarm, as the worked run demonstrates.
Copying memories prevents later motion from changing their stored positions. Freezing the social guide makes each complete iteration use the specified synchronous rule. Reserving all $N$ evaluations before an iteration keeps returned state at a completed boundary. None of these invariants establishes global optimality: identical suboptimal memories and positions with zero velocities form a fixed point even when $w,c_1,c_2$ are positive.
| Method | Work for a stated budget | Live search storage, excluding history | Useful guarantee or assumption |
|---|---|---|---|
| This global-best PSO | $O(NC_f+kN(d+C_f))$ expected search work | $O(Nd)$ | Personal and swarm record scores never worsen; current scores may worsen |
| DE/rand/1/bin | $O(NC_f+kN(d+C_f))$ expected search work | $O(Nd)$ | Greedy replacement prevents each target's computed objective from worsening |
| Real-valued genetic algorithm | $O(NC_f+kN(d+C_f))$ for ordinary vector variation | $O(Nd)$ | Representation/operator dependent; explicit elitism can preserve population best |
| Simulated annealing | $O(K(d+C_f))$ for $K$ full-vector proposals | $O(d)$ plus archive | Explores through probabilistic acceptance of worse current states |
| Gradient descent | $O(K(d+C_{\nabla f}))$ for $K$ steps | $O(d)$ | Uses derivatives; convergence claims depend on objective and step policy |
| Uniform random search | $O(K(d+C_f))$ for $K$ full-box samples | $O(d)$ plus archive | Independent exploration baseline without swarm memory or velocity |
Each personal memory stores the best evaluated visit of its particle, and the swarm archive stores the best evaluated visit across all particles. Keep those points and scores paired with independent copies: their objective values never worsen even though current particles can move away, while feasibility and full-iteration budget checks keep returned state consistent.
Variants, Pitfalls, and Optimizations
Avoid memory aliasing and stale scores. Assigning a mutable current-position array directly to a personal best or swarm archive can change the remembered position during later motion without changing its cached objective. Copy the vector when recording a best, and copy nested rows when retaining a snapshot. The displayed counterexample uses the actual move from $(0,-1)$ to $(-1.5,-2.5)$: the true scores are $1$ and $8.5$, so an aliased “best” position with cached score $1$ is inconsistent.
Keep synchronous and asynchronous variants distinct. A synchronous sweep uses one old social guide for all particles. Updating and reusing that guide immediately gives an order-dependent asynchronous variant. Both can be studied, but mixing them silently changes the algorithm. For reproducible parallel evaluation, assign random draws and evaluations to fixed particle/coordinate indices, collect the full iteration, and commit memories in a defined tie-breaking order.
Specify boundary and velocity behavior together. This implementation caps velocity, proposes a position, clips strict box crossings, and zeros only the crossed velocity coordinates. Reflection, wrapping, random relocation, and alternative damping rules produce different motion. Resetting the entire velocity when only one coordinate crosses also changes the policy. Box repair alone does not satisfy nonlinear engineering constraints. A zero cap freezes that coordinate; a fixed bound may cause its initial nonzero velocity to be zeroed on the first attempted crossing.
Do not interpret attraction coefficients as probabilities. The random multipliers are in $[0,1)$, but $c_1,c_2$ can exceed one. Large pulls and momentum may cause oscillation or repeated clipping; small caps and coefficients can make progress slow. The accepted validation ranges keep arithmetic manageable here; they are not a theorem guaranteeing stable convergence for every objective or trajectory. PSO stability analyses depend on assumptions, topology, randomness, and the exact update rule. A bounded trajectory or convergent velocity is still not proof of finding a global minimizer.
Preserve diversity without claiming random attraction is exploration everywhere. If every particle, personal best, and swarm best equals the same suboptimal point and all velocities are zero, both attraction differences are zero for every random multiplier. The swarm stays there forever. Restarts, random immigrants, or hybrid local search can introduce new candidates, but they change the method and its evaluation budget. A tiny swarm spread or stalled archive is a practical stopping signal, not a certificate.
Choose the neighborhood and parameter policy deliberately. Global-best PSO shares one record with every particle. Local-best or ring variants use neighborhood records, altering information flow and exploration. Inertia schedules, coefficient adaptation, constriction formulations, and hybrid methods require their own equations and assumptions; do not add a constriction multiplier while treating it as an unrelated cosmetic parameter. The PySwarms global-best implementation is a primary reference for position/velocity updates and memory handling; its random precision, boundaries, stopping rules, and initialization policies differ from this teaching program.
Normalize and evaluate honestly. Variables with very different ranges can benefit from scaled coordinates and cap choices tied to their meaningful units. Binary, integer, and categorical decisions need appropriate PSO variants or a carefully specified decoder. Compare repeated seeds under equal objective budgets against random search and suitable local methods. A smooth convex sphere is an excellent correctness check but can be solved directly; it does not establish that a swarm is the most efficient solver.
Treat noisy objectives as a different memory problem. A lucky noisy observation can become a persistent attractor if cached indefinitely. Use a stated resampling or statistical policy and validate final candidates on independent data. Returning the archive rather than only the final current minimum preserves historical quality only when the stored point and its score remain meaningful.
Copy remembered positions, freeze the intended social guide, and evaluate the repaired point before associating it with a score. Velocity caps, boundary rules, tie policies, and random-draw order change the trajectory; zero spread, a stationary swarm, or a stalled best value is not a global optimality proof.
Practice Problems and Real-World Use
Begin with objectives whose reference solutions are known. For the box-constrained shifted sphere, clipping the center into each coordinate interval gives the exact real-valued minimizer, since the squared terms minimize independently. Compare returned positions and computed scores with that reference, taking floating-point rounding into account. Test a nonzero initial velocity as well as a stationary swarm so the role of momentum is visible.
For an applied study, document the objective, units, bounds, constraints, initialization, coefficients, random precision and seed policy, topology, synchronous/asynchronous timing, velocity and position handling, memory ties, budget, and final validation. Report variation across seeds and objective evaluations as well as the best run. Sensor calibration and simulation-based design can supply meaningful continuous objectives; feasibility and evaluator reliability remain part of the problem.
| Problem or application | Exercise | Main idea tested | Difficulty |
|---|---|---|---|
| Shifted sphere | Reproduce the full trace and compare with the analytic minimizer | Velocity arithmetic, synchronous guides, and objective accounting | Easy |
| One-particle momentum | Compare zero and nonzero initial velocities | Inertia, personal memory, and degenerate swarms | Easy |
| Boundary laboratory | Try exact-bound landings, crossings, and zero caps | Position repair and coordinate-wise velocity reset | Medium |
| Memory-integrity tests | Move away from a good point and verify archived coordinates | Copying, score associations, and worse current moves | Medium |
| Rosenbrock benchmark | Compare scaling and cap policies | Coupled coordinates and narrow valleys | Medium |
| Rastrigin benchmark | Compare ring and global guides at equal evaluation budgets | Multimodality, diversity, and empirical success rates | Hard |
| Sensor or model calibration | Optimize bounded real parameters on validated residual data | Evaluator reliability, units, noise, and validation | Hard |
| Simulation-based engineering design | Specify feasibility and compare repeated seeded runs | Expensive objectives, constraints, and reproducible parallel evaluation | Advanced |