qml.shadow_expval

shadow_expval(H, k=1, seed_recipes=True)[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 (Hamiltonian or Tensor) – Observable 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_recipes (bool) – If True, a seed will be generated that is used for the randomly sampled Pauli measurements. This is to ensure that the same recipes are used when a tape containing this measurement is copied. Different seeds are still generated for different constructed tapes.

Returns

expectation value estimate.

Return type

float

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.PauliZ(0) @ qml.PauliZ(1), qml.PauliX(0) @ qml.PauliX(1)])

dev = qml.device("default.qubit", wires=range(2), shots=10000)
@qml.qnode(dev)
def qnode(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.

>>> qnode(x, H)
tensor(1.827, requires_grad=True)
>>> qml.grad(qnode)(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.PauliX(0), qml.PauliY(0), qml.PauliZ(0)]
>>> qnode(x, Hs)
[ 1.88586e+00,  4.50000e-03,  1.32000e-03, -1.92000e-03]
>>> qml.jacobian(qnode)(x, Hs)
[-0.48312, -0.00198, -0.00375,  0.00168]