qml.shadow_expval

shadow_expval(H, k=1, seed=None, 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 (Union[Iterable, Hamiltonian, Tensor]) – 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.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]