catalyst.passes.ppr_to_ppm¶
- ppr_to_ppm(qnode=None, *, decompose_method='pauli-corrected', avoid_y_measure=False)[source]¶
A quantum compilation pass that decomposes Pauli product rotations (PPRs), \(P(\theta) = \exp(-iP\theta)\), into Pauli product measurements (PPMs).
This pass is used to decompose both non-Clifford and Clifford PPRs into PPMs. The non-Clifford PPRs (\(\theta = \tfrac{\pi}{8}\)) are decomposed first, then Clifford PPRs (\(\theta = \tfrac{\pi}{4}\)) are decomposed.
For more information on PPRs and PPMs, check out the Compilation Hub.
Note
The circuits that generated from this pass are currently not executable on any backend. This pass is only for analysis with the
null.qubitdevice and potential future execution when a suitable backend is available.- Parameters:
qnode (QNode) – QNode to apply the pass to.
decompose_method (str, optional) – The method to use for decomposing non-Clifford PPRs. Options are
"pauli-corrected","auto-corrected", and"clifford-corrected". Defaults to"pauli-corrected"."pauli-corrected"uses a reactive measurement for correction that is based on Figure 13 in arXiv:2211.15465."auto-corrected"uses an additional measurement for correction that is based on Figure 7 in A Game of Surface Codes, and"clifford-corrected"uses a Clifford rotation for correction that is based on Figure 17(b) in A Game of Surface Codes.avoid_y_measure (bool) – Rather than performing a Pauli-Y measurement for Clifford rotations (sometimes more costly), a \(Y\) state (\(Y\vert 0 \rangle\)) is used instead (requires \(Y\)-state preparation). This is currently only supported when using the
"clifford-corrected"and"pauli-corrected"decomposition method. Defaults toFalse.
- Returns:
Example
The
ppr_to_ppmcompilation pass can be applied as a dectorator on a QNode:import pennylane as qml from functools import partial import jax.numpy as jnp qml.capture.enable() @qml.qjit(target="mlir") @partial(ppr_to_ppm, decompose_method="auto-corrected") @qml.qnode(qml.device("null.qubit", wires=2)) def circuit(): # equivalent to a Hadamard gate qml.PauliRot(jnp.pi / 2, pauli_word="Z", wires=0) qml.PauliRot(jnp.pi / 2, pauli_word="X", wires=0) qml.PauliRot(jnp.pi / 2, pauli_word="Z", wires=0) # equivalent to a CNOT gate qml.PauliRot(jnp.pi / 2, pauli_word="ZX", wires=[0, 1]) qml.PauliRot(-jnp.pi / 2, pauli_word="Z", wires=[0]) qml.PauliRot(-jnp.pi / 2, pauli_word="X", wires=[1]) # equivalent to a T gate qml.PauliRot(jnp.pi / 4, pauli_word="Z", wires=0) return
For clear and inspectable results, use
target="mlir"in theqjitdecorator, ensure that PennyLane’s program capture is enabled,pennylane.capture.enable(), and callppr_to_ppmfrom the PennyLane frontend (qml.transforms.ppr_to_ppm) instead of withcatalyst.passes.ppr_to_ppm.>>> print(qml.specs(circuit, level="all")()['resources']) { 'No transforms': ..., 'Before MLIR Passes (MLIR-0)': ..., 'ppr-to-ppm (MLIR-1)': Resources( num_wires=8, num_gates=21, gate_types=defaultdict(<class 'int'>, {'PPM-w2': 6, 'PPM-w1': 7, 'PPR-pi/2-w1': 6, 'PPM-w3': 1, 'PPR-pi/2-w2': 1}), gate_sizes=defaultdict(<class 'int'>, {2: 7, 1: 13, 3: 1}), depth=None, shots=Shots(total_shots=None, shot_vector=()) ) }
In the above output,
PPM-weightdenotes the type of PPM present in the circuit, whereweightis the PPM weight.PPR-theta-weightdenotes the type of PPR present in the circuit, wherethetais the PPR angle (\(\theta\)) andweightis the PPR weight. Note that \(\theta = \tfrac{\pi}{2}\) PPRs correspond to Pauli operators: \(P(\tfrac{\pi}{2}) = \exp(-iP\tfrac{\pi}{2}) = P\). Pauli operators can be commuted to the end of the circuit and absorbed into terminal measurements.