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

Move gates.Gate.decompose to transpiler.decompositions #1188

Merged
merged 12 commits into from
Feb 7, 2024
124 changes: 61 additions & 63 deletions src/qibo/gates/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,11 @@ def decompose(self):
being the :class:`qibo.gates.RX` gate. More precisely,
:math:`\\sqrt{X} = e^{i \\pi / 4} \\, \\text{RX}(\\pi / 2)`.
"""
return [RX(self.init_args[0], np.pi / 2, trainable=False)]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)

def _dagger(self):
""""""
Expand Down Expand Up @@ -314,7 +318,11 @@ def decompose(self):
being the :class:`qibo.gates.RX` gate. More precisely,
:math:`(\\sqrt{X})^{\\dagger} = e^{-i \\pi / 4} \\, \\text{RX}(-\\pi / 2)`.
"""
return [RX(self.init_args[0], -np.pi / 2, trainable=False)]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)

def _dagger(self):
""""""
Expand Down Expand Up @@ -892,14 +900,11 @@ def decompose(self) -> List[Gate]:
where :math:`\\text{RZ}` and :math:`\\sqrt{X}` are, respectively,
:class:`qibo.gates.RZ` and :class`qibo.gates.SX`.
"""
q = self.init_args[0]
return [
RZ(q, self.init_kwargs["lam"]),
SX(q),
RZ(q, self.init_kwargs["theta"] + math.pi),
SX(q),
RZ(q, self.init_kwargs["phi"] + math.pi),
]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)


class U1q(_Un_):
Expand Down Expand Up @@ -1020,8 +1025,11 @@ def decompose(self) -> List[Gate]:
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)]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)


class CZ(Gate):
Expand Down Expand Up @@ -1063,8 +1071,11 @@ def decompose(self) -> List[Gate]:
the target qubit, followed by :class:`qibo.gates.CNOT`, followed
by another :class:`qibo.gates.H` in the target qubit
"""
q0, q1 = self.init_args
return [H(q1), CNOT(q0, q1), H(q1)]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)


class CSX(Gate):
Expand Down Expand Up @@ -1100,8 +1111,11 @@ def qasm_label(self):

def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]:
""""""
q0, q1 = self.init_args
return [H(q1), CU1(q0, q1, np.pi / 2), H(q1)]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)

def _dagger(self):
""""""
Expand Down Expand Up @@ -1141,8 +1155,11 @@ def qasm_label(self):

def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]:
""""""
q0, q1 = self.init_args
return [H(q1), CU1(q0, q1, -np.pi / 2), H(q1)]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)

def _dagger(self):
""""""
Expand Down Expand Up @@ -1901,9 +1918,11 @@ def __init__(self, q0, q1, theta, trainable=True):

def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]:
""""""
q0, q1 = self.target_qubits
theta = self.init_kwargs["theta"]
return [H(q1), CNOT(q0, q1), RZ(q1, theta), CNOT(q0, q1), H(q1)]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)


class RXXYY(_Rnn_):
Expand Down Expand Up @@ -1942,22 +1961,11 @@ def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]:
the original gate due to a phase difference in
:math:`\\left(\\sqrt{X}\\right)^{\\dagger}`.
"""
q0, q1 = self.target_qubits
theta = self.init_kwargs["theta"]
return [
RZ(q1, -np.pi / 2),
S(q0),
SX(q1),
RZ(q1, np.pi / 2),
CNOT(q1, q0),
RY(q0, -theta / 2),
RY(q1, -theta / 2),
CNOT(q1, q0),
SDG(q0),
RZ(q1, -np.pi / 2),
SX(q1).dagger(),
RZ(q1, np.pi / 2),
]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)


class MS(ParametrizedGate):
Expand Down Expand Up @@ -2062,18 +2070,13 @@ def _dagger(self) -> "Gate":
return self.__class__(*self.target_qubits, -self.parameters[0])

def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]:
"""Decomposition of Givens gate according to `ArXiv:2106.13839
<https://arxiv.org/abs/2106.13839>`_."""
q0, q1 = self.target_qubits
theta = self.init_kwargs["theta"]
return [
CNOT(q0, q1),
RY(q0, theta),
CNOT(q1, q0),
RY(q0, -theta),
CNOT(q1, q0),
CNOT(q0, q1),
]
"""Decomposition of RBS gate according to `ArXiv:2109.09685
<https://arxiv.org/abs/2109.09685>`_."""
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)


class RBS(ParametrizedGate):
Expand Down Expand Up @@ -2123,18 +2126,11 @@ def _dagger(self) -> "Gate":
def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]:
"""Decomposition of RBS gate according to `ArXiv:2109.09685
<https://arxiv.org/abs/2109.09685>`_."""
q0, q1 = self.target_qubits
theta = self.init_kwargs["theta"]
return [
H(q0),
CNOT(q0, q1),
H(q1),
RY(q0, theta),
RY(q1, -theta),
H(q1),
CNOT(q0, q1),
H(q0),
]
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

return standard_decompositions(self)


class ECR(Gate):
Expand Down Expand Up @@ -2175,9 +2171,11 @@ def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]:
\\textup{ECR} = e^{i 7 \\pi / 4} \\, S(q_{0}) \\, \\sqrt{X}(q_{1}) \\,
\\textup{CNOT}(q_{0}, q_{1}) \\, X(q_{0})
"""
from qibo.transpiler.decompositions import ( # pylint: disable=C0415
standard_decompositions,
)

q0, q1 = self.target_qubits
return [S(q0), SX(q1), CNOT(q0, q1), X(q0)]
return standard_decompositions(self)


class TOFFOLI(Gate):
Expand Down
105 changes: 89 additions & 16 deletions src/qibo/transpiler/decompositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def _u3_to_gpi2(t, p, l):

# Decompose single qubit gates using U3
u3_dec = GateDecompositions()
u3_dec.add(gates.H, [gates.U3(0, 7 * np.pi / 2, np.pi, 0)])
u3_dec.add(gates.H, [gates.U3(0, -np.pi / 2, np.pi, 0)])
u3_dec.add(gates.X, [gates.U3(0, np.pi, 0, np.pi)])
u3_dec.add(gates.Y, [gates.U3(0, np.pi, 0, 0)])
u3_dec.add(gates.Z, [gates.Z(0)])
Expand Down Expand Up @@ -159,28 +159,28 @@ def _u3_to_gpi2(t, p, l):
gates.CNOT,
[
gates.U3(0, 3 * np.pi / 2, np.pi, 0),
gates.U3(1, np.pi / 2, -np.pi, -np.pi),
gates.U3(1, np.pi / 2, np.pi, np.pi),
gates.iSWAP(0, 1),
gates.U3(0, np.pi, 0, np.pi),
gates.U3(1, np.pi / 2, -np.pi, -np.pi),
gates.U3(1, np.pi / 2, np.pi, np.pi),
gates.iSWAP(0, 1),
gates.U3(0, np.pi / 2, np.pi / 2, -np.pi),
gates.U3(1, np.pi / 2, -np.pi, -np.pi / 2),
gates.U3(0, np.pi / 2, np.pi / 2, np.pi),
gates.U3(1, np.pi / 2, np.pi, -np.pi / 2),
],
)
iswap_dec.add(
gates.CZ,
[
gates.U3(0, 7 * np.pi / 2, np.pi, 0),
gates.U3(1, 7 * np.pi / 2, np.pi, 0),
gates.U3(1, np.pi / 2, -np.pi, -np.pi),
gates.U3(0, -np.pi / 2, np.pi, 0),
gates.U3(1, -np.pi / 2, np.pi, 0),
gates.U3(1, np.pi / 2, np.pi, np.pi),
gates.iSWAP(0, 1),
gates.U3(0, np.pi, 0, np.pi),
gates.U3(1, np.pi / 2, -np.pi, -np.pi),
gates.U3(1, np.pi / 2, np.pi, np.pi),
gates.iSWAP(0, 1),
gates.U3(0, np.pi / 2, np.pi / 2, -np.pi),
gates.U3(1, np.pi / 2, -np.pi, -np.pi / 2),
gates.U3(1, 7 * np.pi / 2, np.pi, 0),
gates.U3(0, np.pi / 2, np.pi / 2, np.pi),
gates.U3(1, np.pi / 2, np.pi, -np.pi / 2),
gates.U3(1, -np.pi / 2, np.pi, 0),
],
)
iswap_dec.add(
Expand Down Expand Up @@ -304,14 +304,14 @@ def _u3_to_gpi2(t, p, l):
cz_dec.add(
gates.FSWAP,
[
gates.U3(0, np.pi / 2, -np.pi / 2, -np.pi),
gates.U3(0, np.pi / 2, -np.pi / 2, np.pi),
gates.U3(1, np.pi / 2, np.pi / 2, np.pi / 2),
gates.CZ(0, 1),
gates.U3(0, np.pi / 2, 0, -np.pi / 2),
gates.U3(1, np.pi / 2, 0, np.pi / 2),
gates.CZ(0, 1),
gates.U3(0, np.pi / 2, np.pi / 2, -np.pi),
gates.U3(1, np.pi / 2, 0, -np.pi),
gates.U3(0, np.pi / 2, np.pi / 2, np.pi),
gates.U3(1, np.pi / 2, 0, np.pi),
],
)
cz_dec.add(
Expand All @@ -328,7 +328,7 @@ def _u3_to_gpi2(t, p, l):
gates.RYY,
lambda gate: [
gates.RX(0, np.pi / 2),
gates.U3(1, np.pi / 2, np.pi / 2, -np.pi),
gates.U3(1, np.pi / 2, np.pi / 2, np.pi),
gates.CZ(0, 1),
gates.RX(1, gate.parameters[0]),
gates.CZ(0, 1),
Expand Down Expand Up @@ -392,3 +392,76 @@ def _u3_to_gpi2(t, p, l):
gates.H(1),
],
)


# standard gate decompositions used by :meth:`qibo.gates.gates.Gate.decompose`
standard_decompositions = GateDecompositions()
standard_decompositions.add(gates.SX, [gates.RX(0, np.pi / 2, trainable=False)])
standard_decompositions.add(gates.SXDG, [gates.RX(0, -np.pi / 2, trainable=False)])
standard_decompositions.add(
gates.U3,
lambda gate: [
gates.RZ(0, gate.parameters[2]),
gates.SX(0),
gates.RZ(0, gate.parameters[0] + np.pi),
gates.SX(0),
gates.RZ(0, gate.parameters[1] + np.pi),
],
)
standard_decompositions.add(gates.CY, [gates.SDG(1), gates.CNOT(0, 1), gates.S(1)])
standard_decompositions.add(gates.CZ, [gates.H(1), gates.CNOT(0, 1), gates.H(1)])
standard_decompositions.add(
gates.CSX, [gates.H(1), gates.CU1(0, 1, np.pi / 2), gates.H(1)]
)
standard_decompositions.add(
gates.CSXDG, [gates.H(1), gates.CU1(0, 1, -np.pi / 2), gates.H(1)]
)
standard_decompositions.add(
gates.RZX,
lambda gate: [
gates.H(1),
gates.CNOT(0, 1),
gates.RZ(1, gate.parameters[0]),
gates.CNOT(0, 1),
gates.H(1),
],
)
standard_decompositions.add(
gates.RXXYY,
lambda gate: [
gates.RZ(1, -np.pi / 2),
gates.S(0),
gates.SX(1),
gates.RZ(1, np.pi / 2),
gates.CNOT(1, 0),
gates.RY(0, -gate.parameters[0] / 2),
gates.RY(1, -gate.parameters[0] / 2),
gates.CNOT(1, 0),
gates.SDG(0),
gates.RZ(1, -np.pi / 2),
gates.SX(1).dagger(),
gates.RZ(1, np.pi / 2),
],
)
standard_decompositions.add(
gates.RBS,
lambda gate: [
gates.H(0),
gates.CNOT(0, 1),
gates.H(1),
gates.RY(0, gate.parameters[0]),
gates.RY(1, -gate.parameters[0]),
gates.H(1),
gates.CNOT(0, 1),
gates.H(0),
],
)
standard_decompositions.add(
gates.GIVENS, lambda gate: gates.RBS(0, 1, -gate.parameters[0]).decompose()
)
standard_decompositions.add(
gates.FSWAP, [gates.X(1)] + gates.GIVENS(0, 1, np.pi / 2).decompose() + [gates.X(0)]
)
standard_decompositions.add(
gates.ECR, [gates.S(0), gates.SX(1), gates.CNOT(0, 1), gates.X(0)]
)
Loading