Skip to main content

Adaptive Mirror-Consensus Particle Swarm Optimization (AMC-PSO): a gradient-assisted swarm optimizer with entropy-regulated annealing and free feasibility on constrained domains.

Project description

amcpso — Adaptive Mirror-Consensus Particle Swarm Optimization

amcpso is a gradient-assisted particle swarm optimizer that evolves particles in the dual space of a strongly convex mirror potential. This buys two things classical PSO doesn't have:

  • Feasibility by construction. With the entropic mirror, every iterate is automatically a valid point on the probability simplex (x_k >= 0, sum(x) == 1) — no clip-and-renormalize projection distorting the search.
  • Entropy-regulated annealing. A swarm-dispersion signal r_t in [0, 1] closes a feedback loop that cools exploration (noise, consensus pull) automatically as the swarm converges, instead of using a fixed schedule.

It combines five forces per iteration — inertia, natural-gradient descent, mirrored cognitive/social attraction, graph-Laplacian consensus over a time-varying neighborhood topology, and annealed Gaussian noise.

Installation

pip install amcpso

Requires Python >= 3.8 and NumPy >= 1.20.

When to use it (and when not to)

Use amcpso when your problem is constrained, geometry-sensitive, and/or multimodal:

  • Simplex-constrained problems — recovering or optimizing over a probability distribution, mixture weights, portfolio allocations, or any compositional/proportion data (h_type='entropic'). This is where the mirror machinery pays off most: feasibility is structural, not statistical, and the algorithm is significantly better than projection-based PSO in the reference benchmarks.
  • Rugged, multimodal landscapes in ordinary R^d (h_type='euclidean'), such as the Rastrigin function. The entropy-regulated schedule and local (rather than global-best) topology help delay premature convergence to a poor local minimum, and it is competitive-to-better than classical constriction PSO in the reference benchmarks.
  • You have (or can cheaply compute, e.g. via autodiff or finite differences) a gradient of the objective — amcpso is gradient-assisted, not a purely black-box method.

Don't expect a win when:

  • Your objective is smooth and unimodal (e.g. a plain quadratic bowl) — classical PSO's noiseless contraction is typically competitive or better here, consistent with the No-Free-Lunch theorem.
  • You have no usable gradient and computing one is expensive or impossible — consider a derivative-free method instead.

Quick start

import numpy as np
from amcpso import amc_pso

def sphere(x):
    return float(np.sum(x**2))

def sphere_grad(x):
    return 2 * x

x_best, f_best = amc_pso(sphere, sphere_grad, d=5, seed=0)
print(x_best, f_best)

The function: amc_pso(...)

from amcpso import amc_pso

x_best, f_best = amc_pso(
    f, grad_f, d,
    N=50, T=500, h_type='euclidean', init_range=(-5, 5),
    beta=0.7, eta0=0.05, c10=1.5, c20=1.5, lambda0=0.3,
    T0=0.5, alpha=5.0, gamma=1.0, bandwidth=2.0, epsilon=1e-10,
    kappa=1e-3, p=0.5, G_max=10.0, v_max=None,
    natural='diag', naive=False, entropy_feedback=True,
    return_history=False, seed=None,
)

Required arguments

Argument Type Description
f callable Objective function f(x) -> float, x is shape (d,). The function being minimized.
grad_f callable Gradient grad_f(x) -> array of shape (d,). Required — amcpso is gradient-assisted.
d int Problem dimension.

Key optional arguments

Argument Default Description
N 50 Swarm size.
T 500 Number of iterations (optimization budget).
h_type 'euclidean' 'euclidean' for unconstrained R^d; 'entropic' for the probability simplex (feasibility for free).
init_range (-5, 5) Per-coordinate init range, used only for h_type='euclidean'.
beta 0.7 Inertia weight, in [0, 1).
eta0, p 0.05, 0.5 Step-size schedule eta_t = eta0 / (1 + t) ** p.
c10, c20 1.5, 1.5 Initial cognitive / social gains (linearly annealed to 0).
lambda0 0.3 Base consensus gain; effective gain scales with the dispersion ratio r_t.
T0, alpha, gamma 0.5, 5.0, 1.0 Exploration temperature schedule.
bandwidth, kappa 2.0, 1e-3 Gaussian-kernel neighborhood topology bandwidth and cutoff.
G_max 10.0 Gradient-norm clip (rescales, doesn't truncate).
v_max None Optional dual-velocity norm clip for extra robustness.
natural 'diag' Natural-gradient preconditioner for the entropic mirror: 'diag' or 'fisher'.
return_history False If True, also return a dict of per-iteration traces (best, r, T, lam, eta).
seed None RNG seed for reproducibility.
naive, entropy_feedback False, True Ablation flags — leave at defaults for actual optimization; see the docstring for details.

Full parameter-by-parameter documentation is available in the function's docstring: help(amc_pso).

Returns

  • x_best (numpy.ndarray, shape (d,)) — best position found.
  • f_best (float) — objective value at x_best.
  • history (dict, only if return_history=True) — per-iteration traces.

Example: multimodal optimization (Rastrigin, R^d)

This is the best-use-case scenario for the Euclidean mirror: a rugged, multimodal landscape.

import numpy as np
from amcpso import amc_pso
from amcpso.benchmarks import rastrigin, rastrigin_grad

d = 10
x_best, f_best = amc_pso(
    rastrigin, rastrigin_grad, d=d,
    h_type='euclidean', init_range=(-5.12, 5.12),
    N=50, T=500, seed=7,
)
print(f"best objective: {f_best:.4f}")

Example: constrained optimization on the probability simplex

This is the best use case for amcpso: recovering a probability vector x* on the simplex from noisy linear measurements b = A @ x*, where every iterate must satisfy x >= 0 and sum(x) == 1.

import numpy as np
from amcpso import amc_pso

rng = np.random.default_rng(12345)
d = 20
A = rng.standard_normal((40, d))
x_star = rng.dirichlet(np.ones(d))   # ground truth on the simplex
b = A @ x_star

def loss(x):
    return float(np.sum((A @ x - b) ** 2))

def loss_grad(x):
    return 2.0 * A.T @ (A @ x - b)

x_best, f_best = amc_pso(loss, loss_grad, d=d, h_type='entropic', seed=0)

print("sum(x_best) =", x_best.sum())      # 1.0, always -- feasible by construction
print("min(x_best) =", x_best.min())      # >= 0, always
print("loss        =", f_best)

Unlike classical PSO with clip-and-renormalize projection, amc_pso with h_type='entropic' never produces an infeasible iterate at any point during the search — the softmax inverse mirror map guarantees it structurally.

Diagnosing convergence with return_history

x_best, f_best, hist = amc_pso(
    rastrigin, rastrigin_grad, d=10,
    h_type='euclidean', init_range=(-5.12, 5.12),
    seed=7, return_history=True,
)

# hist['best']: best-so-far objective per iteration
# hist['r']:    dispersion ratio r_t in [0, 1]
# hist['T']:    temperature T_t
# hist['lam']:  consensus gain lambda_t
# hist['eta']:  step size eta_t

Algorithm summary

Each particle keeps a primal position x, a dual variable y = grad_h(x), and a dual velocity v. Every iteration:

  1. Rebuilds a time-varying neighborhood topology from a thresholded Gaussian kernel on pairwise distances.
  2. Measures swarm dispersion S_t (half log-determinant of the swarm covariance) and derives a dispersion ratio r_t = min(1, exp((S_t - S_0) / d)), which drives the consensus gain and temperature schedules.
  3. Updates the dual velocity as the sum of inertia, natural-gradient descent, cognitive attraction, social attraction, Laplacian consensus, and annealed noise.
  4. Maps back to the primal space with the inverse mirror map (x = grad_h_star(y)), which is the identity for the Euclidean mirror and a softmax for the entropic mirror.

See the function docstring (help(amc_pso)) and the accompanying manuscript for the full derivation.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

amcpso-1.0.0.tar.gz (15.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

amcpso-1.0.0-py3-none-any.whl (12.5 kB view details)

Uploaded Python 3

File details

Details for the file amcpso-1.0.0.tar.gz.

File metadata

  • Download URL: amcpso-1.0.0.tar.gz
  • Upload date:
  • Size: 15.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for amcpso-1.0.0.tar.gz
Algorithm Hash digest
SHA256 956514d502219ccb6ca91091b65d53c12f9f673a14822f98370209566bf5dead
MD5 1171e0268c64839f86cd950128c58297
BLAKE2b-256 bd285973b1d4b10fb6ebb972abb7e4d7f8429ba455d1a593374afe0db41fbe60

See more details on using hashes here.

Provenance

The following attestation bundles were made for amcpso-1.0.0.tar.gz:

Publisher: publish.yml on razibmustafiz/AMC-PSO

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file amcpso-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: amcpso-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 12.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for amcpso-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 21d267fa6bb65dd77da9cbee66fc4781488b9eb4f1ceae3a5c8a0a9b66f72eed
MD5 2645650881ae5832af2ce769fe03f765
BLAKE2b-256 5a4e96bbc52f10d307e5733e1a42d5a0e987e1cdf2d99881b94516880616b4bc

See more details on using hashes here.

Provenance

The following attestation bundles were made for amcpso-1.0.0-py3-none-any.whl:

Publisher: publish.yml on razibmustafiz/AMC-PSO

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page