SPSAOptimizer

class SPSAOptimizer(learning_rate=0.2, c=0.2, alpha=0.602, gamma=0.101, A=None, resamplings=1, blocking=False, blocking_history=5, blocking_tol=2.0, exact_loss=False)[source]

Bases: _SPSAConfigMixin, Optimizer

Simultaneous Perturbation Stochastic Approximation (Spall).

Estimates the gradient from just two cost evaluations per step, independent of the parameter count, by perturbing all parameters at once along a random Bernoulli ±1 direction \(h\):

\[\hat g_k = \frac{f(\theta + c_k h) - f(\theta - c_k h)}{2 c_k}\, h, \qquad \theta \leftarrow \theta - a_k \hat g_k,\]

with decaying gains \(a_k = a/(A+k+1)^\alpha\) and \(c_k = c/(k+1)^\gamma\). This makes it attractive for many-parameter, shot-noisy circuits where parameter-shift gradients are prohibitively expensive. Single-point optimizer (n_param_sets == 1); gradient-free, so any jac/metric_fn supplied by the variational algorithm is ignored.

Parameters:
  • learning_rate (float) – Spall’s \(a\) — the learning-rate gain numerator.

  • c (float) – Perturbation-size gain numerator \(c\) (≈ the std of the cost noise is a good starting scale).

  • alpha (float) – Decay exponent for the learning-rate gain (Spall default 0.602).

  • gamma (float) – Decay exponent for the perturbation gain (Spall default 0.101).

  • A (float | None) – Learning-rate stability constant; defaults to 0.1 * max_iterations.

  • resamplings (int) – Average this many independent SPSA gradient samples per step to reduce variance (each costs two more evaluations).

  • blocking (bool) – Enable look-ahead blocking — evaluate the candidate’s loss and reject the step if it exceeds the current loss by more than blocking_tol·std of the recent window, otherwise accept. Prevents runaway divergence on noisy/high-curvature landscapes. Costs one extra evaluation per step, plus one at the start to seed the baseline. Off by default.

  • blocking_history (int) – Window length for the std band used by blocking.

  • blocking_tol (float) – Reject a candidate whose loss exceeds the current loss by more than blocking_tol·std of the recent window. This is the knob that absorbs cost noise in the accept/reject decision (resamplings de-noises the gradient, not this single-evaluation comparison).

  • exact_loss (bool) – When True, spend one extra unperturbed evaluation per step to record the exact f(theta) for the callback and best-iterate tracking, instead of the (biased but free) perturbation-average proxy. Has no effect when blocking is set — blocking already records the exact loss.

Methods Summary

optimize(cost_fn[, initial_params, callback_fn])

Run SPSA for max_iterations steps.

Methods Documentation

optimize(cost_fn, initial_params=None, callback_fn=None, **kwargs)[source]

Run SPSA for max_iterations steps.

Parameters:
  • cost_fn (Callable[[ndarray[tuple[Any, ...], dtype[double]]], float | ndarray[tuple[Any, ...], dtype[double]]]) – Cost function; called with a two-row batch per gradient sample so both perturbations share one stochastic-cost draw.

  • initial_params (ndarray[tuple[Any, ...], dtype[double]] | None) – Starting parameters (1D, or 2D with a single row).

  • callback_fn (Callable[[OptimizeResult], Any] | None) – Called after each step with an OptimizeResult whose x is 2D and fun is 1D. May raise StopIteration.

  • **kwargsmax_iterations (default 50, must be >= 1) and rng (the perturbation directions — pass it for reproducible runs). jac and metric_fn are accepted and ignored (SPSA is gradient-free).

Return type:

OptimizeResult