qml.snapshots

snapshots(tape)[source]

This transform processes Snapshot instances contained in a circuit, depending on the compatibility of the execution device. For supported devices, the snapshots’ measurements are computed as the execution progresses. Otherwise, the QuantumTape gets split into several, one for each snapshot, with each aggregating all the operations up to that specific snapshot.

Parameters

tape (QNode or QuantumTape or Callable) – a quantum circuit.

Returns

The transformed circuit as described in qml.transform.

Return type

dictionary (dict) or qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]

If tape splitting is carried out, the transform will be conservative about the wires that it includes in each tape. So, if all operations preceding a snapshot in a 3-qubit circuit has been applied to only one wire, the tape would only be looking at this wire. This can be overriden by the configuration of the execution device and its nature.

Regardless of the transform’s behaviour, the output is a dictionary where each key is either the tag supplied to the snapshot or its index in order of appearance, in addition to an "execution_results" entry that returns the final output of the quantum circuit. The post-processing function is responsible for aggregating the results into this dictionary.

When the transform is applied to a QNode, the shots configuration is inherited from the device. Therefore, the snapshot measurements must be supported by the device’s nature. An exception of this are the qml.state measurements on finite-shot simulators.

Warning

For devices that do not support snapshots (e.g QPUs, external plug-in simulators), be mindful of additional costs that you might incur due to the 1 separate execution/snapshot behaviour.

Example

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

@qml.qnode(dev, interface=None)
def circuit():
    qml.Snapshot(measurement=qml.expval(qml.Z(0)))
    qml.Hadamard(wires=0)
    qml.CNOT(wires=[0, 1])
    qml.Snapshot()
    return qml.expval(qml.X(0))
>>> qml.snapshots(circuit)()
{0: 1.0,
1: array([0.70710678+0.j, 0.        +0.j, 0.        +0.j, 0.70710678+0.j]),
'execution_results': 0.0}
dev = qml.device("default.qubit", shots=200, wires=2)

@qml.snapshots
@qml.qnode(dev, interface=None)
def circuit():
    qml.Hadamard(wires=0)
    qml.Snapshot()
    qml.CNOT(wires=[0, 1])
    return qml.counts()
>>> circuit()
{0: array([0.70710678+0.j, 0.        +0.j, 0.70710678+0.j, 0.        +0.j]),
'execution_results': {'00': 101, '11': 99}}

Here one can see how a device that does not natively support snapshots executes two different circuits. Additionally, a warning is raised along with the results:

dev = qml.device("lightning.qubit", shots=100, wires=2)

@qml.snapshots
@qml.qnode(dev)
def circuit():
    qml.Hadamard(wires=0),
    qml.Snapshot(qml.counts())
    qml.CNOT(wires=[0, 1])
    return qml.expval(qml.PauliZ(0))

with circuit.device.tracker:
    out = circuit()
>>> circuit.device.tracker.totals
UserWarning: Snapshots are not supported for the given device. Therefore, a tape will be created for each snapshot, resulting in a total of n_snapshots + 1 executions.
  warnings.warn(
{'batches': 1,
 'simulations': 2,
 'executions': 2,
 'shots': 200,
 'results': -0.16}
>>> out
{0: {'00': tensor(52, requires_grad=True),
  '10': tensor(48, requires_grad=True)},
 'execution_results': tensor(-0.1, requires_grad=True)}

Here you can see the default behaviour of the transform for unsupported devices and you can see how the amount of wires included in each resulting tape is minimal:

ops = [
    qml.Snapshot(),
    qml.Hadamard(wires=0),
    qml.Snapshot("very_important_state"),
    qml.CNOT(wires=[0, 1]),
    qml.Snapshot(),
]

measurements = [qml.expval(qml.PauliX(0))]

tape = qml.tape.QuantumTape(ops, measurements)

tapes, collect_results_into_dict = qml.snapshots(tape)
>>> print(tapes)
[<QuantumTape: wires=[], params=0>, <QuantumTape: wires=[0], params=0>, <QuantumTape: wires=[0, 1], params=0>, <QuantumTape: wires=[0, 1], params=0>]

Contents

Using PennyLane

Release news

Development

API

Internals