Repository: PennyLaneAI/pennylane
Pull request #3840 (2023-02-28 03:00:34)

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/3840?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
> Merging [#3840](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (44aa99b) into [master](https://codecov.io/gh/PennyLaneAI/pennylane/commit/1a795a0164fe21438e451aae3f92adf7fe5523aa?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (1a795a0) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff           @@
##           master    #3840   +/-   ##
=======================================
  Coverage   99.71%   99.71%           
=======================================
  Files         338      338           
  Lines       29500    29503    +3     
=======================================
+ Hits        29416    29419    +3     
  Misses         84       84           
```


| [Impacted Files](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Coverage Δ | |
|---|---|---|
| [pennylane/\_qubit\_device.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL19xdWJpdF9kZXZpY2UucHk=) | `99.37% <ø> (ø)` | |
| [pennylane/data/dataset.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2RhdGEvZGF0YXNldC5weQ==) | `100.00% <ø> (ø)` | |
| [pennylane/devices/default\_qubit.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2RldmljZXMvZGVmYXVsdF9xdWJpdC5weQ==) | `99.69% <ø> (ø)` | |
| [pennylane/drawer/style.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2RyYXdlci9zdHlsZS5weQ==) | `100.00% <ø> (ø)` | |
| [pennylane/gradients/parameter\_shift.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2dyYWRpZW50cy9wYXJhbWV0ZXJfc2hpZnQucHk=) | `100.00% <ø> (ø)` | |
| [pennylane/math/is\_independent.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL21hdGgvaXNfaW5kZXBlbmRlbnQucHk=) | `100.00% <ø> (ø)` | |
| [pennylane/operation.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL29wZXJhdGlvbi5weQ==) | `97.36% <ø> (ø)` | |
| [pennylane/ops/functions/eigvals.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL29wcy9mdW5jdGlvbnMvZWlndmFscy5weQ==) | `100.00% <ø> (ø)` | |
| [pennylane/ops/op\_math/controlled.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL29wcy9vcF9tYXRoL2NvbnRyb2xsZWQucHk=) | `100.00% <ø> (ø)` | |
| [pennylane/ops/qubit/matrix\_ops.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL29wcy9xdWJpdC9tYXRyaXhfb3BzLnB5) | `100.00% <ø> (ø)` | |
| ... and [12 more](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3840?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | |

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/development/deprecations.rst b/doc/development/deprecations.rst
index b6ee5cd34..b2e77f4f5 100644
--- a/doc/development/deprecations.rst
+++ b/doc/development/deprecations.rst
@@ -15,21 +15,21 @@ Pending deprecations
   instead. Using a list of observables in ``QubitDevice.statistics`` is deprecated. Please use a
   ``QuantumTape`` instead.
 
-  - Still accessible in v0.28
-  - Will be removed in v0.29
+  - Still accessible in v0.28, v0.29
+  - Will be removed in v0.30
 
 * The ``seed_recipes`` argument in ``qml.classical_shadow`` and ``qml.shadow_expval`` is deprecated.
   A new argument ``seed`` has been added, which defaults to ``None`` and can contain an integer with the 
   wanted seed.
 
-  - Still accessible in v0.28
-  - Will be removed in v0.29
+  - Still accessible in v0.28, v0.29
+  - Will be removed in v0.30
 
 * The ``grouping`` module is deprecated. The functionality has been moved and
   reorganized in the new ``pauli`` module under ``pauli/utils.py`` or ``pauli/grouping/``.
 
-  - Still accessible in v0.27, v0.28
-  - Will be removed in v0.29
+  - Still accessible in v0.27, v0.28, v0.29
+  - Will be removed in v0.30
 
   The functions from ``grouping/pauli.py``, ``grouping/transformations.py`` and
   ``grouping/utils.py`` have been moved to ``pauli/utils.py``. The remaining functions
diff --git a/doc/introduction/circuits.rst b/doc/introduction/circuits.rst
index fedbecf77..c8809ff2f 100644
--- a/doc/introduction/circuits.rst
+++ b/doc/introduction/circuits.rst
@@ -95,8 +95,9 @@ the available options that can be passed to the device loader.
 
 .. note::
 
-    For example, check out the ``'lightning.qubit'`` `plugin <https://github.com/PennyLaneAI/pennylane-lightning>`_,
-    which is a fast state-vector simulator supporting GPUs.
+    For example, check out the ``'lightning.gpu'``
+    `plugin <https://docs.pennylane.ai/projects/lightning-gpu/en/latest/index.html>`_,
+    which is a fast state-vector simulator offloading to the NVIDIA cuQuantum SDK for GPU accelerated circuit simulation.
 
 .. note::
 
diff --git a/doc/introduction/interfaces/numpy.rst b/doc/introduction/interfaces/numpy.rst
index 3da07f0b3..e432ac13b 100644
--- a/doc/introduction/interfaces/numpy.rst
+++ b/doc/introduction/interfaces/numpy.rst
@@ -21,7 +21,7 @@ provided by PennyLane alongside with the PennyLane library:
     import pennylane as qml
     from pennylane import numpy as np
 
-This is powered via `autograd <https://github.com/HIPS/autograd>`_, and enables
+This is powered via `Autograd <https://github.com/HIPS/autograd>`_, and enables
 automatic differentiation and backpropagation of classical computations using familiar
 NumPy functions and modules (such as ``np.sin``, ``np.cos``, ``np.exp``, ``np.linalg``,
 ``np.fft``), as well as standard Python constructs, such as ``if`` statements, and ``for``
@@ -289,21 +289,22 @@ the partial derivative of the first/second expectation value with respect to the
 Advanced Autograd usage
 -----------------------
 
-The PennyLane NumPy interface leverages the Python library `autograd
+The PennyLane NumPy interface leverages the Python library `Autograd
 <https://github.com/HIPS/autograd>`_ to enable automatic differentiation of NumPy code, and extends
 it to provide gradients of quantum circuit functions encapsulated in QNodes. In order to make NumPy
 code differentiable, Autograd provides a wrapped version of NumPy (exposed in PennyLane as
 :code:`pennylane.numpy`).
 
-As stated in other sections, using this interface, any hybrid computation should be coded using the
-wrapped version of NumPy provided by PennyLane. **If you accidentally import the vanilla version of
-NumPy, your code will not be automatically differentiable.**
+.. warning::
+    As stated in other sections, using this interface, any hybrid computation should be coded using the
+    wrapped version of NumPy provided by PennyLane. If you accidentally import the vanilla version of
+    NumPy, your code will not be automatically differentiable.
 
-Because of the way autograd wraps NumPy, the PennyLane NumPy interface allows standard NumPy
+Because of the way Autograd wraps NumPy, the PennyLane NumPy interface allows standard NumPy
 functions and basic Python control statements (``if`` statements, loops, etc.) for declaring
 differentiable classical computations.
 
-That being said, autograd's coverage of NumPy is not complete. It is best to consult the `autograd
+That being said, Autograd's coverage of NumPy is not complete. It is best to consult the `Autograd
 docs <https://github.com/HIPS/autograd/blob/master/docs/tutorial.md>`_ for a more complete overview
 of supported and unsupported features. We highlight a few of the major 'gotchas' here.
 
diff --git a/doc/releases/changelog-0.29.0.md b/doc/releases/changelog-0.29.0.md
index 99900a41a..a5c0099d5 100644
--- a/doc/releases/changelog-0.29.0.md
+++ b/doc/releases/changelog-0.29.0.md
@@ -18,21 +18,21 @@
   [(#3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)
   [(#3730)](https://github.com/PennyLaneAI/pennylane/pull/3730)
 
-  A time-dependent Hamiltonian can be created using `qml.ParametrizedHamiltonian`, which 
+  A time-dependent Hamiltonian can be created using `qml.pulse.ParametrizedHamiltonian`, which 
   holds information representing a linear combination of operators
   with parametrized coefficents and can be constructed as follows:
 
-  ```pycon
+  ```python
   from jax import numpy as jnp
-  
+
   f1 = lambda p, t: p * jnp.sin(t) * (t - 1)
   f2 = lambda p, t: p[0] * jnp.cos(p[1]* t ** 2)
 
-  XX = qml.PauliX(1) @ qml.PauliX(1)
-  YY = qml.PauliY(0) @ qml.PauliY(0)
+  XX = qml.PauliX(0) @ qml.PauliX(1)
+  YY = qml.PauliY(0) @ qml.PauliY(1)
   ZZ = qml.PauliZ(0) @ qml.PauliZ(1)
 
-  H =  2 * XX + f1 * YY + f2 * ZZ
+  H =  2 * ZZ + f1 * XX + f2 * YY
   ```
 
   ```pycon
@@ -41,29 +41,29 @@
   >>> p1 = jnp.array(1.2)
   >>> p2 = jnp.array([2.3, 3.4])
   >>> H((p1, p2), t=0.5)
-  (2*(PauliX(wires=[1]) @ PauliX(wires=[1]))) + ((-0.2876553535461426*(PauliY(wires=[0]) @ PauliY(wires=[0]))) + (1.5179612636566162*(PauliZ(wires=[0]) @ PauliZ(wires=[1]))))
+  (2*(PauliZ(wires=[0]) @ PauliZ(wires=[1]))) + ((-0.2876553231625218*(PauliX(wires=[0]) @ PauliX(wires=[1]))) + (1.517961235535459*(PauliY(wires=[0]) @ PauliY(wires=[1]))))
   ```
 
   The time-dependent Hamiltonian can be used within a circuit with `qml.evolve`:
 
   ```python
   def pulse_circuit(params, time):
-      qml.Hadamard(0)
       qml.evolve(H)(params, time)
-      return qml.expval(qml.PauliX(0) @ qml.PauliZ(1))
+      return qml.expval(qml.PauliX(0) @ qml.PauliY(1))
   ```
 
-  Pulse-based circuits can be executed on the `default.qubit` simulator using JAX as an interface:
+  Pulse-based circuits can be executed and differentiated on the `default.qubit` simulator using JAX
+  as an interface:
 
   ```pycon
-  >>> dev = dev = qml.device("default.qubit", wires=2)
+  >>> dev = qml.device("default.qubit", wires=2)
   >>> qnode = qml.QNode(pulse_circuit, dev, interface="jax")
   >>> params = (p1, p2)
   >>> qnode(params, time=0.5)
-  Array(-0.5441851, dtype=float32)
+  Array(0.72153819, dtype=float64)
   >>> jax.grad(qnode)(params, time=0.5)
-  [Array(-0.0096471, dtype=float32),
-   Array([-0.7750168 ,  0.07650781], dtype=float32)]
+  (Array(-0.11324919, dtype=float64),
+   Array([-0.64399616,  0.06326374], dtype=float64))
   ```
 
   Check out the [qml.pulse](https://docs.pennylane.ai/en/stable/code/qml_pulse.html) documentation
@@ -111,7 +111,10 @@
   ```
 
   This operation can be differentiated with hardware-compatible methods like parameter shifts
-  and it supports parameter broadcasting/batching, but not both at the same time.
+  and it supports parameter broadcasting/batching, but not both at the same time. Learn more by
+  visiting the
+  [qml.SpecialUnitary](https://docs.pennylane.ai/en/stable/code/api/pennylane.SpecialUnitary.html)
+  documentation.
 
 <h4>Always differentiable 📈</h4>
 
@@ -143,7 +146,7 @@
   autodifferentiation:
 
   ```pycon
-  >>> dev = qml.device("default.qubit", wires=3)
+  >>> dev = qml.device("default.qubit", wires=2)
   >>> @qml.qnode(dev, interface="jax", diff_method="hadamard")
   ... def circuit(params):
   ...     qml.RX(params[0], wires=0)
@@ -163,11 +166,10 @@
   as differentiable with SPSA. It can be selected via
 
   ```pycon
-  >>> dev = qml.device("default.qubit", wires=2)
+  >>> dev = qml.device("default.qubit", wires=1)
   >>> @qml.qnode(dev, interface="jax", diff_method="spsa", h=0.05, num_directions=20)
   ... def circuit(x):
   ...     qml.RX(x, 0)
-  ...     qml.RX(x, 1)
   ...     return qml.expval(qml.PauliZ(0))
   >>> jax.jacobian(circuit)(jax.numpy.array(0.5))
   Array(-0.4792258, dtype=float32, weak_type=True)
@@ -278,11 +280,10 @@
   ```
 
 * The kernel matrix utility functions in `qml.kernels` are now autodifferentiation-compatible.
-  In addition they support batching, for example for quantum kernel execution with shot vectors.
+  In addition, they support batching, for example for quantum kernel execution with shot vectors.
   [(#3742)](https://github.com/PennyLaneAI/pennylane/pull/3742)
 
-  In addition to the autodifferentiation support in JAX, Autograd, Tensorflow and PyTorch,
-  optional batching was added, allowing for the following:
+  This allows for the following:
   
   ```python
   dev = qml.device('default.qubit', wires=2, shots=(100, 100))
@@ -295,8 +296,6 @@
   kernel = lambda x1, x2: circuit(x1, x2)
   ```
 
-  Note that we extract the first probability vector entry for both
-  evaluations using 100 shots each.
   We can then compute the kernel matrix on a set of 4 (random) feature
   vectors `X` but using two sets of 100 shots each via
 
@@ -313,6 +312,8 @@
            [0.92, 1.  , 0.91, 1.  ]]], requires_grad=True)
   ```
 
+  Note that we have extracted the first probability vector entry for each 100-shot evaluation.
+
 <h4>Smartly decompose Hamiltonian evolution 💯</h4>
 
 * Hamiltonian evolution using `qml.evolve` or `qml.exp` can now be decomposed into operations.
@@ -408,11 +409,11 @@
           [-0.   +0.j   , -0.   +0.j   , -0.   +0.j   , -0.438+0.899j]], requires_grad=True)
   ```
 
-* A new function called `qml.load_basisset` has been added to extract `qml.qchem` basis set data from the Basis Set Exchange
+* A new function called `qml.qchem.load_basisset` has been added to extract `qml.qchem` basis set data from the Basis Set Exchange
   library.
   [(#3363)](https://github.com/PennyLaneAI/pennylane/pull/3363)
 
-* A new function called `qml.max_entropy` has been added to compute the maximum entropy of a quantum state.
+* A new function called `qml.math.max_entropy` has been added to compute the maximum entropy of a quantum state.
   [(#3594)](https://github.com/PennyLaneAI/pennylane/pull/3594)
 
 * A new template called `qml.TwoLocalSwapNetwork` has been added that implements a canonical 2-complete linear (2-CCL) swap network
@@ -442,11 +443,11 @@
   4: ─────────────────╰RY(0.81)─╰SWAP─────────────────╰RY(0.06)─╰SWAP─────────────────┤  State
   ```
 
-<h3>Improvements</h3>
+<h3>Improvements 🛠</h3>
 
 <h4>Pulse programming</h4>
 
-* A new function called `qml.pwc` has been added as a convenience function for defining a `qml.ParametrizedHamiltonian`.
+* A new function called `qml.pulse.pwc` has been added as a convenience function for defining a `qml.pulse.ParametrizedHamiltonian`.
   This function can be used to create a callable coefficient by setting
   the timespan over which the function should be non-zero. The resulting callable
   can be passed an array of parameters and a time.
@@ -469,7 +470,8 @@
   DeviceArray(0., dtype=float32)
   ```
 
-* A new function called`qml.pwc_from_function` as a decorator for defining a `qml.ParametrizedHamiltonian`.
+* A new function called`qml.pulse.pwc_from_function` has been added as a decorator for defining a
+  `qml.pulse.ParametrizedHamiltonian`.
   This function can be used to decorate a function and create a piecewise constant
   approximation of it.
   [(#3645)](https://github.com/PennyLaneAI/pennylane/pull/3645)
@@ -501,7 +503,7 @@
 
 <h4>Operations and batching</h4>
 
-* A new function called `qml.dot` has been added to compute the dot product between a vector and a list of operators.
+* The function `qml.dot` has been updated to compute the dot product between a vector and a list of operators.
   [(#3586)](https://github.com/PennyLaneAI/pennylane/pull/3586)
 
   ```pycon
@@ -538,10 +540,10 @@
   removal of in-place inversion.
   [(#3566)](https://github.com/PennyLaneAI/pennylane/pull/3566)
 
-* The `qml.utils.sparse_hamiltonian` function has been moved to thee `~.Hamiltonian.sparse_matrix` method.
+* The `qml.utils.sparse_hamiltonian` function has been moved to thee `qml.Hamiltonian.sparse_matrix` method.
   [(#3585)](https://github.com/PennyLaneAI/pennylane/pull/3585)
 
-* The `qml.PauliSentence.operation()` method has been improved to avoid instantiating an `SProd` operator when
+* The `qml.pauli.PauliSentence.operation()` method has been improved to avoid instantiating an `SProd` operator when
   the coefficient is equal to 1.
   [(#3595)](https://github.com/PennyLaneAI/pennylane/pull/3595)
 
@@ -606,12 +608,9 @@
 * The `Sum._sort` method now takes into account the name of the operator when sorting.
   [(#3691)](https://github.com/PennyLaneAI/pennylane/pull/3691)
 
-* A new tape transform called 'qml.sign_expand' has been added. It 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](https://arxiv.org/abs/2207.09479).
+* A new tape transform called `qml.transforms.sign_expand` has been added. It 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](https://arxiv.org/abs/2207.09479).
   [(#2852)](https://github.com/PennyLaneAI/pennylane/pull/2852)
 
-* `Sum` and `Prod` operations now support broadcasted operands.
-  [(#3611)](https://github.com/PennyLaneAI/pennylane/pull/3611)
-
 <h4>Differentiability and interfaces</h4>
 
 * The `qml.math` module now also contains a submodule for
@@ -661,18 +660,13 @@
 * `qml.QuantumMonteCarlo` template is now JAX-JIT compatible when passing `jax.numpy` arrays to the template.
   [(#3734)](https://github.com/PennyLaneAI/pennylane/pull/3734)
 
-* `DefaultQubitJax` now supports evolving the state vector when executing `qml.ParametrizedEvolution`
+* `DefaultQubitJax` now supports evolving the state vector when executing `qml.pulse.ParametrizedEvolution`
   gates.
   [(#3743)](https://github.com/PennyLaneAI/pennylane/pull/3743)
 
 * `SProd.sparse_matrix` now supports interface-specific variables with a single element as the `scalar`.
   [(#3770)](https://github.com/PennyLaneAI/pennylane/pull/3770)
 
-* Validation has been added on gradient keyword arguments when initializing a QNode — if unexpected keyword arguments are passed,
-  a `UserWarning` is raised. A list of the current expected gradient function keyword arguments can be accessed via
-  `qml.gradients.SUPPORTED_GRADIENT_KWARGS`.
-  [(#3526)](https://github.com/PennyLaneAI/pennylane/pull/3526)
-
 * Added `argnum` argument to `metric_tensor`. By passing a sequence of indices referring to trainable tape parameters,
   the metric tensor is only computed with respect to these parameters. This reduces the number of tapes that have to
   be run.
@@ -697,7 +691,7 @@
 
 * The `simulate` function is added to `devices/qubit` that turns a single quantum tape into a measurement result.
   The function only supports state based measurements with either no observables or observables with diagonalizing gates.
-  It supports simultanous measurement of non-commuting observables.
+  It supports simultaneous measurement of non-commuting observables.
   [(#3700)](https://github.com/PennyLaneAI/pennylane/pull/3700)
 
 * The `ExecutionConfig` data class has been added.
@@ -712,30 +706,18 @@
 * `qml.BasisState` now implements the `StatePrep` interface.
   [(#3693)](https://github.com/PennyLaneAI/pennylane/pull/3693)
 
-* `qml.QubitStateVector` now implements the `StatePrep` interface.
-  [(#3685)](https://github.com/PennyLaneAI/pennylane/pull/3685)
-
-* `qml.BasisState` now implements the `StatePrep` interface.
-  [(#3693)](https://github.com/PennyLaneAI/pennylane/pull/3693)
-
 * New Abstract Base Class for devices `Device` is added to the `devices.experimental` submodule.
   This interface is still in experimental mode and not integrated with the rest of pennylane.
   [(#3602)](https://github.com/PennyLaneAI/pennylane/pull/3602)
 
-* The `apply_operation` single-dispatch function is added to `devices/qubit` that applies an operation
-  to a state and returns a new state.
-  [(#3637)](https://github.com/PennyLaneAI/pennylane/pull/3637)
-
-<h4>Data</h4>
+<h4>Other improvements</h4>
 
 * Writing Hamiltonians to a file using the `qml.data` module has been improved by employing a condensed writing format.
   [(#3592)](https://github.com/PennyLaneAI/pennylane/pull/3592)
 
-* Lazy-loading in the `qml.Dataset.read()` method is more universally supported.
+* Lazy-loading in the `qml.data.Dataset.read()` method is more universally supported.
   [(#3605)](https://github.com/PennyLaneAI/pennylane/pull/3605)
 
-<h4>Other</h4>
-
 * The `qchem.Molecule` class raises an error when the molecule has an odd number of electrons or
   when the spin multiplicity is not 1.
   [(#3748)](https://github.com/PennyLaneAI/pennylane/pull/3748)
@@ -748,7 +730,7 @@
   property if it is set.
   [(#3820)](https://github.com/PennyLaneAI/pennylane/pull/3820)
 
-<h3>Breaking changes</h3>
+<h3>Breaking changes 💔</h3>
 
 * The argument `mode` in execution has been replaced by the boolean `grad_on_execution` in the new execution pipeline.
   [(#3723)](https://github.com/PennyLaneAI/pennylane/pull/3723)
@@ -764,7 +746,7 @@
   The interface is determined during the QNode call instead of the
   initialization. It means that the `gradient_fn` and `gradient_kwargs` are only defined on the QNode at the beginning
   of the call. Moreover, without specifying the interface it is not possible to guarantee that the device will not be changed
-  during the call if you are using backprop (such as `default.qubit` changing to `default.qubit,jax`) whereas before it was happening at
+  during the call if you are using backprop (such as `default.qubit` changing to `default.qubit.jax`) whereas before it was happening at
   initialization.
 
 * The tape method `get_operation` can also now return the operation index in the tape, and it can be
@@ -802,7 +784,7 @@
   [(#3282)](https://github.com/PennyLaneAI/pennylane/pull/3282)
 
 * `qml.qchem.scf`, `qml.RandomLayers.compute_decomposition`, and `qml.Wires.select_random` now use
-  local random number generators instead of global random number generators. This may lead to slighlty
+  local random number generators instead of global random number generators. This may lead to slightly
   different random numbers and an independence of the results from the global random number generation state.
   Please provide a seed to each individual function instead if you want controllable results.
   [(#3624)](https://github.com/PennyLaneAI/pennylane/pull/3624)
@@ -825,10 +807,10 @@
   a wire order such as `marginal_prob`, `estimate_probability` or `analytic_probability`).
   [(#3753)](https://github.com/PennyLaneAI/pennylane/pull/3753)
 
-<h3>Deprecations</h3>
+<h3>Deprecations 👋</h3>
 
 * `qml.utils.sparse_hamiltonian` function has been deprecated, and usage will now raise a warning.
-  Instead, one should use the `~.Hamiltonian.sparse_matrix` method.
+  Instead, one should use the `qml.Hamiltonian.sparse_matrix` method.
   [(#3585)](https://github.com/PennyLaneAI/pennylane/pull/3585)
 
 * The `collections` module has been deprecated.
@@ -842,7 +824,16 @@
   This new function changes the sign of the given parameter.
   [(#3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)
 
-<h3>Documentation</h3>
+* Use of `qml.dot` with a `QNodeCollection` has been deprecated.
+  [(#3586)](https://github.com/PennyLaneAI/pennylane/pull/3586)
+
+<h3>Documentation 📝</h3>
+
+* Revise note on GPU support in the [circuit introduction](https://docs.pennylane.ai/en/stable/introduction/circuits.html#defining-a-device).
+[(#3836)](https://github.com/PennyLaneAI/pennylane/pull/3836)
+
+* Make warning about vanilla version of NumPy for differentiation more prominent.
+  [(#3838)](https://github.com/PennyLaneAI/pennylane/pull/3838)
 
 * The documentation for `qml.operation` has been improved.
   [(#3664)](https://github.com/PennyLaneAI/pennylane/pull/3664)
@@ -853,10 +844,14 @@
 * A hyperlink has been added in the text for a URL in the `qml.qchem.mol_data` docstring.
   [(#3644)](https://github.com/PennyLaneAI/pennylane/pull/3644)
 
-* A typo was corrected in the documentation for `qml.math.vn_entropy()`.
+* A typo was corrected in the documentation for `qml.math.vn_entropy`.
 [(#3740)](https://github.com/PennyLaneAI/pennylane/pull/3740)
 
-<h3>Bug fixes</h3>
+<h3>Bug fixes 🐛</h3>
+
+* Fixed a bug where measuring ``qml.probs`` in the computational basis with non-commuting
+  measurements returned incorrect results. Now an error is raised.
+  [(#3811)](https://github.com/PennyLaneAI/pennylane/pull/3811)
 
 * Fixed a bug where measuring ``qml.probs`` in the computational basis with non-commuting
   measurements returned incorrect results. Now an error is raised.
@@ -889,7 +884,7 @@
 * A typo has been fixed in the calculation and error messages in `operation.py`
   [(#3536)](https://github.com/PennyLaneAI/pennylane/pull/3536)
 
-* `qml.Dataset.write()` now ensures that any lazy-loaded values are loaded before they are written to a file.
+* `qml.data.Dataset.write()` now ensures that any lazy-loaded values are loaded before they are written to a file.
   [(#3605)](https://github.com/PennyLaneAI/pennylane/pull/3605)
 
 * `Tensor._batch_size` is now set to `None` during initialization, copying and `map_wires`.
@@ -937,7 +932,7 @@
 * Only converts input to `qml.Hermitian` to a numpy array if the input is a list.
   [(#3820)](https://github.com/PennyLaneAI/pennylane/pull/3820)
 
-<h3>Contributors</h3>
+<h3>Contributors ✍</h3>
 
 This release contains contributions from (in alphabetical order):
 
diff --git a/pennylane/_qubit_device.py b/pennylane/_qubit_device.py
index a3609f306..a1dd255b8 100644
--- a/pennylane/_qubit_device.py
+++ b/pennylane/_qubit_device.py
@@ -760,8 +760,8 @@ class QubitDevice(Device):
             elif obs.return_type is State:
                 if len(measurements) > 1:
                     raise qml.QuantumFunctionError(
-                        "The state or density matrix cannot be returned in combination"
-                        " with other return types"
+                        "The state or density matrix cannot be returned in combination "
+                        "with other return types"
                     )
 
                 if self.shots is not None:
@@ -824,16 +824,16 @@ class QubitDevice(Device):
             elif obs.return_type is Shadow:
                 if len(measurements) > 1:
                     raise qml.QuantumFunctionError(
-                        "Classical shadows cannot be returned in combination"
-                        " with other return types"
+                        "Classical shadows cannot be returned in combination "
+                        "with other return types"
                     )
                 results.append(self.classical_shadow(obs, circuit))
 
             elif obs.return_type is ShadowExpval:
                 if len(measurements) > 1:
                     raise qml.QuantumFunctionError(
-                        "Classical shadows cannot be returned in combination"
-                        " with other return types"
+                        "Classical shadows cannot be returned in combination "
+                        "with other return types"
                     )
                 results.append(self.shadow_expval(obs, circuit=circuit))
 
@@ -976,8 +976,8 @@ class QubitDevice(Device):
             elif isinstance(m, StateMP):
                 if len(measurements) > 1:
                     raise qml.QuantumFunctionError(
-                        "The state or density matrix cannot be returned in combination"
-                        " with other return types"
+                        "The state or density matrix cannot be returned in combination "
+                        "with other return types"
                     )
 
                 if self.shots is not None:
@@ -1039,16 +1039,16 @@ class QubitDevice(Device):
             elif isinstance(m, ClassicalShadowMP):
                 if len(measurements) > 1:
                     raise qml.QuantumFunctionError(
-                        "Classical shadows cannot be returned in combination"
-                        " with other return types"
+                        "Classical shadows cannot be returned in combination "
+                        "with other return types"
                     )
                 result = self.classical_shadow(obs, circuit)
 
             elif isinstance(m, ShadowExpvalMP):
                 if len(measurements) > 1:
                     raise qml.QuantumFunctionError(
-                        "Classical shadows cannot be returned in combination"
-                        " with other return types"
+                        "Classical shadows cannot be returned in combination "
+                        "with other return types"
                     )
                 result = self.shadow_expval(obs, circuit=circuit)
 
@@ -1907,8 +1907,8 @@ class QubitDevice(Device):
 
         if self.shots is not None:
             warnings.warn(
-                "Requested adjoint differentiation to be computed with finite shots."
-                " The derivative is always exact when using the adjoint differentiation method.",
+                "Requested adjoint differentiation to be computed with finite shots. "
+                "The derivative is always exact when using the adjoint differentiation method.",
                 UserWarning,
             )
 
diff --git a/pennylane/data/dataset.py b/pennylane/data/dataset.py
index e2c21b338..44d1af67d 100644
--- a/pennylane/data/dataset.py
+++ b/pennylane/data/dataset.py
@@ -32,7 +32,7 @@ def _import_zstd_dill():
         import zstd, dill
     except ImportError as Error:
         raise ImportError(
-            "This feature requires zstd and dill."
+            "This feature requires zstd and dill. "
             "They can be installed with:\n\n pip install zstd dill."
         ) from Error
 
diff --git a/pennylane/devices/default_qubit.py b/pennylane/devices/default_qubit.py
index 3760f8a34..2d3fd6a0f 100644
--- a/pennylane/devices/default_qubit.py
+++ b/pennylane/devices/default_qubit.py
@@ -286,8 +286,8 @@ class DefaultQubit(QubitDevice):
             operation (ParametrizedEvolution): operation to apply on the state
         """
         raise NotImplementedError(
-            f"The device {self.short_name} cannot execute a ParametrizedEvolution operation."
-            "Please use the jax  interface."
+            f"The device {self.short_name} cannot execute a ParametrizedEvolution operation. "
+            "Please use the jax interface."
         )
 
     def _apply_operation(self, state, operation):
diff --git a/pennylane/devices/default_qubit_jax.py b/pennylane/devices/default_qubit_jax.py
index 3c1921385..fa663022c 100644
--- a/pennylane/devices/default_qubit_jax.py
+++ b/pennylane/devices/default_qubit_jax.py
@@ -11,7 +11,7 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-"""This module contains an jax implementation of the :class:`~.DefaultQubit`
+"""This module contains a jax implementation of the :class:`~.DefaultQubit`
 reference plugin.
 """
 # pylint: disable=ungrouped-imports
@@ -30,11 +30,25 @@ try:
 
     from pennylane.pulse.parametrized_hamiltonian_pytree import ParametrizedHamiltonianPytree
 
-
 except ImportError as e:  # pragma: no cover
     raise ImportError("default.qubit.jax device requires installing jax>0.3.20") from e
 
 
+def _validate_jax_version():
+    if jax.__version__ == "0.4.4":
+        raise RuntimeError(
+            "\nYour installed version of JAX is 0.4.4 but Pennylane is incompatible with it.\n\n"
+            "You can either downgrade JAX to version 0.4.3 or update to a more recent version if available.\n"
+            "If you downgrade, you will also need to downgrade JAXLIB to version 0.4.3 or earlier.\n"
+            "If you are using pip to manage your packages, you can run the following command:\n\n"
+            "\tpip install 'jax==0.4.3' 'jaxlib==0.4.3'\n\n"
+            "If you are using conda to manage your packages, you can run the following command:\n\n"
+            "\tconda install 'jax==0.4.3' 'jaxlib==0.4.3'\n\n"
+            "If you still have problems, please open an issue at the following link:\n\n"
+            "\thttps://github.com/PennyLaneAI/pennylane/issues\n"
+        )
+
+
 class DefaultQubitJax(DefaultQubit):
     """Simulator plugin based on ``"default.qubit"``, written using jax.
 
@@ -119,7 +133,7 @@ class DefaultQubitJax(DefaultQubit):
             a = keyed_circuit(key1)
             b = keyed_circuit(key2) # b will be different samples now.
 
-        Check out out the `JAX random documentation <https://jax.readthedocs.io/en/latest/jax.random.html>`__
+        Check out the `JAX random documentation <https://jax.readthedocs.io/en/latest/jax.random.html>`__
         for more information.
 
     Args:
@@ -136,6 +150,8 @@ class DefaultQubitJax(DefaultQubit):
 
     """
 
+    _validate_jax_version()
+
     name = "Default qubit (jax) PennyLane plugin"
     short_name = "default.qubit.jax"
 
@@ -163,6 +179,8 @@ class DefaultQubitJax(DefaultQubit):
     _ndim = staticmethod(jnp.ndim)
 
     def __init__(self, wires, *, shots=None, prng_key=None, analytic=None):
+        _validate_jax_version()
+
         if jax_config.read("jax_enable_x64"):
             c_dtype = jnp.complex128
             r_dtype = jnp.float64
diff --git a/pennylane/drawer/style.py b/pennylane/drawer/style.py
index 80dfca628..3102a19df 100644
--- a/pennylane/drawer/style.py
+++ b/pennylane/drawer/style.py
@@ -37,7 +37,7 @@ def _needs_mpl(func):
     def wrapper():
         if not _has_mpl:  # pragma: no cover
             raise ImportError(
-                "The drawer style module requires matplotlib."
+                "The drawer style module requires matplotlib. "
                 "You can install matplotlib via \n\n   pip install matplotlib"
             )
         func()
diff --git a/pennylane/gradients/hadamard_gradient.py b/pennylane/gradients/hadamard_gradient.py
index fd31f219f..8c04e94c9 100644
--- a/pennylane/gradients/hadamard_gradient.py
+++ b/pennylane/gradients/hadamard_gradient.py
@@ -354,7 +354,7 @@ def _expval_hadamard_grad(tape, argnum, aux_wire):
             else:
                 axis = None if not multi_measurements else 0
                 grads.append(qml.math.sum(final_res[idx : idx + num_tape], axis=axis))
-                idx += 1
+                idx += num_tape
 
         if not multi_measurements and not multi_params:
             return grads[0]
diff --git a/pennylane/gradients/parameter_shift.py b/pennylane/gradients/parameter_shift.py
index 0f34169ca..c0ef0dc4f 100644
--- a/pennylane/gradients/parameter_shift.py
+++ b/pennylane/gradients/parameter_shift.py
@@ -1598,11 +1598,11 @@ def _param_shift_new(
             res = fn(results)
         except (ValueError, TypeError) as e:
             raise e.__class__(
-                "The processing function of the gradient transform ran into errors"
-                " while the new return type system was turned on. Make sure to"
-                " pass the device shots to the param_shift gradient transform"
-                " using the shots argument or disable the new return type"
-                " system by calling the qml.disable_return function."
+                "The processing function of the gradient transform ran into errors "
+                "while the new return type system was turned on. Make sure to "
+                "pass the device shots to the param_shift gradient transform "
+                "using the shots argument or disable the new return type "
+                "system by calling the qml.disable_return function."
             ) from e
         return res
 
diff --git a/pennylane/math/is_independent.py b/pennylane/math/is_independent.py
index 499f0bf53..0a18d2af2 100644
--- a/pennylane/math/is_independent.py
+++ b/pennylane/math/is_independent.py
@@ -373,9 +373,9 @@ def is_independent(
 
     if interface == "torch":
         warnings.warn(
-            "The function is_independent is only available numerically for the PyTorch interface."
-            " Make sure that sampling positions and evaluating the function at these positions"
-            " is a sufficient test, or change the interface."
+            "The function is_independent is only available numerically for the PyTorch interface. "
+            "Make sure that sampling positions and evaluating the function at these positions "
+            "is a sufficient test, or change the interface."
         )
 
     return _is_indep_numerical(func, interface, args, kwargs, num_pos, seed, atol, rtol, bounds)
diff --git a/pennylane/operation.py b/pennylane/operation.py
index 7aee02cdf..0cfeed70f 100644
--- a/pennylane/operation.py
+++ b/pennylane/operation.py
@@ -1919,8 +1919,8 @@ class Tensor(Observable):
         if base_label is not None:
             if len(base_label) != len(self.obs):
                 raise ValueError(
-                    "Tensor label requires ``base_label`` keyword to be same length"
-                    " as tensor components."
+                    "Tensor label requires ``base_label`` keyword to be same length "
+                    "as tensor components."
                 )
             return "@".join(
                 ob.label(decimals=decimals, base_label=lbl) for ob, lbl in zip(self.obs, base_label)
diff --git a/pennylane/ops/functions/eigvals.py b/pennylane/ops/functions/eigvals.py
index 690fdb1b4..fbd002af9 100644
--- a/pennylane/ops/functions/eigvals.py
+++ b/pennylane/ops/functions/eigvals.py
@@ -107,7 +107,7 @@ def eigvals(op, k=1, which="SA"):
     if isinstance(op, qml.Hamiltonian):
         warnings.warn(
             "For Hamiltonians, the eigenvalues will be computed numerically. "
-            "This may be computationally intensive for a large number of wires."
+            "This may be computationally intensive for a large number of wires. "
             "Consider using a sparse representation of the Hamiltonian with qml.SparseHamiltonian.",
             UserWarning,
         )
diff --git a/pennylane/ops/op_math/controlled.py b/pennylane/ops/op_math/controlled.py
index ba9188a27..45c1dbaf4 100644
--- a/pennylane/ops/op_math/controlled.py
+++ b/pennylane/ops/op_math/controlled.py
@@ -635,6 +635,6 @@ class ControlledOp(Controlled, operation.Operation):
             return [qml.gradients.eigvals_to_frequencies(processed_gen_eigvals)]
         raise operation.ParameterFrequenciesUndefinedError(
             f"Operation {self.name} does not have parameter frequencies defined, "
-            "and parameter frequencies can not be computed via generator for more than one"
+            "and parameter frequencies can not be computed via generator for more than one "
             "parameter."
         )
diff --git a/pennylane/ops/qubit/matrix_ops.py b/pennylane/ops/qubit/matrix_ops.py
index 1bf0dcae5..a8e9de3c4 100644
--- a/pennylane/ops/qubit/matrix_ops.py
+++ b/pennylane/ops/qubit/matrix_ops.py
@@ -100,7 +100,7 @@ class QubitUnitary(Operation):
             )
         ):
             warnings.warn(
-                f"Operator {U}\n may not be unitary."
+                f"Operator {U}\n may not be unitary. "
                 "Verify unitarity of operation, or use a datatype with increased precision.",
                 UserWarning,
             )
diff --git a/pennylane/ops/qubit/parametric_ops.py b/pennylane/ops/qubit/parametric_ops.py
index eb98a8184..fc42471a5 100644
--- a/pennylane/ops/qubit/parametric_ops.py
+++ b/pennylane/ops/qubit/parametric_ops.py
@@ -1674,8 +1674,8 @@ class PauliRot(Operation):
 
         if not PauliRot._check_pauli_word(pauli_word):
             raise ValueError(
-                f'The given Pauli word "{pauli_word}" contains characters that are not allowed.'
-                " Allowed characters are I, X, Y and Z"
+                f'The given Pauli word "{pauli_word}" contains characters that are not allowed. '
+                "Allowed characters are I, X, Y and Z"
             )
 
         num_wires = 1 if isinstance(wires, int) else len(wires)
@@ -1760,8 +1760,8 @@ class PauliRot(Operation):
         """
         if not PauliRot._check_pauli_word(pauli_word):
             raise ValueError(
-                f'The given Pauli word "{pauli_word}" contains characters that are not allowed.'
-                " Allowed characters are I, X, Y and Z"
+                f'The given Pauli word "{pauli_word}" contains characters that are not allowed. '
+                "Allowed characters are I, X, Y and Z"
             )
 
         interface = qml.math.get_interface(theta)
diff --git a/pennylane/ops/qutrit/matrix_ops.py b/pennylane/ops/qutrit/matrix_ops.py
index f9592fac4..0b24f4a92 100644
--- a/pennylane/ops/qutrit/matrix_ops.py
+++ b/pennylane/ops/qutrit/matrix_ops.py
@@ -88,7 +88,7 @@ class QutritUnitary(Operation):
                 )
             ):
                 warnings.warn(
-                    f"Operator {U}\n may not be unitary."
+                    f"Operator {U}\n may not be unitary. "
                     "Verify unitarity of operation, or use a datatype with increased precision.",
                     UserWarning,
                 )
diff --git a/pennylane/qchem/convert.py b/pennylane/qchem/convert.py
index 758611989..b90ec396c 100644
--- a/pennylane/qchem/convert.py
+++ b/pennylane/qchem/convert.py
@@ -209,8 +209,8 @@ def _pennylane_to_openfermion(coeffs, ops, wires=None):
         import openfermion
     except ImportError as Error:
         raise ImportError(
-            "This feature requires openfermion."
-            " It can be installed with: pip install openfermion"
+            "This feature requires openfermion. "
+            "It can be installed with: pip install openfermion"
         ) from Error
 
     all_wires = Wires.all_wires([op.wires for op in ops], sort=True)
diff --git a/pennylane/qchem/molecule.py b/pennylane/qchem/molecule.py
index 3005e539e..6313bde53 100644
--- a/pennylane/qchem/molecule.py
+++ b/pennylane/qchem/molecule.py
@@ -81,9 +81,9 @@ class Molecule:
             "cc-pvdz",
         ]:
             raise ValueError(
-                "Currently, the only supported basis sets are 'sto-3g', '6-31g', '6-311g' and"
-                " 'cc-pvdz'. Please consider using `load_data=True` to download the basis set from"
-                " an external library that can be installed with: pip install basis-set-exchange."
+                "Currently, the only supported basis sets are 'sto-3g', '6-31g', '6-311g' and "
+                "'cc-pvdz'. Please consider using `load_data=True` to download the basis set from "
+                "an external library that can be installed with: pip install basis-set-exchange."
             )
 
         if set(symbols) - set(atomic_numbers):
@@ -103,8 +103,8 @@ class Molecule:
 
         if self.n_electrons % 2 == 1 or self.mult != 1:
             raise ValueError(
-                "Openshell systems are not supported. Change the charge or spin"
-                " multiplicity of the molecule."
+                "Openshell systems are not supported. Change the charge or spin "
+                "multiplicity of the molecule."
             )
 
         if l is None:
diff --git a/pennylane/qnode.py b/pennylane/qnode.py
index 6ccbf998d..01756b134 100644
--- a/pennylane/qnode.py
+++ b/pennylane/qnode.py
@@ -702,8 +702,8 @@ class QNode:
 
         if device.shots is not None:
             warnings.warn(
-                "Requested adjoint differentiation to be computed with finite shots."
-                " Adjoint differentiation always calculated exactly.",
+                "Requested adjoint differentiation to be computed with finite shots. "
+                "Adjoint differentiation always calculated exactly.",
                 UserWarning,
             )
         return "device", {"use_device_state": True, "method": "adjoint_jacobian"}, device
@@ -788,8 +788,8 @@ class QNode:
             # pylint: disable=no-member
             if isinstance(obj, qml.ops.qubit.SparseHamiltonian) and self.gradient_fn == "backprop":
                 raise qml.QuantumFunctionError(
-                    "SparseHamiltonian observable must be used with the parameter-shift"
-                    " differentiation method"
+                    "SparseHamiltonian observable must be used with the parameter-shift "
+                    "differentiation method"
                 )
 
         # Apply the deferred measurement principle if the device doesn't
@@ -819,11 +819,7 @@ class QNode:
 
         if old_interface == "auto":
             self.interface = qml.math.get_interface(*args, *list(kwargs.values()))
-            if self.device is not self._original_device:
-                warnings.warn(
-                    "The device was switched during the call of the QNode, to avoid this behaviour define "
-                    "an interface argument instead of auto."
-                )
+            self.device.tracker = self._original_device.tracker
 
         if not self._qfunc_uses_shots_arg:
             # If shots specified in call but not in qfunc signature,
diff --git a/pennylane/tape/qscript.py b/pennylane/tape/qscript.py
index a5d3f08e8..51f8b8baf 100644
--- a/pennylane/tape/qscript.py
+++ b/pennylane/tape/qscript.py
@@ -567,7 +567,7 @@ class QuantumScript:
         if return_op_index:
             return self._get_operation(idx)
         warnings.warn(
-            "The get_operation will soon be updated to also return the index of the trainable operation in the tape."
+            "The get_operation will soon be updated to also return the index of the trainable operation in the tape. "
             "If you want to switch to the new behavior, you can pass `return_op_index=True`"
         )
 
diff --git a/pennylane/templates/embeddings/amplitude.py b/pennylane/templates/embeddings/amplitude.py
index f3595510b..cbf19ea8a 100644
--- a/pennylane/templates/embeddings/amplitude.py
+++ b/pennylane/templates/embeddings/amplitude.py
@@ -225,7 +225,7 @@ class AmplitudeEmbedding(Operation):
                     feature_set = feature_set / qml.math.sqrt(norm)
                 else:
                     raise ValueError(
-                        f"Features must be a vector of norm 1.0; got norm {norm}."
+                        f"Features must be a vector of norm 1.0; got norm {norm}. "
                         "Use 'normalize=True' to automatically normalize."
                     )
 
diff --git a/pennylane/templates/subroutines/qmc.py b/pennylane/templates/subroutines/qmc.py
index b195bc536..8b4bebe39 100644
--- a/pennylane/templates/subroutines/qmc.py
+++ b/pennylane/templates/subroutines/qmc.py
@@ -60,7 +60,7 @@ def probs_to_unitary(probs):
     ):  # skip check and error if jitting to avoid JAX tracer errors
         if not qml.math.allclose(sum(probs), 1) or min(probs) < 0:
             raise ValueError(
-                "A valid probability distribution of non-negative numbers that sum to one"
+                "A valid probability distribution of non-negative numbers that sum to one "
                 "must be input"
             )
 
diff --git a/pennylane/transforms/qcut/tapes.py b/pennylane/transforms/qcut/tapes.py
index 1bc4a4270..64a67b644 100644
--- a/pennylane/transforms/qcut/tapes.py
+++ b/pennylane/transforms/qcut/tapes.py
@@ -391,8 +391,8 @@ def _qcut_expand_fn(
 
     if not (auto_cutter is True or callable(auto_cutter)):
         raise ValueError(
-            "No WireCut operations found in the circuit. Consider increasing the max_depth value if"
-            " operations or nested tapes contain WireCut operations."
+            "No WireCut operations found in the circuit. Consider increasing the max_depth value if "
+            "operations or nested tapes contain WireCut operations."
         )
 
     return tape
diff --git a/pennylane/transforms/sign_expand/sign_expand.py b/pennylane/transforms/sign_expand/sign_expand.py
index 1c8a86715..3ced52d8e 100644
--- a/pennylane/transforms/sign_expand/sign_expand.py
+++ b/pennylane/transforms/sign_expand/sign_expand.py
@@ -71,7 +71,7 @@ def evolve_under(ops, coeffs, time, controls):
     """
     ops_temp = []
     for op, coeff in zip(ops, coeffs):
-        pauli_word = qml.grouping.pauli_word_to_string(op)
+        pauli_word = qml.pauli.pauli_word_to_string(op)
         ops_temp.append(
             controlled_pauli_evolution(
                 coeff * time,
@@ -110,7 +110,7 @@ def calculate_xi_decomposition(hamiltonian):
       projs (List[np.array]): The analytical observables associated with these groups,
        to be measured by qml.Hermitian
     """
-    mat = qml.utils.sparse_hamiltonian(hamiltonian).toarray()
+    mat = hamiltonian.sparse_matrix().toarray()
     size = len(mat)
     eigs, eigvecs = np.linalg.eigh(mat)
     norm = eigs[-1]
@@ -168,26 +168,27 @@ def construct_sgn_circuit(  # pylint: disable=too-many-arguments
     coeffs = hamiltonian.data
     tapes = []
     for mu, time in zip(mus, times):
-        with tape.__class__() as new_tape:
-            # Put state prep and ansatz on tape in the 'old' register
-            for op in tape.operations:
-                op.queue()
-
-            # Put QSP and Hadamard test on the two ancillas Target and Control
-            qml.Hadamard(controls[0])
-            for i, phi in enumerate(phis):
-                qml.CRX(phi, wires=controls)
-                if i == len(phis) - 1:
-                    qml.CRY(np.pi, wires=controls)
-                else:
-                    evolve_under(hamiltonian.ops, coeffs, 2 * time, controls)
-                    qml.CRZ(-2 * mu * time, wires=controls)
-            qml.Hadamard(controls[0])
-
-            if tape.measurements[0].return_type == qml.measurements.Expectation:
-                qml.expval(-1 * qml.PauliZ(controls[0]))
+        added_operations = []
+        # Put QSP and Hadamard test on the two ancillas Target and Control
+        added_operations.append(qml.Hadamard(controls[0]))
+        for i, phi in enumerate(phis):
+            added_operations.append(qml.CRX(phi, wires=controls))
+            if i == len(phis) - 1:
+                added_operations.append(qml.CRY(np.pi, wires=controls))
             else:
-                qml.var(qml.PauliZ(controls[0]))
+                for ops in evolve_under(hamiltonian.ops, coeffs, 2 * time, controls):
+                    added_operations.extend(ops)
+                added_operations.append(qml.CRZ(-2 * mu * time, wires=controls))
+        added_operations.append(qml.Hadamard(controls[0]))
+
+        operations = tape.operations + added_operations
+
+        if tape.measurements[0].return_type == qml.measurements.Expectation:
+            measurements = [qml.expval(-1 * qml.PauliZ(controls[0]))]
+        else:
+            measurements = [qml.var(qml.PauliZ(controls[0]))]
+
+        new_tape = qml.tape.QuantumScript(operations, measurements)
 
         tapes.append(new_tape)
     return tapes
@@ -232,10 +233,17 @@ def sign_expand(  # pylint: disable=too-many-arguments
 
         H = qml.PauliZ(0) + 0.5 * qml.PauliZ(2) + qml.PauliZ(1)
 
-    and a circuit of the form,
+    a device with auxiliary qubits,
 
     .. code-block:: python3
 
+        dev = qml.device("default.qubit", wires=[0,1,2,'Hadamard','Target'])
+
+    and a circuit of the form, with the transform as decorator.
+
+    .. code-block:: python3
+
+        @qml.transforms.sign_expand
         @qml.qnode(dev)
         def circuit():
             qml.Hadamard(wires=0)
@@ -243,40 +251,56 @@ def sign_expand(  # pylint: disable=too-many-arguments
             qml.PauliX(wires=2)
             return qml.expval(H)
 
+    >>> circuit()
+    -0.4999999999999999
+
+    You can also work directly on tapes:
+
+    .. code-block:: python3
+
+            operations = [qml.Hadamard(wires=0), qml.CNOT(wires=[0, 1]), qml.PauliX(wires=2)]
+            measurements = [qml.expval(H)]
+            tape = qml.tape.QuantumTape(operations, measurements)
+
     We can use the ``sign_expand`` transform to generate new tapes and a classical
     post-processing function for computing the expectation value of the Hamiltonian in these new decompositions
 
     >>> tapes, fn = qml.transforms.sign_expand(tape)
 
-    We can evaluate these tapes on a device, it needs two additional ancilla gates labeled 'Hadamard' and 'Target' if one wants to make the circuit approximation of the decomposition:
+    We can evaluate these tapes on a device, it needs two additional ancilla gates labeled 'Hadamard' and 'Target' if
+    one wants to make the circuit approximation of the decomposition:
 
     >>> dev = qml.device("default.qubit", wires=[0,1,2,'Hadamard','Target'])
     >>> res = dev.batch_execute(tapes)
     >>> fn(res)
+    -0.4999999999999999
 
-    To evaluate the circuit approximation of the decomposition one can construct the sgn-decomposition by changing the kwarg circuit to True:
+    To evaluate the circuit approximation of the decomposition one can construct the sgn-decomposition by changing the
+    kwarg circuit to True:
 
-    .. code-block:: python3
+    >>> tapes, fn = qml.transforms.sign_expand(tape, circuit=True, J=20, delta=0)
+    >>> dev = qml.device("default.qubit", wires=[0,1,2,'Hadamard','Target'])
+    >>> dev.batch_execute(tapes)
+    >>> fn(res)
+    -0.24999999999999994
 
-        tapes, fn = qml.transforms.sign_expand(tape, circuit=True, J=20, delta=0)
-        dev = qml.device("default.qubit", wires=[0,1,2,'Hadamard','Target'])
-        res = dev.batch_execute(tapes)
 
+    Lastly, as the paper is about minimizing variance, one can also calculate the variance of the estimator by
+    changing the tape:
 
-    As a last thing, as the paper is about variance minimizing one can also calculate the variance of the estimator by changing the tape
 
     .. code-block:: python3
 
-        @qml.qnode(dev)
-        def circuit():
-            qml.Hadamard(wires=0)
-            qml.CNOT(wires=[0, 1])
-            qml.PauliX(wires=2)
-            return qml.var(H)
+            operations = [qml.Hadamard(wires=0), qml.CNOT(wires=[0, 1]), qml.PauliX(wires=2)]
+            measurements = [qml.var(H)]
+            tape = qml.tape.QuantumTape(operations, measurements)
+
+    >>> tapes, fn = qml.transforms.sign_expand(tape, circuit=True, J=20, delta=0)
+    >>> dev = qml.device("default.qubit", wires=[0,1,2,'Hadamard','Target'])
+    >>> res = dev.batch_execute(tapes)
+    >>> fn(res)
+    10.108949481425782
 
-        tapes, fn = qml.transforms.sign_expand(tape, circuit=True, J=20, delta=0)
-        dev = qml.device("default.qubit", wires=[0,1,2,'Hadamard','Target'])
-        res = dev.batch_execute(tapes)
     """
     path_str = path.dirname(__file__)
     with open(path_str + "/sign_expand_data.json", "r", encoding="utf-8") as f:
@@ -324,13 +348,12 @@ def sign_expand(  # pylint: disable=too-many-arguments
     # make one tape per observable
     tapes = []
     for proj in projs:
-        with tape.__class__() as new_tape:
-            for op in tape.operations:
-                op.queue()
-            if tape.measurements[0].return_type == qml.measurements.Expectation:
-                qml.expval(qml.Hermitian(proj, wires=wires))
-            else:
-                qml.var(qml.Hermitian(proj, wires=wires))
+        if tape.measurements[0].return_type == qml.measurements.Expectation:
+            measurements = [qml.expval(qml.Hermitian(proj, wires=wires))]
+        else:
+            measurements = [qml.var(qml.Hermitian(proj, wires=wires))]
+
+        new_tape = qml.tape.QuantumScript(tape.operations, measurements)
 
         tapes.append(new_tape)
 


Test patch:
diff --git a/tests/devices/test_default_qubit_jax.py b/tests/devices/test_default_qubit_jax.py
index 0a2dcab28..986cf4378 100644
--- a/tests/devices/test_default_qubit_jax.py
+++ b/tests/devices/test_default_qubit_jax.py
@@ -15,6 +15,7 @@ import pytest
 
 jax = pytest.importorskip("jax", minversion="0.2")
 jnp = jax.numpy
+import jaxlib
 import numpy as np
 from jax.config import config
 
@@ -24,6 +25,49 @@ from pennylane.devices.default_qubit_jax import DefaultQubitJax
 from pennylane.pulse import ParametrizedHamiltonian
 
 
+@pytest.mark.jax
+@pytest.mark.parametrize(
+    "version, package, should_raise",
+    [
+        ("0.4.4", jax, True),
+        ("0.4.3", jax, False),
+    ],
+)
+def test_jax_version(version, package, should_raise, monkeypatch):
+    from pennylane.devices.default_qubit_jax import _validate_jax_version
+
+    with monkeypatch.context() as m:
+        m.setattr(package, "__version__", version)
+
+        if should_raise:
+            msg = "version of JAX is 0.4.4"
+
+            with pytest.raises(RuntimeError, match=msg):
+                _validate_jax_version()
+
+            dev = qml.device("default.qubit", wires=1)
+
+            with pytest.raises(RuntimeError, match=msg):
+
+                @qml.qnode(dev, interface="jax", diff_method="backprop")
+                def circuit():
+                    return None
+
+            with pytest.raises(RuntimeError, match=msg):
+                dev = qml.device("default.qubit.jax", wires=1)
+
+        else:
+            _validate_jax_version()
+
+            _ = qml.device("default.qubit.jax", wires=1)
+
+            dev = qml.device("default.qubit", wires=1)
+
+            @qml.qnode(dev, interface="jax")
+            def circuit():
+                return None
+
+
 @pytest.mark.jax
 def test_analytic_deprecation():
     """Tests if the kwarg `analytic` is used and displays error message."""
diff --git a/tests/returntypes/gradients/test_hadamard_grad.py b/tests/returntypes/gradients/test_hadamard_grad.py
index 70f8e3cbf..cc17ab257 100644
--- a/tests/returntypes/gradients/test_hadamard_grad.py
+++ b/tests/returntypes/gradients/test_hadamard_grad.py
@@ -143,6 +143,22 @@ class TestHadamardGrad:
 
         assert np.allclose(res_hadamard, expected, atol=tol, rtol=0)
 
+    def test_control_rotations(self, tol):
+        """Test RX, CRX and CRY."""
+        dev = qml.device("default.qubit", wires=4)
+
+        with qml.queuing.AnnotatedQueue() as q:
+            qml.RX(0.1, wires=0)
+            qml.CRY(0.2, wires=[2, 0])
+            qml.CRX(0.3, wires=[0, 1])
+            qml.expval(qml.PauliX(0))
+
+        tape = qml.tape.QuantumScript.from_queue(q)
+        tape.trainable_params = {0, 1, 2}
+
+        res_hadamard, _ = grad_fn(tape, dev)
+        assert np.allclose(res_hadamard, np.zeros(3), atol=tol, rtol=0)
+
     @pytest.mark.parametrize("theta", np.linspace(-2 * np.pi, 2 * np.pi, 7))
     @pytest.mark.parametrize("G", [qml.CRX, qml.CRY, qml.CRZ])
     def test_controlled_rotation_gradient_multi(self, G, theta, tol):
diff --git a/tests/test_qnode.py b/tests/test_qnode.py
index 6b536104c..2b71bc420 100644
--- a/tests/test_qnode.py
+++ b/tests/test_qnode.py
@@ -560,9 +560,8 @@ class TestValidation:
         assert "Use diff_method instead" in str(w[0].message)
         assert "Use diff_method instead" in str(w[1].message)
 
-    def test_auto_interface_device_switched_warning(self):
-        """Test that checks that a warning is raised if the device is switched during the QNode call due to auto
-        interface."""
+    def test_auto_interface_tracker_device_switched(self):
+        """Test that checks that the tracker is switched to the new device."""
         dev = qml.device("default.qubit", wires=1)
 
         @qml.qnode(dev)
@@ -570,12 +569,18 @@ class TestValidation:
             qml.RX(params, wires=0)
             return qml.expval(qml.PauliZ(0))
 
-        with pytest.warns(
-            UserWarning,
-            match="The device was switched during the call of the QNode",
-        ):
+        with qml.Tracker(dev) as tracker:
             circuit(qml.numpy.array(0.1, requires_grad=True))
 
+        assert tracker.totals == {"executions": 1, "batches": 1, "batch_len": 1}
+        assert np.allclose(tracker.history.pop("results")[0], 0.99500417)
+        assert tracker.history == {
+            "executions": [1],
+            "shots": [None],
+            "batches": [1],
+            "batch_len": [1],
+        }
+
     def test_autograd_interface_device_switched_no_warnings(self):
         """Test that checks that no warning is raised for device switch when you define an interface."""
         dev = qml.device("default.qubit", wires=1)