catalyst.passes.merge_ppr_ppm

merge_ppr_ppm(qnode=None, *, max_pauli_size=0)[source]

A quantum compilation pass that absorbs Clifford Pauli product rotation (PPR) operations, \(\exp{-iP\tfrac{\pi}{4}}\), into the final Pauli product measurements (PPMs).

Note

For improved integration with the PennyLane frontend, including inspectability with pennylane.specs(), please use pennylane.transforms.merge_ppr_ppm().

For more information on PPRs and PPMs, check out the Compilation Hub.

Parameters:
  • fn (QNode) – QNode to apply the pass to

  • max_pauli_size (int) – The maximum size of the Pauli strings after merging.

Returns:

QNode

Example

In this example, the Clifford+T gates will be converted into PPRs first, then the Clifford PPRs will be commuted past the non-Clifford PPR, and finally the Clifford PPRs will be absorbed into the Pauli Product Measurements.

import pennylane as qml
import catalyst

p = [("my_pipe", ["quantum-compilation-stage"])]

@qml.qjit(pipelines=p, target="mlir")
@catalyst.passes.merge_ppr_ppm
@catalyst.passes.commute_ppr
@catalyst.passes.to_ppr
@qml.qnode(qml.device("lightning.qubit", wires=1))
def circuit():
    qml.H(0)
    qml.T(0)
    return catalyst.measure(0), catalyst.measure(1)

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
%mres, %out_qubits = qec.ppm ["X"] %2 : i1, !quantum.bit
%from_elements = tensor.from_elements %mres : tensor<i1>
%3 = quantum.extract %0[ 1] : !quantum.reg -> !quantum.bit
%mres_0, %out_qubits_1 = qec.ppm ["Z"] %3 : i1, !quantum.bit
. . .

If a merging resulted in a PPM acting on more than max_pauli_size qubits (here, max_pauli_size = 2), that merging would be skipped.

p = [("my_pipe", ["quantum-compilation-stage"])]

@qml.qjit(pipelines=p, target="mlir")
@catalyst.passes.merge_ppr_ppm(max_pauli_size=2)
@catalyst.passes.commute_ppr
@catalyst.passes.to_ppr
@qml.qnode(qml.device("lightning.qubit", wires=3))
def circuit():
    qml.CNOT([1, 2])
    qml.CNOT([0, 1])
    qml.CNOT([0, 2])
    return catalyst.measure(0), catalyst.measure(1)

print(circuit.mlir_opt)

Example MLIR Representation:

. . .
%mres, %out_qubits:2 = qec.ppm ["Z", "Z"] %1, %3 : i1, !quantum.bit, !quantum.bit
%mres_0, %out_qubits_1 = qec.ppm ["Z"] %out_qubits#1 : i1, !quantum.bit
. . .