catalyst.passes.ions_decomposition¶
- ions_decomposition(qnode)[source]¶
Specify that the
--ions-decomposition
MLIR compiler pass should be applied to the decorated QNode duringqjit()
compilation.This compiler pass decomposes the gates from the set {T, S, PauliZ, Hadamard, PhaseShift, RZ, CNOT} into gates from the set {RX, RY, MS}, where MS is the Mølmer–Sørensen gate, commonly used by trapped-ion quantum devices.
Note
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 ions-decomposition pass to
- Return type
QNode
Example
import pennylane as qml from pennylane.devices import NullQubit import catalyst from catalyst import qjit from catalyst.debug import get_compilation_stage @qjit(keep_intermediate=True) @catalyst.passes.ions_decomposition @qml.qnode(NullQubit(2)) def circuit(): qml.Hadamard(wires=[0]) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliY(wires=0))
>>> print(get_compilation_stage(circuit, stage="QuantumCompilationPass")) module @circuit { func.func public @jit_circuit() -> tensor<f64> attributes {llvm.emit_c_interface} { %0 = call @circuit_0() : () -> tensor<f64> return %0 : tensor<f64> } func.func public @circuit_0() -> tensor<f64> attributes {diff_method = "parameter-shift", llvm.linkage = #llvm.linkage<internal>, qnode} { %c0_i64 = arith.constant 0 : i64 %cst = arith.constant 0.000000e+00 : f64 %cst_0 = arith.constant 1.5707963267948966 : f64 %cst_1 = arith.constant 3.1415926535897931 : f64 %cst_2 = arith.constant -1.5707963267948966 : f64 quantum.device shots(%c0_i64) ["catalyst/runtime/build/lib/librtd_null_qubit.so", "NullQubit", "{'shots': 0}"] %0 = quantum.alloc( 2) : !quantum.reg %1 = quantum.extract %0[ 0] : !quantum.reg -> !quantum.bit %out_qubits = quantum.custom "RX"(%cst) %1 : !quantum.bit %out_qubits_3 = quantum.custom "RY"(%cst_0) %out_qubits : !quantum.bit %out_qubits_4 = quantum.custom "RX"(%cst_1) %out_qubits_3 : !quantum.bit %2 = quantum.extract %0[ 1] : !quantum.reg -> !quantum.bit %out_qubits_5 = quantum.custom "RY"(%cst_0) %out_qubits_4 : !quantum.bit %out_qubits_6:2 = quantum.custom "MS"(%cst_0) %out_qubits_5, %2 : !quantum.bit, !quantum.bit %out_qubits_7 = quantum.custom "RX"(%cst_2) %out_qubits_6#0 : !quantum.bit %out_qubits_8 = quantum.custom "RY"(%cst_2) %out_qubits_6#1 : !quantum.bit %out_qubits_9 = quantum.custom "RY"(%cst_2) %out_qubits_7 : !quantum.bit %3 = quantum.namedobs %out_qubits_8[ PauliY] : !quantum.obs %4 = quantum.expval %3 : f64 %from_elements = tensor.from_elements %4 : tensor<f64> %5 = quantum.insert %0[ 0], %out_qubits_8 : !quantum.reg, !quantum.bit %6 = quantum.insert %5[ 1], %out_qubits_9 : !quantum.reg, !quantum.bit quantum.dealloc %6 : !quantum.reg quantum.device_release return %from_elements : tensor<f64> } func.func @setup() { quantum.init return } func.func @teardown() { quantum.finalize return } }
You can see that the Hadamard gate has been decomposed to RX(0)RY(pi/2)RX(pi):
%cst = arith.constant 0.000000e+00 : f64 %cst_0 = arith.constant 1.5707963267948966 : f64 %cst_1 = arith.constant 3.1415926535897931 : f64 ... %out_qubits = quantum.custom "RX"(%cst) %1 : !quantum.bit %out_qubits_3 = quantum.custom "RY"(%cst_0) %out_qubits : !quantum.bit %out_qubits_4 = quantum.custom "RX"(%cst_1) %out_qubits_3 : !quantum.bit
and that the CNOT gate has been decomposed to its corresponding circuit implementation using the RX, RY and MS gates:
%cst_0 = arith.constant 1.5707963267948966 : f64 %cst_2 = arith.constant -1.5707963267948966 : f64 ... %out_qubits_5 = quantum.custom "RY"(%cst_0) %out_qubits_4 : !quantum.bit %out_qubits_6:2 = quantum.custom "MS"(%cst_0) %out_qubits_5, %2 : !quantum.bit, !quantum.bit %out_qubits_7 = quantum.custom "RX"(%cst_2) %out_qubits_6#0 : !quantum.bit %out_qubits_8 = quantum.custom "RY"(%cst_2) %out_qubits_6#1 : !quantum.bit %out_qubits_9 = quantum.custom "RY"(%cst_2) %out_qubits_7 : !quantum.bit