qml.shadow_expval

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.

Parameters:
  • 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.

Returns:

Measurement process instance

Return type:

ShadowExpvalMP

Note

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.

Example

from functools import partial
H = qml.Hamiltonian([1., 1.], [qml.Z(0) @ qml.Z(1), qml.X(0) @ qml.X(1)])

dev = qml.device("default.qubit", wires=range(2))
@partial(qml.set_shots, shots=10000)
@qml.qnode(dev)
def circuit(x, obs):
    qml.Hadamard(0)
    qml.CNOT((0,1))
    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)
array(1.8774)
>>> qml.grad(circuit)(x, H)
-0.44999999999999984

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.X(0), qml.Y(0), qml.Z(0)]
>>> circuit(x, Hs)
array([ 1.881 , -0.0312, -0.0027, -0.0087])
>>> qml.jacobian(circuit)(x, Hs)
array([-0.4518,  0.0174, -0.0216, -0.0063])