원클릭으로
spsa
Concise guide to the SPSA estimator and sampler gradient examples for parameterized quantum circuits.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Concise guide to the SPSA estimator and sampler gradient examples for parameterized quantum circuits.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Root entrypoint for the quantum-skills package. Use this skill to route requests to the correct simulator or algorithm sub-skill, enforce full skill-chain reading before coding, and avoid duplicating implementation details that are already defined in leaf skills.
A set of quantum algorithms for solving linear systems of equations and related Fourier/signal-processing subroutines. This skill includes UnitaryLab implementations and educational resources for AQC, HHL, LCU, QFT, the basic single-qubit QSP demo, QSVT-QLSA, and VQLS.
Solve user-provided linear systems Ax = b with the UnitaryLab Variational Quantum Linear Solver, using a hardware-efficient ansatz and selectable local Hadamard-test, local classical, or global cost functions.
A top-level index of quantum algorithms centered on the UnitaryLab implementation, covering quantum primitives, linear systems, state preparation, cryptography, Hamiltonian simulation, Schrodingerization, quantum machine learning, eigensolvers, gradients, and quantum error correction, with selected Qiskit, PennyLane, and Classiq examples included as reference extensions.
Use when users ask about solving the discrete logarithm problem g^x ≡ y (mod P) with Shor-style two-register Fourier sampling, building/explaining DLP circuits, running simulator demos, or debugging post-processing (continued fractions plus two-dimensional Fourier-sample congruence solving). Relevant trigger terms include discrete log, DLP, Shor discrete logarithm, g^x mod P, modular exponentiation, two-dimensional Fourier sampling, continued fractions, congruence solving, and quantum cryptography demos.
Use this skill when the user asks for Shor integer factorization, quantum order-finding, period estimation, or implementing/running/debugging ShorAlgorithm in this repository (especially matrix/operator methods, IQFT-based phase post-processing, and continued-fraction period recovery). Relevant keywords include shor, factor N, order finding, period finding, modular exponentiation, continued fraction, quantum factoring, and ShorAlgorithm.
| name | spsa |
| description | Concise guide to the SPSA estimator and sampler gradient examples for parameterized quantum circuits. |
Use this skill for the SPSA gradient examples in this folder:
scripts/algorithm.pyThey estimate gradients of:
SPSAEstimatorGradientSPSASamplerGradientSPSA is useful when circuits have many parameters, because each batch needs only 2 * batch_size circuit evaluations, independent of parameter count.
For each random perturbation vector delta in {+1, -1}^d, the implementation evaluates:
f(theta + epsilon * delta)f(theta - epsilon * delta)It then forms a central-difference estimate and averages across batch_size perturbations.
The real entry classes are:
SPSAEstimatorGradientSPSASamplerGradientPublic usage goes through inherited run(...); the algorithm itself is implemented in _run(...).
Minimal estimator example:
from qiskit.circuit import QuantumCircuit, ParameterVector
from qiskit.primitives import StatevectorEstimator
from qiskit.quantum_info import SparsePauliOp
from qiskit_algorithms.gradients import SPSAEstimatorGradient
theta = ParameterVector("theta", 2)
qc = QuantumCircuit(2)
qc.ry(theta[0], 0)
qc.ry(theta[1], 1)
qc.cx(0, 1)
estimator = StatevectorEstimator()
obs = SparsePauliOp("ZZ")
grad = SPSAEstimatorGradient(estimator=estimator, epsilon=0.01, batch_size=4, seed=123)
result = grad.run(
circuits=[qc],
observables=[obs],
parameter_values=[[0.3, -0.2]],
parameters=[[theta[0], theta[1]]],
precision=None,
).result()
print(result.gradients)
Minimal sampler example:
from qiskit.circuit import QuantumCircuit, ParameterVector
from qiskit.primitives import StatevectorSampler
from qiskit_algorithms.gradients import SPSASamplerGradient
theta = ParameterVector("theta", 2)
qc = QuantumCircuit(2)
qc.ry(theta[0], 0)
qc.ry(theta[1], 1)
qc.cx(0, 1)
qc.measure_all()
sampler = StatevectorSampler()
grad = SPSASamplerGradient(sampler=sampler, epsilon=0.01, batch_size=4, seed=123)
result = grad.run(
circuits=[qc],
parameter_values=[[0.3, -0.2]],
parameters=[[theta[0], theta[1]]],
shots=None,
).result()
print(result.gradients)
SPSAEstimatorGradientestimator: expectation-value primitiveepsilon: perturbation size, must be positivebatch_size=1: number of SPSA samples to averageseed=None: RNG seedprecision=None: estimator precision overridetranspiler=None, transpiler_options=None: optional transpilationRun inputs:
circuitsobservablesparameter_valuesparametersprecisionReturn fields:
gradientsmetadataprecisionSPSASamplerGradientsampler: sampling primitiveepsilon: perturbation size, must be positivebatch_size=1: number of SPSA samples to averageseed=None: RNG seedshots=None: sampler shot overridetranspiler=None, transpiler_options=None: optional transpilationRun inputs:
circuitsparameter_valuesparametersshotsReturn fields:
gradientsmetadatashotsSPSAEstimatorGradient._run(...) does the following:
precision.batch_size random sign vectors.theta + epsilon * delta and theta - epsilon * delta parameter sets.Simplified reconstruction:
for each circuit:
deltas = random_pm_one_vectors(batch_size)
plus = [theta + epsilon * d for d in deltas]
minus = [theta - epsilon * d for d in deltas]
pubs.append((circuit, observable, plus + minus, precision))
results = estimator.run(pubs).result()
gradient = mean(((f_plus - f_minus) / (2 * epsilon)) / delta over batch)
SPSASamplerGradient._run(...) is similar, but works on probability distributions:
shots.Simplified reconstruction:
for each circuit:
deltas = random_pm_one_vectors(batch_size)
plus = [theta + epsilon * d for d in deltas]
minus = [theta - epsilon * d for d in deltas]
pubs.append((circuit, plus + minus, shots))
results = sampler.run(pubs).result()
for each target parameter j:
gradient_j = average_k(diff_distribution_k * deltas[k][j])
U(theta)f(theta)p_theta(z)delta in {+1, -1}^dtheta +/- epsilon * deltatheta: parameter_valuesdelta: random +1/-1 vectors built with NumPy RNGepsilon: constructor argument epsilonf(theta + epsilon * delta), f(theta - epsilon * delta): plus and minus evaluationsparametersFor scalar objective f(theta):
$$ \hat g_i(\theta) = \frac{f(\theta + \epsilon \delta) - f(\theta - \epsilon \delta)}{2\epsilon,\delta_i} $$
For batch_size = B:
$$ \hat g(\theta) = \frac{1}{B}\sum_{k=1}^B \frac{f(\theta + \epsilon \delta^{(k)}) - f(\theta - \epsilon \delta^{(k)})}{2\epsilon} \odot \delta^{(k)} $$
Since delta_i in {+1, -1}, dividing by delta_i is equivalent to multiplying by delta_i.
For sampler gradients, the same idea is applied per output bitstring probability.
If you request only a parameter subset, the output keeps that order:
result = grad.run(
circuits=[qc],
observables=[obs],
parameter_values=[[0.1, -0.4, 0.7]],
parameters=[[theta[0], theta[2]]],
precision=None,
).result()
print(result.gradients[0])
print(result.metadata[0]["parameters"])
Expected behavior:
parameters=[[...]]import numpy as np
def spsa_gradient(eval_fn, theta, epsilon, batch_size, rng):
grads = []
for _ in range(batch_size):
delta = (-1) ** rng.integers(0, 2, len(theta))
f_plus = eval_fn(theta + epsilon * delta)
f_minus = eval_fn(theta - epsilon * delta)
grads.append(((f_plus - f_minus) / (2 * epsilon)) / delta)
return np.mean(np.asarray(grads), axis=0)
This matches the core logic of the estimator implementation; the sampler version replaces scalar outputs with sparse probability dictionaries.
epsilon <= 0 raises ValueError.epsilon can make noise dominate.batch_size reduces variance but increases runtime.epsilon and batch_size are not exposed as public attributes on gradient objects; prefer tracking configured values in local variables rather than reading grad.epsilon or grad.batch_size.