catalyst.passes.ppr_to_ppm¶
- ppr_to_ppm(qnode=None, *, decompose_method='pauli-corrected', avoid_y_measure=False)[source]¶
Applies a quantum compilation pass that decomposes Pauli product rotations (PPRs), \(\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, and then Clifford PPRs (\(\theta = \tfrac{\pi}{4}\)) are decomposed. Non-Clifford decomposition can be performed in one of three ways:
"pauli-corrected"
(default),"clifford-corrected"
or"auto-corrected"
. The"pauli-corrected"
method is based on Figure 13 in arXiv:2211.15465. The latter two methods are based on A Game of Surface Codes (figures 7 and 17(b), respectively).See also
For more information on PPRs and PPMs, check out the Compilation Hub.
- 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."auto-corrected"
uses an additional measurement for correction."clifford-corrected"
uses a Clifford rotation for correction.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
This example shows the sequence of passes that will be applied. The last pass will convert the non-Clifford PPR into Pauli Product Measurements.
import pennylane as qml from catalyst import qjit, measure from catalyst.passes import to_ppr, commute_ppr, merge_ppr_ppm, ppr_to_ppm pipeline = [("pipe", ["enforce-runtime-invariants-pipeline"])] @qjit(pipelines=pipeline, target="mlir") @to_ppr @commute_ppr @merge_ppr_ppm @ppr_to_ppm(decompose_method="auto-corrected") @qml.qnode(qml.device("null.qubit", wires=2)) def circuit(): qml.H(0) qml.T(0) qml.CNOT([0, 1]) return measure(0), measure(1) print(circuit.mlir_opt)
Example MLIR Representation:
. . . %5 = qec.fabricate zero : !quantum.bit %6 = qec.fabricate magic : !quantum.bit %mres, %out_qubits:2 = qec.ppm ["X", "Z"] %1, %6 : !quantum.bit, !quantum.bit %mres_0, %out_qubits_1:2 = qec.ppm ["Z", "Y"](-1) %5, %out_qubits#1 : !quantum.bit, !quantum.bit %mres_2, %out_qubits_3 = qec.ppm ["X"] %out_qubits_1#1 : !quantum.bit %mres_4, %out_qubits_5 = qec.select.ppm(%mres, ["X"], ["Z"]) %out_qubits_1#0 : !quantum.bit %7 = arith.xori %mres_0, %mres_2 : i1 %8 = qec.ppr ["X"](2) %out_qubits#0 cond(%7) : !quantum.bit . . .