catalyst.passes.commute_ppr¶
- commute_ppr(qnode=None, *, max_pauli_size=0)[source]¶
A quantum compilation pass that commutes Clifford Pauli product rotation (PPR) gates, \(\exp(-{iP\tfrac{\pi}{4}})\), past non-Clifford PPRs gates, \(\exp(-{iP\tfrac{\pi}{8}})\), where \(P\) is a Pauli word.
Note
For improved integration with the PennyLane frontend, including inspectability with
pennylane.specs(), please usepennylane.transforms.commute_ppr().For more information on PPRs, check out the Compilation Hub.
Note
The
commute_pprcompilation pass requires thatto_ppr()be applied first.- Parameters:
fn (QNode) – QNode to apply the pass to.
max_pauli_size (int) – The maximum size of the Pauli strings after commuting.
- Returns:
Example
The
commute_pprpass must be used in conjunction withto_ppr()to first convert gates into PPRs. In this example, the Clifford+T gates in the circuit will be converted into PPRs first, then the Clifford PPRs will be commuted past the non-Clifford PPR.import pennylane as qml import catalyst p = [("my_pipe", ["quantum-compilation-stage"])] @qml.qjit(pipelines=p, target="mlir") @catalyst.passes.commute_ppr @catalyst.passes.to_ppr @qml.qnode(qml.device("null.qubit", wires=1)) def circuit(): qml.H(0) qml.T(0) return print(circuit.mlir_opt)
Because Catalyst does not currently support execution of Pauli-based computation operations, we must halt the pipeline after
quantum-compilation-stage. This ensures that only the quantum passes will be applied to the initial MLIR, without attempting to further compile for execution.Example MLIR Representation:
. . . %2 = qec.ppr ["X"](8) %1 : !quantum.bit %3 = qec.ppr ["Z"](4) %2 : !quantum.bit %4 = qec.ppr ["X"](4) %3 : !quantum.bit %5 = qec.ppr ["Z"](4) %4 : !quantum.bit %6 = quantum.insert %0[ 0], %5 : !quantum.reg, !quantum.bit . . .
If a commutation resulted in a PPR acting on more than
max_pauli_sizequbits (here,max_pauli_size = 2), that commutation would be skipped.@qml.qjit(pipelines=p, target="mlir") @catalyst.passes.commute_ppr(max_pauli_size=2) @catalyst.passes.to_ppr @qml.qnode(qml.device("lightning.qubit", wires=3)) def circuit(): qml.H(0) qml.CNOT([1, 2]) qml.CNOT([0, 1]) qml.CNOT([0, 2]) for i in range(3): qml.T(i) return print(circuit.mlir_opt)
Example MLIR Representation:
. . . %4:2 = qec.ppr ["Z", "X"](4) %2, %3 : !quantum.bit, !quantum.bit %5 = qec.ppr ["X"](8) %1 : !quantum.bit %6:2 = qec.ppr ["X", "Y"](-8) %5, %4#1 : !quantum.bit, !quantum.bit %7 = qec.ppr ["X"](-4) %6#1 : !quantum.bit %8:2 = qec.ppr ["X", "Z"](8) %6#0, %4#0 : !quantum.bit, !quantum.bit %9 = qec.ppr ["Z"](4) %8#0 : !quantum.bit %10 = qec.ppr ["X"](4) %9 : !quantum.bit %11 = qec.ppr ["Z"](4) %10 : !quantum.bit %12 = qec.ppr ["Z"](-4) %8#1 : !quantum.bit %13:2 = qec.ppr ["Z", "X"](4) %11, %12 : !quantum.bit, !quantum.bit %14 = qec.ppr ["X"](-4) %13#1 : !quantum.bit %15 = qec.ppr ["Z"](-4) %13#0 : !quantum.bit %16:2 = qec.ppr ["Z", "X"](4) %15, %7 : !quantum.bit, !quantum.bit %17 = qec.ppr ["Z"](-4) %16#0 : !quantum.bit %18 = qec.ppr ["X"](-4) %16#1 : !quantum.bit . . .