qml.transforms.diagonalize_measurements¶
- diagonalize_measurements(tape, supported_base_obs=(<class 'pennylane.ops.qubit.non_parametric_ops.PauliZ'>, <class 'pennylane.ops.identity.Identity'>), to_eigvals=False)[source]¶
Diagonalize a set of measurements into the standard basis. Raises an error if the measurements do not commute.
See the usage details for more information on which measurements are supported.
- Parameters
tape (QNode or QuantumScript or Callable) – The quantum circuit to modify the measurements of.
supported_base_obs (Optional, Iterable(Observable)) – A list of supported base observable classes. Allowed observables are
qml.X
,qml.Y
,qml.Z
,qml.Hadamard
andqml.Identity
. Z and Identity are always treated as supported, regardless of input. If no list is provided, the transform will diagonalize everything into the Z basis. If a list is provided, only unsupported observables will be diagonalized to the Z basis.
- Returns
The transformed circuit as described in
qml.transform
.- Return type
qnode (QNode) or tuple[List[QuantumScript], function]
Note
This transform will raise an error if it encounters non-commuting terms. To avoid non-commuting terms in circuit measurements, the
split_non_commuting
transform can be applied.Examples:
This transform allows us to transform QNode measurements into the measurement basis by adding the relevant diagonalizing gates to the end of the tape operations.
from pennylane.transforms import diagonalize_measurements dev = qml.device("default.qubit") @diagonalize_measurements @qml.qnode(dev) def circuit(x): qml.RY(x[0], wires=0) qml.RX(x[1], wires=1) return qml.expval(qml.X(0) @ qml.Z(1)), qml.var(0.5 * qml.Y(2) + qml.X(0))
Applying the transform appends the relevant gates to the end of the circuit to allow measurements to be in the Z basis, so the original circuit
>>> print(qml.draw(circuit, level=0)([np.pi/4, np.pi/4])) 0: ──RY(0.79)─┤ ╭<X@Z> ╭Var[(0.50*Y)+X] 1: ──RX(0.79)─┤ ╰<X@Z> │ 2: ───────────┤ ╰Var[(0.50*Y)+X]
becomes
>>> print(qml.draw(circuit)([np.pi/4, np.pi/4])) 0: ──RY(0.79)──H────┤ ╭<Z@Z> ╭Var[(0.50*Z)+Z] 1: ──RX(0.79)───────┤ ╰<Z@Z> │ 2: ──Z─────────S──H─┤ ╰Var[(0.50*Z)+Z]
>>> circuit([np.pi/4, np.pi/4]) (tensor(0.5, requires_grad=True), tensor(0.75, requires_grad=True))
Usage Details
The transform diagonalizes observables from the local Pauli basis only, i.e. it diagonalizes X, Y, Z, and Hadamard.
The transform can also diagonalize only a subset of these operators. By default, the only supported base observable is Z. What if a backend device can handle X, Y and Z, but doesn’t provide support for Hadamard? We can set this by passing
supported_base_obs
to the transform. Let’s create a tape with some measurements:measurements = [ qml.expval(qml.X(0) + qml.Hadamard(1)), qml.expval(qml.X(0) + 0.2 * qml.Hadamard(1)), qml.var(qml.Y(2) + qml.X(0)), ] tape = qml.tape.QuantumScript(measurements=measurements) tapes, processing_fn = diagonalize_measurements( tape, supported_base_obs=[qml.X, qml.Y, qml.Z] )
Now
tapes
is a tuple containing a single tape with the updated measurements, where only the Hadamard gate has been diagonalized:>>> tapes[0].measurements [expval(X(0) + Z(1)), expval(X(0) + 0.2 * Z(1)), var(Y(2) + X(0))]