qml.decomposition.DecompositionGraph¶
- class DecompositionGraph(operations, target_gate_set, fixed_decomps=None, alt_decomps=None)[source]¶
Bases:
object
A graph that models a decomposition problem.
The decomposition graph contains two types of nodes: operator nodes and decomposition nodes. Each decomposition node is a
pennylane.decomposition.DecompositionRule
, and each operator node is aCompressedResourceOp
which contains an operator type and any additional parameters that affects the resource requirements of the operator. Essentially, two instances of the same operator type is represented by the same node in the graph if they’re expected to have the same decompositions.There are also two types of directed edges: edges that connect operators to the decomposition rules that contain them, and edges that connect decomposition rules to the operators that they decompose. The edge weights represent the difference in the gate count between the two states. Edges that connects decomposition rules to operators have a weight of 0 because an operator can be replaced with its decomposition at no additional cost.
On the other hand, edges that connect operators to the decomposition rule that contains them will have a weight that is the total resource estimate of the decomposition minus the resource estimate of the operator. For example the edge that connects a
CNOT
to the following decomposition rule:import pennylane as qml @qml.register_resources({qml.H: 2, qml.CNOT: 1}) def my_cz(wires): qml.H(wires=wires[1]) qml.CNOT(wires=wires) qml.H(wires=wires[1])
will have a weight of 2, because the decomposition rule contains 2 additional
H
gates. Note that this gate count is in terms of gates in the target gate set. IfH
isn’t supported and is in turn decomposed to twoRZ
gates and aRX
gate, the weight of this edge becomes 2 * 3 = 6. This way, the total distance from a basis gate to a high-level gate is conveniently the total number of basis gates required to decompose this high-level gate, which allows us to use Dijkstra’s algorithm to find the most efficient decomposition.- Parameters
operations (list[Operator or CompressedResourceOp]) – The list of operations to decompose.
target_gate_set (set[str]) – The names of the gates in the target gate set.
fixed_decomps (dict) – A dictionary mapping operator names to fixed decompositions.
alt_decomps (dict) – A dictionary mapping operator names to alternative decompositions.
Example
op = qml.CRX(0.5, wires=[0, 1]) graph = DecompositionGraph( operations=[op], target_gate_set={"RZ", "RX", "CNOT", "GlobalPhase"}, ) graph.solve()
>>> with qml.queuing.AnnotatedQueue() as q: ... graph.decomposition(op)(0.5, wires=[0, 1]) >>> q.queue [H(1), CRZ(0.5, wires=Wires([0, 1])), H(1)] >>> graph.resource_estimate(op) num_gates=14, gate_counts={RZ: 6, GlobalPhase: 4, RX: 2, CNOT: 2}
Methods
decomposition
(op)Returns the optimal decomposition rule for a given operator.
is_solved_for
(op)Tests whether the decomposition graph is solved for a given operator.
Returns the resource estimate for a given operator.
solve
([lazy])Solves the graph using the Dijkstra search algorithm.
- decomposition(op)[source]¶
Returns the optimal decomposition rule for a given operator.
- Parameters
op (Operator) – The operator for which to return the optimal decomposition.
- Returns
The optimal decomposition.
- Return type
Example
The decomposition rule is a quantum function that takes
(*op.parameters, wires=op.wires, **op.hyperparameters)
as arguments.op = qml.CRX(0.5, wires=[0, 1]) graph = DecompositionGraph( operations=[op], target_gate_set={"RZ", "RX", "CNOT", "GlobalPhase"}, ) graph.solve() rule = graph.decomposition(op)
>>> with qml.queuing.AnnotatedQueue() as q: ... rule(*op.parameters, wires=op.wires, **op.hyperparameters) >>> q.queue [H(1), CRZ(0.5, wires=Wires([0, 1])), H(1)]
- resource_estimate(op)[source]¶
Returns the resource estimate for a given operator.
- Parameters
op (Operator) – The operator for which to return the resource estimates.
- Returns
The resource estimate.
- Return type
Example
The resource estimate is a gate count in terms of the target gate set, not the immediate set of gates that the operator decomposes to.
op = qml.CRX(0.5, wires=[0, 1]) graph = DecompositionGraph( operations=[op], target_gate_set={"RZ", "RX", "CNOT", "GlobalPhase"}, ) graph.solve()
>>> with qml.queuing.AnnotatedQueue() as q: ... graph.decomposition(op)(0.5, wires=[0, 1]) >>> q.queue [H(1), CRZ(0.5, wires=Wires([0, 1])), H(1)] >>> graph.resource_estimate(op) num_gates=14, gate_counts={RZ: 6, GlobalPhase: 4, RX: 2, CNOT: 2}