Skip to content

Commit

Permalink
Add convenience methods to create PhasedXZ gate from ZYZ decomposition (
Browse files Browse the repository at this point in the history
#6569)

Co-authored-by: Pavol Juhas <[email protected]>
  • Loading branch information
maffoo and pavoljuhas authored May 29, 2024
1 parent 1a8caa4 commit 2cfdf1f
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 2 deletions.
2 changes: 1 addition & 1 deletion cirq-core/cirq/ops/phased_x_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

@value.value_equality(manual_cls=True, approximate=True)
class PhasedXPowGate(raw_types.Gate):
r"""A gate equivalent to $Z^{p} X^t Z^{-p}$.
r"""A gate equivalent to $Z^{-p} X^t Z^{p}$ (in time order).
The unitary matrix of `cirq.PhasedXPowGate(exponent=t, phase_exponent=p)` is:
$$
Expand Down
18 changes: 17 additions & 1 deletion cirq-core/cirq/ops/phased_x_z_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

@value.value_equality(approximate=True)
class PhasedXZGate(raw_types.Gate):
r"""A single qubit gate equivalent to the circuit $Z^z Z^{a} X^x Z^{-a}$.
r"""A single qubit gate equivalent to the circuit $Z^{-a} X^x Z^{a} Z^z$ (in time order).
The unitary matrix of `cirq.PhasedXZGate(x_exponent=x, z_exponent=z, axis_phase_exponent=a)` is:
$$
Expand Down Expand Up @@ -67,6 +67,22 @@ def __init__(
self._z_exponent = z_exponent
self._axis_phase_exponent = axis_phase_exponent

@classmethod
def from_zyz_angles(cls, z0_rad: float, y_rad: float, z1_rad: float) -> 'cirq.PhasedXZGate':
"""Create a PhasedXZGate from ZYZ angles.
The returned gate is equivalent to $Rz(z0_rad) Ry(y_rad) Rz(z1_rad)$ (in time order).
"""
return cls.from_zyz_exponents(z0=z0_rad / np.pi, y=y_rad / np.pi, z1=z1_rad / np.pi)

@classmethod
def from_zyz_exponents(cls, z0: float, y: float, z1: float) -> 'cirq.PhasedXZGate':
"""Create a PhasedXZGate from ZYZ exponents.
The returned gate is equivalent to $Z^z0 Y^y Z^z1$ (in time order).
"""
return PhasedXZGate(axis_phase_exponent=-z0 + 0.5, x_exponent=y, z_exponent=z0 + z1)

def _canonical(self) -> 'cirq.PhasedXZGate':
x = self.x_exponent
z = self.z_exponent
Expand Down
24 changes: 24 additions & 0 deletions cirq-core/cirq/ops/phased_x_z_gate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,30 @@ def test_eq():
eq.add_equality_group(cirq.PhasedXZGate(x_exponent=1, z_exponent=0, axis_phase_exponent=0))


@pytest.mark.parametrize('z0_rad', [-np.pi / 5, 0, np.pi / 5, np.pi / 4, np.pi / 2, np.pi])
@pytest.mark.parametrize('y_rad', [0, np.pi / 5, np.pi / 4, np.pi / 2, np.pi])
@pytest.mark.parametrize('z1_rad', [-np.pi / 5, 0, np.pi / 5, np.pi / 4, np.pi / 2, np.pi])
def test_from_zyz_angles(z0_rad: float, y_rad: float, z1_rad: float) -> None:
q = cirq.q(0)
phxz = cirq.PhasedXZGate.from_zyz_angles(z0_rad, y_rad, z1_rad)
zyz = cirq.Circuit(cirq.rz(z0_rad).on(q), cirq.ry(y_rad).on(q), cirq.rz(z1_rad).on(q))
cirq.testing.assert_allclose_up_to_global_phase(
cirq.unitary(phxz), cirq.unitary(zyz), atol=1e-8
)


@pytest.mark.parametrize('z0', [-0.2, 0, 0.2, 0.25, 0.5, 1])
@pytest.mark.parametrize('y', [0, 0.2, 0.25, 0.5, 1])
@pytest.mark.parametrize('z1', [-0.2, 0, 0.2, 0.25, 0.5, 1])
def test_from_zyz_exponents(z0: float, y: float, z1: float) -> None:
q = cirq.q(0)
phxz = cirq.PhasedXZGate.from_zyz_exponents(z0, y, z1)
zyz = cirq.Circuit(cirq.Z(q) ** z0, cirq.Y(q) ** y, cirq.Z(q) ** z1)
cirq.testing.assert_allclose_up_to_global_phase(
cirq.unitary(phxz), cirq.unitary(zyz), atol=1e-8
)


def test_canonicalization():
def f(x, z, a):
return cirq.PhasedXZGate(x_exponent=x, z_exponent=z, axis_phase_exponent=a)
Expand Down

0 comments on commit 2cfdf1f

Please sign in to comment.