Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create gates.CY #1103

Merged
merged 17 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/source/api-reference/qibo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,13 @@ Controlled-NOT (CNOT)
:members:
:member-order: bysource

Controlled-Y (CY)
"""""""""""""""""""""

.. autoclass:: qibo.gates.CY
:members:
:member-order: bysource

Controlled-phase (CZ)
"""""""""""""""""""""

Expand Down
1 change: 1 addition & 0 deletions src/qibo/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def create(self, dtype):
self.S = self.matrices.S
self.SDG = self.matrices.SDG
self.CNOT = self.matrices.CNOT
self.CY = self.matrices.CY
self.CZ = self.matrices.CZ
self.CSX = self.matrices.CSX
self.CSXDG = self.matrices.CSXDG
Expand Down
7 changes: 7 additions & 0 deletions src/qibo/backends/npmatrices.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ def CNOT(self):
[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]], dtype=self.dtype
)

@cached_property
def CY(self):
return self.np.array(
[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]],
dtype=self.dtype,
)

@cached_property
def CZ(self):
return self.np.array(
Expand Down
52 changes: 52 additions & 0 deletions src/qibo/gates/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,15 @@ def __init__(self, q):
def qasm_label(self):
return "y"

@Gate.check_controls
def controlled_by(self, *q):
"""Fall back to CY if there is only one control."""
if len(q) == 1:
gate = CY(q[0], self.target_qubits[0])
else:
gate = super().controlled_by(*q)
return gate

def basis_rotation(self):
from qibo import matrices # pylint: disable=C0415

Expand Down Expand Up @@ -972,6 +981,49 @@ def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]:
return [self.__class__(q0, q1)]


class CY(Gate):
"""The Controlled-:math:`Y` gate.

Corresponds to the following unitary matrix

.. math::
\\begin{pmatrix}
1 & 0 & 0 & 0 \\\\
0 & 1 & 0 & 0 \\\\
0 & 0 & 0 & -i \\\\
0 & 0 & i & 0 \\\\
\\end{pmatrix}

Args:
q0 (int): the control qubit id number.
q1 (int): the target qubit id number.
"""

def __init__(self, q0, q1):
super().__init__()
self.name = "cy"
self.draw_label = "Y"
self.control_qubits = (q0,)
self.target_qubits = (q1,)
self.init_args = [q0, q1]
self.clifford = True
self.unitary = True

@property
def qasm_label(self):
return "cy"

def decompose(self) -> List[Gate]:
"""Decomposition of :math:`\\text{CY}` gate.

Decompose :math:`\\text{CY}` gate into :class:`qibo.gates.SDG` in
the target qubit, followed by :class:`qibo.gates.CNOT`, followed
by a :class:`qibo.gates.S` in the target qubit.
"""
q0, q1 = self.init_args
return [SDG(q1), CNOT(q0, q1), S(q1)]


class CZ(Gate):
"""The Controlled-Phase gate.

Expand Down
5 changes: 4 additions & 1 deletion tests/test_gates_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,13 @@ def test_one_qubit_rotations_controlled_by(gatename, params):
assert gate.parameters == params


def test_cnot_and_cz_init():
def test_cnot_and_cy_and_cz_init():
gate = gates.CNOT(0, 1)
assert gate.target_qubits == (1,)
assert gate.control_qubits == (0,)
gate = gates.CZ(4, 7)
renatomello marked this conversation as resolved.
Show resolved Hide resolved
assert gate.target_qubits == (7,)
assert gate.control_qubits == (4,)
gate = gates.CZ(3, 2)
assert gate.target_qubits == (2,)
assert gate.control_qubits == (3,)
Expand Down
50 changes: 50 additions & 0 deletions tests/test_gates_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,56 @@ def test_cnot(backend, applyx):
assert gates.CNOT(0, 1).unitary


@pytest.mark.parametrize("seed_observable", list(range(1, 10 + 1)))
@pytest.mark.parametrize("seed_state", list(range(1, 10 + 1)))
@pytest.mark.parametrize("controlled_by", [False, True])
def test_cy(backend, controlled_by, seed_state, seed_observable):
nqubits = 2
initial_state = random_statevector(2**nqubits, seed=seed_state, backend=backend)
matrix = np.array(
[
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, -1j],
[0, 0, 1j, 0],
]
)
matrix = backend.cast(matrix, dtype=matrix.dtype)

target_state = np.dot(matrix, initial_state)
# test decomposition
final_state_decompose = apply_gates(
backend,
gates.CY(0, 1).decompose(),
nqubits=nqubits,
initial_state=initial_state,
)

if controlled_by:
gate = gates.Y(1).controlled_by(0)
else:
gate = gates.CY(0, 1)

final_state = apply_gates(backend, [gate], initial_state=initial_state)

assert gate.name == "cy"

backend.assert_allclose(final_state, target_state)

# testing random expectation value due to global phase difference
observable = random_hermitian(2**nqubits, seed=seed_observable, backend=backend)
backend.assert_allclose(
np.transpose(np.conj(final_state_decompose))
@ observable
@ final_state_decompose,
np.transpose(np.conj(target_state)) @ observable @ target_state,
)

assert gates.CY(0, 1).qasm_label == "cy"
assert gates.CY(0, 1).clifford
assert gates.CY(0, 1).unitary


@pytest.mark.parametrize("seed_observable", list(range(1, 10 + 1)))
@pytest.mark.parametrize("seed_state", list(range(1, 10 + 1)))
@pytest.mark.parametrize("controlled_by", [False, True])
Expand Down
Loading