diff --git a/src/qibo/gates/gates.py b/src/qibo/gates/gates.py index c0879b10d2..ae56a2723b 100644 --- a/src/qibo/gates/gates.py +++ b/src/qibo/gates/gates.py @@ -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): """""" @@ -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): """""" @@ -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_): @@ -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): @@ -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): @@ -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): """""" @@ -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): """""" @@ -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_): @@ -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): @@ -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 - `_.""" - 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 + `_.""" + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) class RBS(ParametrizedGate): @@ -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 `_.""" - 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): @@ -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): diff --git a/src/qibo/transpiler/decompositions.py b/src/qibo/transpiler/decompositions.py index cb106d423b..f559f0088a 100644 --- a/src/qibo/transpiler/decompositions.py +++ b/src/qibo/transpiler/decompositions.py @@ -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)]) @@ -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( @@ -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( @@ -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), @@ -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)] +)