diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 068d357c9c0..cb5f4a98005 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -186,10 +186,15 @@
interface-specific scalar data, eg `[(tf.Variable(1.1), tf.Variable(2.2))]`.
[(#4603)](https://github.com/PennyLaneAI/pennylane/pull/4603)
+* When decomposing a unitary matrix with `one_qubit_decomposition`, and opting to include the `GlobalPhase`
+ in the decomposition, the phase is no longer cast to `dtype=complex`.
+ [(#4653)](https://github.com/PennyLaneAI/pennylane/pull/4653)
+
* `qml.cut_circuit` is now compatible with circuits that compute the expectation values of Hamiltonians
with two or more terms.
[(#4642)](https://github.com/PennyLaneAI/pennylane/pull/4642)
+
* `_qfunc_output` has been removed from `QuantumScript`, as it is no longer necessary. There is
still a `_qfunc_output` property on `QNode` instances.
[(#4651)](https://github.com/PennyLaneAI/pennylane/pull/4651)
@@ -198,6 +203,7 @@
of the computed qubit operator, if imaginary components are smaller than a threshold.
[(#4639)](https://github.com/PennyLaneAI/pennylane/pull/4639)
+
Breaking changes 💔
* The device test suite now converts device kwargs to integers or floats if they can be converted to integers or floats.
diff --git a/pennylane/transforms/decompositions/single_qubit_unitary.py b/pennylane/transforms/decompositions/single_qubit_unitary.py
index b19bbc8daa9..62969e36b7a 100644
--- a/pennylane/transforms/decompositions/single_qubit_unitary.py
+++ b/pennylane/transforms/decompositions/single_qubit_unitary.py
@@ -15,7 +15,7 @@
operations into elementary gates.
"""
-import numpy
+import numpy as np
import pennylane as qml
from pennylane import math
@@ -40,9 +40,9 @@ def _convert_to_su2(U, return_global_phase=False):
# Compute the determinants
U = qml.math.cast(U, "complex128")
dets = math.linalg.det(U)
+ exp_angles = math.angle(dets) / 2
+ U_SU2 = math.cast_like(U, dets) * math.exp(-1j * math.cast_like(exp_angles, 1j))[:, None, None]
- exp_angles = math.cast_like(math.angle(dets), 1j) / 2
- U_SU2 = math.cast_like(U, dets) * math.exp(-1j * exp_angles)[:, None, None]
return (U_SU2, exp_angles) if return_global_phase else U_SU2
@@ -186,9 +186,9 @@ def _zyz_decomposition(U, wire, return_global_phase=False):
phis, thetas, omegas, alphas = map(math.squeeze, [phis, thetas, omegas, alphas])
- phis = phis % (4 * numpy.pi)
- thetas = thetas % (4 * numpy.pi)
- omegas = omegas % (4 * numpy.pi)
+ phis = phis % (4 * np.pi)
+ thetas = thetas % (4 * np.pi)
+ omegas = omegas % (4 * np.pi)
operations = [qml.RZ(phis, wire), qml.RY(thetas, wire), qml.RZ(omegas, wire)]
if return_global_phase:
@@ -250,9 +250,9 @@ def _xyx_decomposition(U, wire, return_global_phase=False):
phis, thetas, lams, gammas = map(math.squeeze, [phis, thetas, lams, gammas])
- phis = phis % (4 * numpy.pi)
- thetas = thetas % (4 * numpy.pi)
- lams = lams % (4 * numpy.pi)
+ phis = phis % (4 * np.pi)
+ thetas = thetas % (4 * np.pi)
+ lams = lams % (4 * np.pi)
operations = [qml.RX(lams, wire), qml.RY(thetas, wire), qml.RX(phis, wire)]
if return_global_phase:
@@ -316,9 +316,9 @@ def _zxz_decomposition(U, wire, return_global_phase=False):
phis, thetas, psis, alphas = map(math.squeeze, [phis, thetas, psis, alphas])
- phis = phis % (4 * numpy.pi)
- thetas = thetas % (4 * numpy.pi)
- psis = psis % (4 * numpy.pi)
+ phis = phis % (4 * np.pi)
+ thetas = thetas % (4 * np.pi)
+ psis = psis % (4 * np.pi)
# Return gates in the order they will be applied on the qubit
operations = [qml.RZ(psis, wire), qml.RX(thetas, wire), qml.RZ(phis, wire)]
diff --git a/tests/transforms/test_decompositions.py b/tests/transforms/test_decompositions.py
index ccaaafd315f..b4bdda9688d 100644
--- a/tests/transforms/test_decompositions.py
+++ b/tests/transforms/test_decompositions.py
@@ -38,16 +38,16 @@
typeof_gates_zyz = (qml.RZ, qml.RY, qml.RZ, qml.GlobalPhase)
single_qubit_decomps_zyz = [
(I, typeof_gates_zyz, [0.0, 0.0, 0.0, 0]),
- (Z, typeof_gates_zyz, [np.pi / 2, 0.0, np.pi / 2, (-1.5707963267948966 + 0j)]),
+ (Z, typeof_gates_zyz, [np.pi / 2, 0.0, np.pi / 2, -1.5707963267948966]),
(
S,
typeof_gates_zyz,
- [np.pi / 4, 0.0, np.pi / 4, (-0.7853981633974483 - 1.6780315470477092e-09j)],
+ [np.pi / 4, 0.0, np.pi / 4, -0.7853981633974483],
),
(
T,
typeof_gates_zyz,
- [np.pi / 8, 0.0, np.pi / 8, (-0.39269908047469393 - 3.225207101387184e-09j)],
+ [np.pi / 8, 0.0, np.pi / 8, -0.39269908047469393],
),
(qml.RZ(0.3, wires=0).matrix(), typeof_gates_zyz, [0.15, 0.0, 0.15, 0]),
(
@@ -70,8 +70,8 @@
typeof_gates_zyz,
[12.382273469673908, np.pi, 0.18409714468526372, 0],
),
- (H, typeof_gates_zyz, [np.pi, np.pi / 2, 0.0, (-1.5707963267948966 + 0j)]),
- (X, typeof_gates_zyz, [np.pi / 2, np.pi, 10.995574287564276, (-1.5707963267948966 + 0j)]),
+ (H, typeof_gates_zyz, [np.pi, np.pi / 2, 0.0, -1.5707963267948966]),
+ (X, typeof_gates_zyz, [np.pi / 2, np.pi, 10.995574287564276, -1.5707963267948966]),
(
np.exp(1j * 0.02) * qml.Rot(-1.0, 2.0, -3.0, wires=0).matrix(),
typeof_gates_zyz,
@@ -79,7 +79,7 @@
11.566370614359172,
2.0,
9.566370614359172,
- (-0.020000000000000042 - 2.122325752640375e-17j),
+ -0.020000000000000042,
],
),
# Add two instances of broadcasted unitaries, one coming from RZ and another from Rot
@@ -196,14 +196,14 @@ def test_zyz_decomposition_jax(self, U, expected_gates, expected_params):
10.845351366405708,
1.3974974118006183,
0.45246583660683803,
- (1.1759220332464762 - 4.163336342344337e-17j),
+ 1.1759220332464762,
),
),
# Try a few specific special unitaries
(I, typeof_gates_xyx, [0, 0, 0, 0]), # This triggers the if conditional trivially
- (X, typeof_gates_xyx, [4.71238898038469, 0.0, 10.995574287564276, (-1.5707963267948966 + 0j)]),
- (Y, typeof_gates_xyx, [1 / 2 * np.pi, np.pi, 1 / 2 * np.pi, (-1.5707963267948966 + 0j)]),
- (Z, typeof_gates_xyx, [10.995574287564276, np.pi, 1 / 2 * np.pi, (-1.5707963267948966 + 0j)]),
+ (X, typeof_gates_xyx, [4.71238898038469, 0.0, 10.995574287564276, -1.5707963267948966]),
+ (Y, typeof_gates_xyx, [1 / 2 * np.pi, np.pi, 1 / 2 * np.pi, -1.5707963267948966]),
+ (Z, typeof_gates_xyx, [10.995574287564276, np.pi, 1 / 2 * np.pi, -1.5707963267948966]),
# Add two instances of broadcasted unitaries, one coming from RZ and another from Rot
(
qml.QubitUnitary(qml.RZ.compute_matrix(np.array([np.pi, np.pi / 2])), wires=0).matrix(),
@@ -311,16 +311,16 @@ def test_xyx_decomposition_jax(self, U, expected_gates, expected_params):
typeof_gates_zxz = (qml.RZ, qml.RX, qml.RZ, qml.GlobalPhase)
single_qubit_decomps_zxz = [
(I, typeof_gates_zxz, [0.0, 0.0, 0.0, 0]),
- (Z, typeof_gates_zxz, [np.pi / 2, 0.0, np.pi / 2, (-1.5707963267948966 + 0j)]),
+ (Z, typeof_gates_zxz, [np.pi / 2, 0.0, np.pi / 2, -1.5707963267948966]),
(
S,
typeof_gates_zxz,
- [np.pi / 4, 0.0, np.pi / 4, (-0.7853981633974483 - 1.6780315470477092e-09j)],
+ [np.pi / 4, 0.0, np.pi / 4, -0.7853981633974483],
),
(
T,
typeof_gates_zxz,
- [np.pi / 8, 0.0, np.pi / 8, (-0.39269908047469393 - 3.225207101387184e-09j)],
+ [np.pi / 8, 0.0, np.pi / 8, -0.39269908047469393],
),
(qml.RZ(0.3, wires=0).matrix(), typeof_gates_zxz, [0.15, 0.0, 0.15, 0]),
(
@@ -484,7 +484,7 @@ def test_zxz_decomposition_jax(self, U, expected_gates, expected_params):
10.845351366405708,
1.3974974118006183,
0.45246583660683803,
- 1.1759220332464762 - 4.163336342344337e-17j,
+ 1.1759220332464762,
),
),
(