shadow_expval(H, k=1, seed=None)[source]

Compute expectation values using classical shadows in a differentiable manner.

The canonical way of computing expectation values is to simply average the expectation values for each local snapshot, \(\langle O \rangle = \sum_t \text{tr}(\rho^{(t)}O) / T\). This corresponds to the case k=1. In the original work, 2002.08953, it has been proposed to split the T measurements into k equal parts to compute the median of means. For the case of Pauli measurements and Pauli observables, there is no advantage expected from setting k>1.

  • H (Union[Iterable[Operator], Operator]) – Observable or iterable of observables to compute the expectation value over.

  • k (int) – Number of equal parts to split the shadow’s measurements to compute the median of means. k=1 (default) corresponds to simply taking the mean over all measurements.

  • seed (Union[None, int]) – Seed used to randomly sample Pauli measurements during the classical shadows protocol. If None, a random seed will be generated. If a tape with a shadow_expval measurement is copied, the seed will also be copied. Different seeds are still generated for different constructed tapes.


Measurement process instance

Return type



This measurement uses the measurement classical_shadow() and the class ClassicalShadow for post-processing internally to compute expectation values. In order to compute correct gradients using PennyLane’s automatic differentiation, you need to use this measurement.


H = qml.Hamiltonian([1., 1.], [qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliX(0) @ qml.PauliX(1)])

dev = qml.device("default.qubit", wires=range(2), shots=10000)
def circuit(x, obs):
    qml.RX(x, wires=0)
    return qml.shadow_expval(obs)

x = np.array(0.5, requires_grad=True)

We can compute the expectation value of H as well as its gradient in the usual way.

>>> circuit(x, H)
tensor(1.827, requires_grad=True)
>>> qml.grad(circuit)(x, H)

In shadow_expval, we can pass a list of observables. Note that each qnode execution internally performs one quantum measurement, so be sure to include all observables that you want to estimate from a single measurement in the same execution.

>>> Hs = [H, qml.PauliX(0), qml.PauliY(0), qml.PauliZ(0)]
>>> circuit(x, Hs)
[ 1.88586e+00,  4.50000e-03,  1.32000e-03, -1.92000e-03]
>>> qml.jacobian(circuit)(x, Hs)
[-0.48312, -0.00198, -0.00375,  0.00168]