Pennylane

Latest version: v0.39.0

Safety actively analyzes 682404 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 3 of 11

0.31.1

<h3>Improvements ๐Ÿ› </h3>

* `data.Dataset` now uses HDF5 instead of dill for serialization. [(4097)](https://github.com/PennyLaneAI/pennylane/pull/4097)

* The `qchem` functions `primitive_norm` and `contracted_norm` are modified to be compatible with higher versions of scipy. [(4321)](https://github.com/PennyLaneAI/pennylane/pull/4321)

<h3>Bug Fixes ๐Ÿ›</h3>

* Dataset URLs are now properly escaped when fetching from S3. [(4412)](https://github.com/PennyLaneAI/pennylane/pull/4412)

<h3>Contributors โœ๏ธ</h3>

This release contains contributions from (in alphabetical order):

Utkarsh Azad, Jack Brown, Diego Guala, Soran Jahangiri, Matthew Silverman

0.31.0

<h3>New features since last release</h3>

<h4>Seamlessly create and combine fermionic operators ๐Ÿ”ฌ</h4>

* Fermionic operators and arithmetic are now available. [(4191)](https://github.com/PennyLaneAI/pennylane/pull/4191) [(#4195)](https://github.com/PennyLaneAI/pennylane/pull/4195) [(#4200)](https://github.com/PennyLaneAI/pennylane/pull/4200) [(#4201)](https://github.com/PennyLaneAI/pennylane/pull/4201) [(#4209)](https://github.com/PennyLaneAI/pennylane/pull/4209) [(#4229)](https://github.com/PennyLaneAI/pennylane/pull/4229) [(#4253)](https://github.com/PennyLaneAI/pennylane/pull/4253) [(#4255)](https://github.com/PennyLaneAI/pennylane/pull/4255) [(#4262)](https://github.com/PennyLaneAI/pennylane/pull/4262) [(#4278)](https://github.com/PennyLaneAI/pennylane/pull/4278)

There are a couple of ways to create fermionic operators with this new feature:

- `qml.FermiC` and `qml.FermiA`: the [fermionic creation](https://docs.pennylane.ai/en/stable/code/api/pennylane.FermiC.html) and [annihilation operators](https://docs.pennylane.ai/en/stable/code/api/pennylane.FermiA.html), respectively. These operators are defined by passing the index of the orbital that the fermionic operator acts on. For instance, the operators `aโบ(0)` and `a(3)` are respectively constructed as

pycon
>>> qml.FermiC(0)
aโบ(0)
>>> qml.FermiA(3)
a(3)


These operators can be composed with (`*`) and linearly combined with (`+` and `-`) other Fermi operators to create arbitrary fermionic Hamiltonians. Multiplying several Fermi operators together creates an operator that we call a Fermi word:

pycon
>>> word = qml.FermiC(0) * qml.FermiA(0) * qml.FermiC(3) * qml.FermiA(3)
>>> word
aโบ(0) a(0) aโบ(3) a(3)


Fermi words can be linearly combined to create a fermionic operator that we call a Fermi sentence:

pycon
>>> sentence = 1.2 * word - 0.345 * qml.FermiC(3) * qml.FermiA(3)
>>> sentence
1.2 * aโบ(0) a(0) aโบ(3) a(3)
- 0.345 * aโบ(3) a(3)


- via [qml.fermi.from_string](https://docs.pennylane.ai/en/stable/code/api/pennylane.fermi.from_string.html): create a fermionic operator that represents multiple creation and annihilation operators being multiplied by each other (a Fermi word).

pycon
>>> qml.fermi.from_string('0+ 1- 0+ 1-')
aโบ(0) a(1) aโบ(0) a(1)
>>> qml.fermi.from_string('0^ 1 0^ 1')
aโบ(0) a(1) aโบ(0) a(1)


Fermi words created with `from_string` can also be linearly combined to create a Fermi sentence:

pycon
>>> word1 = qml.fermi.from_string('0+ 0- 3+ 3-')
>>> word2 = qml.fermi.from_string('3+ 3-')
>>> sentence = 1.2 * word1 + 0.345 * word2
>>> sentence
1.2 * aโบ(0) a(0) aโบ(3) a(3)
+ 0.345 * aโบ(3) a(3)


Additionally, any fermionic operator, be it a single fermionic creation/annihilation operator, a Fermi word, or a Fermi sentence, can be mapped to the qubit basis by using [qml.jordan_wigner](https://docs.pennylane.ai/en/stable/code/api/pennylane.jordan_wigner.html):

pycon
>>> qml.jordan_wigner(sentence)
((0.4725+0j)*(Identity(wires=[0]))) + ((-0.4725+0j)*(PauliZ(wires=[3]))) + ((-0.3+0j)*(PauliZ(wires=[0]))) + ((0.3+0j)*(PauliZ(wires=[0]) PauliZ(wires=[3])))


Learn how to create fermionic Hamiltonians describing some simple chemical systems by checking out our [fermionic operators demo](https://pennylane.ai/qml/demos/tutorial_fermionic_operators)!

<h4>Workflow-level resource estimation ๐Ÿงฎ</h4>

* PennyLane's [Tracker](https://docs.pennylane.ai/en/stable/code/api/pennylane.Tracker.html) now monitors the resource requirements of circuits being executed by the device. [(#4045)](https://github.com/PennyLaneAI/pennylane/pull/4045) [(#4110)](https://github.com/PennyLaneAI/pennylane/pull/4110)

Suppose we have a workflow that involves executing circuits with different qubit numbers. We can obtain the resource requirements as a function of the number of qubits by executing the workflow with the `Tracker` context:

python
dev = qml.device("default.qubit", wires=4)

qml.qnode(dev)
def circuit(n_wires):
for i in range(n_wires):
qml.Hadamard(i)
return qml.probs(range(n_wires))

with qml.Tracker(dev) as tracker:
for i in range(1, 5):
circuit(i)


The resource requirements of individual circuits can then be inspected as follows:

pycon
>>> resources = tracker.history["resources"]
>>> resources[0]
wires: 1
gates: 1
depth: 1
shots: Shots(total=None)
gate_types:
{'Hadamard': 1}
gate_sizes:
{1: 1}
>>> [r.num_wires for r in resources]
[1, 2, 3, 4]


Moreover, it is possible to predict the resource requirements without evaluating circuits using the `null.qubit` device, which follows the standard execution pipeline but returns numeric zeros. Consider the following workflow that takes the gradient of a `50`-qubit circuit:

python
n_wires = 50
dev = qml.device("null.qubit", wires=n_wires)

weight_shape = qml.StronglyEntanglingLayers.shape(2, n_wires)
weights = np.random.random(weight_shape, requires_grad=True)

qml.qnode(dev, diff_method="parameter-shift")
def circuit(weights):
qml.StronglyEntanglingLayers(weights, wires=range(n_wires))
return qml.expval(qml.PauliZ(0))

with qml.Tracker(dev) as tracker:
qml.grad(circuit)(weights)


The tracker can be inspected to extract resource requirements without requiring a 50-qubit circuit run:

pycon
>>> tracker.totals
{'executions': 451, 'batches': 2, 'batch_len': 451}
>>> tracker.history["resources"][0]
wires: 50
gates: 200
depth: 77
shots: Shots(total=None)
gate_types:
{'Rot': 100, 'CNOT': 100}
gate_sizes:
{1: 100, 2: 100}


* Custom operations can now be constructed that solely define resource requirements โ€” an explicit decomposition or matrix representation is not needed. [(4033)](https://github.com/PennyLaneAI/pennylane/pull/4033)

PennyLane is now able to estimate the total resource requirements of circuits that include one or more of these operations, allowing you to estimate requirements for high-level algorithms composed of abstract subroutines.

These operations can be defined by inheriting from [ResourcesOperation](https://docs.pennylane.ai/en/stable/code/api/pennylane.resource.ResourcesOperation.html) and overriding the `resources()` method to return an appropriate [Resources](https://docs.pennylane.ai/en/stable/code/api/pennylane.resource.Resources.html) object:

python
class CustomOp(qml.resource.ResourcesOperation):
def resources(self):
n = len(self.wires)
r = qml.resource.Resources(
num_wires=n,
num_gates=n ** 2,
depth=5,
)
return r


pycon
>>> wires = [0, 1, 2]
>>> c = CustomOp(wires)
>>> c.resources()
wires: 3
gates: 9
depth: 5
shots: Shots(total=None)
gate_types:
{}
gate_sizes:
{}


A quantum circuit that contains `CustomOp` can be created and inspected using [qml.specs](https://docs.pennylane.ai/en/stable/code/api/pennylane.specs.html):

python
dev = qml.device("default.qubit", wires=wires)

qml.qnode(dev)
def circ():
qml.PauliZ(wires=0)
CustomOp(wires)
return qml.state()


pycon
>>> specs = qml.specs(circ)()
>>> specs["resources"].depth
6


<h4>Community contributions from UnitaryHack ๐Ÿค</h4>

* [ParametrizedHamiltonian](https://docs.pennylane.ai/en/stable/code/api/pennylane.pulse.ParametrizedHamiltonian.html) now has an improved string representation. [(#4176)](https://github.com/PennyLaneAI/pennylane/pull/4176)

pycon
>>> def f1(p, t): return p[0] * jnp.sin(p[1] * t)
>>> def f2(p, t): return p * t
>>> coeffs = [2., f1, f2]
>>> observables = [qml.PauliX(0), qml.PauliY(0), qml.PauliZ(0)]
>>> qml.dot(coeffs, observables)
(2.0*(PauliX(wires=[0])))
+ (f1(params_0, t)*(PauliY(wires=[0])))
+ (f2(params_1, t)*(PauliZ(wires=[0])))


* The quantum information module now supports [trace distance](https://en.wikipedia.org/wiki/Trace_distance). [(#4181)](https://github.com/PennyLaneAI/pennylane/pull/4181)

Two cases are enabled for calculating the trace distance:

- A QNode transform via [qml.qinfo.trace_distance](https://docs.pennylane.ai/en/stable/code/api/pennylane.qinfo.transforms.trace_distance.html):

python
dev = qml.device('default.qubit', wires=2)

qml.qnode(dev)
def circuit(param):
qml.RY(param, wires=0)
qml.CNOT(wires=[0, 1])
return qml.state()


pycon
>>> trace_distance_circuit = qml.qinfo.trace_distance(circuit, circuit, wires0=[0], wires1=[0])
>>> x, y = np.array(0.4), np.array(0.6)
>>> trace_distance_circuit((x,), (y,))
0.047862689546603415


- Flexible post-processing via [qml.math.trace_distance](https://docs.pennylane.ai/en/stable/code/api/pennylane.math.trace_distance.html):

pycon
>>> rho = np.array([[0.3, 0], [0, 0.7]])
>>> sigma = np.array([[0.5, 0], [0, 0.5]])
>>> qml.math.trace_distance(rho, sigma)
0.19999999999999998


* It is now possible to prepare qutrit basis states with [qml.QutritBasisState](https://docs.pennylane.ai/en/stable/code/api/pennylane.QutritBasisState.html). [(#4185)](https://github.com/PennyLaneAI/pennylane/pull/4185)

python
wires = range(2)
dev = qml.device("default.qutrit", wires=wires)

qml.qnode(dev)
def qutrit_circuit():
qml.QutritBasisState([1, 1], wires=wires)
qml.TAdd(wires=wires)
return qml.probs(wires=1)


pycon
>>> qutrit_circuit()
array([0., 0., 1.])


* A new transform called [one_qubit_decomposition](https://docs.pennylane.ai/en/stable/code/api/pennylane.transforms.one_qubit_decomposition.html) has been added to provide a unified interface for decompositions of a single-qubit unitary matrix into sequences of X, Y, and Z rotations. All decompositions simplify the rotations angles to be between `0` and `4` pi. [(#4210)](https://github.com/PennyLaneAI/pennylane/pull/4210) [(#4246)](https://github.com/PennyLaneAI/pennylane/pull/4246)

pycon
>>> from pennylane.transforms import one_qubit_decomposition
>>> U = np.array([[-0.28829348-0.78829734j, 0.30364367+0.45085995j],
... [ 0.53396245-0.10177564j, 0.76279558-0.35024096j]])
>>> one_qubit_decomposition(U, 0, "ZYZ")
[RZ(tensor(12.32427531, requires_grad=True), wires=[0]),
RY(tensor(1.14938178, requires_grad=True), wires=[0]),
RZ(tensor(1.73305815, requires_grad=True), wires=[0])]
>>> one_qubit_decomposition(U, 0, "XYX", return_global_phase=True)
[RX(tensor(10.84535137, requires_grad=True), wires=[0]),
RY(tensor(1.39749741, requires_grad=True), wires=[0]),
RX(tensor(0.45246584, requires_grad=True), wires=[0]),
(0.38469215914523336-0.9230449299422961j)*(Identity(wires=[0]))]


* The `has_unitary_generator` attribute in `qml.ops.qubit.attributes` no longer contains operators with non-unitary generators. [(4183)](https://github.com/PennyLaneAI/pennylane/pull/4183)

* PennyLane Docker builds have been updated to include the latest plugins and interface versions. [(4178)](https://github.com/PennyLaneAI/pennylane/pull/4178)

<h4>Extended support for differentiating pulses โš›๏ธ</h4>

* The stochastic parameter-shift gradient method can now be used with hardware-compatible Hamiltonians. [(4132)](https://github.com/PennyLaneAI/pennylane/pull/4132) [(#4215)](https://github.com/PennyLaneAI/pennylane/pull/4215)

This new feature generalizes the stochastic parameter-shift gradient transform for pulses (`stoch_pulse_grad`) to support Hermitian generating terms beyond just Pauli words in pulse Hamiltonians, which makes it hardware-compatible.

* A new differentiation method called [qml.gradients.pulse_generator](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.pulse_generator.html) is available, which combines classical processing with the parameter-shift rule for multivariate gates to differentiate pulse programs. Access it in your pulse programs by setting `diff_method=qml.gradients.pulse_generator`. [(#4160)](https://github.com/PennyLaneAI/pennylane/pull/4160)

* `qml.pulse.ParametrizedEvolution` now uses _batched_ compressed sparse row (`BCSR`) format. This allows for computing Jacobians of the unitary directly even when `dense=False`. [(4126)](https://github.com/PennyLaneAI/pennylane/pull/4126)

python
def U(params):
H = jnp.polyval * qml.PauliZ(0) time dependent Hamiltonian
Um = qml.evolve(H, dense=False)(params, t=10.)
return qml.matrix(Um)
params = jnp.array([[0.5]], dtype=complex)
jac = jax.jacobian(U, holomorphic=True)(params)


<h4>Broadcasting and other tweaks to Torch and Keras layers ๐Ÿฆพ</h4>

* The `TorchLayer` and `KerasLayer` integrations with `torch.nn` and `Keras` have been upgraded. Consider the following `TorchLayer`:

python
n_qubits = 2
dev = qml.device("default.qubit", wires=n_qubits)

qml.qnode(dev)
def qnode(inputs, weights):
qml.AngleEmbedding(inputs, wires=range(n_qubits))
qml.BasicEntanglerLayers(weights, wires=range(n_qubits))
return [qml.expval(qml.PauliZ(wires=i)) for i in range(n_qubits)]

n_layers = 6
weight_shapes = {"weights": (n_layers, n_qubits)}
qlayer = qml.qnn.TorchLayer(qnode, weight_shapes)


The following features are now available:

- Native support for parameter broadcasting. [(4131)](https://github.com/PennyLaneAI/pennylane/pull/4131)

pycon
>>> batch_size = 10
>>> inputs = torch.rand((batch_size, n_qubits))
>>> qlayer(inputs)
>>> dev.num_executions == 1
True


- The ability to draw a `TorchLayer` and `KerasLayer` using `qml.draw()` and `qml.draw_mpl()`. [(4197)](https://github.com/PennyLaneAI/pennylane/pull/4197)

pycon
>>> print(qml.draw(qlayer, show_matrices=False)(inputs))
0: โ”€โ•ญAngleEmbedding(M0)โ”€โ•ญBasicEntanglerLayers(M1)โ”€โ”ค <Z>
1: โ”€โ•ฐAngleEmbedding(M0)โ”€โ•ฐBasicEntanglerLayers(M1)โ”€โ”ค <Z>


- Support for `KerasLayer` model saving and clearer instructions on `TorchLayer` model saving. [(4149)](https://github.com/PennyLaneAI/pennylane/pull/4149) [(#4158)](https://github.com/PennyLaneAI/pennylane/pull/4158)

pycon
>>> torch.save(qlayer.state_dict(), "weights.pt") Saving
>>> qlayer.load_state_dict(torch.load("weights.pt")) Loading
>>> qlayer.eval()


Hybrid models containing `KerasLayer` or `TorchLayer` objects can also be saved and loaded.

<h3>Improvements ๐Ÿ› </h3>

<h4>A more flexible projector</h4>

* `qml.Projector` now accepts a state vector representation, which enables the creation of projectors in any basis. [(4192)](https://github.com/PennyLaneAI/pennylane/pull/4192)

python
dev = qml.device("default.qubit", wires=2)
qml.qnode(dev)
def circuit(state):
return qml.expval(qml.Projector(state, wires=[0, 1]))
zero_state = [0, 0]
plusplus_state = np.array([1, 1, 1, 1]) / 2


pycon
>>> circuit(zero_state)
tensor(1., requires_grad=True)
>>> circuit(plusplus_state)
tensor(0.25, requires_grad=True)


<h4>Do more with qutrits</h4>

* Three qutrit rotation operators have been added that are analogous to `RX`, `RY`, and `RZ`:

- `qml.TRX`: an X rotation
- `qml.TRY`: a Y rotation
- `qml.TRZ`: a Z rotation

[(2845)](https://github.com/PennyLaneAI/pennylane/pull/2845) [(#2846)](https://github.com/PennyLaneAI/pennylane/pull/2846) [(#2847)](https://github.com/PennyLaneAI/pennylane/pull/2847)

* Qutrit devices now support parameter-shift differentiation. [(2845)](https://github.com/PennyLaneAI/pennylane/pull/2845)

<h4>The qchem module</h4>

* `qchem.molecular_hamiltonian()`, `qchem.qubit_observable()`, `qchem.import_operator()`, and `qchem.dipole_moment()` now return an arithmetic operator if `enable_new_opmath()` is active.
[(4138)](https://github.com/PennyLaneAI/pennylane/pull/4138) [(#4159)](https://github.com/PennyLaneAI/pennylane/pull/4159) [(#4189)](https://github.com/PennyLaneAI/pennylane/pull/4189) [(#4204)](https://github.com/PennyLaneAI/pennylane/pull/4204)

* Non-cubic lattice support for all electron resource estimation has been added. [(3956)](https://github.com/PennyLaneAI/pennylane/pull/3956)

* The `qchem.molecular_hamiltonian()` function has been upgraded to support custom wires for constructing differentiable Hamiltonians. The zero imaginary component of the Hamiltonian coefficients have been removed. [(4050)](https://github.com/PennyLaneAI/pennylane/pull/4050) [(#4094)](https://github.com/PennyLaneAI/pennylane/pull/4094)

* Jordan-Wigner transforms that cache Pauli gate objects have been accelerated. [(4046)](https://github.com/PennyLaneAI/pennylane/pull/4046)

* An error is now raised by `qchem.molecular_hamiltonian` when the `dhf` method is used for an open-shell system. This duplicates a similar error in `qchem.Molecule` but makes it clear that the `pyscf` backend can be used for open-shell calculations. [(4058)](https://github.com/PennyLaneAI/pennylane/pull/4058)

* Updated various qubit tapering methods to support operator arithmetic. [(4252)](https://github.com/PennyLaneAI/pennylane/pull/4252)

<h4>Next-generation device API</h4>

* The new device interface has been integrated with `qml.execute` for autograd, backpropagation, and no differentiation. [(3903)](https://github.com/PennyLaneAI/pennylane/pull/3903)

* Support for adjoint differentiation has been added to the `DefaultQubit2` device. [(4037)](https://github.com/PennyLaneAI/pennylane/pull/4037)

* A new function called `measure_with_samples` that returns a sample-based measurement result given a state has been added. [(4083)](https://github.com/PennyLaneAI/pennylane/pull/4083) [(#4093)](https://github.com/PennyLaneAI/pennylane/pull/4093) [(#4162)](https://github.com/PennyLaneAI/pennylane/pull/4162) [(#4254)](https://github.com/PennyLaneAI/pennylane/pull/4254)

* `DefaultQubit2.preprocess` now returns a new `ExecutionConfig` object with decisions for `gradient_method`, `use_device_gradient`, and `grad_on_execution`. [(4102)](https://github.com/PennyLaneAI/pennylane/pull/4102)

* Support for sample-based measurements has been added to the `DefaultQubit2` device. [(4105)](https://github.com/PennyLaneAI/pennylane/pull/4105) [(#4114)](https://github.com/PennyLaneAI/pennylane/pull/4114) [(#4133)](https://github.com/PennyLaneAI/pennylane/pull/4133) [(#4172)](https://github.com/PennyLaneAI/pennylane/pull/4172)

* The `DefaultQubit2` device now has a `seed` keyword argument. [(4120)](https://github.com/PennyLaneAI/pennylane/pull/4120)

* Added a `dense` keyword to `ParametrizedEvolution` that allows forcing dense or sparse matrices. [(4079)](https://github.com/PennyLaneAI/pennylane/pull/4079) [(#4095)](https://github.com/PennyLaneAI/pennylane/pull/4095) [(#4285)](https://github.com/PennyLaneAI/pennylane/pull/4285)

* Adds the Type variables `pennylane.typing.Result` and `pennylane.typing.ResultBatch` for type hinting the result of an execution. [(4018)](https://github.com/PennyLaneAI/pennylane/pull/4108)

* `qml.devices.ExecutionConfig` no longer has a `shots` property, as it is now on the `QuantumScript`. It now has a `use_device_gradient` property. `ExecutionConfig.grad_on_execution = None` indicates a request for `"best"`, instead of a string. [(4102)](https://github.com/PennyLaneAI/pennylane/pull/4102)

* The new device interface for Jax has been integrated with `qml.execute`. [(4137)](https://github.com/PennyLaneAI/pennylane/pull/4137)

* The new device interface is now integrated with `qml.execute` for Tensorflow. [(4169)](https://github.com/PennyLaneAI/pennylane/pull/4169)

* The experimental device `DefaultQubit2` now supports `qml.Snapshot`. [(4193)](https://github.com/PennyLaneAI/pennylane/pull/4193)

* The experimental device interface is integrated with the `QNode`. [(4196)](https://github.com/PennyLaneAI/pennylane/pull/4196)

* The new device interface in integrated with `qml.execute` for Torch. [(4257)](https://github.com/PennyLaneAI/pennylane/pull/4257)

<h4>Handling shots</h4>

* `QuantumScript` now has a `shots` property, allowing shots to be tied to executions instead of devices. [(4067)](https://github.com/PennyLaneAI/pennylane/pull/4067) [(#4103)](https://github.com/PennyLaneAI/pennylane/pull/4103) [(#4106)](https://github.com/PennyLaneAI/pennylane/pull/4106) [(#4112)](https://github.com/PennyLaneAI/pennylane/pull/4112)

* Several Python built-in functions are now properly defined for instances of the `Shots` class.

- `print`: printing `Shots` instances is now human-readable
- `str`: converting `Shots` instances to human-readable strings
- `==`: equating two different `Shots` instances
- `hash`: obtaining the hash values of `Shots` instances

[(4081)](https://github.com/PennyLaneAI/pennylane/pull/4081) [(#4082)](https://github.com/PennyLaneAI/pennylane/pull/4082)

* `qml.devices.ExecutionConfig` no longer has a `shots` property, as it is now on the `QuantumScript`. It now has a `use_device_gradient` property. `ExecutionConfig.grad_on_execution = None` indicates a request for `"best"` instead of a string. [(4102)](https://github.com/PennyLaneAI/pennylane/pull/4102)

* `QuantumScript.shots` has been integrated with QNodes so that shots are placed on the `QuantumScript` during `QNode` construction. [(4110)](https://github.com/PennyLaneAI/pennylane/pull/4110)

* The `gradients` module has been updated to use the new `Shots` object internally [(4152)](https://github.com/PennyLaneAI/pennylane/pull/4152)

<h4>Operators</h4>

* `qml.prod` now accepts a single quantum function input for creating new `Prod` operators. [(4011)](https://github.com/PennyLaneAI/pennylane/pull/4011)

* `DiagonalQubitUnitary` now decomposes into `RZ`, `IsingZZ` and `MultiRZ` gates instead of a `QubitUnitary` operation with a dense matrix. [(4035)](https://github.com/PennyLaneAI/pennylane/pull/4035)

* All objects being queued in an `AnnotatedQueue` are now wrapped so that `AnnotatedQueue` is not dependent on the has of any operators or measurement processes. [(4087)](https://github.com/PennyLaneAI/pennylane/pull/4087)

* A `dense` keyword to `ParametrizedEvolution` that allows forcing dense or sparse matrices has been added. [(4079)](https://github.com/PennyLaneAI/pennylane/pull/4079) [(#4095)](https://github.com/PennyLaneAI/pennylane/pull/4095)

* Added a new function `qml.ops.functions.bind_new_parameters` that creates a copy of an operator with new parameters without mutating the original operator. [(4113)](https://github.com/PennyLaneAI/pennylane/pull/4113) [(#4256)](https://github.com/PennyLaneAI/pennylane/pull/4256)

* `qml.CY` has been moved from `qml.ops.qubit.non_parametric_ops` to `qml.ops.op_math.controlled_ops` and now inherits from `qml.ops.op_math.ControlledOp`. [(4116)](https://github.com/PennyLaneAI/pennylane/pull/4116/)

* `qml.CZ` now inherits from the `ControlledOp` class and supports exponentiation to arbitrary powers with `pow`, which is no longer limited to integers. It also supports `sparse_matrix` and `decomposition` representations. [(4117)](https://github.com/PennyLaneAI/pennylane/pull/4117)

* The construction of the Pauli representation for the `Sum` class is now faster. [(4142)](https://github.com/PennyLaneAI/pennylane/pull/4142)

* `qml.drawer.drawable_layers.drawable_layers` and `qml.CircuitGraph` have been updated to not rely on `Operator` equality or hash to work correctly. [(4143)](https://github.com/PennyLaneAI/pennylane/pull/4143)

<h4>Other improvements</h4>

* A transform dispatcher and program have been added. [(4109)](https://github.com/PennyLaneAI/pennylane/pull/4109) [(#4187)](https://github.com/PennyLaneAI/pennylane/pull/4187)

* Reduced density matrix functionality has been added via `qml.math.reduce_dm` and `qml.math.reduce_statevector`. Both functions have broadcasting support. [(4173)](https://github.com/PennyLaneAI/pennylane/pull/4173)

* The following functions in `qml.qinfo` now support parameter broadcasting:

- `reduced_dm`
- `purity`
- `vn_entropy`
- `mutual_info`
- `fidelity`
- `relative_entropy`
- `trace_distance`

[(4234)](https://github.com/PennyLaneAI/pennylane/pull/4234)

* The following functions in `qml.math` now support parameter broadcasting:

- `purity`
- `vn_entropy`
- `mutual_info`
- `fidelity`
- `relative_entropy`
- `max_entropy`
- `sqrt_matrix`

[(4186)](https://github.com/PennyLaneAI/pennylane/pull/4186)

* `pulse.ParametrizedEvolution` now raises an error if the number of input parameters does not match the number of parametrized coefficients in the `ParametrizedHamiltonian` that generates it. An exception is made for `HardwareHamiltonian`s which are not checked. [(4216)](https://github.com/PennyLaneAI/pennylane/pull/4216)

* The default value for the `show_matrices` keyword argument in all drawing methods is now `True`. This allows for quick insights into broadcasted tapes, for example. [(3920)](https://github.com/PennyLaneAI/pennylane/pull/3920)

* Type variables for `qml.typing.Result` and `qml.typing.ResultBatch` have been added for type hinting the result of an execution. [(4108)](https://github.com/PennyLaneAI/pennylane/pull/4108)

* The Jax-JIT interface now uses symbolic zeros to determine trainable parameters. [(4075)](https://github.com/PennyLaneAI/pennylane/pull/4075)

* A new function called `pauli.pauli_word_prefactor()` that extracts the prefactor for a given Pauli word has been added. [(4164)](https://github.com/PennyLaneAI/pennylane/pull/4164)

* Variable-length argument lists of functions and methods in some docstrings is now more clear. [(4242)](https://github.com/PennyLaneAI/pennylane/pull/4242)

* `qml.drawer.drawable_layers.drawable_layers` and `qml.CircuitGraph` have been updated to not rely on `Operator` equality or hash to work correctly. [(4143)](https://github.com/PennyLaneAI/pennylane/pull/4143)

* Drawing mid-circuit measurements connected by classical control signals to conditional operations is now possible. [(4228)](https://github.com/PennyLaneAI/pennylane/pull/4228)

* The autograd interface now submits all required tapes in a single batch on the backward pass. [(4245)](https://github.com/PennyLaneAI/pennylane/pull/4245)

<h3>Breaking changes ๐Ÿ’”</h3>

* The default value for the `show_matrices` keyword argument in all drawing methods is now `True`. This allows for quick insights into broadcasted tapes, for example. [(3920)](https://github.com/PennyLaneAI/pennylane/pull/3920)

* `DiagonalQubitUnitary` now decomposes into `RZ`, `IsingZZ`, and `MultiRZ` gates rather than a `QubitUnitary`. [(4035)](https://github.com/PennyLaneAI/pennylane/pull/4035)

* Jax trainable parameters are now `Tracer` instead of `JVPTracer`. It is not always the right definition for the JIT interface, but we update them in the custom JVP using symbolic zeros. [(4075)](https://github.com/PennyLaneAI/pennylane/pull/4075)

* The experimental Device interface `qml.devices.experimental.Device` now requires that the `preprocess` method also returns an `ExecutionConfig` object. This allows the device to choose what `"best"` means for various hyperparameters like `gradient_method` and `grad_on_execution`. [(4007)](https://github.com/PennyLaneAI/pennylane/pull/4007) [(#4102)](https://github.com/PennyLaneAI/pennylane/pull/4102)

* Gradient transforms with Jax no longer support `argnum`. Use `argnums` instead. [(4076)](https://github.com/PennyLaneAI/pennylane/pull/4076)

* `qml.collections`, `qml.op_sum`, and `qml.utils.sparse_hamiltonian` have been removed. [(4071)](https://github.com/PennyLaneAI/pennylane/pull/4071)

* The `pennylane.transforms.qcut` module now uses `(op, id(op))` as nodes in directed multigraphs that are used within the circuit cutting workflow instead of `op`. This change removes the dependency of the module on the hash of operators. [(4227)](https://github.com/PennyLaneAI/pennylane/pull/4227)

* `Operator.data` now returns a `tuple` instead of a `list`. [(4222)](https://github.com/PennyLaneAI/pennylane/pull/4222)

* The pulse differentiation methods, `pulse_generator` and `stoch_pulse_grad`, now raise an error when they are applied to a QNode directly. Instead, use differentiation via a JAX entry point (`jax.grad`, `jax.jacobian`, ...). [(4241)](https://github.com/PennyLaneAI/pennylane/pull/4241)

<h3>Deprecations ๐Ÿ‘‹</h3>

* `LieAlgebraOptimizer` has been renamed to `RiemannianGradientOptimizer`. [(4153)](https://github.com/PennyLaneAI/pennylane/pull/4153)

* `Operation.base_name` has been deprecated. Please use `Operation.name` or `type(op).__name__` instead.

* `QuantumScript`'s `name` keyword argument and property have been deprecated. This also affects `QuantumTape` and `OperationRecorder`. [(4141)](https://github.com/PennyLaneAI/pennylane/pull/4141)

* The `qml.grouping` module has been removed. Its functionality has been reorganized in the `qml.pauli` module.

* The public methods of `DefaultQubit` are pending changes to follow the new device API, as used in `DefaultQubit2`. Warnings have been added to the docstrings to reflect this. [(4145)](https://github.com/PennyLaneAI/pennylane/pull/4145)

* `qml.math.reduced_dm` has been deprecated. Please use `qml.math.reduce_dm` or `qml.math.reduce_statevector` instead. [(4173)](https://github.com/PennyLaneAI/pennylane/pull/4173)

* `qml.math.purity`, `qml.math.vn_entropy`, `qml.math.mutual_info`, `qml.math.fidelity`, `qml.math.relative_entropy`, and `qml.math.max_entropy` no longer support state vectors as input. Please call `qml.math.dm_from_state_vector` on the input before passing to any of these functions. [(4186)](https://github.com/PennyLaneAI/pennylane/pull/4186)

* The `do_queue` keyword argument in `qml.operation.Operator` has been deprecated. Instead of setting `do_queue=False`, use the `qml.QueuingManager.stop_recording()` context. [(4148)](https://github.com/PennyLaneAI/pennylane/pull/4148)

* `zyz_decomposition` and `xyx_decomposition` are now deprecated in favour of `one_qubit_decomposition`. [(4230)](https://github.com/PennyLaneAI/pennylane/pull/4230)

<h3>Documentation ๐Ÿ“</h3>

* The documentation is updated to construct `QuantumTape` upon initialization instead of with queuing. [(4243)](https://github.com/PennyLaneAI/pennylane/pull/4243)

* The docstring for `qml.ops.op_math.Pow.__new__` is now complete and it has been updated along with `qml.ops.op_math.Adjoint.__new__`. [(4231)](https://github.com/PennyLaneAI/pennylane/pull/4231)

* The docstring for `qml.grad` now states that it should be used with the Autograd interface only. [(4202)](https://github.com/PennyLaneAI/pennylane/pull/4202)

* The description of `mult` in the `qchem.Molecule` docstring now correctly states the value of `mult` that is supported. [(4058)](https://github.com/PennyLaneAI/pennylane/pull/4058)

<h3>Bug Fixes ๐Ÿ›</h3>

* Fixed adjoint jacobian results with `grad_on_execution=False` in the JAX-JIT interface. [(4217)](https://github.com/PennyLaneAI/pennylane/pull/4217)

* Fixed the matrix of `SProd` when the coefficient is tensorflow and the target matrix is not `complex128`. [(4249)](https://github.com/PennyLaneAI/pennylane/pull/4249)

* Fixed a bug where `stoch_pulse_grad` would ignore prefactors of rescaled Pauli words in the generating terms of a pulse Hamiltonian. [(4156)](https://github.com/PennyLaneAI/pennylane/pull/4156)

* Fixed a bug where the wire ordering of the `wires` argument to `qml.density_matrix` was not taken into account. [(4072)](https://github.com/PennyLaneAI/pennylane/pull/4072)

* A patch in `interfaces/autograd.py` that checks for the `strawberryfields.gbs` device has been removed. That device is pinned to PennyLane <= v0.29.0, so that patch is no longer necessary. [(4089)](https://github.com/PennyLaneAI/pennylane/pull/4089)

* `qml.pauli.are_identical_pauli_words` now treats all identities as equal. Identity terms on Hamiltonians with non-standard wire orders are no longer eliminated. [(4161)](https://github.com/PennyLaneAI/pennylane/pull/4161)

* `qml.pauli_sentence()` is now compatible with empty Hamiltonians `qml.Hamiltonian([], [])`. [(4171)](https://github.com/PennyLaneAI/pennylane/pull/4171)

* Fixed a bug with Jax where executing multiple tapes with `gradient_fn="device"` would fail. [(4190)](https://github.com/PennyLaneAI/pennylane/pull/4190)

* A more meaningful error message is raised when broadcasting with adjoint differentiation on `DefaultQubit`. [(4203)](https://github.com/PennyLaneAI/pennylane/pull/4203)

* The `has_unitary_generator` attribute in `qml.ops.qubit.attributes` no longer contains operators with non-unitary generators. [(4183)](https://github.com/PennyLaneAI/pennylane/pull/4183)

* Fixed a bug where `op = qml.qsvt()` was incorrect up to a global phase when using `convention="Wx""` and `qml.matrix(op)`. [(4214)](https://github.com/PennyLaneAI/pennylane/pull/4214)

* Fixed a buggy calculation of the angle in `xyx_decomposition` that causes it to give an incorrect decomposition. An `if` conditional was intended to prevent divide by zero errors, but the division was by the sine of the argument. So, any multiple of $\pi$ should trigger the conditional, but it was only checking if the argument was 0. Example: `qml.Rot(2.3, 2.3, 2.3)` [(4210)](https://github.com/PennyLaneAI/pennylane/pull/4210)

* Fixed bug that caused `ShotAdaptiveOptimizer` to truncate dimensions of parameter-distributed shots during optimization. [(4240)](https://github.com/PennyLaneAI/pennylane/pull/4240)

* `Sum` observables can now have trainable parameters. [(4251)](https://github.com/PennyLaneAI/pennylane/pull/4251) [(#4275)](https://github.com/PennyLaneAI/pennylane/pull/4275)

<h3>Contributors โœ๏ธ</h3>

This release contains contributions from (in alphabetical order):

Venkatakrishnan AnushKrishna,
Utkarsh Azad,
Thomas Bromley,
Isaac De Vlugt,
Lillian M. A. Frederiksen,
Emiliano Godinez Ramirez
Nikhil Harle
Soran Jahangiri,
Edward Jiang,
Korbinian Kottmann,
Christina Lee,
Vincent Michaud-Rioux,
Romain Moyard,
Tristan Nemoz,
Mudit Pandey,
Manul Patel,
Borja Requena,
Modjtaba Shokrian-Zini,
Mainak Roy,
Matthew Silverman,
Jay Soni,
Edward Thomas,
David Wierichs,
Frederik Wilde.

0.30.0

<h3>New features since last release</h3>

<h4>Pulse programming on hardware โš›๏ธ๐Ÿ”ฌ</h4>

* Support for loading time-dependent Hamiltonians that are compatible with quantum hardware has been added, making it possible to load a Hamiltonian that describes an ensemble of Rydberg atoms or a collection of transmon qubits. [(3749)](https://github.com/PennyLaneAI/pennylane/pull/3749) [(#3911)](https://github.com/PennyLaneAI/pennylane/pull/3911) [(#3930)](https://github.com/PennyLaneAI/pennylane/pull/3930) [(#3936)](https://github.com/PennyLaneAI/pennylane/pull/3936) [(#3966)](https://github.com/PennyLaneAI/pennylane/pull/3966) [(#3987)](https://github.com/PennyLaneAI/pennylane/pull/3987) [(#4021)](https://github.com/PennyLaneAI/pennylane/pull/4021) [(#4040)](https://github.com/PennyLaneAI/pennylane/pull/4040)

[Rydberg atoms](https://en.wikipedia.org/wiki/Rydberg_atom) are the foundational unit for neutral atom quantum computing. A Rydberg-system Hamiltonian can be constructed from a [drive term](https://docs.pennylane.ai/en/stable/code/api/pennylane.pulse.rydberg_drive.html)
* `qml.pulse.rydberg_drive` โ€” and an
[interaction term](https://docs.pennylane.ai/en/stable/code/api/pennylane.pulse.rydberg_interaction.html)
* `qml.pulse.rydberg_interaction`:

python
from jax import numpy as jnp

atom_coordinates = [[0, 0], [0, 4], [4, 0], [4, 4]]
wires = [0, 1, 2, 3]

amplitude = lambda p, t: p * jnp.sin(jnp.pi * t)
phase = jnp.pi / 2
detuning = 3 * jnp.pi / 4

H_d = qml.pulse.rydberg_drive(amplitude, phase, detuning, wires)
H_i = qml.pulse.rydberg_interaction(atom_coordinates, wires)
H = H_d + H_i


The time-dependent Hamiltonian `H` can be used in a PennyLane pulse-level differentiable circuit:

python
dev = qml.device("default.qubit.jax", wires=wires)

qml.qnode(dev, interface="jax")
def circuit(params):
qml.evolve(H)(params, t=[0, 10])
return qml.expval(qml.PauliZ(0))


pycon
>>> params = jnp.array([2.4])
>>> circuit(params)
Array(0.6316659, dtype=float32)
>>> import jax
>>> jax.grad(circuit)(params)
Array([1.3116529], dtype=float32)


The [qml.pulse](https://docs.pennylane.ai/en/stable/code/qml_pulse.html) page contains additional details. Check out our [release blog post](https://pennylane.ai/blog/2023/05/pennylane-v030-released/) for demonstration of how to perform the execution on actual hardware!

* A pulse-level circuit can now be differentiated using a [stochastic parameter-shift](https://arxiv.org/abs/2210.15812) method. [(#3780)](https://github.com/PennyLaneAI/pennylane/pull/3780) [(#3900)](https://github.com/PennyLaneAI/pennylane/pull/3900) [(#4000)](https://github.com/PennyLaneAI/pennylane/pull/4000) [(#4004)](https://github.com/PennyLaneAI/pennylane/pull/4004)

The new [qml.gradient.stoch_pulse_grad](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.stoch_pulse_grad.html) differentiation method unlocks stochastic-parameter-shift differentiation for pulse-level circuits. The current version of this new method is restricted to Hamiltonians composed of parametrized [Pauli words](https://docs.pennylane.ai/en/stable/code/api/pennylane.pauli.PauliWord.html), but future updates to extend to parametrized [Pauli sentences](https://docs.pennylane.ai/en/stable/code/api/pennylane.pauli.PauliSentence.html) can allow this method to be compatible with hardware-based systems such as an ensemble of Rydberg atoms.

This method can be activated by setting `diff_method` to [qml.gradient.stoch_pulse_grad](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.stoch_pulse_grad.html):

pycon
>>> dev = qml.device("default.qubit.jax", wires=2)
>>> sin = lambda p, t: jax.numpy.sin(p * t)
>>> ZZ = qml.PauliZ(0) qml.PauliZ(1)
>>> H = 0.5 * qml.PauliX(0) + qml.pulse.constant * ZZ + sin * qml.PauliX(1)
>>> qml.qnode(dev, interface="jax", diff_method=qml.gradients.stoch_pulse_grad)
>>> def ansatz(params):
... qml.evolve(H)(params, (0.2, 1.))
... return qml.expval(qml.PauliY(1))
>>> params = [jax.numpy.array(0.4), jax.numpy.array(1.3)]
>>> jax.grad(ansatz)(params)
[Array(0.16921353, dtype=float32, weak_type=True),
Array(-0.2537478, dtype=float32, weak_type=True)]


<h4>Quantum singular value transformation ๐Ÿ›โžก๏ธ๐Ÿฆ‹</h4>

* PennyLane now supports the [quantum singular value transformation](https://arxiv.org/abs/1806.01838) (QSVT), which describes how a quantum circuit can be constructed to apply a polynomial transformation to the singular values of an input matrix. [(#3756)](https://github.com/PennyLaneAI/pennylane/pull/3756) [(#3757)](https://github.com/PennyLaneAI/pennylane/pull/3757) [(#3758)](https://github.com/PennyLaneAI/pennylane/pull/3758) [(#3905)](https://github.com/PennyLaneAI/pennylane/pull/3905) [(#3909)](https://github.com/PennyLaneAI/pennylane/pull/3909) [(#3926)](https://github.com/PennyLaneAI/pennylane/pull/3926) [(#4023)](https://github.com/PennyLaneAI/pennylane/pull/4023)

Consider a matrix `A` along with a vector `angles` that describes the target polynomial transformation. The `qml.qsvt` function creates a corresponding circuit:

python
dev = qml.device("default.qubit", wires=2)

A = np.array([[0.1, 0.2], [0.3, 0.4]])
angles = np.array([0.1, 0.2, 0.3])

qml.qnode(dev)
def example_circuit(A):
qml.qsvt(A, angles, wires=[0, 1])
return qml.expval(qml.PauliZ(wires=0))


This circuit is composed of `qml.BlockEncode` and `qml.PCPhase` operations.

pycon
>>> example_circuit(A)
tensor(0.97777078, requires_grad=True)
>>> print(example_circuit.qtape.expand(depth=1).draw(decimals=2))
0: โ”€โ•ญโˆ_ฯ•(0.30)โ”€โ•ญBlockEncode(M0)โ”€โ•ญโˆ_ฯ•(0.20)โ”€โ•ญBlockEncode(M0)โ€ โ”€โ•ญโˆ_ฯ•(0.10)โ”€โ”ค <Z>
1: โ”€โ•ฐโˆ_ฯ•(0.30)โ”€โ•ฐBlockEncode(M0)โ”€โ•ฐโˆ_ฯ•(0.20)โ”€โ•ฐBlockEncode(M0)โ€ โ”€โ•ฐโˆ_ฯ•(0.10)โ”€โ”ค


The [qml.qsvt](https://docs.pennylane.ai/en/stable/code/api/pennylane.qsvt.html) function creates a circuit that is targeted at simulators due to the use of matrix-based operations. For advanced users, you can use the [operation-based](https://docs.pennylane.ai/en/stable/code/api/pennylane.QSVT.html) `qml.QSVT` template to perform the transformation with a custom choice of unitary and projector operations, which may be hardware compatible if a decomposition is provided.

The QSVT is a complex but powerful transformation capable of [generalizing important algorithms](https://arxiv.org/abs/2105.02859) like amplitude amplification. Stay tuned for a demo in the coming few weeks to learn more!

<h4>Intuitive QNode returns โ†ฉ๏ธ</h4>

* An updated QNode return system has been introduced. PennyLane QNodes now return exactly what you tell them to! ๐ŸŽ‰ [(3957)](https://github.com/PennyLaneAI/pennylane/pull/3957) [(#3969)](https://github.com/PennyLaneAI/pennylane/pull/3969) [(#3946)](https://github.com/PennyLaneAI/pennylane/pull/3946) [(#3913)](https://github.com/PennyLaneAI/pennylane/pull/3913) [(#3914)](https://github.com/PennyLaneAI/pennylane/pull/3914) [(#3934)](https://github.com/PennyLaneAI/pennylane/pull/3934)

This was an experimental feature introduced in version 0.25 of PennyLane that was enabled via `qml.enable_return()`. Now, it's the default return system. Let's see how it works.

Consider the following circuit:

python
import pennylane as qml

dev = qml.device("default.qubit", wires=1)

qml.qnode(dev)
def circuit(x):
qml.RX(x, wires=0)
return qml.expval(qml.PauliZ(0)), qml.probs(0)


In version 0.29 and earlier of PennyLane, `circuit()` would return a single length-3 array:

pycon
>>> circuit(0.5)
tensor([0.87758256, 0.93879128, 0.06120872], requires_grad=True)


In versions 0.30 and above, `circuit()` returns a length-2 tuple containing the expectation value and probabilities separately:

pycon
>>> circuit(0.5)
(tensor(0.87758256, requires_grad=True),
tensor([0.93879128, 0.06120872], requires_grad=True))


You can find [more details about this change](https://docs.pennylane.ai/en/stable/introduction/returns.html), along with help and troubleshooting tips to solve any issues. If you still have questions, comments, or concerns, we encourage you to post on the PennyLane [discussion forum](https://discuss.pennylane.ai).

<h4>A bunch of performance tweaks ๐Ÿƒ๐Ÿ’จ</h4>

* Single-qubit operations that have multi-qubit control can now be decomposed more efficiently using fewer CNOT gates. [(3851)](https://github.com/PennyLaneAI/pennylane/pull/3851)

Three decompositions from [arXiv:2302.06377](https://arxiv.org/abs/2302.06377) are provided and compare favourably to the already-available `qml.ops.ctrl_decomp_zyz`:

python
wires = [0, 1, 2, 3, 4, 5]
control_wires = wires[1:]

qml.qnode(qml.device('default.qubit', wires=6))
def circuit():
with qml.QueuingManager.stop_recording():
the decomposition does not un-queue the target
target = qml.RX(np.pi/2, wires=0)
qml.ops.ctrl_decomp_bisect(target, (1,2,3,4,5))
return qml.state()

print(qml.draw(circuit, expansion_strategy="device")())



0: โ”€โ”€Hโ”€โ•ญXโ”€โ”€U(M0)โ”€โ•ญXโ”€โ”€U(M0)โ€ โ”€โ•ญXโ”€โ”€U(M0)โ”€โ•ญXโ”€โ”€U(M0)โ€ โ”€โ”€Hโ”€โ”ค State
1: โ”€โ”€โ”€โ”€โ”œโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”œโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค State
2: โ”€โ”€โ”€โ”€โ”œโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”œโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค State
3: โ”€โ”€โ”€โ”€โ•ฐโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฐโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค State
4: โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”œโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”œโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค State
5: โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฐโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฐโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค State


* A new decomposition to `qml.SingleExcitation` has been added that halves the number of CNOTs required. [(3976)](https://github.com/PennyLaneAI/pennylane/pull/3976)

pycon
>>> qml.SingleExcitation.compute_decomposition(1.23, wires=(0,1))
[Adjoint(T(wires=[0])), Hadamard(wires=[0]), S(wires=[0]),
Adjoint(T(wires=[1])), Adjoint(S(wires=[1])), Hadamard(wires=[1]),
CNOT(wires=[1, 0]), RZ(-0.615, wires=[0]), RY(0.615, wires=[1]),
CNOT(wires=[1, 0]), Adjoint(S(wires=[0])), Hadamard(wires=[0]),
T(wires=[0]), Hadamard(wires=[1]), S(wires=[1]), T(wires=[1])]


* The adjoint differentiation method can now be more efficient, avoiding the decomposition of operations that can be differentiated directly. Any operation that defines a ``generator()`` can be differentiated with the adjoint method. [(3874)](https://github.com/PennyLaneAI/pennylane/pull/3874)

For example, in version 0.29 the ``qml.CRY`` operation would be decomposed when calculating the adjoint-method gradient. Executing the code below shows that this decomposition no longer takes place in version 0.30 and ``qml.CRY`` is differentiated directly:

python
import jax
from jax import numpy as jnp

def compute_decomposition(self, phi, wires):
print("A decomposition has been performed!")
decomp_ops = [
qml.RY(phi / 2, wires=wires[1]),
qml.CNOT(wires=wires),
qml.RY(-phi / 2, wires=wires[1]),
qml.CNOT(wires=wires),
]
return decomp_ops

qml.CRY.compute_decomposition = compute_decomposition

dev = qml.device("default.qubit", wires=2)

qml.qnode(dev, diff_method="adjoint")
def circuit(phi):
qml.Hadamard(wires=0)
qml.CRY(phi, wires=[0, 1])
return qml.expval(qml.PauliZ(1))

phi = jnp.array(0.5)
jax.grad(circuit)(phi)


* Derivatives are computed more efficiently when using `jax.jit` with gradient transforms; the trainable parameters are now set correctly instead of every parameter having to be set as trainable.
[(3697)](https://github.com/PennyLaneAI/pennylane/pull/3697)

In the circuit below, only the derivative with respect to parameter `b` is now calculated:

python
dev = qml.device("default.qubit", wires=2)

qml.qnode(dev, interface="jax-jit")
def circuit(a, b):
qml.RX(a, wires=0)
qml.RY(b, wires=0)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0))

a = jnp.array(0.4)
b = jnp.array(0.5)

jac = jax.jacobian(circuit, argnums=[1])
jac_jit = jax.jit(jac)

jac_jit(a, b)
assert len(circuit.tape.trainable_params) == 1


<h3>Improvements ๐Ÿ› </h3>

<h4>Next-generation device API</h4>

In this release and future releases, we will be making changes to our device API with the goal in mind to make
developing plugins much easier for developers and unlock new device capabilities. Users shouldn't yet feel any of
these changes when using PennyLane, but here is what has changed this release:

* Several functions in `devices/qubit` have been added or improved:
- `sample_state`: returns a series of samples based on a given state vector and a number of shots. [(3720)](https://github.com/PennyLaneAI/pennylane/pull/3720)
- `simulate`: supports measuring expectation values of large observables such as `qml.Hamiltonian`, `qml.SparseHamiltonian`, and `qml.Sum`. [(3759)](https://github.com/PennyLaneAI/pennylane/pull/3759)
- `apply_operation`: supports broadcasting. [(3852)](https://github.com/PennyLaneAI/pennylane/pull/3852)
- `adjoint_jacobian`: supports adjoint differentiation in the new qubit state-vector device. [(3790)](https://github.com/PennyLaneAI/pennylane/pull/3790)

* `qml.devices.qubit.preprocess` now allows circuits with non-commuting observables. [(3857)](https://github.com/PennyLaneAI/pennylane/pull/3857)

* `qml.devices.qubit.measure` now computes the expectation values of `Hamiltonian` and `Sum` in a backpropagation-compatible way. [(3862)](https://github.com/PennyLaneAI/pennylane/pull/3862/)

<h4>Pulse programming</h4>

* Here are the functions, classes, and more that were added or improved to facilitate simulating ensembles of Rydberg atoms: [(3749)](https://github.com/PennyLaneAI/pennylane/pull/3749) [(#3911)](https://github.com/PennyLaneAI/pennylane/pull/3911) [(#3930)](https://github.com/PennyLaneAI/pennylane/pull/3930) [(#3936)](https://github.com/PennyLaneAI/pennylane/pull/3936) [(#3966)](https://github.com/PennyLaneAI/pennylane/pull/3966) [(#3987)](https://github.com/PennyLaneAI/pennylane/pull/3987) [(#3889)](https://github.com/PennyLaneAI/pennylane/pull/3889) [(#4021)](https://github.com/PennyLaneAI/pennylane/pull/4021)
- `HardwareHamiltonian`: an internal class that contains additional information about pulses and settings.
- `rydberg_interaction`: a user-facing function that returns a `HardwareHamiltonian` containing the Hamiltonian of the interaction of all the Rydberg atoms.
- `transmon_interaction`: a user-facing function for constructing the Hamiltonian that describes the circuit QED interaction Hamiltonian of superconducting transmon systems.
- `drive`: a user-facing function function that returns a `ParametrizedHamiltonian` (`HardwareHamiltonian`) containing the Hamiltonian of the interaction between a driving electro-magnetic field and a group of qubits.
- `rydberg_drive`: a user-facing function that returns a `ParametrizedHamiltonian` (`HardwareHamiltonian`) containing the Hamiltonian of the interaction between a driving laser field and a group of Rydberg atoms.
- `max_distance`: a keyword argument added to `qml.pulse.rydberg_interaction` to allow for the removal of negligible contributions from atoms beyond `max_distance` from each other.

* `ParametrizedEvolution` now takes two new Boolean keyword arguments: `return_intermediate` and `complementary`. They allow computing intermediate time evolution matrices. [(3900)](https://github.com/PennyLaneAI/pennylane/pull/3900)

Activating `return_intermediate` will return intermediate time evolution steps, for example for the matrix of the Operation, or of a quantum circuit when used in a QNode. Activating `complementary` will make these intermediate steps be the _remaining_ time evolution complementary to the output for `complementary=False`. See the [docstring](https://docs.pennylane.ai/en/stable/code/api/pennylane.pulse.ParametrizedEvolution.html) for details.

* Hardware-compatible pulse sequence gradients with `qml.gradient.stoch_pulse_grad` can now be calculated faster using the new keyword argument `use_broadcasting`. Executing a `ParametrizedEvolution` that returns intermediate evolutions has increased performance using the state vector ODE solver, as well. [(4000)](https://github.com/PennyLaneAI/pennylane/pull/4000) [(#4004)](https://github.com/PennyLaneAI/pennylane/pull/4004)

<h4>Intuitive QNode returns</h4>

* The QNode keyword argument `mode` has been replaced by the boolean `grad_on_execution`. [(3969)](https://github.com/PennyLaneAI/pennylane/pull/3969)

* The `"default.gaussian"` device and parameter-shift CV both support the new return system, but only for single measurements. [(3946)](https://github.com/PennyLaneAI/pennylane/pull/3946)

* Keras and Torch NN modules are now compatible with the new return type system. [(3913)](https://github.com/PennyLaneAI/pennylane/pull/3913) [(#3914)](https://github.com/PennyLaneAI/pennylane/pull/3914)

* `DefaultQutrit` now supports the new return system. [(3934)](https://github.com/PennyLaneAI/pennylane/pull/3934)

<h4>Performance improvements</h4>

* The efficiency of `tapering()`, `tapering_hf()` and `clifford()` have been improved. [(3942)](https://github.com/PennyLaneAI/pennylane/pull/3942)

* The peak memory requirements of `tapering()` and `tapering_hf()` have been improved when used for larger observables. [(3977)](https://github.com/PennyLaneAI/pennylane/pull/3977)

* Pauli arithmetic has been updated to convert to a Hamiltonian more efficiently. [(3939)](https://github.com/PennyLaneAI/pennylane/pull/3939)

* `Operator` has a new Boolean attribute `has_generator`. It returns whether or not the `Operator` has a `generator` defined. `has_generator` is used in `qml.operation.has_gen`, which improves its performance and extends differentiation support. [(3875)](https://github.com/PennyLaneAI/pennylane/pull/3875)

* The performance of `CompositeOp` has been significantly improved now that it overrides determining whether it is being used with a batch of parameters (see `Operator._check_batching`). `Hamiltonian` also now overrides this, but it does nothing since it does not support batching. [(3915)](https://github.com/PennyLaneAI/pennylane/pull/3915)

* The performance of a `Sum` operator has been significantly improved now that `is_hermitian` checks that all coefficients are real if the operator has a pre-computed Pauli representation. [(3915)](https://github.com/PennyLaneAI/pennylane/pull/3915)

* The `coefficients` function and the `visualize` submodule of the `qml.fourier` module now allow assigning different degrees for different parameters of the input function. [(3005)](https://github.com/PennyLaneAI/pennylane/pull/3005)

Previously, the arguments `degree` and `filter_threshold` to `qml.fourier.coefficients` were expected to be integers. Now, they can be a sequences of integers with one integer per function parameter (i.e. `len(degree)==n_inputs`), resulting in a returned array with shape `(2*degrees[0]+1,..., 2*degrees[-1]+1)`. The functions in `qml.fourier.visualize` accordingly accept such arrays of coefficients.

<h4>Other improvements</h4>

* A `Shots` class has been added to the `measurements` module to hold shot-related data. [(3682)](https://github.com/PennyLaneAI/pennylane/pull/3682)

* The custom JVP rules in PennyLane also now support non-scalar and mixed-shape tape parameters as well as multi-dimensional tape return types, like broadcasted `qml.probs`, for example. [(3766)](https://github.com/PennyLaneAI/pennylane/pull/3766)

* The `qchem.jordan_wigner` function has been extended to support more fermionic operator orders. [(3754)](https://github.com/PennyLaneAI/pennylane/pull/3754) [(#3751)](https://github.com/PennyLaneAI/pennylane/pull/3751)

* The `AdaptiveOptimizer` has been updated to use non-default user-defined QNode arguments. [(3765)](https://github.com/PennyLaneAI/pennylane/pull/3765)

* Operators now use `TensorLike` types dunder methods. [(3749)](https://github.com/PennyLaneAI/pennylane/pull/3749)

* `qml.QubitStateVector.state_vector` now supports broadcasting. [(3852)](https://github.com/PennyLaneAI/pennylane/pull/3852)

* `qml.SparseHamiltonian` can now be applied to any wires in a circuit rather than being restricted to all wires in the circuit. [(3888)](https://github.com/PennyLaneAI/pennylane/pull/3888)

* Operators can now be divided by scalars with `/` with the addition of the `Operation.__truediv__` dunder method. [(3749)](https://github.com/PennyLaneAI/pennylane/pull/3749)

* Printing an instance of `MutualInfoMP` now displays the distribution of the wires between the two subsystems. [(3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* `Operator.num_wires` has been changed from an abstract value to `AnyWires`. [(3919)](https://github.com/PennyLaneAI/pennylane/pull/3919)

* `qml.transforms.sum_expand` is not run in `Device.batch_transform` if the device supports `Sum` observables. [(3915)](https://github.com/PennyLaneAI/pennylane/pull/3915)

* The type of `n_electrons` in `qml.qchem.Molecule` has been set to `int`. [(3885)](https://github.com/PennyLaneAI/pennylane/pull/3885)

* Explicit errors have been added to `QutritDevice` if `classical_shadow` or `shadow_expval` is measured. [(3934)](https://github.com/PennyLaneAI/pennylane/pull/3934)

* `QubitDevice` now defines the private `_get_diagonalizing_gates(circuit)` method and uses it when executing circuits. This allows devices that inherit from `QubitDevice` to override and customize their definition of diagonalizing gates. [(3938)](https://github.com/PennyLaneAI/pennylane/pull/3938)

* `retworkx` has been renamed to `rustworkx` to accommodate the change in the package name. [(3975)](https://github.com/PennyLaneAI/pennylane/pull/3975)

* `Exp`, `Sum`, `Prod`, and `SProd` operator data is now a flat list instead of nested. [(3958)](https://github.com/PennyLaneAI/pennylane/pull/3958) [(#3983)](https://github.com/PennyLaneAI/pennylane/pull/3983)

* `qml.transforms.convert_to_numpy_parameters` has been added to convert a circuit with interface-specific parameters to one with only numpy parameters. This transform is designed to replace `qml.tape.Unwrap`. [(3899)](https://github.com/PennyLaneAI/pennylane/pull/3899)

* `qml.operation.WiresEnum.AllWires` is now -2 instead of 0 to avoid the ambiguity between `op.num_wires = 0` and `op.num_wires = AllWires`. [(3978)](https://github.com/PennyLaneAI/pennylane/pull/3978)

* Execution code has been updated to use the new `qml.transforms.convert_to_numpy_parameters` instead of `qml.tape.Unwrap`. [(3989)](https://github.com/PennyLaneAI/pennylane/pull/3989)

* A sub-routine of `expand_tape` has been converted into `qml.tape.tape.rotations_and_diagonal_measurements`, a helper function that computes rotations and diagonal measurements for a tape with measurements with overlapping wires. [(3912)](https://github.com/PennyLaneAI/pennylane/pull/3912)

* Various operators and templates have been updated to ensure that their decompositions only return lists of operators. [(3243)](https://github.com/PennyLaneAI/pennylane/pull/3243)

* The `qml.operation.enable_new_opmath` toggle has been introduced to cause dunder methods to return arithmetic operators instead of a `Hamiltonian` or `Tensor`. [(4008)](https://github.com/PennyLaneAI/pennylane/pull/4008)

pycon
>>> type(qml.PauliX(0) qml.PauliZ(1))
<class 'pennylane.operation.Tensor'>
>>> qml.operation.enable_new_opmath()
>>> type(qml.PauliX(0) qml.PauliZ(1))
<class 'pennylane.ops.op_math.prod.Prod'>
>>> qml.operation.disable_new_opmath()
>>> type(qml.PauliX(0) qml.PauliZ(1))
<class 'pennylane.operation.Tensor'>


* A new data class called `Resources` has been added to store resources like the number of gates and circuit depth throughout a quantum circuit. [(3981)](https://github.com/PennyLaneAI/pennylane/pull/3981/)

* A new function called `_count_resources()` has been added to count the resources required when executing a `QuantumTape` for a given number of shots. [(3996)](https://github.com/PennyLaneAI/pennylane/pull/3996)

* `QuantumScript.specs` has been modified to make use of the new `Resources` class. This also modifies the output of `qml.specs()`. [(4015)](https://github.com/PennyLaneAI/pennylane/pull/4015)

* A new class called `ResourcesOperation` has been added to allow users to define operations with custom resource information. [(4026)](https://github.com/PennyLaneAI/pennylane/pull/4026)

For example, users can define a custom operation by inheriting from this new class:

pycon
>>> class CustomOp(qml.resource.ResourcesOperation):
... def resources(self):
... return qml.resource.Resources(num_wires=1, num_gates=2,
... gate_types={"PauliX": 2})
...
>>> CustomOp(wires=1)
CustomOp(wires=[1])


Then, we can track and display the resources of the workflow using `qml.specs()`:

pycon
>>> dev = qml.device("default.qubit", wires=[0,1])
>>> qml.qnode(dev)
... def circ():
... qml.PauliZ(wires=0)
... CustomOp(wires=1)
... return qml.state()
...
>>> print(qml.specs(circ)()['resources'])
wires: 2
gates: 3
depth: 1
shots: 0
gate_types:
{'PauliZ': 1, 'PauliX': 2}


* `MeasurementProcess.shape` now accepts a `Shots` object as one of its arguments to reduce exposure to unnecessary execution details. [(4012)](https://github.com/PennyLaneAI/pennylane/pull/4012)

<h3>Breaking changes ๐Ÿ’”</h3>

* The `seed_recipes` argument has been removed from `qml.classical_shadow` and `qml.shadow_expval`. [(4020)](https://github.com/PennyLaneAI/pennylane/pull/4020)

* The tape method `get_operation` has an updated signature. [(3998)](https://github.com/PennyLaneAI/pennylane/pull/3998)

* Both JIT interfaces are no longer compatible with JAX `>0.4.3` (we raise an error for those versions). [(3877)](https://github.com/PennyLaneAI/pennylane/pull/3877)

* An operation that implements a custom `generator` method, but does not always return a valid generator, also has to implement a `has_generator` property that reflects in which scenarios a generator will be returned. [(3875)](https://github.com/PennyLaneAI/pennylane/pull/3875)

* Trainable parameters for the Jax interface are the parameters that are `JVPTracer`, defined by setting `argnums`. Previously, all JAX tracers, including those used for JIT compilation, were interpreted to be trainable. [(3697)](https://github.com/PennyLaneAI/pennylane/pull/3697)

* The keyword argument `argnums` is now used for gradient transforms using Jax instead of `argnum`. `argnum` is automatically converted to `argnums` when using Jax and will no longer be supported in v0.31 of PennyLane. [(3697)](https://github.com/PennyLaneAI/pennylane/pull/3697) [(#3847)](https://github.com/PennyLaneAI/pennylane/pull/3847)

* `qml.OrbitalRotation` and, consequently, `qml.GateFabric` are now more consistent with the interleaved Jordan-Wigner ordering. Previously, they were consistent with the sequential Jordan-Wigner ordering. [(3861)](https://github.com/PennyLaneAI/pennylane/pull/3861)

* Some `MeasurementProcess` classes can now only be instantiated with arguments that they will actually use. For example, you can no longer create `StateMP(qml.PauliX(0))` or `PurityMP(eigvals=(-1,1), wires=Wires(0))`. [(3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* `Exp`, `Sum`, `Prod`, and `SProd` operator data is now a flat list, instead of nested. [(3958)](https://github.com/PennyLaneAI/pennylane/pull/3958) [(#3983)](https://github.com/PennyLaneAI/pennylane/pull/3983)

* `qml.tape.tape.expand_tape` and, consequentially, `QuantumScript.expand` no longer update the input tape with rotations and diagonal measurements. Note that the newly expanded tape that is returned will still have the rotations and diagonal measurements. [(3912)](https://github.com/PennyLaneAI/pennylane/pull/3912)

* `qml.Evolution` now initializes the coefficient with a factor of `-1j` instead of `1j`. [(4024)](https://github.com/PennyLaneAI/pennylane/pull/4024)

<h3>Deprecations ๐Ÿ‘‹</h3>

Nothing for this release!

<h3>Documentation ๐Ÿ“</h3>

* The documentation of `QubitUnitary` and `DiagonalQubitUnitary` was clarified regarding the parameters of the operations. [(4031)](https://github.com/PennyLaneAI/pennylane/pull/4031)

* A typo has been corrected in the documentation for the introduction to `inspecting_circuits` and `chemistry`. [(3844)](https://github.com/PennyLaneAI/pennylane/pull/3844)

* `Usage Details` and `Theory` sections have been separated in the documentation for `qml.qchem.taper_operation`. [(3977)](https://github.com/PennyLaneAI/pennylane/pull/3977)

<h3>Bug fixes ๐Ÿ›</h3>

* `ctrl_decomp_bisect` and `ctrl_decomp_zyz` are no longer used by default when decomposing controlled operations due to the presence of a global phase difference in the zyz decomposition of some target operators.

* Fixed a bug where `qml.math.dot` returned a numpy array instead of an autograd array, breaking autograd derivatives in certain circumstances. [(4019)](https://github.com/PennyLaneAI/pennylane/pull/4019)

* Operators now cast a `tuple` to an `np.ndarray` as well as `list`. [(4022)](https://github.com/PennyLaneAI/pennylane/pull/4022)

* Fixed a bug where `qml.ctrl` with parametric gates was incompatible with PyTorch tensors on GPUs. [(4002)](https://github.com/PennyLaneAI/pennylane/pull/4002)

* Fixed a bug where the broadcast expand results were stacked along the wrong axis for the new return system. [(3984)](https://github.com/PennyLaneAI/pennylane/pull/3984)

* A more informative error message is raised in `qml.jacobian` to explain potential problems with the new return types specification. [(3997)](https://github.com/PennyLaneAI/pennylane/pull/3997)

* Fixed a bug where calling `Evolution.generator` with `coeff` being a complex ArrayBox raised an error. [(3796)](https://github.com/PennyLaneAI/pennylane/pull/3796)

* `MeasurementProcess.hash` now uses the hash property of the observable. The property now depends on all properties that affect the behaviour of the object, such as `VnEntropyMP.log_base` or the distribution of wires between the two subsystems in `MutualInfoMP`. [(3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* The enum `measurements.Purity` has been added so that `PurityMP.return_type` is defined. `str` and `repr` for `PurityMP` are also now defined. [(3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* `Sum.hash` and `Prod.hash` have been changed slightly to work with non-numeric wire labels. `sum_expand` should now return correct results and not treat some products as the same operation. [(3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* Fixed bug where the coefficients where not ordered correctly when summing a `ParametrizedHamiltonian` with other operators. [(3749)](https://github.com/PennyLaneAI/pennylane/pull/3749) [(#3902)](https://github.com/PennyLaneAI/pennylane/pull/3902)

* The metric tensor transform is now fully compatible with Jax and therefore users can provide multiple parameters. [(3847)](https://github.com/PennyLaneAI/pennylane/pull/3847)

* `qml.math.ndim` and `qml.math.shape` are now registered for built-ins and autograd to accomodate Autoray 0.6.1. [3864](https://github.com/PennyLaneAI/pennylane/pull/3865)

* Ensured that `qml.data.load` returns datasets in a stable and expected order. [(3856)](https://github.com/PennyLaneAI/pennylane/pull/3856)

* The `qml.equal` function now handles comparisons of `ParametrizedEvolution` operators. [(3870)](https://github.com/PennyLaneAI/pennylane/pull/3870)

* `qml.devices.qubit.apply_operation` catches the `tf.errors.UnimplementedError` that occurs when `PauliZ` or `CNOT` gates are applied to a large (>8 wires) tensorflow state. When that occurs, the logic falls back to the tensordot logic instead. [(3884)](https://github.com/PennyLaneAI/pennylane/pull/3884/)

* Fixed parameter broadcasting support with `qml.counts` in most cases and introduced explicit errors otherwise. [(3876)](https://github.com/PennyLaneAI/pennylane/pull/3876)

* An error is now raised if a QNode with Jax-jit in use returns `counts` while having trainable parameters [(3892)](https://github.com/PennyLaneAI/pennylane/pull/3892)

* A correction has been added to the reference values in `test_dipole_of` to account for small changes (~`2e-8`) in the computed dipole moment values resulting from the new [PySCF 2.2.0](https://github.com/pyscf/pyscf/releases/tag/v2.2.0) release. [(#3908)](https://github.com/PennyLaneAI/pennylane/pull/3908)

* `SampleMP.shape` is now correct when sampling only occurs on a subset of the device wires. [(3921)](https://github.com/PennyLaneAI/pennylane/pull/3921)

* An issue has been fixed in `qchem.Molecule` to allow basis sets other than the hard-coded ones to be used in the `Molecule` class. [(3955)](https://github.com/PennyLaneAI/pennylane/pull/3955)

* Fixed bug where all devices that inherit from `DefaultQubit` claimed to support `ParametrizedEvolution`. Now, only `DefaultQubitJax` supports the operator, as expected. [(3964)](https://github.com/PennyLaneAI/pennylane/pull/3964)

* Ensured that parallel `AnnotatedQueues` do not queue each other's contents. [(3924)](https://github.com/PennyLaneAI/pennylane/pull/3924)

* Added a `map_wires` method to `PauliWord` and `PauliSentence`, and ensured that operators call it in their respective `map_wires` methods if they have a Pauli rep. [(3985)](https://github.com/PennyLaneAI/pennylane/pull/3985)

* Fixed a bug when a `Tensor` is multiplied by a `Hamiltonian` or vice versa. [(4036)](https://github.com/PennyLaneAI/pennylane/pull/4036)

<h3>Contributors โœ๏ธ</h3>

This release contains contributions from (in alphabetical order):

Komi Amiko,
Utkarsh Azad,
Thomas Bromley,
Isaac De Vlugt,
Olivia Di Matteo,
Lillian M. A. Frederiksen,
Diego Guala,
Soran Jahangiri,
Korbinian Kottmann,
Christina Lee,
Vincent Michaud-Rioux,
Albert Mitjans Coma,
Romain Moyard,
Lee J. O'Riordan,
Mudit Pandey,
Matthew Silverman,
Jay Soni,
David Wierichs.

0.29.1

<h3>Bug fixes</h3>

* Defines `qml.math.ndim` and `qml.math.shape` for builtins and autograd. Accommodates changes made by Autograd v0.6.1.

<h3>Contributors</h3>

This release contains contributions from (in alphabetical order):

Christina Lee

0.29.0

<h3>New features since last release</h3>

<h4>Pulse programming ๐Ÿ”Š</h4>

* Support for creating pulse-based circuits that describe evolution under a time-dependent Hamiltonian has now been added, as well as the ability to execute and differentiate these pulse-based circuits on simulator.
[(3586)](https://github.com/PennyLaneAI/pennylane/pull/3586)[(#3617)](https://github.com/PennyLaneAI/pennylane/pull/3617)[(#3645)](https://github.com/PennyLaneAI/pennylane/pull/3645)[(#3652)](https://github.com/PennyLaneAI/pennylane/pull/3652)[(#3665)](https://github.com/PennyLaneAI/pennylane/pull/3665)[(#3673)](https://github.com/PennyLaneAI/pennylane/pull/3673)[(#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.pulse.ParametrizedHamiltonian`, which holds information representing a linear combination of operators with parametrized coefficents and can be constructed as follows:

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(0) qml.PauliX(1)
YY = qml.PauliY(0) qml.PauliY(1)
ZZ = qml.PauliZ(0) qml.PauliZ(1)

H = 2 * ZZ + f1 * XX + f2 * YY


pycon
>>> H
ParametrizedHamiltonian: terms=3
>>> p1 = jnp.array(1.2)
>>> p2 = jnp.array([2.3, 3.4])
>>> H((p1, p2), t=0.5)
(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.evolve(H)(params, time)
return qml.expval(qml.PauliX(0) qml.PauliY(1))


Pulse-based circuits can be executed and differentiated on the `default.qubit.jax` simulator using JAX as an interface:

pycon
>>> dev = qml.device("default.qubit.jax", wires=2)
>>> qnode = qml.QNode(pulse_circuit, dev, interface="jax")
>>> params = (p1, p2)
>>> qnode(params, time=0.5)
Array(0.72153819, dtype=float64)
>>> jax.grad(qnode)(params, time=0.5)
(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 page for more details!

<h4>Special unitary operation ๐ŸŒž</h4>

* A new operation `qml.SpecialUnitary` has been 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)

`qml.SpecialUnitary` creates a unitary that exponentiates a linear combination of all possible Pauli words in lexicographical order โ€” except for the identity operator โ€” for `num_wires` wires, of which there are `4**num_wires - 1`. As its first argument, `qml.SpecialUnitary` takes a list of the `4**num_wires - 1` parameters that are the coefficients of the linear combination.

To see all possible Pauli words for `num_wires` wires, you can use the `qml.ops.qubit.special_unitary.pauli_basis_strings` function:

pycon
>>> qml.ops.qubit.special_unitary.pauli_basis_strings(1) 4**1-1 = 3 Pauli words
['X', 'Y', 'Z']
>>> qml.ops.qubit.special_unitary.pauli_basis_strings(2) 4**2-1 = 15 Pauli words
['IX', 'IY', 'IZ', 'XI', 'XX', 'XY', 'XZ', 'YI', 'YX', 'YY', 'YZ', 'ZI', 'ZX', 'ZY', 'ZZ']


To use `qml.SpecialUnitary`, for example, on a single qubit, we may define

pycon
>>> thetas = np.array([0.2, 0.1, -0.5])
>>> U = qml.SpecialUnitary(thetas, 0)
>>> qml.matrix(U)
array([[ 0.8537127 -0.47537233j, 0.09507447+0.19014893j],
[-0.09507447+0.19014893j, 0.8537127 +0.47537233j]])


A single non-zero entry in the parameters will create a Pauli rotation:

pycon
>>> x = 0.412
>>> theta = x * np.array([1, 0, 0]) The first entry belongs to the Pauli word "X"
>>> su = qml.SpecialUnitary(theta, wires=0)
>>> rx = qml.RX(-2 * x, 0) RX introduces a prefactor -0.5 that has to be compensated
>>> qml.math.allclose(qml.matrix(su), qml.matrix(rx))
True


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. Learn more by visiting the [qml.SpecialUnitary](https://docs.pennylane.ai/en/stable/code/api/pennylane.SpecialUnitary.html) documentation.

<h4>Always differentiable ๐Ÿ“ˆ</h4>

* The Hadamard test gradient transform is now available via `qml.gradients.hadamard_grad`. This transform is also available as a differentiation method within `QNode`s. [(3625)](https://github.com/PennyLaneAI/pennylane/pull/3625) [(#3736)](https://github.com/PennyLaneAI/pennylane/pull/3736)

`qml.gradients.hadamard_grad` is a hardware-compatible transform that calculates the gradient of a quantum circuit using the Hadamard test. Note that the device requires an auxiliary wire to calculate the gradient.

pycon
>>> dev = qml.device("default.qubit", wires=2)
>>> qml.qnode(dev)
... def circuit(params):
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... return qml.expval(qml.PauliZ(0))
>>> params = np.array([0.1, 0.2, 0.3], requires_grad=True)
>>> qml.gradients.hadamard_grad(circuit)(params)
(tensor(-0.3875172, requires_grad=True),
tensor(-0.18884787, requires_grad=True),
tensor(-0.38355704, requires_grad=True))


This transform can be registered directly as the quantum gradient transform to use during autodifferentiation:

pycon
>>> dev = qml.device("default.qubit", wires=2)
>>> qml.qnode(dev, interface="jax", diff_method="hadamard")
... def circuit(params):
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... return qml.expval(qml.PauliZ(0))
>>> params = jax.numpy.array([0.1, 0.2, 0.3])
>>> jax.jacobian(circuit)(params)
Array([-0.3875172 , -0.18884787, -0.38355705], dtype=float32)


* The gradient transform `qml.gradients.spsa_grad` is now registered as a differentiation method for QNodes.
[(3440)](https://github.com/PennyLaneAI/pennylane/pull/3440)

The SPSA gradient transform can now be used implicitly by marking a QNode as differentiable with SPSA. It can be selected via

pycon
>>> 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)
... return qml.expval(qml.PauliZ(0))
>>> jax.jacobian(circuit)(jax.numpy.array(0.5))
Array(-0.4792258, dtype=float32, weak_type=True)


The argument `num_directions` determines how many directions of simultaneous perturbation are used and therefore the number of circuit evaluations, up to a prefactor. See the [SPSA gradient transform documentation](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.spsa_grad.html) for details. Note: The full SPSA optimization method is already available as `qml.SPSAOptimizer`.

* The default interface is now `auto`. There is no need to specify the interface anymore; it is automatically determined by checking your QNode parameters.
[(3677)](https://github.com/PennyLaneAI/pennylane/pull/3677)[(#3752)](https://github.com/PennyLaneAI/pennylane/pull/3752) [(#3829)](https://github.com/PennyLaneAI/pennylane/pull/3829)

python
import jax
import jax.numpy as jnp

qml.enable_return()
a = jnp.array(0.1)
b = jnp.array(0.2)

dev = qml.device("default.qubit", wires=2)

qml.qnode(dev)
def circuit(a, b):
qml.RY(a, wires=0)
qml.RX(b, wires=1)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliY(1))


pycon
>>> circuit(a, b)
(Array(0.9950042, dtype=float32), Array(-0.19767681, dtype=float32))
>>> jac = jax.jacobian(circuit)(a, b)
>>> jac
(Array(-0.09983341, dtype=float32, weak_type=True), Array(0.01983384, dtype=float32, weak_type=True))


* The JAX-JIT interface now supports higher-order gradient computation with the new return types system.
[(3498)](https://github.com/PennyLaneAI/pennylane/pull/3498)

Here is an example of using JAX-JIT to compute the Hessian of a circuit:

python
import pennylane as qml
import jax
from jax import numpy as jnp

jax.config.update("jax_enable_x64", True)

qml.enable_return()

dev = qml.device("default.qubit", wires=2)

jax.jit
qml.qnode(dev, interface="jax-jit", diff_method="parameter-shift", max_diff=2)
def circuit(a, b):
qml.RY(a, wires=0)
qml.RX(b, wires=1)
return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

a, b = jnp.array(1.0), jnp.array(2.0)


pycon
>>> jax.hessian(circuit, argnums=[0, 1])(a, b)
(((Array(-0.54030231, dtype=float64, weak_type=True),
Array(0., dtype=float64, weak_type=True)),
(Array(-1.76002563e-17, dtype=float64, weak_type=True),
Array(0., dtype=float64, weak_type=True))),
((Array(0., dtype=float64, weak_type=True),
Array(-1.00700085e-17, dtype=float64, weak_type=True)),
(Array(0., dtype=float64, weak_type=True),
Array(0.41614684, dtype=float64, weak_type=True))))


* The `qchem` workflow has been modified to support both Autograd and JAX frameworks.
[(3458)](https://github.com/PennyLaneAI/pennylane/pull/3458) [(#3462)](https://github.com/PennyLaneAI/pennylane/pull/3462) [(#3495)](https://github.com/PennyLaneAI/pennylane/pull/3495)

The JAX interface is automatically used when the differentiable parameters are JAX objects. Here is an example for computing the Hartree-Fock energy gradients with respect to the atomic coordinates.

python
import pennylane as qml
from pennylane import numpy as np
import jax

symbols = ["H", "H"]
geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]])

mol = qml.qchem.Molecule(symbols, geometry)

args = [jax.numpy.array(mol.coordinates)]


pycon
>>> jax.grad(qml.qchem.hf_energy(mol))(*args)
Array([[ 0. , 0. , 0.3650435],
[ 0. , 0. , -0.3650435]], dtype=float64)


* 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.
[(3742)](https://github.com/PennyLaneAI/pennylane/pull/3742)

This allows for the following:

python
dev = qml.device('default.qubit', wires=2, shots=(100, 100))
qml.qnode(dev)
def circuit(x1, x2):
qml.templates.AngleEmbedding(x1, wires=dev.wires)
qml.adjoint(qml.templates.AngleEmbedding)(x2, wires=dev.wires)
return qml.probs(wires=dev.wires)

kernel = lambda x1, x2: circuit(x1, x2)


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

pycon
>>> X = np.random.random((4, 2))
>>> qml.kernels.square_kernel_matrix(X, kernel)[:, 0]
tensor([[[1. , 0.86, 0.88, 0.92],
[0.86, 1. , 0.75, 0.97],
[0.88, 0.75, 1. , 0.91],
[0.92, 0.97, 0.91, 1. ]],
[[1. , 0.93, 0.91, 0.92],
[0.93, 1. , 0.8 , 1. ],
[0.91, 0.8 , 1. , 0.91],
[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.
[(3691)](https://github.com/PennyLaneAI/pennylane/pull/3691) [(#3777)](https://github.com/PennyLaneAI/pennylane/pull/3777)

If the time-evolved Hamiltonian is equivalent to another PennyLane operation, then that operation is returned as the decomposition:

pycon
>>> exp_op = qml.evolve(qml.PauliX(0) qml.PauliX(1))
>>> exp_op.decomposition()
[IsingXX((2+0j), wires=[0, 1])]


If the Hamiltonian is a Pauli word, then the decomposition is provided as a `qml.PauliRot` operation:

pycon
>>> qml.evolve(qml.PauliZ(0) qml.PauliX(1)).decomposition()
[PauliRot((2+0j), ZX, wires=[0, 1])]


Otherwise, the Hamiltonian is a linear combination of operators and the Suzuki-Trotter decomposition is used:

pycon
>>> qml.evolve(qml.sum(qml.PauliX(0), qml.PauliY(0), qml.PauliZ(0)), num_steps=2).decomposition()
[RX((1+0j), wires=[0]),
RY((1+0j), wires=[0]),
RZ((1+0j), wires=[0]),
RX((1+0j), wires=[0]),
RY((1+0j), wires=[0]),
RZ((1+0j), wires=[0])]


<h4>Tools for quantum chemistry and other applications ๐Ÿ› ๏ธ</h4>

* A new method called `qml.qchem.givens_decomposition` has been added, which decomposes a unitary into a sequence of Givens rotation gates with phase shifts and a diagonal phase matrix.
[(3573)](https://github.com/PennyLaneAI/pennylane/pull/3573)

python
unitary = np.array([[ 0.73678+0.27511j, -0.5095 +0.10704j, -0.06847+0.32515j],
[-0.21271+0.34938j, -0.38853+0.36497j, 0.61467-0.41317j],
[ 0.41356-0.20765j, -0.00651-0.66689j, 0.32839-0.48293j]])

phase_mat, ordered_rotations = qml.qchem.givens_decomposition(unitary)


pycon
>>> phase_mat
tensor([-0.20604358+0.9785369j , -0.82993272+0.55786114j,
0.56230612-0.82692833j], requires_grad=True)
>>> ordered_rotations
[(tensor([[-0.65087861-0.63937521j, -0.40933651-0.j ],
[-0.29201359-0.28685265j, 0.91238348-0.j ]], requires_grad=True),
(0, 1)),
(tensor([[ 0.47970366-0.33308926j, -0.8117487 -0.j ],
[ 0.66677093-0.46298215j, 0.5840069 -0.j ]], requires_grad=True),
(1, 2)),
(tensor([[ 0.36147547+0.73779454j, -0.57008306-0.j ],
[ 0.2508207 +0.51194108j, 0.82158706-0.j ]], requires_grad=True),
(0, 1))]


* A new template called `qml.BasisRotation` has been added, which performs a basis transformation defined by a set of fermionic ladder operators.
[(3573)](https://github.com/PennyLaneAI/pennylane/pull/3573)

python
import pennylane as qml
from pennylane import numpy as np

V = np.array([[ 0.53672126+0.j , -0.1126064 -2.41479668j],
[-0.1126064 +2.41479668j, 1.48694623+0.j ]])
eigen_vals, eigen_vecs = np.linalg.eigh(V)
umat = eigen_vecs.T
wires = range(len(umat))
def circuit():
qml.adjoint(qml.BasisRotation(wires=wires, unitary_matrix=umat))
for idx, eigenval in enumerate(eigen_vals):
qml.RZ(eigenval, wires=[idx])
qml.BasisRotation(wires=wires, unitary_matrix=umat)


pycon
>>> circ_unitary = qml.matrix(circuit)()
>>> np.round(circ_unitary/circ_unitary[0][0], 3)
tensor([[ 1. -0.j , -0. +0.j , -0. +0.j , -0. +0.j ],
[-0. +0.j , -0.516-0.596j, -0.302-0.536j, -0. +0.j ],
[-0. +0.j , 0.35 +0.506j, -0.311-0.724j, -0. +0.j ],
[-0. +0.j , -0. +0.j , -0. +0.j , -0.438+0.899j]], requires_grad=True)


* 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.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 described in [arXiv:1905.05118](https://arxiv.org/abs/1905.05118).
[(3447)](https://github.com/PennyLaneAI/pennylane/pull/3447)

python3
dev = qml.device('default.qubit', wires=5)
weights = np.random.random(size=qml.templates.TwoLocalSwapNetwork.shape(len(dev.wires)))
acquaintances = lambda index, wires, param: (qml.CRY(param, wires=index)
if np.abs(wires[0]-wires[1]) else qml.CRZ(param, wires=index))
qml.qnode(dev)
def swap_network_circuit():
qml.templates.TwoLocalSwapNetwork(dev.wires, acquaintances, weights, fermionic=False)
return qml.state()


pycon
>>> print(weights)
tensor([0.20308242, 0.91906199, 0.67988804, 0.81290256, 0.08708985,
0.81860084, 0.34448344, 0.05655892, 0.61781612, 0.51829044], requires_grad=True)
>>> print(qml.draw(swap_network_circuit, expansion_strategy = 'device')())
0: โ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ”ค State
1: โ”€โ•ฐRY(0.20)โ”€โ•ฐSWAPโ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ•ฐRY(0.09)โ”€โ•ฐSWAPโ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ•ฐRY(0.62)โ”€โ•ฐSWAPโ”€โ”ค State
2: โ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ•ฐRY(0.68)โ”€โ•ฐSWAPโ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ•ฐRY(0.34)โ”€โ•ฐSWAPโ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ”ค State
3: โ”€โ•ฐRY(0.92)โ”€โ•ฐSWAPโ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ•ฐRY(0.82)โ”€โ•ฐSWAPโ”€โ•ญโ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ญSWAPโ”€โ•ฐRY(0.52)โ”€โ•ฐSWAPโ”€โ”ค State
4: โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฐRY(0.81)โ”€โ•ฐSWAPโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฐRY(0.06)โ”€โ•ฐSWAPโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค State


<h3>Improvements ๐Ÿ› </h3>

<h4>Pulse programming</h4>

* 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.
[(3645)](https://github.com/PennyLaneAI/pennylane/pull/3645)

pycon
>>> timespan = (2, 4)
>>> f = qml.pulse.pwc(timespan)
>>> f * qml.PauliX(0)
ParametrizedHamiltonian: terms=1


The `params` array will be used as bin values evenly distributed over the timespan, and the parameter `t` will determine which of the bins is returned.

pycon
>>> f(params=[1.2, 2.3, 3.4, 4.5], t=3.9)
DeviceArray(4.5, dtype=float32)
>>> f(params=[1.2, 2.3, 3.4, 4.5], t=6) zero outside the range (2, 4)
DeviceArray(0., dtype=float32)


* 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)

pycon
>>> qml.pulse.pwc_from_function((2, 4), num_bins=10)
... def f1(p, t):
... return p * t


The resulting function approximates the same of `p**2 * t` on the interval `t=(2, 4)` in 10 bins, and returns zero outside the interval.

pycon
t=2 and t=2.1 are within the same bin
>>> f1(3, 2), f1(3, 2.1)
(DeviceArray(6., dtype=float32), DeviceArray(6., dtype=float32))
next bin
>>> f1(3, 2.2)
DeviceArray(6.6666665, dtype=float32)
outside the interval t=(2, 4)
>>> f1(3, 5)
DeviceArray(0., dtype=float32)


* Add `ParametrizedHamiltonianPytree` class, which is a pytree jax object representing a parametrized Hamiltonian, where the matrix computation is delayed to improve performance.
[(3779)](https://github.com/PennyLaneAI/pennylane/pull/3779)

<h4>Operations and batching</h4>

* 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
>>> coeffs = np.array([1.1, 2.2])
>>> ops = [qml.PauliX(0), qml.PauliY(0)]
>>> qml.dot(coeffs, ops)
(1.1*(PauliX(wires=[0]))) + (2.2*(PauliY(wires=[0])))
>>> qml.dot(coeffs, ops, pauli=True)
1.1 * X(0) + 2.2 * Y(0)


* `qml.evolve` returns the evolution of an `Operator` or a `ParametrizedHamiltonian`.
[(3617)](https://github.com/PennyLaneAI/pennylane/pull/3617) [(#3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)

* `qml.ControlledQubitUnitary` now inherits from `qml.ops.op_math.ControlledOp`, which defines `decomposition`, `expand`, and `sparse_matrix` rather than raising an error.
[(3450)](https://github.com/PennyLaneAI/pennylane/pull/3450)

* Parameter broadcasting support has been added for the `qml.ops.op_math.Controlled` class if the base operator supports broadcasting.
[(3450)](https://github.com/PennyLaneAI/pennylane/pull/3450)

* The `qml.generator` function now checks if the generator is Hermitian, rather than whether it is a subclass of `Observable`. This allows it to return valid generators from `SymbolicOp` and `CompositeOp` classes.
[(3485)](https://github.com/PennyLaneAI/pennylane/pull/3485)

* The `qml.equal` function has been extended to compare `Prod` and `Sum` operators.
[(3516)](https://github.com/PennyLaneAI/pennylane/pull/3516)

* `qml.purity` has been added as a measurement process for purity
[(3551)](https://github.com/PennyLaneAI/pennylane/pull/3551)

* In-place inversion has been removed for qutrit operations in preparation for the removal of in-place inversion.
[(3566)](https://github.com/PennyLaneAI/pennylane/pull/3566)

* 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.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)

* Batching is now allowed in all `SymbolicOp` operators, which include `Exp`, `Pow` and `SProd`.
[(3597)](https://github.com/PennyLaneAI/pennylane/pull/3597)

* The `Sum` and `Prod` operations now have broadcasted operands.
[(3611)](https://github.com/PennyLaneAI/pennylane/pull/3611)

* The XYX single-qubit unitary decomposition has been implemented.
[(3628)](https://github.com/PennyLaneAI/pennylane/pull/3628)

* All dunder methods now return `NotImplemented`, allowing the right dunder method (e.g. `__radd__`) of the other class to be called.
[(3631)](https://github.com/PennyLaneAI/pennylane/pull/3631)

* The `qml.GellMann` operators now include their index when displayed.
[(3641)](https://github.com/PennyLaneAI/pennylane/pull/3641)

* `qml.ops.ctrl_decomp_zyz` has been added to compute the decomposition of a controlled single-qubit operation given a single-qubit operation and the control wires.
[(3681)](https://github.com/PennyLaneAI/pennylane/pull/3681)

* `qml.pauli.is_pauli_word` now supports `Prod` and `SProd` operators, and it returns `False` when a `Hamiltonian` contains more than one term.
[(3692)](https://github.com/PennyLaneAI/pennylane/pull/3692)

* `qml.pauli.pauli_word_to_string` now supports `Prod`, `SProd` and `Hamiltonian` operators.
[(3692)](https://github.com/PennyLaneAI/pennylane/pull/3692)

* `qml.ops.op_math.Controlled` can now decompose single qubit target operations more effectively using the ZYZ decomposition.
[(3726)](https://github.com/PennyLaneAI/pennylane/pull/3726)

* The `qml.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)

* `qml.qchem.basis_rotation` now accounts for spin, allowing it to perform Basis Rotation Groupings for molecular hamiltonians.
[(3714)](https://github.com/PennyLaneAI/pennylane/pull/3714)[(#3774)](https://github.com/PennyLaneAI/pennylane/pull/3774)

* The gradient transforms work for the new return type system with non-trivial classical jacobians.
[(3776)](https://github.com/PennyLaneAI/pennylane/pull/3776)

* The `default.mixed` device has received a performance improvement for multi-qubit operations. This also allows to apply channels that act on more than seven qubits, which was not possible before.
[(3584)](https://github.com/PennyLaneAI/pennylane/pull/3584)

* `qml.dot` now groups coefficients together.
[(3691)](https://github.com/PennyLaneAI/pennylane/pull/3691)

pycon
>>> qml.dot(coeffs=[2, 2, 2], ops=[qml.PauliX(0), qml.PauliY(1), qml.PauliZ(2)])
2*(PauliX(wires=[0]) + PauliY(wires=[1]) + PauliZ(wires=[2]))


* `qml.generator` now supports operators with `Sum` and `Prod` generators.
[(3691)](https://github.com/PennyLaneAI/pennylane/pull/3691)

* 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.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)

<h4>Differentiability and interfaces</h4>

* The `qml.math` module now also contains a submodule for fast Fourier transforms, `qml.math.fft`.
[(1440)](https://github.com/PennyLaneAI/pennylane/pull/1440)

The submodule in particular provides differentiable versions of the following functions, available in all common interfaces for PennyLane

* [fft](https://numpy.org/doc/stable/reference/generated/numpy.fft.fft.html)
* [ifft](https://numpy.org/doc/stable/reference/generated/numpy.fft.ifft.html)
* [fft2](https://numpy.org/doc/stable/reference/generated/numpy.fft.fft2.html)
* [ifft2](https://numpy.org/doc/stable/reference/generated/numpy.fft.ifft2.html)

Note that the output of the derivative of these functions may differ when used with complex-valued inputs, due to different conventions on complex-valued derivatives.

* 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)

* The `numpy` version has been constrained to `<1.24`.
[(3563)](https://github.com/PennyLaneAI/pennylane/pull/3563)

* Support for two-qubit unitary decomposition with JAX-JIT has been added.
[(3569)](https://github.com/PennyLaneAI/pennylane/pull/3569)

* `qml.math.size` now supports PyTorch tensors.
[(3606)](https://github.com/PennyLaneAI/pennylane/pull/3606)

* Most quantum channels are now fully differentiable on all interfaces.
[(3612)](https://github.com/PennyLaneAI/pennylane/pull/3612)

* `qml.math.matmul` now supports PyTorch and Autograd tensors.
[(3613)](https://github.com/PennyLaneAI/pennylane/pull/3613)

* Add `qml.math.detach`, which detaches a tensor from its trace. This stops automatic gradient computations.
[(3674)](https://github.com/PennyLaneAI/pennylane/pull/3674)

* Add `typing.TensorLike` type.
[(3675)](https://github.com/PennyLaneAI/pennylane/pull/3675)

* `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.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)

* 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.
[(3587)](https://github.com/PennyLaneAI/pennylane/pull/3587)

* The parameter-shift derivative of variances saves a redundant evaluation of the corresponding unshifted expectation value tape, if possible
[(3744)](https://github.com/PennyLaneAI/pennylane/pull/3744)

<h4>Next generation device API</h4>

* 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)

* The `preprocess` function is added to `devices/qubit` that validates, expands, and transforms a batch of `QuantumTape` objects to abstract preprocessing details away from the device.
[(3708)](https://github.com/PennyLaneAI/pennylane/pull/3708)

* The `create_initial_state` function is added to `devices/qubit` that returns an initial state for an execution.
[(3683)](https://github.com/PennyLaneAI/pennylane/pull/3683)

* 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 simultaneous measurement of non-commuting observables.
[(3700)](https://github.com/PennyLaneAI/pennylane/pull/3700)

* The `ExecutionConfig` data class has been added.
[(3649)](https://github.com/PennyLaneAI/pennylane/pull/3649)

* The `StatePrep` class has been added as an interface that state-prep operators must implement.
[(3654)](https://github.com/PennyLaneAI/pennylane/pull/3654)

* `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)

<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.data.Dataset.read()` method is more universally supported.
[(3605)](https://github.com/PennyLaneAI/pennylane/pull/3605)

* 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)

* `qml.draw` and `qml.draw_mpl` have been updated to draw any quantum function, which allows for visualizing only part of a complete circuit/QNode.
[(3760)](https://github.com/PennyLaneAI/pennylane/pull/3760)

* The string representation of a Measurement Process now includes the `_eigvals` property if it is set.
[(3820)](https://github.com/PennyLaneAI/pennylane/pull/3820)

<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)

* `qml.VQECost` has been removed.
[(3735)](https://github.com/PennyLaneAI/pennylane/pull/3735)

* The default interface is now `auto`.
[(3677)](https://github.com/PennyLaneAI/pennylane/pull/3677)[(#3752)](https://github.com/PennyLaneAI/pennylane/pull/3752)[(#3829)](https://github.com/PennyLaneAI/pennylane/pull/3829)

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 initialization.

* The tape method `get_operation` can also now return the operation index in the tape, and it can be activated by setting the `return_op_index` to `True`: `get_operation(idx, return_op_index=True)`. It will become the default in version `0.30`.
[(3667)](https://github.com/PennyLaneAI/pennylane/pull/3667)

* `Operation.inv()` and the `Operation.inverse` setter have been removed. Please use `qml.adjoint` or `qml.pow` instead.
[(3618)](https://github.com/PennyLaneAI/pennylane/pull/3618)

For example, instead of

pycon
>>> qml.PauliX(0).inv()


use

pycon
>>> qml.adjoint(qml.PauliX(0))


* The `Operation.inverse` property has been removed completely.
[(3725)](https://github.com/PennyLaneAI/pennylane/pull/3725)

* The target wires of `qml.ControlledQubitUnitary` are no longer available via `op.hyperparameters["u_wires"]`. Instead, they can be accesses via `op.base.wires` or `op.target_wires`.
[(3450)](https://github.com/PennyLaneAI/pennylane/pull/3450)

* The tape constructed by a `QNode` is no longer queued to surrounding contexts.
[(3509)](https://github.com/PennyLaneAI/pennylane/pull/3509)

* Nested operators like `Tensor`, `Hamiltonian`, and `Adjoint` now remove their owned operators from the queue instead of updating their metadata to have an `"owner"`.
[(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 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)

* `qml.transforms.measurement_grouping` has been removed. Users should use `qml.transforms.hamiltonian_expand` instead.
[(3701)](https://github.com/PennyLaneAI/pennylane/pull/3701)

* `op.simplify()` for operators which are linear combinations of Pauli words will use a builtin Pauli representation to more efficiently compute the simplification of the operator.
[(3481)](https://github.com/PennyLaneAI/pennylane/pull/3481)

* All `Operator`'s input parameters that are lists are cast into vanilla numpy arrays.
[(3659)](https://github.com/PennyLaneAI/pennylane/pull/3659)

* `QubitDevice.expval` no longer permutes an observable's wire order before passing it to `QubitDevice.probability`. The associated downstream changes for `default.qubit` have been made, but this may still affect expectations for other devices that inherit from `QubitDevice` and override `probability` (or any other helper functions that take a wire order such as `marginal_prob`, `estimate_probability` or `analytic_probability`).
[(3753)](https://github.com/PennyLaneAI/pennylane/pull/3753)

<h3>Deprecations ๐Ÿ‘‹</h3>

* `qml.utils.sparse_hamiltonian` function has been deprecated, and usage will now raise a warning. Instead, one should use the `qml.Hamiltonian.sparse_matrix` method.
[(3585)](https://github.com/PennyLaneAI/pennylane/pull/3585)

* The `collections` module has been deprecated.
[(3686)](https://github.com/PennyLaneAI/pennylane/pull/3686)
[(3687)](https://github.com/PennyLaneAI/pennylane/pull/3687)

* `qml.op_sum` has been deprecated. Users should use `qml.sum` instead.
[(3686)](https://github.com/PennyLaneAI/pennylane/pull/3686)

* The use of `Evolution` directly has been deprecated. Users should use `qml.evolve` instead. This new function changes the sign of the given parameter.
[(3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)

* 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)

* The code example in `qml.SparseHamiltonian` has been updated with the correct wire range.
[(3643)](https://github.com/PennyLaneAI/pennylane/pull/3643)

* 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`.
[(3740)](https://github.com/PennyLaneAI/pennylane/pull/3740)

<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 in the drawer where nested controlled operations would output the label of the operation being controlled, rather than the control values.
[(3745)](https://github.com/PennyLaneAI/pennylane/pull/3745)

* Fixed a bug in `qml.transforms.metric_tensor` where prefactors of operation generators were taken into account multiple times, leading to wrong outputs for non-standard operations.
[(3579)](https://github.com/PennyLaneAI/pennylane/pull/3579)

* Local random number generators are now used where possible to avoid mutating the global random state.
[(3624)](https://github.com/PennyLaneAI/pennylane/pull/3624)

* The `networkx` version change being broken has been fixed by selectively skipping a `qcut` TensorFlow-JIT test.
[(3609)](https://github.com/PennyLaneAI/pennylane/pull/3609)[(#3619)](https://github.com/PennyLaneAI/pennylane/pull/3619)

* Fixed the wires for the `Y` decomposition in the ZX calculus transform.
[(3598)](https://github.com/PennyLaneAI/pennylane/pull/3598)

* `qml.pauli.PauliWord` is now pickle-able.
[(3588)](https://github.com/PennyLaneAI/pennylane/pull/3588)

* Child classes of `QuantumScript` now return their own type when using `SomeChildClass.from_queue`.
[(3501)](https://github.com/PennyLaneAI/pennylane/pull/3501)

* A typo has been fixed in the calculation and error messages in `operation.py`
[(3536)](https://github.com/PennyLaneAI/pennylane/pull/3536)

* `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`.
[(3642)](https://github.com/PennyLaneAI/pennylane/pull/3642)[(#3661)](https://github.com/PennyLaneAI/pennylane/pull/3661)

* `Tensor.has_matrix` is now set to `True`.
[(3647)](https://github.com/PennyLaneAI/pennylane/pull/3647)

* Fixed typo in the example of `qml.IsingZZ` gate decomposition.
[(3676)](https://github.com/PennyLaneAI/pennylane/pull/3676)

* Fixed a bug that made tapes/qnodes using `qml.Snapshot` incompatible with `qml.drawer.tape_mpl`.
[(3704)](https://github.com/PennyLaneAI/pennylane/pull/3704)

* `Tensor._pauli_rep` is set to `None` during initialization and `Tensor.data` has been added to its setter.
[(3722)](https://github.com/PennyLaneAI/pennylane/pull/3722)

* `qml.math.ndim` has been redirected to `jnp.ndim` when using it on a `jax` tensor.
[(3730)](https://github.com/PennyLaneAI/pennylane/pull/3730)

* Implementations of `marginal_prob` (and subsequently, `qml.probs`) now return probabilities with the expected wire order.
[(3753)](https://github.com/PennyLaneAI/pennylane/pull/3753)

This bug affected most probabilistic measurement processes on devices that inherit from `QubitDevice` when the measured wires are out of order with respect to the device wires and 3 or more wires are measured. The assumption was that marginal probabilities would be computed with the device's state and wire order, then re-ordered according to the measurement process wire order. Instead, the re-ordering went in the inverse direction (that is, from measurement process wire order to device wire order). This is now fixed. Note that this only occurred for 3 or more measured wires because this mapping is identical otherwise. More details and discussion of this bug can be found in [the original bug report](https://github.com/PennyLaneAI/pennylane/issues/3741).

* Empty iterables can no longer be returned from QNodes.
[(3769)](https://github.com/PennyLaneAI/pennylane/pull/3769)

* The keyword arguments for `qml.equal` now are used when comparing the observables of a Measurement Process. The eigvals of measurements are only requested if both observables are `None`, saving computational effort.
[(3820)](https://github.com/PennyLaneAI/pennylane/pull/3820)

* 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>

This release contains contributions from (in alphabetical order):

Gian-Luca Anselmetti,
Guillermo Alonso-Linaje,
Juan Miguel Arrazola,
Ikko Ashimine,
Utkarsh Azad,
Miriam Beddig,
Cristian Boghiu,
Thomas Bromley,
Astral Cai,
Isaac De Vlugt,
Olivia Di Matteo,
Lillian M. A. Frederiksen,
Soran Jahangiri,
Korbinian Kottmann,
Christina Lee,
Albert Mitjans Coma,
Romain Moyard,
Mudit Pandey,
Borja Requena,
Matthew Silverman,
Jay Soni,
Antal Szรกva,
Frederik Wilde,
David Wierichs,
Moritz Willmann.

0.28.0

<h3>New features since last release</h3>

<h4>Custom measurement processes ๐Ÿ“</h4>

* Custom measurements can now be facilitated with the addition of the `qml.measurements` module. [(3286)](https://github.com/PennyLaneAI/pennylane/pull/3286) [(#3343)](https://github.com/PennyLaneAI/pennylane/pull/3343) [(#3288)](https://github.com/PennyLaneAI/pennylane/pull/3288) [(#3312)](https://github.com/PennyLaneAI/pennylane/pull/3312) [(#3287)](https://github.com/PennyLaneAI/pennylane/pull/3287) [(#3292)](https://github.com/PennyLaneAI/pennylane/pull/3292) [(#3287)](https://github.com/PennyLaneAI/pennylane/pull/3287) [(#3326)](https://github.com/PennyLaneAI/pennylane/pull/3326) [(#3327)](https://github.com/PennyLaneAI/pennylane/pull/3327) [(#3388)](https://github.com/PennyLaneAI/pennylane/pull/3388) [(#3439)](https://github.com/PennyLaneAI/pennylane/pull/3439) [(#3466)](https://github.com/PennyLaneAI/pennylane/pull/3466)

Within `qml.measurements` are new subclasses that allow for the possibility to create *custom* measurements:

* `SampleMeasurement`: represents a sample-based measurement
* `StateMeasurement`: represents a state-based measurement
* `MeasurementTransform`: represents a measurement process that requires the application of a batch transform

Creating a custom measurement involves making a class that inherits from one of the classes above. An example is given below. Here, the measurement computes the number of samples obtained of a given state:

python
from pennylane.measurements import SampleMeasurement

class CountState(SampleMeasurement):
def __init__(self, state: str):
self.state = state string identifying the state, e.g. "0101"
wires = list(range(len(state)))
super().__init__(wires=wires)

def process_samples(self, samples, wire_order, shot_range, bin_size):
counts_mp = qml.counts(wires=self._wires)
counts = counts_mp.process_samples(samples, wire_order, shot_range, bin_size)
return counts.get(self.state, 0)

def __copy__(self):
return CountState(state=self.state)


We can now execute the new measurement in a QNode as follows.

python
dev = qml.device("default.qubit", wires=1, shots=10000)

qml.qnode(dev)
def circuit(x):
qml.RX(x, wires=0)
return CountState(state="1")


pycon
>>> circuit(1.23)
tensor(3303., requires_grad=True)


Differentiability is also supported for this new measurement process:

pycon
>>> x = qml.numpy.array(1.23, requires_grad=True)
>>> qml.grad(circuit)(x)
4715.000000000001


For more information about these new features, see the documentation for [`qml.measurements`](https://docs.pennylane.ai/en/stable/code/qml_measurements.html).

<h4>ZX Calculus ๐Ÿงฎ</h4>

* QNodes can now be converted into ZX diagrams via the PyZX framework. [(3446)](https://github.com/PennyLaneAI/pennylane/pull/3446)

ZX diagrams are the medium for which we can envision a quantum circuit as a graph in the ZX-calculus language, showing properties of quantum protocols in a visually compact and logically complete fashion.

QNodes decorated with `qml.transforms.to_zx` will return a PyZX graph that represents the computation in the ZX-calculus language.

python
dev = qml.device("default.qubit", wires=2)

qml.transforms.to_zx
qml.qnode(device=dev)
def circuit(p):
qml.RZ(p[0], wires=1),
qml.RZ(p[1], wires=1),
qml.RX(p[2], wires=0),
qml.PauliZ(wires=0),
qml.RZ(p[3], wires=1),
qml.PauliX(wires=1),
qml.CNOT(wires=[0, 1]),
qml.CNOT(wires=[1, 0]),
qml.SWAP(wires=[0, 1]),
return qml.expval(qml.PauliZ(0) qml.PauliZ(1))


pycon
>>> params = [5 / 4 * np.pi, 3 / 4 * np.pi, 0.1, 0.3]
>>> circuit(params)
Graph(20 vertices, 23 edges)


Information about PyZX graphs can be found in the [PyZX Graphs API](https://pyzx.readthedocs.io/en/stable/api.html).

<h4>QChem databases and basis sets โš›๏ธ</h4>

* The symbols and geometry of a compound from the PubChem database can now be accessed via `qchem.mol_data()`. [(3289)](https://github.com/PennyLaneAI/pennylane/pull/3289) [(#3378)](https://github.com/PennyLaneAI/pennylane/pull/3378)

pycon
>>> import pennylane as qml
>>> from pennylane.qchem import mol_data
>>> mol_data("BeH2")
(['Be', 'H', 'H'],
tensor([[ 4.79404621, 0.29290755, 0. ],
[ 3.77945225, -0.29290755, 0. ],
[ 5.80882913, -0.29290755, 0. ]], requires_grad=True))
>>> mol_data(223, "CID")
(['N', 'H', 'H', 'H', 'H'],
tensor([[ 0. , 0. , 0. ],
[ 1.82264085, 0.52836742, 0.40402345],
[ 0.01417295, -1.67429735, -0.98038991],
[-0.98927163, -0.22714508, 1.65369933],
[-0.84773114, 1.373075 , -1.07733286]], requires_grad=True))


* Perform quantum chemistry calculations with two new basis sets: `6-311g` and `CC-PVDZ`. [(3279)](https://github.com/PennyLaneAI/pennylane/pull/3279)

pycon
>>> symbols = ["H", "He"]
>>> geometry = np.array([[1.0, 0.0, 0.0], [0.0, 0.0, 0.0]], requires_grad=False)
>>> charge = 1
>>> basis_names = ["6-311G", "CC-PVDZ"]
>>> for basis_name in basis_names:
... mol = qml.qchem.Molecule(symbols, geometry, charge=charge, basis_name=basis_name)
... print(qml.qchem.hf_energy(mol)())
[-2.84429531]
[-2.84061284]


<h4>A bunch of new operators ๐Ÿ‘€</h4>

* The controlled CZ gate and controlled Hadamard gate are now available via `qml.CCZ` and `qml.CH`, respectively. [(3408)](https://github.com/PennyLaneAI/pennylane/pull/3408)

pycon
>>> ccz = qml.CCZ(wires=[0, 1, 2])
>>> qml.matrix(ccz)
[[ 1 0 0 0 0 0 0 0]
[ 0 1 0 0 0 0 0 0]
[ 0 0 1 0 0 0 0 0]
[ 0 0 0 1 0 0 0 0]
[ 0 0 0 0 1 0 0 0]
[ 0 0 0 0 0 1 0 0]
[ 0 0 0 0 0 0 1 0]
[ 0 0 0 0 0 0 0 -1]]
>>> ch = qml.CH(wires=[0, 1])
>>> qml.matrix(ch)
[[ 1. 0. 0. 0. ]
[ 0. 1. 0. 0. ]
[ 0. 0. 0.70710678 0.70710678]
[ 0. 0. 0.70710678 -0.70710678]]


* Three new parametric operators, `qml.CPhaseShift00`, `qml.CPhaseShift01`, and `qml.CPhaseShift10`, are now available. Each of these operators performs a phase shift akin to `qml.ControlledPhaseShift` but on different positions of the state vector. [(2715)](https://github.com/PennyLaneAI/pennylane/pull/2715)

pycon
>>> dev = qml.device("default.qubit", wires=2)
>>> qml.qnode(dev)
>>> def circuit():
... qml.PauliX(wires=1)
... qml.CPhaseShift01(phi=1.23, wires=[0,1])
... return qml.state()
...
>>> circuit()
tensor([0. +0.j , 0.33423773+0.9424888j,
1. +0.j , 0. +0.j ], requires_grad=True)


* A new gate operation called `qml.FermionicSWAP` has been added. This implements the exchange of spin orbitals representing fermionic-modes while maintaining proper anti-symmetrization. [(3380)](https://github.com/PennyLaneAI/pennylane/pull/3380)

python
dev = qml.device('default.qubit', wires=2)

qml.qnode(dev)
def circuit(phi):
qml.BasisState(np.array([0, 1]), wires=[0, 1])
qml.FermionicSWAP(phi, wires=[0, 1])
return qml.state()


pycon
>>> circuit(0.1)
tensor([0. +0.j , 0.99750208+0.04991671j,
0.00249792-0.04991671j, 0. +0.j ], requires_grad=True)


* Create operators defined from a generator via `qml.ops.op_math.Evolution`. [(3375)](https://github.com/PennyLaneAI/pennylane/pull/3375)

`qml.ops.op_math.Evolution` defines the exponential of an operator $\hat{O}$ of the form $e^{ix\hat{O}}$, with a single trainable parameter, $x$. Limiting to a single trainable parameter allows the use of `qml.gradients.param_shift` to find the gradient with respect to the parameter $x$.

python
dev = qml.device('default.qubit', wires=2)

qml.qnode(dev, diff_method=qml.gradients.param_shift)
def circuit(phi):
qml.ops.op_math.Evolution(qml.PauliX(0), -.5 * phi)
return qml.expval(qml.PauliZ(0))


pycon
>>> phi = np.array(1.2)
>>> circuit(phi)
tensor(0.36235775, requires_grad=True)
>>> qml.grad(circuit)(phi)
-0.9320390495504149


* The qutrit Hadamard gate, `qml.THadamard`, is now available. [(3340)](https://github.com/PennyLaneAI/pennylane/pull/3340)

The operation accepts a `subspace` keyword argument which determines which variant of the qutrit Hadamard to use.

pycon
>>> th = qml.THadamard(wires=0, subspace=[0, 1])
>>> qml.matrix(th)
array([[ 0.70710678+0.j, 0.70710678+0.j, 0. +0.j],
[ 0.70710678+0.j, -0.70710678+0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 1. +0.j]])


<h4>New transforms, functions, and more ๐Ÿ˜ฏ</h4>

* Calculating the purity of arbitrary quantum states is now supported. [(3290)](https://github.com/PennyLaneAI/pennylane/pull/3290)

The purity can be calculated in an analogous fashion to, say, the Von Neumann entropy:

* `qml.math.purity` can be used as an in-line function:

pycon
>>> x = [1, 0, 0, 1] / np.sqrt(2)
>>> qml.math.purity(x, [0, 1])
1.0
>>> qml.math.purity(x, [0])
0.5

>>> x = [[1 / 2, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1 / 2]]
>>> qml.math.purity(x, [0, 1])
0.5


* `qml.qinfo.transforms.purity` can transform a QNode returning a state to a
function that returns the purity:

python3
dev = qml.device("default.mixed", wires=2)

qml.qnode(dev)
def circuit(x):
qml.IsingXX(x, wires=[0, 1])
return qml.state()


pycon
>>> qml.qinfo.transforms.purity(circuit, wires=[0])(np.pi / 2)
0.5
>>> qml.qinfo.transforms.purity(circuit, wires=[0, 1])(np.pi / 2)
1.0


As with the other methods in `qml.qinfo`, the purity is fully differentiable:

pycon
>>> param = np.array(np.pi / 4, requires_grad=True)
>>> qml.grad(qml.qinfo.transforms.purity(circuit, wires=[0]))(param)
-0.5


* A new gradient transform, `qml.gradients.spsa_grad`, that is based on the idea of SPSA is now available. [(3366)](https://github.com/PennyLaneAI/pennylane/pull/3366)

This new transform allows users to compute a single estimate of a quantum gradient using simultaneous perturbation of parameters and a stochastic approximation. A QNode that takes, say, an argument `x`, the approximate gradient can be computed as follows.

pycon
>>> dev = qml.device("default.qubit", wires=2)
>>> x = np.array(0.4, requires_grad=True)
>>> qml.qnode(dev)
... def circuit(x):
... qml.RX(x, 0)
... qml.RX(x, 1)
... return qml.expval(qml.PauliZ(0))
>>> grad_fn = qml.gradients.spsa_grad(circuit, h=0.1, num_directions=1)
>>> grad_fn(x)
array(-0.38876964)


The argument `num_directions` determines how many directions of simultaneous perturbation are used, which is proportional to the number of circuit evaluations. See the [SPSA gradient transform documentation](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.spsa_grad.html) for details. Note that the full SPSA optimizer is already available as `qml.SPSAOptimizer`.

* Multiple mid-circuit measurements can now be combined arithmetically to create new conditionals. [(3159)](https://github.com/PennyLaneAI/pennylane/pull/3159)

python
dev = qml.device("default.qubit", wires=3)

qml.qnode(dev)
def circuit():
qml.Hadamard(wires=0)
qml.Hadamard(wires=1)
m0 = qml.measure(wires=0)
m1 = qml.measure(wires=1)
combined = 2 * m1 + m0
qml.cond(combined == 2, qml.RX)(1.3, wires=2)
return qml.probs(wires=2)


pycon
>>> circuit()
[0.90843735 0.09156265]


* A new method called `pauli_decompose()` has been added to the `qml.pauli` module, which takes a hermitian matrix, decomposes it in the Pauli basis, and returns it either as a `qml.Hamiltonian` or `qml.PauliSentence` instance. [(3384)](https://github.com/PennyLaneAI/pennylane/pull/3384)

* `Operation` or `Hamiltonian` instances can now be generated from a `qml.PauliSentence` or `qml.PauliWord` via the new `operation()` and `hamiltonian()` methods. [(3391)](https://github.com/PennyLaneAI/pennylane/pull/3391)

pycon
>>> pw = qml.pauli.PauliWord({0: 'X', 1: 'Y'})
>>> print(pw.operation())
PauliX(wires=[0]) PauliY(wires=[1])
>>> print(pw.hamiltonian())
(1) [X0 Y1]
>>> ps = qml.pauli.PauliSentence({pw: -1.23})
>>> print(ps.operation())
-1.23*(PauliX(wires=[0]) PauliY(wires=[1]))
>>> print(ps.hamiltonian())
(-1.23) [X0 Y1]


* A `sum_expand` function has been added for tapes, which splits a tape measuring a `Sum` expectation into mutliple tapes of summand expectations, and provides a function to recombine the results. [(3230)](https://github.com/PennyLaneAI/pennylane/pull/3230)

<h4>(Experimental) More interface support for multi-measurement and gradient output types ๐Ÿงช</h4>

* The autograd and Tensorflow interfaces now support devices with shot vectors when `qml.enable_return()` has been called. [(3374)](https://github.com/PennyLaneAI/pennylane/pull/3374) [(#3400)](https://github.com/PennyLaneAI/pennylane/pull/3400)

Here is an example using Tensorflow:

python
import tensorflow as tf
qml.enable_return()

dev = qml.device("default.qubit", wires=2, shots=[1000, 2000, 3000])

qml.qnode(dev, diff_method="parameter-shift", interface="tf")
def circuit(a):
qml.RY(a, wires=0)
qml.RX(0.2, wires=0)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0)), qml.probs([0, 1])


pycon
>>> a = tf.Variable(0.4)
>>> with tf.GradientTape() as tape:
... res = circuit(a)
... res = tf.stack([tf.experimental.numpy.hstack(r) for r in res])
...
>>> res
<tf.Tensor: shape=(3, 5), dtype=float64, numpy=
array([[0.902, 0.951, 0. , 0. , 0.049],
[0.898, 0.949, 0. , 0. , 0.051],
[0.892, 0.946, 0. , 0. , 0.054]])>
>>> tape.jacobian(res, a)
<tf.Tensor: shape=(3, 5), dtype=float64, numpy=
array([[-0.345 , -0.1725 , 0. , 0. , 0.1725 ],
[-0.383 , -0.1915 , 0. , 0. , 0.1915 ],
[-0.38466667, -0.19233333, 0. , 0. , 0.19233333]])>


* The PyTorch interface is now fully supported when `qml.enable_return()` has been called, allowing the calculation of the Jacobian and the Hessian using custom differentiation methods (e.g., parameter-shift, finite difference, or adjoint). [(3416)](https://github.com/PennyLaneAI/pennylane/pull/3414)

python
import torch

qml.enable_return()

dev = qml.device("default.qubit", wires=2)

qml.qnode(dev, diff_method="parameter-shift", interface="torch")
def circuit(a, b):
qml.RY(a, wires=0)
qml.RX(b, wires=1)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0)), qml.probs([0, 1])


pycon
>>> a = torch.tensor(0.1, requires_grad=True)
>>> b = torch.tensor(0.2, requires_grad=True)
>>> torch.autograd.functional.jacobian(circuit, (a, b))
((tensor(-0.0998), tensor(0.)), (tensor([-0.0494, -0.0005, 0.0005, 0.0494]), tensor([-0.0991, 0.0991, 0.0002, -0.0002])))


* The JAX-JIT interface now supports first-order gradient computation when `qml.enable_return()` has been called. [(3235)](https://github.com/PennyLaneAI/pennylane/pull/3235) [(#3445)](https://github.com/PennyLaneAI/pennylane/pull/3445)

python
import jax
from jax import numpy as jnp

jax.config.update("jax_enable_x64", True)

qml.enable_return()

dev = qml.device("lightning.qubit", wires=2)

jax.jit
qml.qnode(dev, interface="jax-jit", diff_method="parameter-shift")
def circuit(a, b):
qml.RY(a, wires=0)
qml.RX(b, wires=0)
return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

a, b = jnp.array(1.0), jnp.array(2.0)


pycon
>>> jax.jacobian(circuit, argnums=[0, 1])(a, b)
((Array(0.35017549, dtype=float64, weak_type=True),
Array(-0.4912955, dtype=float64, weak_type=True)),
(Array(5.55111512e-17, dtype=float64, weak_type=True),
Array(0., dtype=float64, weak_type=True)))


<h3>Improvements ๐Ÿ› </h3>

* `qml.pauli.is_pauli_word` now supports instances of `qml.Hamiltonian`. [(3389)](https://github.com/PennyLaneAI/pennylane/pull/3389)

* When `qml.probs`, `qml.counts`, and `qml.sample` are called with no arguments, they measure all wires. Calling any of the aforementioned measurements with an empty wire list (e.g., `qml.sample(wires=[])`) will raise an error. [(3299)](https://github.com/PennyLaneAI/pennylane/pull/3299)

* Made `qml.gradients.finite_diff` more convenient to use with custom data type observables/devices by reducing the number of magic methods that need to be defined in the custom data type to support `finite_diff`. [(3426)](https://github.com/PennyLaneAI/pennylane/pull/3426)

* The `qml.ISWAP` gate is now natively supported on `default.mixed`, improving on its efficiency. [(3284)](https://github.com/PennyLaneAI/pennylane/pull/3284)

* Added more input validation to `qml.transforms.hamiltonian_expand` such that Hamiltonian objects with no terms raise an error. [(3339)](https://github.com/PennyLaneAI/pennylane/pull/3339)

* Continuous integration checks are now performed for Python 3.11 and Torch v1.13. Python 3.7 is dropped. [(3276)](https://github.com/PennyLaneAI/pennylane/pull/3276)

* `qml.Tracker` now also logs results in `tracker.history` when tracking the execution of a circuit. [(3306)](https://github.com/PennyLaneAI/pennylane/pull/3306)

* The execution time of `Wires.all_wires` has been improved by avoiding data type changes and making use of `itertools.chain`. [(3302)](https://github.com/PennyLaneAI/pennylane/pull/3302)

* Printing an instance of `qml.qchem.Molecule` is now more concise and informational. [(3364)](https://github.com/PennyLaneAI/pennylane/pull/3364)

* The error message for `qml.transforms.insert` when it fails to diagonalize non-qubit-wise-commuting observables is now more detailed. [(3381)](https://github.com/PennyLaneAI/pennylane/pull/3381)

* Extended the `qml.equal` function to `qml.Hamiltonian` and `Tensor` objects. [(3390)](https://github.com/PennyLaneAI/pennylane/pull/3390)

* `QuantumTape._process_queue` has been moved to `qml.queuing.process_queue` to disentangle its functionality from the `QuantumTape` class. [(3401)](https://github.com/PennyLaneAI/pennylane/pull/3401)

* QPE can now accept a target operator instead of a matrix and target wires pair. [(3373)](https://github.com/PennyLaneAI/pennylane/pull/3373)

* The `qml.ops.op_math.Controlled.map_wires` method now uses `base.map_wires` internally instead of the private `_wires` property setter. [(3405)](https://github.com/PennyLaneAI/pennylane/pull/3405)

* A new function called `qml.tape.make_qscript` has been created for converting a quantum function into a quantum script. This replaces `qml.transforms.make_tape`. [(3429)](https://github.com/PennyLaneAI/pennylane/pull/3429)

* Add a `_pauli_rep` attribute to operators to integrate the new Pauli arithmetic classes with native PennyLane objects. [(3443)](https://github.com/PennyLaneAI/pennylane/pull/3443)

* Extended the functionality of `qml.matrix` to qutrits. [(3508)](https://github.com/PennyLaneAI/pennylane/pull/3508)

* The `qcut.py` file in `pennylane/transforms/` has been reorganized into multiple files that are now in `pennylane/transforms/qcut/`. [(3413)](https://github.com/PennyLaneAI/pennylane/pull/3413)

* A warning now appears when creating a `Tensor` object with overlapping wires, informing that this can lead to undefined behaviour. [(3459)](https://github.com/PennyLaneAI/pennylane/pull/3459)

* Extended the `qml.equal` function to `qml.ops.op_math.Controlled` and `qml.ops.op_math.ControlledOp` objects. [(3463)](https://github.com/PennyLaneAI/pennylane/pull/3463)

* Nearly every instance of `with QuantumTape()` has been replaced with `QuantumScript` construction. [(3454)](https://github.com/PennyLaneAI/pennylane/pull/3454)

* Added `validate_subspace` static method to `qml.Operator` to check the validity of the subspace of certain
qutrit operations. [(3340)](https://github.com/PennyLaneAI/pennylane/pull/3340)

* `qml.equal` now supports operators created via `qml.s_prod`, `qml.pow`, `qml.exp`, and `qml.adjoint`. [(3471)](https://github.com/PennyLaneAI/pennylane/pull/3471)

* Devices can now disregard observable grouping indices in Hamiltonians through the optional `use_grouping` attribute. [(3456)](https://github.com/PennyLaneAI/pennylane/pull/3456)

* Add the optional argument `lazy=True` to functions `qml.s_prod`, `qml.prod` and `qml.op_sum` to allow simplification. [(3483)](https://github.com/PennyLaneAI/pennylane/pull/3483)

* Updated the `qml.transforms.zyz_decomposition` function such that it now supports broadcast operators. This means that single-qubit `qml.QubitUnitary` operators, instantiated from a batch of unitaries, can now be decomposed. [(3477)](https://github.com/PennyLaneAI/pennylane/pull/3477)

* The performance of executing circuits under the `jax.vmap` transformation has been improved by being able to leverage the batch-execution capabilities of some devices. [(3452)](https://github.com/PennyLaneAI/pennylane/pull/3452)

* The tolerance for converting openfermion Hamiltonian complex coefficients to real ones has been modified to prevent conversion errors. [(3367)](https://github.com/PennyLaneAI/pennylane/pull/3367)

* `OperationRecorder` now inherits from `AnnotatedQueue` and `QuantumScript` instead of `QuantumTape`. [(3496)](https://github.com/PennyLaneAI/pennylane/pull/3496)

* Updated `qml.transforms.split_non_commuting` to support the new return types. [(3414)](https://github.com/PennyLaneAI/pennylane/pull/3414)

* Updated `qml.transforms.mitigate_with_zne` to support the new return types. [(3415)](https://github.com/PennyLaneAI/pennylane/pull/3415)

* Updated `qml.transforms.metric_tensor`, `qml.transforms.adjoint_metric_tensor`, `qml.qinfo.classical_fisher`, and `qml.qinfo.quantum_fisher` to support the new return types. [(3449)](https://github.com/PennyLaneAI/pennylane/pull/3449)

* Updated `qml.transforms.batch_params` and `qml.transforms.batch_input` to support the new return types. [(3431)](https://github.com/PennyLaneAI/pennylane/pull/3431)

* Updated `qml.transforms.cut_circuit` and `qml.transforms.cut_circuit_mc` to support the new return types. [(3346)](https://github.com/PennyLaneAI/pennylane/pull/3346)

* Limit NumPy version to `<1.24`. [(3346)](https://github.com/PennyLaneAI/pennylane/pull/3346)

<h3>Breaking changes ๐Ÿ’”</h3>

* Python 3.7 support is no longer maintained. PennyLane will be maintained for versions 3.8 and up. [(3276)](https://github.com/PennyLaneAI/pennylane/pull/3276)

* The `log_base` attribute has been moved from `MeasurementProcess` to the new `VnEntropyMP` and `MutualInfoMP` classes, which inherit from `MeasurementProcess`. [(3326)](https://github.com/PennyLaneAI/pennylane/pull/3326)

* `qml.utils.decompose_hamiltonian()` has been removed. Please use `qml.pauli.pauli_decompose()` instead. [(3384)](https://github.com/PennyLaneAI/pennylane/pull/3384)

* The `return_type` attribute of `MeasurementProcess` has been removed where possible. Use `isinstance` checks instead. [(3399)](https://github.com/PennyLaneAI/pennylane/pull/3399)

* Instead of having an `OrderedDict` attribute called `_queue`, `AnnotatedQueue` now inherits from `OrderedDict` and encapsulates the queue. Consequentially, this also applies to the `QuantumTape` class which inherits from `AnnotatedQueue`. [(3401)](https://github.com/PennyLaneAI/pennylane/pull/3401)

* The `ShadowMeasurementProcess` class has been renamed to `ClassicalShadowMP`. [(3388)](https://github.com/PennyLaneAI/pennylane/pull/3388)

* The `qml.Operation.get_parameter_shift` method has been removed. The `gradients` module should be used for general parameter-shift rules instead. [(3419)](https://github.com/PennyLaneAI/pennylane/pull/3419)

* The signature of the `QubitDevice.statistics` method has been changed from

python
def statistics(self, observables, shot_range=None, bin_size=None, circuit=None):


to

python
def statistics(self, circuit: QuantumTape, shot_range=None, bin_size=None):

[(3421)](https://github.com/PennyLaneAI/pennylane/pull/3421)

* The `MeasurementProcess` class is now an abstract class and `return_type` is now a property of the class. [(3434)](https://github.com/PennyLaneAI/pennylane/pull/3434)

<h3>Deprecations ๐Ÿ‘‹</h3>

Deprecations cycles are tracked at [doc/developement/deprecations.rst](https://docs.pennylane.ai/en/stable/development/deprecations.html).

* The following methods are deprecated: [(3281)](https://github.com/PennyLaneAI/pennylane/pull/3281/)

* `qml.tape.get_active_tape`: Use `qml.QueuingManager.active_context()` instead
* `qml.transforms.qcut.remap_tape_wires`: Use `qml.map_wires` instead
* `qml.tape.QuantumTape.inv()`: Use `qml.tape.QuantumTape.adjoint()` instead
* `qml.tape.stop_recording()`: Use `qml.QueuingManager.stop_recording()` instead
* `qml.tape.QuantumTape.stop_recording()`: Use `qml.QueuingManager.stop_recording()` instead
* `qml.QueuingContext` is now `qml.QueuingManager`
* `QueuingManager.safe_update_info` and `AnnotatedQueue.safe_update_info`: Use `update_info` instead.

* `qml.transforms.measurement_grouping` has been deprecated. Use `qml.transforms.hamiltonian_expand` instead. [(3417)](https://github.com/PennyLaneAI/pennylane/pull/3417)

* The `observables` argument in `QubitDevice.statistics` is deprecated. Please use `circuit` instead. [(3433)](https://github.com/PennyLaneAI/pennylane/pull/3433)

* 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. [(3388)](https://github.com/PennyLaneAI/pennylane/pull/3388)

* `qml.transforms.make_tape` has been deprecated. Please use `qml.tape.make_qscript` instead. [(3478)](https://github.com/PennyLaneAI/pennylane/pull/3478)

<h3>Documentation ๐Ÿ“</h3>

* Added documentation on parameter broadcasting regarding both its usage and technical aspects. [(3356)](https://github.com/PennyLaneAI/pennylane/pull/3356)

The [quickstart guide on circuits](https://docs.pennylane.ai/en/stable/introduction/circuits.html#parameter-broadcasting-in-qnodes) as well as the the documentation of [QNodes](https://docs.pennylane.ai/en/stable/code/api/pennylane.QNode.html) and [Operators](https://docs.pennylane.ai/en/stable/code/api/pennylane.operation.Operator.html) now contain introductions and details on parameter broadcasting. The QNode documentation mostly contains usage details, the Operator documentation is concerned with implementation details and a guide to support broadcasting in custom operators.

* The return type statements of gradient and Hessian transforms and a series of other functions that are a `batch_transform` have been corrected. [(3476)](https://github.com/PennyLaneAI/pennylane/pull/3476)

* Developer documentation for the queuing module has been added. [(3268)](https://github.com/PennyLaneAI/pennylane/pull/3268)

* More mentions of diagonalizing gates for all relevant operations have been corrected. [(3409)](https://github.com/PennyLaneAI/pennylane/pull/3409)

The docstrings for `compute_eigvals` used to say that the diagonalizing gates implemented $U$, the unitary such that $O = U \Sigma U^{\dagger}$, where $O$ is the original observable and $\Sigma$ a diagonal matrix. However, the diagonalizing gates actually implement $U^{\dagger}$, since $\langle \psi | O | \psi \rangle = \langle \psi | U \Sigma U^{\dagger} | \psi \rangle$, making $U^{\dagger} | \psi \rangle$ the actual state being measured in the $Z$-basis.

* A warning about using ``dill`` to pickle and unpickle datasets has been added. [(3505)](https://github.com/PennyLaneAI/pennylane/pull/3505)

<h3>Bug fixes ๐Ÿ›</h3>

* Fixed a bug that prevented `qml.gradients.param_shift` from being used for broadcasted tapes. [(3528)](https://github.com/PennyLaneAI/pennylane/pull/3528)

* Fixed a bug where `qml.transforms.hamiltonian_expand` didn't preserve the type of the input results in its output. [(3339)](https://github.com/PennyLaneAI/pennylane/pull/3339)

* Fixed a bug that made `qml.gradients.param_shift` raise an error when used with unshifted terms only in a custom recipe, and when using any unshifted terms at all under the new return type system. [(3177)](https://github.com/PennyLaneAI/pennylane/pull/3177)

* The original tape `_obs_sharing_wires` attribute is updated during its expansion. [(3293)](https://github.com/PennyLaneAI/pennylane/pull/3293)

* An issue with `drain=False` in the adaptive optimizer has been fixed. Before the fix, the operator pool needed to be reconstructed inside the optimization pool when `drain=False`. With this fix, this reconstruction is no longer needed. [(3361)](https://github.com/PennyLaneAI/pennylane/pull/3361)

* If the device originally has no shots but finite shots are dynamically specified, Hamiltonian expansion now occurs. [(3369)](https://github.com/PennyLaneAI/pennylane/pull/3369)

* `qml.matrix(op)` now fails if the operator truly has no matrix (e.g., `qml.Barrier`) to match `op.matrix()`. [(3386)](https://github.com/PennyLaneAI/pennylane/pull/3386)

* The `pad_with` argument in the `qml.AmplitudeEmbedding` template is now compatible with all interfaces. [(3392)](https://github.com/PennyLaneAI/pennylane/pull/3392)

* `Operator.pow` now queues its constituents by default. [(3373)](https://github.com/PennyLaneAI/pennylane/pull/3373)

* Fixed a bug where a QNode returning `qml.sample` would produce incorrect results when run on a device defined with a shot vector. [(3422)](https://github.com/PennyLaneAI/pennylane/pull/3422)

* The `qml.data` module now works as expected on Windows. [(3504)](https://github.com/PennyLaneAI/pennylane/pull/3504)

<h3>Contributors โœ๏ธ</h3>

This release contains contributions from (in alphabetical order):

Guillermo Alonso, Juan Miguel Arrazola, Utkarsh Azad, Samuel Banning, Thomas Bromley, Astral Cai, Albert Mitjans Coma, Ahmed Darwish, Isaac De Vlugt, Olivia Di Matteo, Amintor Dusko, Pieter Eendebak, Lillian M. A. Frederiksen, Diego Guala, Katharine Hyatt, Josh Izaac, Soran Jahangiri, Edward Jiang, Korbinian Kottmann, Christina Lee, Romain Moyard, Lee James O'Riordan, Mudit Pandey, Kevin Shen, Matthew Silverman, Jay Soni, Antal Szรกva, David Wierichs, Moritz Willmann, and Filippo Vicentini.

Page 3 of 11

ยฉ 2024 Safety CLI Cybersecurity Inc. All Rights Reserved.