qml.transforms.merge_rotations

merge_rotations(tape, atol=1e-08, include_gates=None)[source]

Quantum transform to combine rotation gates of the same type that act sequentially.

If the combination of two rotation produces an angle that is close to 0, neither gate will be applied.

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

  • atol (float) – After fusion of gates, if the fused angle \(\theta\) is such that \(|\theta|\leq \text{atol}\), no rotation gate will be applied.

  • include_gates (None or list[str]) – A list of specific operations to merge. If set to None (default), all operations in the ~.pennylane.ops.qubit.attributes.composable_rotations attribute will be merged. Otherwise, only the operations whose names match those in the list will undergo merging.

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

@merge_rotations
@qml.qnode(device=dev)
def circuit(x, y, z):
    qml.RX(x, wires=0)
    qml.RX(y, wires=0)
    qml.CNOT(wires=[1, 2])
    qml.RY(y, wires=1)
    qml.Hadamard(wires=2)
    qml.CRZ(z, wires=[2, 0])
    qml.RY(-y, wires=1)
    return qml.expval(qml.Z(0))
>>> circuit(0.1, 0.2, 0.3)
0.9553364891256055

You can also apply it on quantum function.

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

The circuit before optimization:

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

By inspection, we can combine the two RX rotations on the first qubit. On the second qubit, we have a cumulative angle of 0, and the gates will cancel.

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

It is also possible to explicitly specify which rotations merge_rotations should be merged using the include_gates argument. For example, if in the above circuit we wanted only to merge the “RX” gates, we could do so as follows:

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