Analytical Gradients (parameter-shift rule)¶
Variational algorithms (VQE, QAOA, …) repeatedly minimize an expectation
value over circuit parameters. The SDK provides exact analytic
gradients via the parameter-shift rule — no finite differences, no
automatic differentiation — together with symbolic derivatives on
Parameter and
ParameterExpression.
The parameter-shift rule¶
For a single-qubit rotation gate \(U(\\theta)=e^{-i\\theta P/2}\) with Pauli generator \(P \\in \\{X, Y, Z\\}\), the derivative of any expectation value \(\\langle O\\rangle\) with respect to \(\\theta\) is
for any shift \(s\) that is not an integer multiple of \(\\pi\). The default \(s=\\pi/2\) gives the classic two-term rule.
The estimation¶
from microquantum import Operator, Parameter, QuantumCircuit, gradient
theta = Parameter("theta")
qc = QuantumCircuit(1).ry(theta, 0)
# Scalar derivative d<Z>/d(theta) at theta = pi/4.
from microquantum import parameter_shift_gradient
d = parameter_shift_gradient(qc, Operator.Z(), theta, {theta: 0.5})
# Full gradient vector over every circuit parameter, in the
# deterministic order of ``qc.parameters``.
grads = gradient(qc, Operator.Z(), {theta: 0.5})
print(grads[theta]) # d<Z>/dtheta at theta=0.5
gradient() returns a dict keyed by the circuit’s
Parameter objects, so it plugs directly into the
gradient-mode optimizers as gradient_fn
(GradientDescent,
Adam,
BFGS, …).
Symbolic derivatives¶
A Parameter is the identity scalar field in its own
variable; a ParameterExpression a * p + c has
derivative a with respect to p:
(2 * theta).gradient() # 2.0 (chain-rule coefficient)
(2 * theta).gradient("phi") # 0.0 (unrelated parameter)
theta.gradient() # 1.0
The additive constant never contributes — the derivative only depends on the coefficient.
Chain rule for expressions¶
When a gate angle is an expression a * theta + c, each occurrence of
theta contributes a times its parameter-shift difference:
qc = QuantumCircuit(1).ry(2 * theta, 0).ry(theta, 0)
d = parameter_shift_gradient(qc, Operator.Z(), theta, {theta: 0.4})
A parameter used in several gates contributes the sum of its per-occurrence gradients (product rule). Because gates compose, the exact gradient of the composed unitary is what is computed — nothing is approximated.
Observables¶
The observable may be:
a dense
Operator,a
PauliString, ora
PauliSum(a Hamiltonian),
and may act on a subset of the circuit’s qubits via targets=:
from microquantum import PauliString, PauliSum
phi = Parameter("phi")
qc2 = QuantumCircuit(2).ry(theta, 0).rz(phi, 1)
obs = PauliSum([PauliString("X", 0.5), PauliString("Z", -0.3)])
d = parameter_shift_gradient(qc, obs, theta, {theta: 0.6})
# Pauli observable on qubit 1 of a 2-qubit circuit.
d = parameter_shift_gradient(qc2, PauliString("X"), phi,
{theta: 0.5, phi: 0.8}, targets=[1])
PauliString/PauliSum terms are evaluated without building dense matrices.
Execution through a backend¶
By default the shifted circuits are simulated with the built-in state
vector engine. Pass backend= to route the shifted-circuit evaluations
through the MQ-11/12 execution core (backend.run), with optional
seed and shots:
from microquantum import StatevectorBackend
grads = gradient(qc, obs, {theta: 0.5},
backend=StatevectorBackend(), seed=7)
Expectation values are computed from the exact state vector, so the
gradient is deterministic at any seed. A backend that cannot return a
state vector raises ValueError.
Requirements & validation¶
param_valuesmust be aMappingproviding a value for every circuit parameter (the differentiation point).shiftmust not be an integer multiple of \(\\pi\).The observable must be an
Operator,PauliStringorPauliSum.Parameters are matched by name, consistent with the MQ-12 parameter model.
Ordering & determinism¶
The gradient vector follows the deterministic, name-sorted order of
parameters, and — because evaluation
uses exact state vectors — is reproducible regardless of RNG seeding.
Examples¶
examples/15_parameter_shift_gradient.py— symbolic derivatives, closed-form agreement,PauliSumobservables and backend-integrated evaluation.examples/16_gradient_descent_loop.py— a gradient-driven variational loop withgradient_fn(the pattern used by gradient-based VQE/QAOA).
Run them directly:
python examples/15_parameter_shift_gradient.py
python examples/16_gradient_descent_loop.py