catalyst.passes.cancel_inverses¶
- cancel_inverses(qnode)[source]¶
Specify that the
-removed-chained-self-inverseMLIR compiler pass for cancelling two neighbouring self-inverse gates should be applied to the decorated QNode duringqjit()compilation.The full list of supported gates are as follows:
One-bit Gates:
qml.Hadamard,qml.PauliX,qml.PauliY,qml.PauliZTwo-bit Gates:
qml.CNOT,qml.CY,qml.CZ,qml.SWAPThree-bit Gates: -
qml.ToffoliNote
Unlike PennyLane circuit transformations, the QNode itself will not be changed or transformed by applying these decorators.
As a result, circuit inspection tools such as
draw()will continue to display the circuit as written in Python.To instead view the optimized circuit, the MLIR must be viewed after the
"QuantumCompilationPass"stage via theget_compilation_stage()function.- Parameters:
fn (QNode) – the QNode to apply the cancel inverses compiler pass to
- Return type:
QNode
Example
from catalyst.debug import get_compilation_stage from catalyst.passes import cancel_inverses dev = qml.device("lightning.qubit", wires=1) @qjit(keep_intermediate=True) @cancel_inverses @qml.qnode(dev) def circuit(x: float): qml.RX(x, wires=0) qml.Hadamard(wires=0) qml.Hadamard(wires=0) return qml.expval(qml.PauliZ(0))
>>> circuit(0.54) Array(0.85770868, dtype=float64)
Note that the QNode will be unchanged in Python, and will continue to include self-inverse gates when inspected with Python (for example, with
draw()).To instead view the optimized circuit, the MLIR must be viewed after the
"QuantumCompilationPass"stage:>>> print(get_compilation_stage(circuit, stage="QuantumCompilationPass")) module @circuit { func.func public @jit_circuit(%arg0: tensor<f64>) -> tensor<f64> attributes {llvm.emit_c_interface} { %0 = call @circuit(%arg0) : (tensor<f64>) -> tensor<f64> return %0 : tensor<f64> } func.func private @circuit(%arg0: tensor<f64>) -> tensor<f64> attributes {diff_method = "parameter-shift", llvm.linkage = #llvm.linkage<internal>, qnode} { quantum.device["catalyst/utils/../lib/librtd_lightning.dylib", "LightningSimulator", "{'shots': 0, 'mcmc': False, 'num_burnin': 0, 'kernel_name': None}"] %0 = quantum.alloc( 1) : !quantum.reg %1 = quantum.extract %0[ 0] : !quantum.reg -> !quantum.bit %extracted = tensor.extract %arg0[] : tensor<f64> %out_qubits = quantum.custom "RX"(%extracted) %1 : !quantum.bit %2 = quantum.namedobs %out_qubits[ PauliZ] : !quantum.obs %3 = quantum.expval %2 : f64 %from_elements = tensor.from_elements %3 : tensor<f64> %4 = quantum.insert %0[ 0], %out_qubits : !quantum.reg, !quantum.bit quantum.dealloc %4 : !quantum.reg quantum.device_release return %from_elements : tensor<f64> } func.func @setup() { quantum.init return } func.func @teardown() { quantum.finalize return } }
It can be seen that both Hadamards have been cancelled, and the measurement directly follows the
RXgate:%out_qubits = quantum.custom "RX"(%extracted) %1 : !quantum.bit %2 = quantum.namedobs %out_qubits[ PauliZ] : !quantum.obs %3 = quantum.expval %2 : f64