catalyst.passes.graph_decomposition¶
- graph_decomposition(qnode, gate_set: Iterable[type | str] | dict[type | str, float], fixed_decomps: dict | None = None, alt_decomps: dict | None = None, bytecode_rules: str | None = None, _builtin_rule_path: Path = PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/xanaduai-catalyst/envs/stable/lib/python3.11/site-packages/catalyst/resources/decomposition_rules_3126674625638fee8413d5828b24d2b074a0aeb4.mlirbc'))¶
Specify that the
-graph-decompositionMLIR compiler pass for applying the graph-based decomposition should be applied to the decorated QNode duringqjit()compilation.The graph-based decomposition pass decomposes gates into a weighted target
gate_setby applying user-provided and built-in decomposition rules. The graph-based framework allows multiple decomposition rules to be defined for a quantum operation, and the graph solver will determine the optimal decomposition rules to apply, minimizing the overall gate count or the cost according to user-specified weights.Note
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
"QuantumCompilationStage"stage via theget_compilation_stage()function.- Parameters:
fn (QNode) – the QNode to apply the graph decomposition compiler pass to.
gate_set (Iterable[type | str] | dict[type | str, float]) – the set of gates that are permissable after decomposition.
fixed_decomps – map operators to specific decomposition rules that will be applied if the operators need to be decomposed (i.e. when they’re not in the target gate set).
- Return type:
QNode
Example
import pennylane as qp import pennylane.numpy as np from catalyst import qjit from catalyst.jax_primitives import decomposition_rule from catalyst.passes import cancel_inverses, graph_decomposition, merge_rotations @decomposition_rule(op_type=qp.PauliX) def x_to_rx(wire: int): qp.RX(np.pi, wire) @decomposition_rule(op_type=qp.PauliY) def y_to_ry(wire: int): qp.RY(np.pi, wire) @decomposition_rule(op_type=qp.Hadamard) def h_to_rx_ry(wire: int): qp.RX(np.pi / 2, wire) qp.RY(np.pi / 2, wire) @qjit(capture=True) @graph_decomposition(gate_set={qp.Rot}) @merge_rotations @graph_decomposition( gate_set={qp.RX, qp.RY}, fixed_decomps={qp.PauliX: x_to_rx, qp.PauliY: y_to_ry}, alt_decomps={qp.H: [h_to_rx_ry]}, ) @cancel_inverses @qp.qnode(qp.device("lightning.qubit", wires=2)) def circuit(x: float, y: float): qp.H(0) qp.H(0) qp.RX(x, wires=0) qp.PauliX(0) qp.RY(y, wires=0) qp.PauliY(0) qp.RY(x + y, wires=0) # register custom decomposition rules x_to_rx(int) y_to_ry(int) h_to_rx_ry(int) return qp.state()
>>> qp.specs(circuit, level="device")(1.23, 4.56).resources.gate_types {'Rot': 2}