catalyst.passes.ppm_compilation¶
- ppm_compilation(qnode=None, *, decompose_method='pauli-corrected', avoid_y_measure=False, max_pauli_size=0)[source]¶
A quantum compilation pass that transforms Clifford+T gates into Pauli product measurements (PPMs).
Note
For improved integration with the PennyLane frontend, including inspectability with
pennylane.specs(), please usepennylane.transforms.ppm_compilation().This pass combines multiple sub-passes:
to_ppr(): Converts gates into Pauli Product Rotations (PPRs)commute_ppr(): Commutes PPRs past non-Clifford PPRsmerge_ppr_ppm(): Merges PPRs into Pauli Product Measurements (PPMs)ppr_to_ppm(): Decomposes PPRs into PPMs
The
avoid_y_measureanddecompose_methodarguments are passed to theppr_to_ppm()pass. Themax_pauli_sizeargument is passed to thecommute_ppr()andmerge_ppr_ppm()passes.For more information on PPRs and PPMs, check out the Compilation Hub.
- Parameters:
qnode (QNode, optional) – QNode to apply the pass to. If None, returns a decorator.
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). Defaults to
False.max_pauli_size (int) – The maximum size of the Pauli strings after commuting or merging. Defaults to 0 (no limit).
- Returns:
Example
If a merging resulted in a PPM acting on more than
max_pauli_sizequbits (here,max_pauli_size = 2), that merging would be skipped. However, when decomposed into PPMs, at least one qubit will be applied, so the final PPMs will act on at least one additional qubit.import pennylane as qml import catalyst p = [("my_pipe", ["quantum-compilation-stage"])] method = "clifford-corrected" @qml.qjit(pipelines=p, target="mlir") @catalyst.passes.ppm_compilation(decompose_method=method, max_pauli_size=2) @qml.qnode(qml.device("null.qubit", wires=2)) def circuit(): qml.CNOT([0, 1]) qml.CNOT([1, 0]) qml.adjoint(qml.T)(0) qml.T(1) return catalyst.measure(0), catalyst.measure(1) print(circuit.mlir_opt)
Example MLIR Representation:
. . . %3 = pbc.fabricate magic : !quantum.bit %mres, %out_qubits:3 = pbc.ppm ["Z", "Z", "Z"] %1, %2, %3 : i1, !quantum.bit, !quantum.bit, !quantum.bit %4:2 = scf.if %mres -> (!quantum.bit, !quantum.bit) { %11 = quantum.alloc_qb : !quantum.bit %mres_16, %out_qubits_17:3 = pbc.ppm ["Z", "Z", "Y"](-1) %out_qubits_2#0, %out_qubits_2#1, %11 : i1, !quantum.bit, !quantum.bit, !quantum.bit %mres_18, %out_qubits_19 = pbc.ppm ["X"] %out_qubits_17#2 : i1, !quantum.bit %12 = arith.xori %mres_16, %mres_18 : i1 %13:2 = scf.if %12 -> (!quantum.bit, !quantum.bit) { %14:2 = pbc.ppr ["Z", "Z"](2) %out_qubits_17#0, %out_qubits_17#1 : !quantum.bit, !quantum.bit scf.yield %14#0, %14#1 : !quantum.bit, !quantum.bit } else { scf.yield %out_qubits_17#0, %out_qubits_17#1 : !quantum.bit, !quantum.bit } quantum.dealloc_qb %out_qubits_19 : !quantum.bit scf.yield %13#0, %13#1 : !quantum.bit, !quantum.bit } else { scf.yield %out_qubits_2#0, %out_qubits_2#1 : !quantum.bit, !quantum.bit } %mres_3, %out_qubits_4 = pbc.ppm ["X"] %out_qubits_2#2 : i1, !quantum.bit %5:2 = scf.if %mres_3 -> (!quantum.bit, !quantum.bit) { %11:2 = pbc.ppr ["Z", "Z"](2) %4#0, %4#1 : !quantum.bit, !quantum.bit scf.yield %11#0, %11#1 : !quantum.bit, !quantum.bit } else { scf.yield %4#0, %4#1 : !quantum.bit, !quantum.bit } quantum.dealloc_qb %out_qubits_4 : !quantum.bit %6 = quantum.alloc_qb : !quantum.bit %out_qubits_5 = quantum.custom "Hadamard"() %6 : !quantum.bit %out_qubits_6 = quantum.custom "T"() %out_qubits_5 adj : !quantum.bit %mres_7, %out_qubits_8:2 = pbc.ppm ["Z", "Z"] %5#1, %out_qubits_6 : i1, !quantum.bit, !quantum.bit %7 = scf.if %mres_7 -> (!quantum.bit) { %11 = quantum.alloc_qb : !quantum.bit %mres_16, %out_qubits_17:2 = pbc.ppm ["Z", "Y"](-1) %out_qubits_8#0, %11 : i1, !quantum.bit, !quantum.bit %mres_18, %out_qubits_19 = pbc.ppm ["X"] %out_qubits_17#1 : i1, !quantum.bit %12 = arith.xori %mres_16, %mres_18 : i1 %13 = scf.if %12 -> (!quantum.bit) { %14 = pbc.ppr ["Z"](2) %out_qubits_17#0 : !quantum.bit scf.yield %14 : !quantum.bit } else { scf.yield %out_qubits_17#0 : !quantum.bit } quantum.dealloc_qb %out_qubits_19 : !quantum.bit scf.yield %13 : !quantum.bit } else { scf.yield %out_qubits_8#0 : !quantum.bit } %mres_9, %out_qubits_10 = pbc.ppm ["X"] %out_qubits_8#1 : i1, !quantum.bit %8 = scf.if %mres_9 -> (!quantum.bit) { %11 = pbc.ppr ["Z"](2) %7 : !quantum.bit scf.yield %11 : !quantum.bit } else { scf.yield %7 : !quantum.bit } quantum.dealloc_qb %out_qubits_10 : !quantum.bit %mres_11, %out_qubits_12:2 = pbc.ppm ["Z", "Z"] %5#0, %8 : i1, !quantum.bit, !quantum.bit %mres_13, %out_qubits_14 = pbc.ppm ["Z"] %out_qubits_12#1 : i1, !quantum.bit
…