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 a CompressedResourceOp 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. If H isn’t supported and is in turn decomposed to two RZ gates and a RX 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}

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.

resource_estimate(op)

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

DecompositionRule

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)]
is_solved_for(op)[source]

Tests whether the decomposition graph is solved for a given operator.

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

Resources

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}
solve(lazy=True)[source]

Solves the graph using the Dijkstra search algorithm.

Parameters

lazy (bool) – If True, the Dijkstra search will stop once optimal decompositions are found for all operations that the graph was initialized with. Otherwise, the entire graph will be explored.