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

H = qml.Hamiltonian([1., 1.], [qml.Z(0) @ qml.Z(1), qml.X(0) @ qml.X(1)])

dev = qml.device("default.qubit", seed=42, wires=range(2))

@qml.set_shots(shots=10_000)
@qml.qnode(dev)
def circuit(x, obs):
    qml.Hadamard(0)
    qml.CNOT((0,1))
    qml.RX(x, wires=0)
    return qml.shadow_expval(obs, seed=42)

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

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

>>> print(circuit(x, H))
1.8936
>>> print(qml.grad(circuit)(x, H))
-0.4536...

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)]
>>> print(circuit(x, Hs))
[ 1.917   0.0282 -0.0156 -0.0066]
>>> print(qml.jacobian(circuit)(x, Hs))
[-4.743e-01 -1.140e-02 -4.500e-03  3.000e-04]