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

This transform requires decorating the workflow with @qml.qjit. In addition, the circuits generated by this pass are currently not executable on any backend. This pass is only for Pauli-based-computation analysis with the null.qubit device and potential future execution when a suitable backend is available.

Lastly, the pennylane.transforms.to_ppr() transform must be applied before commute_ppr.

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

Args:

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. Note that the default max_pauli_size=0 indicates no limit.

Returns:

QNode

See also

to_ppr(), merge_ppr_ppm(), ppr_to_ppm(), ppm_compilation(), reduce_t_depth(), decompose_arbitrary_ppr()

Note

For better compatibility with other PennyLane functionality, ensure that PennyLane program capture is enabled with @qjit(capture=True).

Example

The commute_ppr compilation pass can be applied as a decorator on a QNode:

import pennylane as qml
import jax.numpy as jnp

@qml.qjit(capture=True)
@qml.transforms.commute_ppr(max_pauli_size=2)
@qml.transforms.to_ppr
@qml.qnode(qml.device("lightning.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))
>>> circuit()
Array(-1.11022302e-16, dtype=float64)
>>> print(qml.specs(circuit, level=2)())
Device: lightning.qubit
Device wires: 2
Shots: Shots(total=None)
Level: commute-ppr

Wire allocations: 2
Total gates: 7
Gate counts:
- PPR-pi/8-w1: 1
- PPR-pi/4-w1: 5
- PPR-pi/4-w2: 1
Measurements:
- expval(PauliZ): 1
Depth: Not computed

In the example above, the Clifford PPRs (PauliRot instances with an angle of rotation of \(\tfrac{\pi}{2}\)) will be commuted past the non-Clifford PPR (PauliRot instances with an angle of rotation of \(\tfrac{\pi}{4}\)). In the above output, PPR-theta-w<int> denotes the type of PPR present in the circuit, where theta is the PPR angle (\(\theta\)) and w<int> denotes the PPR weight (the number of qubits it acts on, or the length of the Pauli word).

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.