Repository: PennyLaneAI/pennylane
Pull request #3810 (2023-02-23 02:58:50)

Daily rc sync to master $(date +'%Y-%m-%d')
Automatic sync from the release candidate to master during a feature freeze.

codecov[bot]: # [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3810?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
> :exclamation: No coverage uploaded for pull request base (`master@9af6878`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#section-missing-base-commit).
> The diff coverage is `n/a`.

```diff
@@            Coverage Diff            @@
##             master    #3810   +/-   ##
=========================================
  Coverage          ?   99.73%           
=========================================
  Files             ?      336           
  Lines             ?    29447           
  Branches          ?        0           
=========================================
  Hits              ?    29368           
  Misses            ?       79           
  Partials          ?        0           
```


| [Impacted Files](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3810?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Coverage Δ | |
|---|---|---|
| [pennylane/devices/default\_mixed.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3810?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2RldmljZXMvZGVmYXVsdF9taXhlZC5weQ==) | `100.00% <ø> (ø)` | |
| [pennylane/devices/null\_qubit.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3810?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2RldmljZXMvbnVsbF9xdWJpdC5weQ==) | `100.00% <ø> (ø)` | |
| [pennylane/ops/qubit/special\_unitary.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3810?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL29wcy9xdWJpdC9zcGVjaWFsX3VuaXRhcnkucHk=) | `100.00% <ø> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI)


Patch:
diff --git a/doc/releases/changelog-0.29.0.md b/doc/releases/changelog-0.29.0.md
index 2353354ae..3143c3d0f 100644
--- a/doc/releases/changelog-0.29.0.md
+++ b/doc/releases/changelog-0.29.0.md
@@ -4,7 +4,9 @@
 
 <h3>New features since last release</h3>
 
-* Added 'qml.sign_expand' tape tranforms which implements the optimal decomposition of a fast-forwardable Hamiltonian that minimizes the variance of its estimator in the Single-Qubit-Measurement from  arXiv:2207.09479
+* Added 'qml.sign_expand' tape tranforms which implements the optimal decomposition of a
+  fast-forwardable Hamiltonian that minimizes the variance of its estimator in the
+  Single-Qubit-Measurement from  arXiv:2207.09479
   [(#2852)](https://github.com/PennyLaneAI/pennylane/pull/2852)
 
 * The `qml.math` module now also contains a submodule for
@@ -31,6 +33,7 @@
 * A new operation `SpecialUnitary` was added, providing access to an arbitrary
   unitary gate via a parametrization in the Pauli basis.
   [(#3650)](https://github.com/PennyLaneAI/pennylane/pull/3650)
+  [(#3651)](https://github.com/PennyLaneAI/pennylane/pull/3651)
   [(#3674)](https://github.com/PennyLaneAI/pennylane/pull/3674)
 
   The new operation takes a single argument, a one-dimensional `tensor_like`
diff --git a/pennylane/devices/default_mixed.py b/pennylane/devices/default_mixed.py
index 3a075dde5..100d663e5 100644
--- a/pennylane/devices/default_mixed.py
+++ b/pennylane/devices/default_mixed.py
@@ -76,6 +76,7 @@ class DefaultMixed(QubitDevice):
         "ControlledQubitUnitary",
         "MultiControlledX",
         "DiagonalQubitUnitary",
+        "SpecialUnitary",
         "PauliX",
         "PauliY",
         "PauliZ",
@@ -128,6 +129,7 @@ class DefaultMixed(QubitDevice):
         "QFT",
         "ThermalRelaxationError",
         "ECR",
+        "ParametrizedEvolution",
     }
 
     _reshape = staticmethod(qnp.reshape)
diff --git a/pennylane/devices/null_qubit.py b/pennylane/devices/null_qubit.py
index bb6714df6..5ee3fdf62 100644
--- a/pennylane/devices/null_qubit.py
+++ b/pennylane/devices/null_qubit.py
@@ -49,6 +49,7 @@ class NullQubit(QubitDevice):
         "ControlledQubitUnitary",
         "MultiControlledX",
         "DiagonalQubitUnitary",
+        "SpecialUnitary",
         "PauliX",
         "PauliY",
         "PauliZ",
diff --git a/pennylane/ops/qubit/special_unitary.py b/pennylane/ops/qubit/special_unitary.py
index f3b3df700..7a80c7bc8 100644
--- a/pennylane/ops/qubit/special_unitary.py
+++ b/pennylane/ops/qubit/special_unitary.py
@@ -222,7 +222,7 @@ class SpecialUnitary(Operation):
     Note that for specific operations like the ``RX`` rotation gate above, it is
     strongly recommended to use the specialized implementation ``qml.RX`` rather
     than ``PauliRot`` or ``SpecialUnitary``.
-    However, ``SpecialUnitary`` gates go beyong such rotations: Multiple Pauli words
+    However, ``SpecialUnitary`` gates go beyond such rotations: Multiple Pauli words
     can be activated simultaneously, giving access to more complex operations.
     For two qubits, this could look like this:
 
@@ -418,7 +418,7 @@ class SpecialUnitary(Operation):
 
             U(\theta) = \exp(i\sum_{m=1}^d \theta_m P_m)
 
-        See :func:`~.ops.qubit.matrix_ops.pauli_basis_strings` for the ordering of Pauli words.
+        See the main class documentation above for the ordering of Pauli words.
 
         .. note::
 


Test patch:
diff --git a/pennylane/devices/tests/test_gates.py b/pennylane/devices/tests/test_gates.py
index 590595409..cae7b72df 100644
--- a/pennylane/devices/tests/test_gates.py
+++ b/pennylane/devices/tests/test_gates.py
@@ -559,7 +559,8 @@ class TestGatesQubit:
         res = circuit()
 
         # Disabling Pylint test because qml.ops can be misunderstood as qml.ops.qubit.ops
-        basis = qml.ops.qubit.matrix_ops.pauli_basis(n_wires)  # pylint: disable=no-member
+        basis_fn = qml.ops.qubit.special_unitary.pauli_basis_matrices  # pylint: disable=no-member
+        basis = basis_fn(n_wires)
         mat = qml.math.expm(1j * np.tensordot(theta_, basis, axes=[[0], [0]]))
         expected = np.abs(mat @ rnd_state) ** 2
         assert np.allclose(res, expected, atol=tol(dev.shots))
diff --git a/tests/devices/test_default_mixed.py b/tests/devices/test_default_mixed.py
index f972381a0..1f18c3e3a 100644
--- a/tests/devices/test_default_mixed.py
+++ b/tests/devices/test_default_mixed.py
@@ -1049,6 +1049,22 @@ class TestApply:
 
         assert np.allclose(dev.state, target_rho, atol=tol, rtol=0)
 
+    @pytest.mark.parametrize("num_wires", [1, 2, 3])
+    def test_apply_specialunitary(self, tol, num_wires):
+        """Tests that a special unitary is correctly applied"""
+        np.random.seed(2514)
+        theta = np.random.random(4**num_wires - 1)
+
+        dev = qml.device("default.mixed", wires=num_wires)
+        dev.apply([qml.SpecialUnitary(theta, wires=list(range(num_wires)))])
+
+        mat = qml.SpecialUnitary.compute_matrix(theta, num_wires)
+        init_rho = np.zeros((2**num_wires, 2**num_wires))
+        init_rho[0, 0] = 1
+        target_rho = mat @ init_rho @ mat.conj().T
+
+        assert np.allclose(dev.state, target_rho, atol=tol, rtol=0)
+
     def test_apply_pauli_error(self, tol):
         """Tests that PauliError gate is correctly applied"""
         nr_wires = 3
diff --git a/tests/devices/test_default_qubit.py b/tests/devices/test_default_qubit.py
index ecdd4ab41..f7d4acaf3 100644
--- a/tests/devices/test_default_qubit.py
+++ b/tests/devices/test_default_qubit.py
@@ -407,6 +407,16 @@ class TestApply:
             [cmath.exp(1j * 0.4) / 2, cmath.exp(1j * -0.4) * math.sqrt(3) / 4],
             [np.array([cmath.exp(1j * 0.4), cmath.exp(1j * -0.4)])],
         ),
+        (qml.SpecialUnitary, [1, 0], [0, 1j], [np.array([np.pi / 2, 0, 0])]),
+        (qml.SpecialUnitary, [1, 0], [0, -1], [np.array([0, np.pi / 2, 0])]),
+        (qml.SpecialUnitary, [1, 0], [1j, 0], [np.array([0, 0, np.pi / 2])]),
+        (qml.SpecialUnitary, [0.6, 0.8], [0.573 + 0.236j, 0.764 + 0.177j], [np.array([0.3, 0, 0])]),
+        (
+            qml.SpecialUnitary,
+            [0.8j, -0.6],
+            [-0.808 + 0.049j, -0.411 + 0.419j],
+            [np.array([0.4, 0.2, 1.2])],
+        ),
     ]
 
     @pytest.mark.parametrize(
@@ -536,6 +546,42 @@ class TestApply:
             [np.array([1, 1, 1, -1])],
         ),
         (qml.DiagonalQubitUnitary, [0, 0, 1, 0], [0, 0, 1j, 0], [np.array([-1, 1j, 1j, -1])]),
+        (
+            qml.SpecialUnitary,
+            [0.5, -0.5j, 0.5j, -0.5],
+            [0.382 - 0.322j, -0.322 - 0.382j, 0.322 + 0.382j, -0.382 + 0.322j],
+            [np.eye(15)[4] * 0.7],
+        ),
+        (
+            qml.SpecialUnitary,
+            [0.6, 0, 0, -0.8],
+            [0.553, 0.312, -0.234, -0.737],
+            [np.eye(15)[10] * 0.4],
+        ),
+        (
+            qml.SpecialUnitary,
+            [0, 0, 1, 0],
+            [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0],
+            [-np.eye(15)[4] * np.pi / 4],
+        ),  # Like Ising XX
+        (
+            qml.SpecialUnitary,
+            [0, 0, 1, 0],
+            [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0],
+            [-np.eye(15)[9] * np.pi / 4],
+        ),  # Like Ising YY
+        (
+            qml.SpecialUnitary,
+            [0, 0, 0, 1],
+            [0, 0, 0, 1 / math.sqrt(2) - 1j / math.sqrt(2)],
+            [-np.eye(15)[14] * np.pi / 4],
+        ),  # Like Ising ZZ
+        (
+            qml.SpecialUnitary,
+            [0.5, -0.5j, -0.5, -0.5],
+            [-0.616 - 0.018j, 0.316 + 0.243j, 0.427 + 0.437j, 0.294 + 0.043j],
+            [np.linspace(0.1, 3, 15)],
+        ),
         (qml.IsingXX, [0, 0, 1, 0], [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], [math.pi / 2]),
         (qml.IsingXX, [0, 0, 0, 1], [-1j / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], [math.pi / 2]),
         (qml.IsingXX, [1, 0, 0, 0], [1 / math.sqrt(2), 0, 0, -1j / math.sqrt(2)], [math.pi / 2]),
diff --git a/tests/devices/test_default_qubit_broadcasting.py b/tests/devices/test_default_qubit_broadcasting.py
index f51e80b95..ffe14d388 100644
--- a/tests/devices/test_default_qubit_broadcasting.py
+++ b/tests/devices/test_default_qubit_broadcasting.py
@@ -236,6 +236,18 @@ class TestApplyBroadcasted:
         for s, par in [(state_1, diag_par_5), (state_5, diag_par_1), (state_5, diag_par_5)]
     ]
 
+    # Add qml.SpecialUnitary test cases
+    theta_1_par_1 = [np.array([np.pi / 2, 0, 0])]
+    theta_1_par_5 = [
+        np.array(
+            [[np.pi / 2, 0, 0], [0, np.pi / 2, 0], [0, 0, np.pi / 2], [0.3, 0, 0], [0.4, 0.2, 1.2]]
+        )
+    ]
+    test_data_single_wire_with_parameters += [
+        (qml.SpecialUnitary, s, mat_vec(qml.SpecialUnitary.compute_matrix(par[0], 1), s), par)
+        for s, par in [(state_1, theta_1_par_5), (state_5, theta_1_par_1), (state_5, theta_1_par_5)]
+    ]
+
     # Add qml.Rot test cases
     multi_par_1 = {
         "rz_0": [0.632, 0, 0],
@@ -371,6 +383,14 @@ class TestApplyBroadcasted:
         for s, par in [(state_1, diag_par_5), (state_5, diag_par_1), (state_5, diag_par_5)]
     ]
 
+    # Add qml.SpecialUnitary test cases
+    theta_2_par_1 = [np.linspace(0.1, 3, 15)]
+    theta_2_par_5 = [np.array([0.4, -0.2, 1.2, -0.5, 2.2])[:, np.newaxis] * np.eye(15)[2::3]]
+    test_data_two_wires_with_parameters += [
+        (qml.SpecialUnitary, s, mat_vec(qml.SpecialUnitary.compute_matrix(par[0], 2), s), par)
+        for s, par in [(state_1, theta_2_par_5), (state_5, theta_2_par_1), (state_5, theta_2_par_5)]
+    ]
+
     @pytest.mark.parametrize(
         "operation,input,expected_output,par", test_data_two_wires_with_parameters
     )
diff --git a/tests/devices/test_null_qubit.py b/tests/devices/test_null_qubit.py
index 61395b5ee..5cdaef7e6 100644
--- a/tests/devices/test_null_qubit.py
+++ b/tests/devices/test_null_qubit.py
@@ -14,9 +14,8 @@
 """
 Unit tests for the :mod:`pennylane.plugin.NullQubit` device.
 """
-import cmath
-
 # pylint: disable=protected-access,cell-var-from-loop
+from collections import defaultdict
 import math
 
 import pytest
@@ -25,12 +24,18 @@ from pennylane import numpy as np, DeviceError
 from pennylane.devices.null_qubit import NullQubit
 from pennylane import Tracker
 
-from collections import defaultdict
 
+@pytest.fixture(
+    name="nullqubit_device",
+    scope="function",
+    params=[(np.float32, np.complex64), (np.float64, np.complex128)],
+)
+def fixture_nullqubit_device(request):
+    """Create a NullQubit device with the indicated number of wires,
+    parametrizing over real and complex dtypes."""
 
-@pytest.fixture(scope="function", params=[(np.float32, np.complex64), (np.float64, np.complex128)])
-def nullqubit_device(request):
     def _device(wires):
+        """Create NullQubit device."""
         return qml.device(
             "null.qubit", wires=wires, r_dtype=request.param[0], c_dtype=request.param[1]
         )
@@ -62,11 +67,15 @@ def test_dtype_errors():
 
 def test_custom_op_with_matrix():
     """Test that a dummy op with a matrix is supported."""
+    # pylint: disable=too-few-public-methods
 
     class DummyOp(qml.operation.Operation):
+        """Placeholder Operation on a single wire."""
+
         num_wires = 1
 
         def compute_matrix(self):
+            """Compute the matrix of the DummyOp"""
             return np.eye(2)
 
     with qml.queuing.AnnotatedQueue() as q:
@@ -103,28 +112,6 @@ class TestApply:
         dev.apply([operation(input, wires=[0, 1])])
         assert dev._state == [0.0]
 
-    test_data_single_wire_with_parameters = [
-        (qml.PhaseShift, [1 / math.sqrt(5), 2 / math.sqrt(5)], [math.pi / 4]),
-        (qml.RX, [1 / math.sqrt(5), 2 / math.sqrt(5)], [math.pi / 4]),
-        (qml.RY, [1 / math.sqrt(5), 2 / math.sqrt(5)], [math.pi / 4]),
-        (qml.RZ, [1 / math.sqrt(5), 2 / math.sqrt(5)], [math.pi / 4]),
-        (qml.MultiRZ, [1 / math.sqrt(5), 2 / math.sqrt(5)], [math.pi / 4]),
-        (qml.Rot, [1 / math.sqrt(5), 2 / math.sqrt(5)], [math.pi / 2, math.pi / 4, math.pi / 8]),
-        (
-            qml.QubitUnitary,
-            [1 / math.sqrt(5), 2 / math.sqrt(5)],
-            [
-                np.array(
-                    [
-                        [1j / math.sqrt(2), 1j / math.sqrt(2)],
-                        [1j / math.sqrt(2), -1j / math.sqrt(2)],
-                    ]
-                )
-            ],
-        ),
-        (qml.DiagonalQubitUnitary, [1 / math.sqrt(5), 2 / math.sqrt(5)], [np.array([-1, 1])]),
-    ]
-
     @pytest.mark.parametrize(
         "op",
         [
@@ -317,6 +304,8 @@ class TestVar:
 class TestSample:
     """Tests that samples are properly (not) calculated."""
 
+    # pylint: disable=too-few-public-methods
+
     def test_sample_values(self):
         """Tests if the samples returned by sample have
         the correct values
@@ -688,6 +677,7 @@ class TestTensorExpval:
 
     def test_hermitian_identity_expectation(self, nullqubit_device, theta, phi, varphi):
         """Test that a tensor product involving an Hermitian matrix and the identity works correctly"""
+        # pylint: disable=unused-argument
         dev = nullqubit_device(wires=2)
 
         A = np.array(
@@ -705,6 +695,7 @@ class TestTensorExpval:
 
     def test_hermitian_two_wires_identity_expectation(self, nullqubit_device, theta, phi, varphi):
         """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly"""
+        # pylint: disable=unused-argument
         dev = nullqubit_device(wires=3)
 
         A = np.array(
@@ -842,6 +833,7 @@ class TestTensorVar:
 
     def test_hermitian_identity_expectation(self, nullqubit_device, theta, phi, varphi):
         """Test that a tensor product involving an Hermitian matrix and the identity works correctly"""
+        # pylint: disable=unused-argument
         dev = nullqubit_device(wires=2)
 
         A = np.array(
@@ -859,6 +851,7 @@ class TestTensorVar:
 
     def test_hermitian_two_wires_identity_expectation(self, nullqubit_device, theta, phi, varphi):
         """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly"""
+        # pylint: disable=unused-argument
         dev = nullqubit_device(wires=3)
 
         A = np.array(
@@ -876,7 +869,6 @@ class TestTensorVar:
         assert dev.var(obs) == [0.0]
 
 
-@pytest.mark.parametrize("inverse", [True, False])
 class TestApplyOps:
     """Tests special methods to apply gates in NullQubit."""
 
@@ -902,40 +894,40 @@ class TestApplyOps:
     ]
 
     @pytest.mark.parametrize("method", single_qubit_ops)
-    def test_apply_single_qubit_op(self, method, inverse):
+    def test_apply_single_qubit_op(self, method):
         """Test if the application of single qubit operations is correct."""
-        state_out = method(self.state, axes=[1], inverse=inverse)
+        state_out = method(self.state, axes=[1])
         assert state_out == [0.0]
 
     @pytest.mark.parametrize("method", two_qubit_ops)
-    def test_apply_two_qubit_op(self, method, inverse):
+    def test_apply_two_qubit_op(self, method):
         """Test if the application of two qubit operations is correct."""
         state_out = method(self.state, axes=[0, 1])
         assert state_out == [0.0]
 
     @pytest.mark.parametrize("method", two_qubit_ops)
-    def test_apply_two_qubit_op_reverse(self, method, inverse):
+    def test_apply_two_qubit_op_reverse(self, method):
         """Test if the application of two qubit operations is correct when the applied wires are
         reversed."""
         state_out = method(self.state, axes=[2, 1])
         assert state_out == [0.0]
 
     @pytest.mark.parametrize("method", three_qubit_ops)
-    def test_apply_three_qubit_op_controls_smaller(self, method, inverse):
+    def test_apply_three_qubit_op_controls_smaller(self, method):
         """Test if the application of three qubit operations is correct when both control wires are
         smaller than the target wire."""
         state_out = method(self.state, axes=[0, 2, 3])
         assert state_out == [0.0]
 
     @pytest.mark.parametrize("method", three_qubit_ops)
-    def test_apply_three_qubit_op_controls_greater(self, method, inverse):
+    def test_apply_three_qubit_op_controls_greater(self, method):
         """Test if the application of three qubit operations is correct when both control wires are
         greater than the target wire."""
         state_out = method(self.state, axes=[2, 1, 0])
         assert state_out == [0.0]
 
     @pytest.mark.parametrize("method", three_qubit_ops)
-    def test_apply_three_qubit_op_controls_split(self, method, inverse):
+    def test_apply_three_qubit_op_controls_split(self, method):
         """Test if the application of three qubit operations is correct when one control wire is smaller
         and one control wire is greater than the target wire."""
         state_out = method(self.state, axes=[3, 1, 2])
@@ -946,9 +938,9 @@ class TestApplyOps:
     ]
 
     @pytest.mark.parametrize("method,par", single_qubit_ops_param)
-    def test_apply_single_qubit_op_(self, method, par, inverse):
+    def test_apply_single_qubit_op_param(self, method, par):
         """Test if the application of single qubit operations (with parameter) is correct."""
-        state_out = method(self.state, axes=[1], parameters=par, inverse=inverse)
+        state_out = method(self.state, axes=[1], parameters=par)
         assert state_out == [0.0]
 
 
@@ -1059,6 +1051,7 @@ class TestOpCallIntegration:
         (qml.RZ, [math.pi / 4], {"RZ": 1}),
         (qml.MultiRZ, [math.pi / 2], {"MultiRZ": 1}),
         (qml.DiagonalQubitUnitary, [np.array([-1, 1])], {"DiagonalQubitUnitary": 1}),
+        (qml.SpecialUnitary, [np.array([-1, 1, 0.4])], {"SpecialUnitary": 1}),
     ]
     two_qubit_ops_par = [
         (qml.CRX, [math.pi / 2], {"CRX": 1}),
@@ -1066,6 +1059,7 @@ class TestOpCallIntegration:
         (qml.CRZ, [math.pi / 2], {"CRZ": 1}),
         (qml.MultiRZ, [math.pi / 2], {"MultiRZ": 1}),
         (qml.DiagonalQubitUnitary, [np.array([-1, 1, -1, 1])], {"DiagonalQubitUnitary": 1}),
+        (qml.SpecialUnitary, [np.linspace(0.1, 2, 15)], {"SpecialUnitary": 1}),
         (qml.IsingXX, [math.pi / 2], {"IsingXX": 1}),
         (qml.IsingYY, [math.pi / 2], {"IsingYY": 1}),
         (qml.IsingZZ, [math.pi / 2], {"IsingZZ": 1}),
@@ -1152,7 +1146,9 @@ class TestOpCallIntegration:
 
 
 class TestState:
-    "Unit test for state and density_matrix operations."
+    """Unit test for state and density_matrix operations."""
+
+    # pylint: disable=too-few-public-methods
     dev = qml.device("null.qubit", wires=3)
 
     @pytest.mark.parametrize(
@@ -1181,9 +1177,13 @@ class TestTrackerIntegration:
             return qml.expval(qml.PauliZ(0))
 
         class callback_wrapper:
+            """Callback wrapping class"""
+
+            # pylint: disable=too-few-public-methods
+
             @staticmethod
-            def callback(totals=dict(), history=dict(), latest=dict()):
-                pass
+            def callback(totals=None, history=None, latest=None):
+                """Wrapped callback function."""
 
         wrapper = callback_wrapper()
         spy = mocker.spy(wrapper, "callback")
@@ -1214,6 +1214,7 @@ class TestTrackerIntegration:
 
     def test_shots_execution(self, nullqubit_device, mocker):
         """Test that correct tracks shots."""
+        # pylint: disable=unexpected-keyword-arg
         dev = nullqubit_device(wires=1)
 
         @qml.qnode(dev)
@@ -1221,9 +1222,13 @@ class TestTrackerIntegration:
             return qml.expval(qml.PauliZ(0))
 
         class callback_wrapper:
+            """Callback wrapping class"""
+
+            # pylint: disable=too-few-public-methods
+
             @staticmethod
-            def callback(totals=dict(), history=dict(), latest=dict()):
-                pass
+            def callback(totals=None, history=None, latest=None):
+                """Wrapped callback function."""
 
         wrapper = callback_wrapper()
         spy = mocker.spy(wrapper, "callback")
diff --git a/tests/pulse/test_parametrized_evolution.py b/tests/pulse/test_parametrized_evolution.py
index 90c095a54..a9cadf6c0 100644
--- a/tests/pulse/test_parametrized_evolution.py
+++ b/tests/pulse/test_parametrized_evolution.py
@@ -358,3 +358,34 @@ class TestIntegration:
             jax.grad(circuit2)(params2),
             atol=5e-4,
         )
+
+    def test_mixed_device(
+        self,
+    ):
+        """Test mixed device integration matches that of default qubit"""
+        import jax
+        import jax.numpy as jnp
+
+        mixed = qml.device("default.mixed", wires=range(3))
+        default = qml.device("default.qubit", wires=range(3))
+
+        coeff = [qml.pulse.pwc(5.0), qml.pulse.pwc(5.0)]
+        ops = [qml.PauliX(0) @ qml.PauliX(1), qml.PauliY(1) @ qml.PauliY(2)]
+        H_pulse = qml.dot(coeff, ops)
+
+        def circuit(x):
+            qml.pulse.ParametrizedEvolution(H_pulse, x, 5.0)
+            return qml.expval(qml.PauliZ(0))
+
+        qnode_def = qml.QNode(circuit, default, interface="jax")
+        qnode_mix = qml.QNode(circuit, mixed, interface="jax")
+
+        x = [jnp.arange(3, dtype=float)] * 2
+        res_def = qnode_def(x)
+        grad_def = jax.grad(qnode_def)(x)
+
+        res_mix = qnode_mix(x)
+        grad_mix = jax.grad(qnode_mix)(x)
+
+        assert qml.math.isclose(res_def, res_mix, atol=1e-4)
+        assert qml.math.allclose(grad_def, grad_mix, atol=1e-4)
diff --git a/tests/tests_passing_pylint.txt b/tests/tests_passing_pylint.txt
index 18d8e29be..57d96e44d 100644
--- a/tests/tests_passing_pylint.txt
+++ b/tests/tests_passing_pylint.txt
@@ -43,3 +43,4 @@ tests/devices/test_default_mixed_autograd.py
 tests/devices/test_default_mixed_jax.py
 tests/devices/test_default_mixed_torch.py
 tests/devices/test_default_mixed_tf.py
+tests/devices/test_null_qubit.py