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
Details on merging ``Rot`` gates
When merging two
Rotgates, there are a number of details to consider:First, the output angles are not always defined uniquely, because Euler angles are not unique for some rotations.
merge_rotationsmakes a particular choice in this case.Second,
merge_rotationsis not differentiable everywhere when used onRot. It has singularities for specific rotation angles where the derivative will be NaN.Finally, this function can be numerically unstable near singular points. It is therefore recommended to use it with 64-bit floating point precision angles.
For a mathematical derivation of the fusion of two
Rotgates, see the documentation ofsingle_qubit_fusion().Usage Details
You can also apply
merge_rotationsto a 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
RXrotations 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_rotationsshould merge using theinclude_gatesargument. 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────────╰●───────────────────┤