qml.transforms.commute_controlled

commute_controlled(tape, direction='right')[source]

Quantum transform to move commuting gates past control and target qubits of controlled operations.

Parameters:
  • tape (QNode or QuantumTape or Callable) – A quantum circuit.

  • direction (str) – The direction in which to move single-qubit gates. Options are “right” (default), or “left”. Single-qubit gates will be pushed through controlled operations as far as possible in the specified direction.

Returns:

The transformed circuit as described in qml.transform.

Return type:

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

Example

>>> dev = qml.device('default.qubit', wires=3)

You can apply the transform directly on QNode:

@partial(commute_controlled, direction="right")
@qml.qnode(device=dev)
def circuit(theta):
    qml.CZ(wires=[0, 2])
    qml.X(2)
    qml.S(wires=0)

    qml.CNOT(wires=[0, 1])

    qml.Y(1)
    qml.CRY(theta, wires=[0, 1])
    qml.PhaseShift(theta/2, wires=0)

    qml.Toffoli(wires=[0, 1, 2])
    qml.T(wires=0)
    qml.RZ(theta/2, wires=1)

    return qml.expval(qml.Z(0))
>>> circuit(0.5)
0.9999999999999999

You can also apply it on quantum function.

def qfunc(theta):
    qml.CZ(wires=[0, 2])
    qml.X(2)
    qml.S(wires=0)

    qml.CNOT(wires=[0, 1])

    qml.Y(1)
    qml.CRY(theta, wires=[0, 1])
    qml.PhaseShift(theta/2, wires=0)

    qml.Toffoli(wires=[0, 1, 2])
    qml.T(wires=0)
    qml.RZ(theta/2, wires=1)

    return qml.expval(qml.Z(0))
>>> qnode = qml.QNode(qfunc, dev)
>>> print(qml.draw(qnode)(0.5))
0: ─╭●──S─╭●────╭●─────────Rϕ(0.25)─╭●──T────────┤  <Z>
1: ─│─────╰X──Y─╰RY(0.50)───────────├●──RZ(0.25)─┤
2: ─╰Z──X───────────────────────────╰X───────────┤

Diagonal gates on either side of control qubits do not affect the outcome of controlled gates; thus we can push all the single-qubit gates on the first qubit together on the right (and fuse them if desired). Similarly, X gates commute with the target of CNOT and Toffoli (and PauliY with CRY). We can use the transform to push single-qubit gates as far as possible through the controlled operations:

>>> optimized_qfunc = commute_controlled(qfunc, direction="right")
>>> optimized_qnode = qml.QNode(optimized_qfunc, dev)
>>> print(qml.draw(optimized_qnode)(0.5))
0: ─╭●─╭●─╭●───────────╭●──S─────────Rϕ(0.25)──T─┤  <Z>
1: ─│──╰X─╰RY(0.50)──Y─├●──RZ(0.25)──────────────┤
2: ─╰Z─────────────────╰X──X─────────────────────┤