diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py
index 1413dbf04..80498321d 100644
--- a/src/qibo/backends/npmatrices.py
+++ b/src/qibo/backends/npmatrices.py
@@ -241,19 +241,29 @@ class NumpyMatrices:
             dtype=self.dtype,
         )
 
-    def MS(self, phi0, phi1):
+    def MS(self, phi0, phi1, theta):
         plus = self.np.exp(1.0j * (phi0 + phi1))
         minus = self.np.exp(1.0j * (phi0 - phi1))
 
         return self.np.array(
             [
-                [1, 0, 0, -1.0j * self.np.conj(plus)],
-                [0, 1, -1.0j * self.np.conj(minus), 0],
-                [0, -1.0j * minus, 1, 0],
-                [-1.0j * plus, 0, 0, 1],
+                [
+                    self.np.cos(theta / 2),
+                    0,
+                    0,
+                    -1.0j * self.np.conj(plus) * self.np.sin(theta / 2),
+                ],
+                [
+                    0,
+                    self.np.cos(theta / 2),
+                    -1.0j * self.np.conj(minus) * self.np.sin(theta / 2),
+                    0,
+                ],
+                [0, -1.0j * minus * self.np.sin(theta / 2), self.np.cos(theta / 2), 0],
+                [-1.0j * plus * self.np.sin(theta / 2), 0, 0, self.np.cos(theta / 2)],
             ],
             dtype=self.dtype,
-        ) / self.np.sqrt(2)
+        )
 
     @cached_property
     def TOFFOLI(self):
diff --git a/src/qibo/gates/gates.py b/src/qibo/gates/gates.py
index c8a913861..11744621d 100644
--- a/src/qibo/gates/gates.py
+++ b/src/qibo/gates/gates.py
@@ -1374,16 +1374,17 @@ class RZZ(_Rnn_):
 
 
 class MS(ParametrizedGate):
-    """The Mølmer–Sørensen (MS) gate is a two qubit gate native to trapped ions.
+    """The (partially entangling) Mølmer–Sørensen (MS) gate
+    is a two qubit gate native to trapped ions.
 
     Corresponds to the following unitary matrix
 
     .. math::
-        \\frac{1}{\\sqrt{2}} \\, \\begin{pmatrix}
-        1 & 0 & 0 & -i e^{-i( \\phi_0 +  \\phi_1)} \\\\
-        0 & 1 & -i e^{-i( \\phi_0 -  \\phi_1)} \\\\
-        0 & -i e^{i( \\phi_0 -  \\phi_1)} & 1 & 0 \\\\
-        -i e^{i( \\phi_0 +  \\phi_1)} & 0 & 0 & 1 \\\\
+        \\begin{pmatrix}
+        \\cos(\\theta / 2) & 0 & 0 & -i e^{-i( \\phi_0 +  \\phi_1)} \\sin(\\theta / 2) \\\\
+        0 & \\cos(\\theta / 2) & -i e^{-i( \\phi_0 -  \\phi_1)} \\sin(\\theta / 2) & 0 \\\\
+        0 & -i e^{i( \\phi_0 -  \\phi_1)} \\sin(\\theta / 2) & \\cos(\\theta / 2) & 0 \\\\
+        -i e^{i( \\phi_0 +  \\phi_1)} \\sin(\\theta / 2) & 0 & 0 & \\cos(\\theta / 2) \\\\
         \\end{pmatrix}
 
     Args:
@@ -1391,31 +1392,45 @@ class MS(ParametrizedGate):
         q1 (int): the second qubit to be swapped id number.
         phi0 (float): first qubit's phase.
         phi1 (float): second qubit's phase
+        theta (float, optional): arbitrary angle in the interval
+            :math:`0 \\leq \\theta \\leq \\pi /2`.  If :math:`\\theta \\rightarrow \\pi / 2`,
+            the fully-entangling MS gate is defined. Defaults to :math:`\\pi / 2`.
         trainable (bool): whether gate parameters can be updated using
-            :meth:`qibo.models.circuit.Circuit.set_parameters`
-            (default is ``True``).
+            :meth:`qibo.models.circuit.Circuit.set_parameters`.
+            Defaults to ``True``.
     """
 
     # TODO: Check how this works with QASM.
 
-    def __init__(self, q0, q1, phi0, phi1, trainable=True):
+    def __init__(self, q0, q1, phi0, phi1, theta: float = math.pi / 2, trainable=True):
         super().__init__(trainable)
         self.name = "ms"
         self.draw_label = "MS"
         self.target_qubits = (q0, q1)
 
-        self.parameter_names = ["phi0", "phi1"]
-        self.parameters = phi0, phi1
-        self.nparams = 2
+        if theta < 0.0 or theta > math.pi / 2:
+            raise_error(
+                ValueError,
+                f"Theta is defined in the interval 0 <= theta <= pi/2, but it is {theta}.",
+            )
+
+        self.parameter_names = ["phi0", "phi1", "theta"]
+        self.parameters = phi0, phi1, theta
+        self.nparams = 3
 
         self.init_args = [q0, q1]
-        self.init_kwargs = {"phi0": phi0, "phi1": phi1, "trainable": trainable}
+        self.init_kwargs = {
+            "phi0": phi0,
+            "phi1": phi1,
+            "theta": theta,
+            "trainable": trainable,
+        }
 
     def _dagger(self) -> "Gate":
         """"""
         q0, q1 = self.target_qubits
-        phi0, phi1 = self.parameters
-        return self.__class__(q0, q1, phi0 + math.pi, phi1)
+        phi0, phi1, theta = self.parameters
+        return self.__class__(q0, q1, phi0 + math.pi, phi1, theta)
 
 
 class TOFFOLI(Gate):

diff --git a/tests/test_gates_gates.py b/tests/test_gates_gates.py
index 37fd4e0e9..4a35676bd 100644
--- a/tests/test_gates_gates.py
+++ b/tests/test_gates_gates.py
@@ -447,6 +447,13 @@ def test_rzz(backend):
 def test_ms(backend):
     phi0 = 0.1234
     phi1 = 0.4321
+    theta = np.pi / 2
+
+    with pytest.raises(NotImplementedError):
+        gates.MS(0, 1, phi0=phi0, phi1=phi1, theta=theta).qasm_label
+    with pytest.raises(ValueError):
+        gates.MS(0, 1, phi0=phi0, phi1=phi1, theta=np.pi)
+
     final_state = apply_gates(
         backend,
         [gates.H(0), gates.H(1), gates.MS(0, 1, phi0=phi0, phi1=phi1)],
@@ -467,9 +474,6 @@ def test_ms(backend):
 
     backend.assert_allclose(final_state, target_state)
 
-    with pytest.raises(NotImplementedError):
-        gates.MS(0, 1, phi0=phi0, phi1=phi1).qasm_label
-
 
 @pytest.mark.parametrize("applyx", [False, True])
 def test_toffoli(backend, applyx):
@@ -782,7 +786,7 @@ GATES = [
     ("RXX", (0, 1, 0.1)),
     ("RYY", (0, 1, 0.2)),
     ("RZZ", (0, 1, 0.3)),
-    ("MS", (0, 1, 0.1, 0.2)),
+    ("MS", (0, 1, 0.1, 0.2, 0.3)),
 ]
 
 

Extend the IonQ native MS gate to include the partially entangled version
We already include the MS gate in Qibo, but recently, IonQ has introduced the Partially Entangled MS gate in their set of native gates. (https://ionq.com/docs/getting-started-with-native-gates)

It adds the possibility to change the angle of rotation from 0 to pi/2, and they even claim that small rotations are more accurate on hardware. We should consider adding that angle to our already available MS gate. 


tests/test_gates_gates.py::test_ms[numpy]
tests/test_gates_gates.py::test_h[numpy] tests/test_gates_gates.py::test_x[numpy] tests/test_gates_gates.py::test_y[numpy] tests/test_gates_gates.py::test_z[numpy] tests/test_gates_gates.py::test_s[numpy] tests/test_gates_gates.py::test_sdg[numpy] tests/test_gates_gates.py::test_t[numpy] tests/test_gates_gates.py::test_tdg[numpy] tests/test_gates_gates.py::test_identity[numpy] tests/test_gates_gates.py::test_align[numpy] tests/test_gates_gates.py::test_rx[numpy] tests/test_gates_gates.py::test_ry[numpy] tests/test_gates_gates.py::test_rz[numpy-True] tests/test_gates_gates.py::test_rz[numpy-False] tests/test_gates_gates.py::test_gpi[numpy] tests/test_gates_gates.py::test_gpi2[numpy] tests/test_gates_gates.py::test_u1[numpy] tests/test_gates_gates.py::test_u2[numpy] tests/test_gates_gates.py::test_u3[numpy] tests/test_gates_gates.py::test_cnot[numpy-False] tests/test_gates_gates.py::test_cnot[numpy-True] tests/test_gates_gates.py::test_cz[numpy-False] tests/test_gates_gates.py::test_cz[numpy-True] tests/test_gates_gates.py::test_cun[numpy-CRX-params0] tests/test_gates_gates.py::test_cun[numpy-CRY-params1] tests/test_gates_gates.py::test_cun[numpy-CRZ-params2] tests/test_gates_gates.py::test_cun[numpy-CU1-params3] tests/test_gates_gates.py::test_cun[numpy-CU2-params4] tests/test_gates_gates.py::test_cun[numpy-CU3-params5] tests/test_gates_gates.py::test_swap[numpy] tests/test_gates_gates.py::test_iswap[numpy] tests/test_gates_gates.py::test_fswap[numpy] tests/test_gates_gates.py::test_multiple_swap[numpy] tests/test_gates_gates.py::test_fsim[numpy] tests/test_gates_gates.py::test_generalized_fsim[numpy] tests/test_gates_gates.py::test_generalized_fsim_parameter_setter[numpy] tests/test_gates_gates.py::test_rxx[numpy] tests/test_gates_gates.py::test_ryy[numpy] tests/test_gates_gates.py::test_rzz[numpy] tests/test_gates_gates.py::test_toffoli[numpy-False] tests/test_gates_gates.py::test_toffoli[numpy-True] tests/test_gates_gates.py::test_unitary_initialization[numpy] tests/test_gates_gates.py::test_controlled_x[numpy] tests/test_gates_gates.py::test_controlled_x_vs_cnot[numpy] tests/test_gates_gates.py::test_controlled_x_vs_toffoli[numpy] tests/test_gates_gates.py::test_controlled_rx[numpy-False] tests/test_gates_gates.py::test_controlled_rx[numpy-True] tests/test_gates_gates.py::test_controlled_u1[numpy] tests/test_gates_gates.py::test_controlled_u2[numpy] tests/test_gates_gates.py::test_controlled_u3[numpy] tests/test_gates_gates.py::test_controlled_swap[numpy-False-False] tests/test_gates_gates.py::test_controlled_swap[numpy-False-True] tests/test_gates_gates.py::test_controlled_swap[numpy-True-False] tests/test_gates_gates.py::test_controlled_swap[numpy-True-True] tests/test_gates_gates.py::test_controlled_swap_double[numpy-False] tests/test_gates_gates.py::test_controlled_swap_double[numpy-True] tests/test_gates_gates.py::test_controlled_fsim[numpy] tests/test_gates_gates.py::test_dagger[numpy-H-args0] tests/test_gates_gates.py::test_dagger[numpy-X-args1] tests/test_gates_gates.py::test_dagger[numpy-Y-args2] tests/test_gates_gates.py::test_dagger[numpy-Z-args3] tests/test_gates_gates.py::test_dagger[numpy-S-args4] tests/test_gates_gates.py::test_dagger[numpy-SDG-args5] tests/test_gates_gates.py::test_dagger[numpy-T-args6] tests/test_gates_gates.py::test_dagger[numpy-TDG-args7] tests/test_gates_gates.py::test_dagger[numpy-RX-args8] tests/test_gates_gates.py::test_dagger[numpy-RY-args9] tests/test_gates_gates.py::test_dagger[numpy-RZ-args10] tests/test_gates_gates.py::test_dagger[numpy-GPI-args11] tests/test_gates_gates.py::test_dagger[numpy-GPI2-args12] tests/test_gates_gates.py::test_dagger[numpy-U1-args13] tests/test_gates_gates.py::test_dagger[numpy-U2-args14] tests/test_gates_gates.py::test_dagger[numpy-U3-args15] tests/test_gates_gates.py::test_dagger[numpy-CNOT-args16] tests/test_gates_gates.py::test_dagger[numpy-CRX-args17] tests/test_gates_gates.py::test_dagger[numpy-CRZ-args18] tests/test_gates_gates.py::test_dagger[numpy-CU1-args19] tests/test_gates_gates.py::test_dagger[numpy-CU2-args20] tests/test_gates_gates.py::test_dagger[numpy-CU3-args21] tests/test_gates_gates.py::test_dagger[numpy-fSim-args22] tests/test_gates_gates.py::test_dagger[numpy-RXX-args23] tests/test_gates_gates.py::test_dagger[numpy-RYY-args24] tests/test_gates_gates.py::test_dagger[numpy-RZZ-args25] tests/test_gates_gates.py::test_dagger[numpy-MS-args26] tests/test_gates_gates.py::test_controlled_dagger[numpy-H-args0] tests/test_gates_gates.py::test_controlled_dagger[numpy-X-args1] tests/test_gates_gates.py::test_controlled_dagger[numpy-Y-args2] tests/test_gates_gates.py::test_controlled_dagger[numpy-S-args3] tests/test_gates_gates.py::test_controlled_dagger[numpy-SDG-args4] tests/test_gates_gates.py::test_controlled_dagger[numpy-T-args5] tests/test_gates_gates.py::test_controlled_dagger[numpy-TDG-args6] tests/test_gates_gates.py::test_controlled_dagger[numpy-RX-args7] tests/test_gates_gates.py::test_controlled_dagger[numpy-U1-args8] tests/test_gates_gates.py::test_controlled_dagger[numpy-U3-args9] tests/test_gates_gates.py::test_dagger_consistency[numpy-0-S-SDG] tests/test_gates_gates.py::test_dagger_consistency[numpy-0-T-TDG] tests/test_gates_gates.py::test_dagger_consistency[numpy-2-S-SDG] tests/test_gates_gates.py::test_dagger_consistency[numpy-2-T-TDG] tests/test_gates_gates.py::test_dagger_consistency[numpy-4-S-SDG] tests/test_gates_gates.py::test_dagger_consistency[numpy-4-T-TDG] tests/test_gates_gates.py::test_controlled_unitary_dagger[numpy] tests/test_gates_gates.py::test_generalizedfsim_dagger[numpy] tests/test_gates_gates.py::test_gate_basis_rotation[numpy] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-True-0-controls0-free0] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-True-2-controls1-free1] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-True-3-controls2-free2] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-True-7-controls3-free3] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-True-5-controls4-free4] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-True-8-controls5-free5] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-False-0-controls0-free0] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-False-2-controls1-free1] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-False-3-controls2-free2] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-False-7-controls3-free3] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-False-5-controls4-free4] tests/test_gates_gates.py::test_x_decomposition_execution[numpy-False-8-controls5-free5]