qml.transforms.decompose

decompose(tape, gate_set=None, max_expansion=None)[source]

Decomposes a quantum circuit into a user-specified gate set.

Parameters
  • tape (QuantumScript or QNode or Callable) – a quantum circuit.

  • gate_set (Iterable[str or type] or Callable, optional) – The target gate set specified as either (1) a sequence of operator types and/or names or (2) a function that returns True if the operator belongs to the target gate set. Defaults to None, in which case the gate set is considered to be all available quantum operators.

  • max_expansion (int, optional) – The maximum depth of the decomposition. Defaults to None. If None, the circuit will be decomposed until the target gate set is reached.

Returns

The decomposed circuit. The output type is explained in qml.transform.

Return type

qnode (QNode) or quantum function (Callable) or tuple[List[QuantumScript], function]

Note

This function does not guarantee a decomposition to the target gate set. If an operation with no defined decomposition is encountered during decomposition, it will be left in the circuit even if it does not belong in the target gate set. In this case, a UserWarning will be raised. To suppress this warning, simply add the operator to the gate set.

See also

qml.devices.preprocess.decompose for a transform that is intended for device developers. This function will decompose a quantum circuit into a set of basis gates available on a specific device architecture.

Example

Consider the following tape:

>>> ops = [qml.IsingXX(1.2, wires=(0,1))]
>>> tape = qml.tape.QuantumScript(ops, measurements=[qml.expval(qml.Z(0))])

You can decompose the circuit into a set of gates:

>>> batch, fn = qml.transforms.decompose(tape, gate_set={qml.CNOT, qml.RX})
>>> batch[0].circuit
[CNOT(wires=[0, 1]), RX(1.2, wires=[0]), CNOT(wires=[0, 1]), expval(Z(0))]

You can also apply the transform directly on a QNode:

from functools import partial

@partial(qml.transforms.decompose, gate_set={qml.Toffoli, "RX", "RZ"})
@qml.qnode(qml.device("default.qubit"))
def circuit():
    qml.Hadamard(wires=[0])
    qml.Toffoli(wires=[0,1,2])
    return qml.expval(qml.Z(0))

Since the Hadamard gate is not defined in our gate set, it will be decomposed into rotations:

>>> print(qml.draw(circuit)())
0: ──RZ(1.57)──RX(1.57)──RZ(1.57)─╭●─┤  <Z>
1: ───────────────────────────────├●─┤
2: ───────────────────────────────╰X─┤

You can also use a function to build a decomposition gate set:

@partial(qml.transforms.decompose, gate_set=lambda op: len(op.wires)<=2)
@qml.qnode(qml.device("default.qubit"))
def circuit():
    qml.Hadamard(wires=[0])
    qml.Toffoli(wires=[0,1,2])
    return qml.expval(qml.Z(0))

The circuit will be decomposed into single or two-qubit operators,

>>> print(qml.draw(circuit)())
0: ──H────────╭●───────────╭●────╭●──T──╭●─┤  <Z>
1: ────╭●─────│─────╭●─────│───T─╰X──T†─╰X─┤
2: ──H─╰X──T†─╰X──T─╰X──T†─╰X──T──H────────┤

You can use the max_expansion argument to control the number of decomposition stages applied to the circuit. By default, the function will decompose the circuit until the desired gate set is reached.

The example below demonstrates how the user can visualize the decomposition in stages:

phase = 1
target_wires = [0]
unitary = qml.RX(phase, wires=0).matrix()
n_estimation_wires = 3
estimation_wires = range(1, n_estimation_wires + 1)

@qml.qnode(qml.device("default.qubit"))
def circuit():
    # Start in the |+> eigenstate of the unitary
    qml.Hadamard(wires=target_wires)
    qml.QuantumPhaseEstimation(
        unitary,
        target_wires=target_wires,
        estimation_wires=estimation_wires,
    )
>>> print(qml.draw(qml.transforms.decompose(circuit, max_expansion=0))())
0: ──H─╭QuantumPhaseEstimation─┤
1: ────├QuantumPhaseEstimation─┤
2: ────├QuantumPhaseEstimation─┤
3: ────╰QuantumPhaseEstimation─┤
>>> print(qml.draw(qml.transforms.decompose(circuit, max_expansion=1))())
0: ──H─╭U(M0)⁴─╭U(M0)²─╭U(M0)¹───────┤
1: ──H─╰●──────│───────│───────╭QFT†─┤
2: ──H─────────╰●──────│───────├QFT†─┤
3: ──H─────────────────╰●──────╰QFT†─┤
>>> print(qml.draw(qml.transforms.decompose(circuit, max_expansion=2))())
0: ──H──RZ(11.00)──RY(1.14)─╭X──RY(-1.14)──RZ(-9.42)─╭X──RZ(-1.57)──RZ(1.57)──RY(1.00)─╭X──RY(-1.00)
1: ──H──────────────────────╰●───────────────────────╰●────────────────────────────────│────────────
2: ──H─────────────────────────────────────────────────────────────────────────────────╰●───────────
3: ──H──────────────────────────────────────────────────────────────────────────────────────────────
───RZ(-6.28)─╭X──RZ(4.71)──RZ(1.57)──RY(0.50)─╭X──RY(-0.50)──RZ(-6.28)─╭X──RZ(4.71)─────────────────
─────────────│────────────────────────────────│────────────────────────│──╭SWAP†────────────────────
─────────────╰●───────────────────────────────│────────────────────────│──│─────────────╭(Rϕ(1.57))†
──────────────────────────────────────────────╰●───────────────────────╰●─╰SWAP†─────H†─╰●──────────
────────────────────────────────────┤
──────╭(Rϕ(0.79))†─╭(Rϕ(1.57))†──H†─┤
───H†─│────────────╰●───────────────┤
──────╰●────────────────────────────┤