qml.shadows

Overview

Measurements

classical_shadow(wires[, seed_recipes])

The classical shadow measurement protocol.

shadow_expval(H[, k, seed_recipes])

Compute expectation values using classical shadows in a differentiable manner.

Shadow class for classical post-processing

ClassicalShadow(bits, recipes[, wire_map])

Class for classical shadow post-processing expectation values, approximate states, and entropies.

QNode transforms

shadow_expval(H[, k])

Transform a QNode returning a classical shadow into one that returns the approximate expectation values in a differentiable manner.

shadow_state(wires[, diffable])

Transform a QNode returning a classical shadow into one that returns the reconstructed state in a differentiable manner.

Classical Shadows formalism

Note

As per arXiv:2103.07510, when computing multiple expectation values it is advisable to directly estimate the desired observables by simultaneously measuring qubit-wise-commuting terms. One way of doing this in PennyLane is via Hamiltonian and setting grouping_type="qwc".

A ClassicalShadow is a classical description of a quantum state that is capable of reproducing expectation values of local Pauli observables, see arXiv:2002.08953.

The idea is to capture \(T\) local snapshots (given by the shots set in the device) of the state by performing measurements in random Pauli bases at each qubit. The measurement outcomes, denoted bits, as well as the choices of measurement bases, recipes, are recorded in two (T, len(wires)) integer tensors, respectively.

From the \(t\)-th measurement, we can reconstruct the local_snapshots (see ClassicalShadow methods)

\[\rho^{(t)} = \bigotimes_{i=1}^{n} 3 U^\dagger_i |b_i \rangle \langle b_i | U_i - \mathbb{I},\]

where \(U_i\) is the rotation corresponding to the measurement (e.g. \(U_i=H\) for measurement in \(X\)) of qubit \(i\) at snapshot \(t\) and \(|b_i\rangle = (1 - b_i, b_i)\) the corresponding computational basis state given the output bit \(b_i\).

From these local snapshots, one can compute expectation values of local Pauli strings, where locality refers to the number of non-Identity operators. The accuracy of the procedure is determined by the number of measurements \(T\) (shots). To target an error \(\epsilon\), one needs of order \(T = \mathcal{O}\left( \log(M) 4^\ell/\epsilon^2 \right)\) measurements to determine \(M\) different, \(\ell\)-local observables.

One can in principle also reconstruct the global state \(\sum_t \rho^{(t)}/T\), though it is not advisable nor practical for larger systems due to its exponential scaling.

Basic usage

The easiest way of computing expectation values with classical shadows in PennyLane is to return shadow_expval() directly from the qnode.

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):
    qml.Hadamard(0)
    qml.CNOT((0,1))
    qml.RX(x, wires=0)
    return qml.shadow_expval(H)

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

The big advantage of this way of computing expectation values is that it is differentiable.

>>> qnode(x)
tensor(1.827, requires_grad=True)
>>> qml.grad(qnode)(x)
-0.44999999999999984

There are more options for post-processing classical shadows in ClassicalShadow.