qml.transforms.commute_controlled

commute_controlled = <function commute_controlled>[source]

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

Parameters
  • qfunc (function) – A quantum function.

  • 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 quantum function

Return type

function

Example

Consider the following quantum function.

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

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

    qml.PauliY(wires=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.PauliZ(0))
>>> dev = qml.device('default.qubit', wires=3)
>>> qnode = qml.QNode(qfunc, dev)
>>> print(qml.draw(qnode)(0.5))
 0: ──╭C──S──╭C─────╭C────────Rϕ(0.25)──╭C──T─────────┤ ⟨Z⟩
 1: ──│──────╰X──Y──╰RY(0.5)────────────├C──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(direction="right")(qfunc)
>>> optimized_qnode = qml.QNode(optimized_qfunc, dev)
>>> print(qml.draw(optimized_qnode)(0.5))
 0: ──╭C──╭C──╭C───────────╭C──S─────────Rϕ(0.25)──T──┤ ⟨Z⟩
 1: ──│───╰X──╰RY(0.5)──Y──├C──RZ(0.25)───────────────┤
 2: ──╰Z───────────────────╰X──X──────────────────────┤