qml.transforms.cancel_inverses

cancel_inverses(tape)[source]

Quantum function transform to remove any operations that are applied next to their (self-)inverses or adjoint.

Parameters

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

Returns

The transformed circuit as described in qml.transform.

Return type

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

Example

You can apply the cancel inverses transform directly on QNode.

>>> dev = qml.device('default.qubit', wires=3)
@cancel_inverses
@qml.qnode(device=dev)
def circuit(x, y, z):
    qml.Hadamard(wires=0)
    qml.Hadamard(wires=1)
    qml.Hadamard(wires=0)
    qml.RX(x, wires=2)
    qml.RY(y, wires=1)
    qml.X(1)
    qml.RZ(z, wires=0)
    qml.RX(y, wires=2)
    qml.CNOT(wires=[0, 2])
    qml.X(1)
    return qml.expval(qml.Z(0))
>>> circuit(0.1, 0.2, 0.3)
0.999999999999999

You can also apply it on quantum functions:

def qfunc(x, y, z):
    qml.Hadamard(wires=0)
    qml.Hadamard(wires=1)
    qml.Hadamard(wires=0)
    qml.RX(x, wires=2)
    qml.RY(y, wires=1)
    qml.X(1)
    qml.RZ(z, wires=0)
    qml.RX(y, wires=2)
    qml.CNOT(wires=[0, 2])
    qml.X(1)
    return qml.expval(qml.Z(0))

The circuit before optimization:

>>> qnode = qml.QNode(qfunc, dev)
>>> print(qml.draw(qnode)(1, 2, 3))
0: ──H─────────H─────────RZ(3.00)─╭●────┤  <Z>
1: ──H─────────RY(2.00)──X────────│───X─┤
2: ──RX(1.00)──RX(2.00)───────────╰X────┤

We can see that there are two adjacent Hadamards on the first qubit that should cancel each other out. Similarly, there are two Pauli-X gates on the second qubit that should cancel. We can obtain a simplified circuit by running the cancel_inverses transform:

>>> optimized_qfunc = cancel_inverses(qfunc)
>>> optimized_qnode = qml.QNode(optimized_qfunc, dev)
>>> print(qml.draw(optimized_qnode)(1, 2, 3))
0: ──RZ(3.00)───────────╭●─┤  <Z>
1: ──H─────────RY(2.00)─│──┤
2: ──RX(1.00)──RX(2.00)─╰X─┤