def test_incorrect_heisenberg_size(self, monkeypatch):
        """The number of dimensions of a CV observable Heisenberg representation does
        not match the ev_order attribute."""
        monkeypatch.setattr(qml.P, "ev_order", 2)

        with pytest.raises(ValueError, match="Mismatch between the polynomial order"):
            _transform_observable(qml.P(0), np.identity(3), device_wires=[0])
示例#2
0
 def test_vacuum_state(self):
     """Test the vacuum state is correct."""
     self.logTestName()
     wires = 3
     means, cov = vacuum_state(wires, hbar=hbar)
     self.assertAllAlmostEqual(means, np.zeros([2*wires]), delta=self.tol)
     self.assertAllAlmostEqual(cov, np.identity(2*wires)*hbar/2, delta=self.tol)
示例#3
0
    def test_controlled_arbitrary_rotation(self):
        """Test controlled arbitrary rotation is correct"""
        self.logTestName()

        # test identity for phi,theta,omega=0
        self.assertAllAlmostEqual(CRot3(0,0,0), np.identity(4), delta=self.tol)

        # test identity for phi,theta,omega=pi
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1], [0, 0, 1, 0]])
        self.assertAllAlmostEqual(CRot3(np.pi,np.pi,np.pi), expected, delta=self.tol)

        def arbitrary_Crotation(x, y, z):
            """controlled arbitrary single qubit rotation"""
            c = np.cos(y / 2)
            s = np.sin(y / 2)
            return np.array(
                [
                    [1, 0, 0, 0],
                    [0, 1, 0, 0],
                    [0, 0, np.exp(-0.5j * (x + z)) * c, -np.exp(0.5j * (x - z)) * s],
                    [0, 0, np.exp(-0.5j * (x - z)) * s, np.exp(0.5j * (x + z)) * c]
                ]
            )

        a, b, c = 0.432, -0.152, 0.9234
        self.assertAllAlmostEqual(
            CRot3(a, b, c), arbitrary_Crotation(a, b, c), delta=self.tol
        )
示例#4
0
 def test_coherent_state(self):
     """Test the coherent state is correct."""
     self.logTestName()
     a = 0.432-0.123j
     means, cov = coherent_state(a, hbar=hbar)
     self.assertAllAlmostEqual(means, np.array([a.real, a.imag])*np.sqrt(2*hbar), delta=self.tol)
     self.assertAllAlmostEqual(cov, np.identity(2)*hbar/2, delta=self.tol)
    def test_higher_order_observable(self, monkeypatch):
        """An exception should be raised if the observable is higher than 2nd order."""
        monkeypatch.setattr(qml.P, "ev_order", 3)

        with pytest.raises(NotImplementedError,
                           match="order > 2 not implemented"):
            _transform_observable(qml.P(0), np.identity(3), device_wires=[0])
示例#6
0
    def test_controlled_arbitrary_rotation(self, tol):
        """Test controlled arbitrary rotation is correct"""

        # test identity for phi,theta,omega=0
        assert np.allclose(CRot3(0, 0, 0), np.identity(4), atol=tol, rtol=0)

        # test identity for phi,theta,omega=pi
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1], [0, 0, 1, 0]])
        assert np.allclose(CRot3(np.pi, np.pi, np.pi), expected, atol=tol, rtol=0)

        def arbitrary_Crotation(x, y, z):
            """controlled arbitrary single qubit rotation"""
            c = np.cos(y / 2)
            s = np.sin(y / 2)
            return np.array(
                [
                    [1, 0, 0, 0],
                    [0, 1, 0, 0],
                    [0, 0, np.exp(-0.5j * (x + z)) * c, -np.exp(0.5j * (x - z)) * s],
                    [0, 0, np.exp(-0.5j * (x - z)) * s, np.exp(0.5j * (x + z)) * c]
                ]
            )

        a, b, c = 0.432, -0.152, 0.9234
        assert np.allclose(CRot3(a, b, c), arbitrary_Crotation(a, b, c), atol=tol, rtol=0)
示例#7
0
    def step_and_cost(self,
                      qnode,
                      *args,
                      grad_fn=None,
                      recompute_tensor=True,
                      metric_tensor_fn=None,
                      **kwargs):
        """Update the parameter array :math:`x` with one step of the optimizer and return the
        corresponding objective function value prior to the step.

        Args:
            qnode (QNode): the QNode for optimization
            *args : variable length argument list for qnode
            grad_fn (function): optional gradient function of the
                qnode with respect to the variables ``*args``.
                If ``None``, the gradient function is computed automatically.
                Must return a ``tuple[array]`` with the same number of elements as ``*args``.
                Each array of the tuple should have the same shape as the corresponding argument.
            recompute_tensor (bool): Whether or not the metric tensor should
                be recomputed. If not, the metric tensor from the previous
                optimization step is used.
            metric_tensor_fn (function): Optional metric tensor function
                with respect to the variables ``args``.
                If ``None``, the metric tensor function is computed automatically.
            **kwargs : variable length of keyword arguments for the qnode

        Returns:
            tuple: the new variable values :math:`x^{(t+1)}` and the objective function output
            prior to the step
        """
        # pylint: disable=arguments-differ
        if not isinstance(
                qnode,
            (qml.QNode, qml.ExpvalCost)) and metric_tensor_fn is None:
            raise ValueError(
                "The objective function must either be encoded as a single QNode or "
                "an ExpvalCost object for the natural gradient to be automatically computed. "
                "Otherwise, metric_tensor_fn must be explicitly provided to the optimizer."
            )

        if recompute_tensor or self.metric_tensor is None:
            if metric_tensor_fn is None:

                metric_tensor_fn = qml.metric_tensor(qnode, approx=self.approx)

            self.metric_tensor = metric_tensor_fn(*args, **kwargs)
            self.metric_tensor += self.lam * np.identity(
                self.metric_tensor.shape[0])

        g, forward = self.compute_grad(qnode, args, kwargs, grad_fn=grad_fn)
        new_args = np.array(self.apply_grad(g, args), requires_grad=True)

        if forward is None:
            forward = qnode(*args, **kwargs)

        # unwrap from list if one argument, cleaner return
        if len(new_args) == 1:
            return new_args[0], forward
        return new_args, forward
示例#8
0
    def test_phase_shift(self, tol):
        """Test phase shift is correct"""

        # test identity for theta=0
        assert np.allclose(Rphi(0), np.identity(2), atol=tol, rtol=0)

        # test arbitrary phase shift
        phi = 0.5432
        expected = np.array([[1, 0], [0, np.exp(1j * phi)]])
        assert np.allclose(Rphi(phi), expected, atol=tol, rtol=0)
示例#9
0
    def test_phase_shift(self):
        """Test phase shift is correct"""
        self.logTestName()

        # test identity for theta=0
        self.assertAllAlmostEqual(Rphi(0), np.identity(2), delta=self.tol)

        # test arbitrary phase shift
        phi = 0.5432
        expected = np.array([[1, 0], [0, np.exp(1j * phi)]])
        self.assertAllAlmostEqual(Rphi(phi), expected, delta=self.tol)
示例#10
0
    def test_z_rotation(self, tol):
        """Test z rotation is correct"""

        # test identity for theta=0
        assert np.allclose(Rotz(0), np.identity(2), atol=tol, rtol=0)

        # test identity for theta=pi/2
        expected = np.diag(np.exp([-1j * np.pi / 4, 1j * np.pi / 4]))
        assert np.allclose(Rotz(np.pi / 2), expected, atol=tol, rtol=0)

        # test identity for theta=pi
        assert np.allclose(Rotz(np.pi), -1j * Z, atol=tol, rtol=0)
示例#11
0
    def test_y_rotation(self, tol):
        """Test y rotation is correct"""

        # test identity for theta=0
        assert np.allclose(Roty(0), np.identity(2), atol=tol, rtol=0)

        # test identity for theta=pi/2
        expected = np.array([[1, -1], [1, 1]]) / np.sqrt(2)
        assert np.allclose(Roty(np.pi / 2), expected, atol=tol, rtol=0)

        # test identity for theta=pi
        expected = np.array([[0, -1], [1, 0]])
        assert np.allclose(Roty(np.pi), expected, atol=tol, rtol=0)
示例#12
0
    def test_z_rotation(self):
        """Test z rotation is correct"""
        self.logTestName()

        # test identity for theta=0
        self.assertAllAlmostEqual(Rotz(0), np.identity(2), delta=self.tol)

        # test identity for theta=pi/2
        expected = np.diag(np.exp([-1j * np.pi / 4, 1j * np.pi / 4]))
        self.assertAllAlmostEqual(Rotz(np.pi / 2), expected, delta=self.tol)

        # test identity for theta=pi
        self.assertAllAlmostEqual(Rotz(np.pi), -1j * Z, delta=self.tol)
示例#13
0
    def test_C_z_rotation(self, tol):
        """Test controlled z rotation is correct"""

        # test identity for theta=0
        assert np.allclose(CRotz(0), np.identity(4), atol=tol, rtol=0)

        # test identity for theta=pi/2
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, np.exp(-1j * np.pi / 4), 0], [0, 0, 0, np.exp(1j * np.pi / 4)]])
        assert np.allclose(CRotz(np.pi / 2), expected, atol=tol, rtol=0)

        # test identity for theta=pi
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1j, 0], [0, 0, 0, 1j]])
        assert np.allclose(CRotz(np.pi), expected, atol=tol, rtol=0)
示例#14
0
    def test_C_y_rotation(self, tol):
        """Test controlled y rotation is correct"""

        # test identity for theta=0
        assert np.allclose(CRoty(0), np.identity(4), atol=tol, rtol=0)

        # test identity for theta=pi/2
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1/np.sqrt(2), -1/np.sqrt(2)], [0, 0, 1/np.sqrt(2), 1/np.sqrt(2)]])
        assert np.allclose(CRoty(np.pi / 2), expected, atol=tol, rtol=0)

        # test identity for theta=pi
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1], [0, 0, 1, 0]])
        assert np.allclose(CRoty(np.pi), expected, atol=tol, rtol=0)
示例#15
0
    def test_C_y_rotation(self):
        """Test controlled y rotation is correct"""
        self.logTestName()

        # test identity for theta=0
        self.assertAllAlmostEqual(CRoty(0), np.identity(4), delta=self.tol)

        # test identity for theta=pi/2
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1/np.sqrt(2), -1/np.sqrt(2)], [0, 0, 1/np.sqrt(2), 1/np.sqrt(2)]])
        self.assertAllAlmostEqual(CRoty(np.pi / 2), expected, delta=self.tol)

        # test identity for theta=pi
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1], [0, 0, 1, 0]])
        self.assertAllAlmostEqual(CRoty(np.pi), expected, delta=self.tol)
示例#16
0
    def test_y_rotation(self):
        """Test y rotation is correct"""
        self.logTestName()

        # test identity for theta=0
        self.assertAllAlmostEqual(Roty(0), np.identity(2), delta=self.tol)

        # test identity for theta=pi/2
        expected = np.array([[1, -1], [1, 1]]) / np.sqrt(2)
        self.assertAllAlmostEqual(Roty(np.pi / 2), expected, delta=self.tol)

        # test identity for theta=pi
        expected = np.array([[0, -1], [1, 0]])
        self.assertAllAlmostEqual(Roty(np.pi), expected, delta=self.tol)
示例#17
0
    def test_C_z_rotation(self):
        """Test controlled z rotation is correct"""
        self.logTestName()

        # test identity for theta=0
        self.assertAllAlmostEqual(CRotz(0), np.identity(4), delta=self.tol)

        # test identity for theta=pi/2
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, np.exp(-1j * np.pi / 4), 0], [0, 0, 0, np.exp(1j * np.pi / 4)]])
        self.assertAllAlmostEqual(CRotz(np.pi / 2), expected, delta=self.tol)

        # test identity for theta=pi
        expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1j, 0], [0, 0, 0, 1j]])
        self.assertAllAlmostEqual(CRotz(np.pi), expected, delta=self.tol)
示例#18
0
            def reference(*x):
                """reference circuit"""
                if callable(qop):
                    # if the default.qubit is an operation accepting parameters,
                    # initialise it using the parameters generated above.
                    O = qop(*x)
                else:
                    # otherwise, the operation is simply an array.
                    O = qop

                # calculate the expected output
                out_state = np.kron(Rotx(a) @ np.array([1, 0]), np.array([1, 0]))
                expectation = out_state.conj() @ np.kron(O, np.identity(2)) @ out_state
                return expectation
示例#19
0
 def GenHamiltonian(self):
     '''
     Define and diagonalize chains hamiltonian
     '''
     # Define Pauli operators
     PauliX = np.array([
         [0, 1],
         [1, 0]
     ])
     PauliY = np.array([
         [0, -1j],
         [1j, 0]
     ])
     PauliZ = np.array([
         [1, 0],
         [0, -1]
     ])
     PauliOps = [PauliX, PauliY, PauliZ]
     # Definition of two-qubit Hamiltonian
     Hij = np.sum(Jint * np.kron(Pauli, Pauli)
                  for Jint, Pauli in zip(self.ExchangeIntegrals, PauliOps))
     # Definition of one-qubit Hamiltonian
     Hi = np.sum(hcomp * Pauli
                 for hcomp, Pauli in zip(self.ExternalField, PauliOps))
     # Definition of Chain Hamiltonian
     Hchain = np.sum(
         np.kron(np.identity(2**idx),
                 np.kron(Hij, np.identity(2**(self.num_spins-(idx + 2))))) +
         np.kron(np.identity(2**idx),
                 np.kron(Hi, np.identity(2**(self.num_spins-(idx + 1)))))
         for idx in range(self.num_spins-1)
     ) + np.kron(np.identity(2**(self.num_spins - 1)), Hi)
     # Diagonalization of Hamiltonian
     self.HamMatEnergies, self.HamMatEstates = np.linalg.eig(Hchain)
     # Storing system hamiltonian
     self.SysHamiltonian = qml.Hermitian(
         Hchain, wires=range(self.num_spins))
示例#20
0
    def test_arbitrary_rotation(self, tol):
        """Test arbitrary single qubit rotation is correct"""

        # test identity for phi,theta,omega=0
        assert np.allclose(Rot3(0, 0, 0), np.identity(2), atol=tol, rtol=0)

        # expected result
        def arbitrary_rotation(x, y, z):
            """arbitrary single qubit rotation"""
            c = np.cos(y / 2)
            s = np.sin(y / 2)
            return np.array(
                [
                    [np.exp(-0.5j * (x + z)) * c, -np.exp(0.5j * (x - z)) * s],
                    [np.exp(-0.5j * (x - z)) * s, np.exp(0.5j * (x + z)) * c],
                ]
            )

        a, b, c = 0.432, -0.152, 0.9234
        assert np.allclose(Rot3(a, b, c), arbitrary_rotation(a, b, c), atol=tol, rtol=0)
示例#21
0
            def reference(*x):
                """reference circuit"""
                if g == 'GaussianState':
                    return x[0][0]

                if g == 'Displacement':
                    alpha = x[0]*np.exp(1j*x[1])
                    return (alpha+a).real*np.sqrt(2*hbar)

                if 'State' in g:
                    mu, _ = qop(*x, hbar=hbar)
                    return mu[0]

                S = qop(*x)

                # calculate the expected output
                if op.num_wires == 1:
                    S = block_diag(S, np.identity(2))[:, [0, 2, 1, 3]][[0, 2, 1, 3]]

                return (S @ np.array([a.real, a.imag, 0, 0])*np.sqrt(2*hbar))[0]
示例#22
0
    def test_controlled_phase(self):
        """Test the CZ symplectic transform."""
        self.logTestName()

        s = 0.543
        S = controlled_phase(s)

        # test that S = R_2(pi/2) CX(s) R_2(pi/2)^\dagger
        R2 = block_diag(np.identity(2), rotation(np.pi/2))[:, [0, 2, 1, 3]][[0, 2, 1, 3]]
        expected = R2 @ controlled_addition(s) @ R2.conj().T
        self.assertAllAlmostEqual(S, expected, delta=self.tol)

        # test that S[x1, x2, p1, p2] -> [x1, x2, p1+sx2, p2+sx1]
        x1 = 0.5432
        x2 = -0.453
        p1 = 0.154
        p2 = -0.123
        out = S @ np.array([x1, x2, p1, p2])*np.sqrt(2*hbar)
        expected = np.array([x1, x2, p1+s*x2, p2+s*x1])*np.sqrt(2*hbar)
        self.assertAllAlmostEqual(out, expected, delta=self.tol)
示例#23
0
            def reference(*x):
                """reference circuit"""
                if callable(qop):
                    # if the default.qubit is an operation accepting parameters,
                    # initialise it using the parameters generated above.
                    O = qop(*x)
                else:
                    # otherwise, the operation is simply an array.
                    O = qop

                # calculate the expected output
                if op.num_wires == 1 or g == "QubitUnitary":
                    out_state = np.kron(O @ np.array([1, 0]), np.array([1, 0]))
                elif g == "QubitStateVector":
                    out_state = x[0]
                elif g == "BasisState":
                    out_state = np.array([0, 0, 0, 1])
                else:
                    out_state = O @ dev._state

                expectation = out_state.conj() @ np.kron(X, np.identity(2)) @ out_state
                return expectation
示例#24
0
    def test_arbitrary_rotation(self):
        """Test arbitrary single qubit rotation is correct"""
        self.logTestName()

        # test identity for theta=0
        self.assertAllAlmostEqual(Rot3(0, 0, 0), np.identity(2), delta=self.tol)

        # expected result
        def arbitrary_rotation(x, y, z):
            """arbitrary single qubit rotation"""
            c = np.cos(y / 2)
            s = np.sin(y / 2)
            return np.array(
                [
                    [np.exp(-0.5j * (x + z)) * c, -np.exp(0.5j * (x - z)) * s],
                    [np.exp(-0.5j * (x - z)) * s, np.exp(0.5j * (x + z)) * c],
                ]
            )

        a, b, c = 0.432, -0.152, 0.9234
        self.assertAllAlmostEqual(
            Rot3(a, b, c), arbitrary_rotation(a, b, c), delta=self.tol
        )
示例#25
0
# Applying this, we can see that
#
# .. math::
#
#     H = 4  + 2I\otimes X + 4I \otimes Z - X\otimes X + 5 Y\otimes Y + 2Z\otimes X.
#
# To perform "doubly stochastic" gradient descent, we simply apply the stochastic
# gradient descent approach from above, but in addition also uniformly sample
# a subset of the terms for the Hamiltonian expectation at each optimization step.
# This inserts another element of stochasticity into the system---all the while
# convergence continues to be guaranteed!
#
# Let's create a QNode that randomly samples a single term from the above
# Hamiltonian as the observable to be measured.

I = np.identity(2)
X = np.array([[0, 1], [1, 0]])
Y = np.array([[0, -1j], [1j, 0]])
Z = np.array([[1, 0], [0, -1]])

terms = np.array([
    2 * np.kron(I, X), 4 * np.kron(I, Z), -np.kron(X, X), 5 * np.kron(Y, Y),
    2 * np.kron(Z, X)
])


@qml.qnode(dev_stochastic)
def circuit(params, n=None):
    StronglyEntanglingLayers(weights=params, wires=[0, 1])
    idx = np.random.choice(np.arange(5), size=n, replace=False)
    A = np.sum(terms[idx], axis=0)
示例#26
0
class DummyDevice(DefaultGaussian):
    """Dummy device to allow Kerr operations"""
    _operation_map = DefaultGaussian._operation_map.copy()
    _operation_map['Kerr'] = lambda *x, **y: np.identity(2)
示例#27
0
# --- Sanity check ---
# @qml.qnode(device)
# def qft_inv_test(input):
#     prepare_state(input)
#     qft()
#     iqft()
#
#     basis_obs = qml.Hermitian(np.diag(range(2 ** n_qubits)), wires=range(n_qubits))
#     return qml.sample(basis_obs)
#
# def test_qft(input):
#     samples = qft_inv_test(input=input).astype(int)
#     q_probs = np.bincount(samples, minlength=2 ** n_qubits) / n_shots
#     return q_probs
#
I16 = np.identity(2**4)

# for i in range(2**4):
#     q_probs = test_qft(I16[i])
#     print(q_probs)


# --- Optimize: state -> QFT (using U) -> QFT (traditional) -> state
def eigenvalues2basisvector(eigenvalues):
    n_basis_vector = sum(
        [2**n if i == -1 else 0 for n, i in enumerate(reversed(eigenvalues))])
    return [
        *([0] * n_basis_vector), 1, *([0] * (2**n_qubits - n_basis_vector - 1))
    ]

##############################################################################
# Comparison of quantum and classical results
# -------------------------------------------
#
# Since the specific problem considered in this tutorial has a small size, we can also
# solve it in a classical way and then compare the results with our quantum solution.
#

##############################################################################
# Classical algorithm
# ^^^^^^^^^^^^^^^^^^^
# To solve the problem in a classical way, we use the explicit matrix representation in
# terms of numerical NumPy arrays.

Id = np.identity(2)
Z = np.array([[1, 0], [0, -1]])
X = np.array([[0, 1], [1, 0]])

A_0 = np.identity(8)
A_1 = np.kron(np.kron(X, Z), Id)
A_2 = np.kron(np.kron(X, Id), Id)

A_num = c[0] * A_0 + c[1] * A_1 + c[2] * A_2
b = np.ones(8) / np.sqrt(8)

##############################################################################
# We can print the explicit values of :math:`A` and :math:`b`:

print("A = \n", A_num)
print("b = \n", b)
示例#29
0
    def test_apply(self):
        """Test the application of gates to a state"""
        self.logTestName()

        # loop through all supported operations
        for gate_name, fn in self.dev._operation_map.items():
            log.debug("\tTesting %s gate...", gate_name)
            self.dev.reset()

            # start in the displaced squeezed state
            alpha = 0.542 + 0.123j
            a = abs(alpha)
            phi_a = np.angle(alpha)
            r = 0.652
            phi_r = -0.124

            self.dev.apply('DisplacedSqueezedState',
                           wires=[0],
                           par=[a, phi_a, r, phi_r])
            self.dev.apply('DisplacedSqueezedState',
                           wires=[1],
                           par=[a, phi_a, r, phi_r])

            # get the equivalent pennylane operation class
            op = qml.ops.__getattribute__(gate_name)
            # the list of wires to apply the operation to
            w = list(range(op.num_wires))

            if op.par_domain == 'A':
                # the parameter is an array
                if gate_name == 'GaussianState':
                    p = [
                        np.array([0.432, 0.123, 0.342, 0.123]),
                        np.diag([0.5234] * 4)
                    ]
                    w = list(range(2))
                    expected_out = p
                elif gate_name == 'Interferometer':
                    w = list(range(2))
                    p = [U]
                    S = fn(*p)
                    expected_out = S @ self.dev._state[0], S @ self.dev._state[
                        1] @ S.T
            else:
                # the parameter is a float
                p = [0.432423, -0.12312, 0.324, 0.751][:op.num_params]

                if gate_name == 'Displacement':
                    alpha = p[0] * np.exp(1j * p[1])
                    state = self.dev._state
                    mu = state[0].copy()
                    mu[w[0]] += alpha.real * np.sqrt(2 * hbar)
                    mu[w[0] + 2] += alpha.imag * np.sqrt(2 * hbar)
                    expected_out = mu, state[1]
                elif 'State' in gate_name:
                    mu, cov = fn(*p, hbar=hbar)
                    expected_out = self.dev._state
                    expected_out[0][[w[0], w[0] + 2]] = mu

                    ind = np.concatenate(
                        [np.array([w[0]]),
                         np.array([w[0]]) + 2])
                    rows = ind.reshape(-1, 1)
                    cols = ind.reshape(1, -1)
                    expected_out[1][rows, cols] = cov
                else:
                    # if the default.gaussian is an operation accepting parameters,
                    # initialise it using the parameters generated above.
                    S = fn(*p)

                    # calculate the expected output
                    if op.num_wires == 1:
                        # reorder from symmetric ordering to xp-ordering
                        S = block_diag(
                            S, np.identity(2))[:, [0, 2, 1, 3]][[0, 2, 1, 3]]

                    expected_out = S @ self.dev._state[0], S @ self.dev._state[
                        1] @ S.T

            self.dev.apply(gate_name, wires=w, par=p)

            # verify the device is now in the expected state
            self.assertAllAlmostEqual(self.dev._state[0],
                                      expected_out[0],
                                      delta=self.tol)
            self.assertAllAlmostEqual(self.dev._state[1],
                                      expected_out[1],
                                      delta=self.tol)