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.

For more information on PPRs, 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.qubit device and potential future execution when a suitable backend is available.

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

  • max_pauli_size (int) – The maximum size of Pauli strings resulting from commutation. If a commutation results in a PPR that acts on more than max_pauli_size qubits, that commutation will not be performed.

Returns:

QNode

Example

The commute_ppr compilation 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(qml.transforms.commute_ppr, max_pauli_size=2)
@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 qml.expval(qml.Z(0))

For clear and inspectable results, use target="mlir" in the qjit decorator, ensure that PennyLane’s program capture is enabled, pennylane.capture.enable(), and call commute_ppr from the PennyLane frontend (qml.transforms.commute_ppr) instead of with catalyst.passes.commute_ppr.

>>> print(qml.specs(circuit, level="all")()['resources'])
{
    'No transforms': ...,
    'Before MLIR Passes (MLIR-0)': ...,
    'commute-ppr (MLIR-1)': Resources(
        num_wires=2,
        num_gates=7,
        gate_types=defaultdict(<class 'int'>, {'PPR-pi/8-w1': 1, 'PPR-pi/4-w1': 5, 'PPR-pi/4-w2': 1}),
        gate_sizes=defaultdict(<class 'int'>, {1: 6, 2: 1}),
        depth=None,
        shots=Shots(total_shots=None, shot_vector=()))
}

In the example above, the Clifford PPRs (H and CNOT) will be commuted past the non-Clifford PPR (T). In the output above, PPR-theta-weight denotes the type of PPR present in the circuit, where theta is the PPR angle (\(\theta\)) and weight is the PPR weight.

Note that if a commutation resulted in a PPR acting on more than max_pauli_size qubits (here, max_pauli_size = 2), that commutation would be skipped.