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─────────────────────┤