Pennylane

Latest version: v0.39.0

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

Scan your dependencies

Page 8 of 11

0.13.0post1

A minor post-release to update the main page of the PennyLane documentation.

0.13.0

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

<h4>Automatically optimize the number of measurements</h4>

* QNodes in tape mode now support returning observables on the same wire whenever the observables are qubit-wise commuting Pauli words. Qubit-wise commuting observables can be evaluated with a *single* device run as they are diagonal in the same basis, via a shared set of single-qubit rotations. [(882)](https://github.com/PennyLaneAI/pennylane/pull/882)

The following example shows a single QNode returning the expectation values of the qubit-wise commuting Pauli words `XX` and `XI`:

python
qml.enable_tape()

qml.qnode(dev)
def f(x):
qml.Hadamard(wires=0)
qml.Hadamard(wires=1)
qml.CRot(0.1, 0.2, 0.3, wires=[1, 0])
qml.RZ(x, wires=1)
return qml.expval(qml.PauliX(0) qml.PauliX(1)), qml.expval(qml.PauliX(0))


pycon
>>> f(0.4)
tensor([0.89431013, 0.9510565 ], requires_grad=True)


* The `ExpvalCost` class (previously `VQECost`) now provides observable optimization using the `optimize` argument, resulting in potentially fewer device executions. [(902)](https://github.com/PennyLaneAI/pennylane/pull/902)

This is achieved by separating the observables composing the Hamiltonian into qubit-wise commuting groups and evaluating those groups on a single QNode using functionality from the `qml.grouping` module:

python
qml.enable_tape()
commuting_obs = [qml.PauliX(0), qml.PauliX(0) qml.PauliZ(1)]
H = qml.vqe.Hamiltonian([1, 1], commuting_obs)

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

cost_opt = qml.ExpvalCost(ansatz, H, dev, optimize=True)
cost_no_opt = qml.ExpvalCost(ansatz, H, dev, optimize=False)

params = qml.init.strong_ent_layers_uniform(3, 2)


Grouping these commuting observables leads to fewer device executions:

pycon
>>> cost_opt(params)
>>> ex_opt = dev.num_executions
>>> cost_no_opt(params)
>>> ex_no_opt = dev.num_executions - ex_opt
>>> print("Number of executions:", ex_no_opt)
Number of executions: 2
>>> print("Number of executions (optimized):", ex_opt)
Number of executions (optimized): 1


<h4>New quantum gradient features</h4>

* Compute the analytic gradient of quantum circuits in parallel on supported devices. [(840)](https://github.com/PennyLaneAI/pennylane/pull/840)

This release introduces support for batch execution of circuits, via a new device API method `Device.batch_execute()`. Devices that implement this new API support submitting a batch of circuits for *parallel* evaluation simultaneously, which can significantly reduce the computation time.

Furthermore, if using tape mode and a compatible device, gradient computations will automatically make use of the new batch API---providing a speedup during optimization.

* Gradient recipes are now much more powerful, allowing for operations to define their gradient via an arbitrary linear combination of circuit evaluations. [(909)](https://github.com/PennyLaneAI/pennylane/pull/909) [(#915)](https://github.com/PennyLaneAI/pennylane/pull/915)

With this change, gradient recipes can now be of the form `\frac{\partial}{\partial\phi_k}f(\phi_k) = \sum_{i} c_i f(a_i \phi_k + s_i )`, and are no longer restricted to two-term shifts with identical (but opposite in sign) shift values.

As a result, PennyLane now supports native analytic quantum gradients for the controlled rotation operations `CRX`, `CRY`, `CRZ`, and `CRot`. This allows for parameter-shift analytic gradients on hardware, without decomposition.

Note that this is a breaking change for developers; please see the *Breaking Changes* section for more details.

* The `qnn.KerasLayer` class now supports differentiating the QNode through classical backpropagation in tape mode. [(869)](https://github.com/PennyLaneAI/pennylane/pull/869)

python
qml.enable_tape()

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

qml.qnode(dev, interface="tf", diff_method="backprop")
def f(inputs, weights):
qml.templates.AngleEmbedding(inputs, wires=range(2))
qml.templates.StronglyEntanglingLayers(weights, wires=range(2))
return [qml.expval(qml.PauliZ(i)) for i in range(2)]

weight_shapes = {"weights": (3, 2, 3)}

qlayer = qml.qnn.KerasLayer(f, weight_shapes, output_dim=2)

inputs = tf.constant(np.random.random((4, 2)), dtype=tf.float32)

with tf.GradientTape() as tape:
out = qlayer(inputs)

tape.jacobian(out, qlayer.trainable_weights)


<h4>New operations, templates, and measurements</h4>

* Adds the `qml.density_matrix` QNode return with partial trace capabilities. [(878)](https://github.com/PennyLaneAI/pennylane/pull/878)

The density matrix over the provided wires is returned, with all other subsystems traced out. `qml.density_matrix` currently works for both the `default.qubit` and `default.mixed` devices.

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

def circuit(x):
qml.PauliY(wires=0)
qml.Hadamard(wires=1)
return qml.density_matrix(wires=[1]) wire 0 is traced out


* Adds the square-root X gate `SX`. [(871)](https://github.com/PennyLaneAI/pennylane/pull/871)

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

qml.qnode(dev)
def circuit():
qml.SX(wires=[0])
return qml.expval(qml.PauliZ(wires=[0]))


* Two new hardware-efficient particle-conserving templates have been implemented to perform VQE-based quantum chemistry simulations. The new templates apply several layers of the particle-conserving entanglers proposed in Figs. 2a and 2b of Barkoutsos *et al*., [arXiv:1805.04340](https://arxiv.org/abs/1805.04340) [(#875)](https://github.com/PennyLaneAI/pennylane/pull/875) [(#876)](https://github.com/PennyLaneAI/pennylane/pull/876)

<h4>Estimate and track resources</h4>

* The `QuantumTape` class now contains basic resource estimation functionality. The method `tape.get_resources()` returns a dictionary with a list of the constituent operations and the number of times they appear in the circuit. Similarly, `tape.get_depth()` computes the circuit depth. [(862)](https://github.com/PennyLaneAI/pennylane/pull/862)

pycon
>>> with qml.tape.QuantumTape() as tape:
... qml.Hadamard(wires=0)
... qml.RZ(0.26, wires=1)
... qml.CNOT(wires=[1, 0])
... qml.Rot(1.8, -2.7, 0.2, wires=0)
... qml.Hadamard(wires=1)
... qml.CNOT(wires=[0, 1])
... qml.expval(qml.PauliZ(0) qml.PauliZ(1))
>>> tape.get_resources()
{'Hadamard': 2, 'RZ': 1, 'CNOT': 2, 'Rot': 1}
>>> tape.get_depth()
4


* The number of device executions over a QNode's lifetime can now be returned using `num_executions`. [(853)](https://github.com/PennyLaneAI/pennylane/pull/853)

pycon
>>> dev = qml.device("default.qubit", wires=2)
>>> qml.qnode(dev)
... def circuit(x, y):
... qml.RX(x, wires=[0])
... qml.RY(y, wires=[1])
... qml.CNOT(wires=[0, 1])
... return qml.expval(qml.PauliZ(0) qml.PauliX(1))
>>> for _ in range(10):
... circuit(0.432, 0.12)
>>> print(dev.num_executions)
10


<h3>Improvements</h3>

* Support for tape mode has improved across PennyLane. The following features now work in tape mode:

- QNode collections [(863)](https://github.com/PennyLaneAI/pennylane/pull/863)

- `qnn.ExpvalCost` [(863)](https://github.com/PennyLaneAI/pennylane/pull/863) [(#911)](https://github.com/PennyLaneAI/pennylane/pull/911)

- `qml.qnn.KerasLayer` [(869)](https://github.com/PennyLaneAI/pennylane/pull/869)

- `qml.qnn.TorchLayer` [(865)](https://github.com/PennyLaneAI/pennylane/pull/865)

- The `qml.qaoa` module [(905)](https://github.com/PennyLaneAI/pennylane/pull/905)

* A new function, `qml.refresh_devices()`, has been added, allowing PennyLane to rescan installed PennyLane plugins and refresh the device list. In addition, the `qml.device` loader will attempt to refresh devices if the required plugin device cannot be found. This will result in an improved experience if installing PennyLane and plugins within a running Python session (for example, on Google Colab), and avoid the need to restart the kernel/runtime. [(907)](https://github.com/PennyLaneAI/pennylane/pull/907)

* When using `grad_fn = qml.grad(cost)` to compute the gradient of a cost function with the Autograd interface, the value of the intermediate forward pass is now available via the `grad_fn.forward` property [(914)](https://github.com/PennyLaneAI/pennylane/pull/914):

python
def cost_fn(x, y):
return 2 * np.sin(x[0]) * np.exp(-x[1]) + x[0] ** 3 + np.cos(y)

params = np.array([0.1, 0.5], requires_grad=True)
data = np.array(0.65, requires_grad=False)
grad_fn = qml.grad(cost_fn)

grad_fn(params, data) perform backprop and evaluate the gradient
grad_fn.forward the cost function value


* Gradient-based optimizers now have a `step_and_cost` method that returns both the next step as well as the objective (cost) function output. [(916)](https://github.com/PennyLaneAI/pennylane/pull/916)

pycon
>>> opt = qml.GradientDescentOptimizer()
>>> params, cost = opt.step_and_cost(cost_fn, params)


* PennyLane provides a new experimental module `qml.proc` which provides framework-agnostic processing functions for array and tensor manipulations. [(886)](https://github.com/PennyLaneAI/pennylane/pull/886)

Given the input tensor-like object, the call is dispatched to the corresponding array manipulation framework, allowing for end-to-end differentiation to be preserved.

pycon
>>> x = torch.tensor([1., 2.])
>>> qml.proc.ones_like(x)
tensor([1, 1])
>>> y = tf.Variable([[0], [5]])
>>> qml.proc.ones_like(y, dtype=np.complex128)
<tf.Tensor: shape=(2, 1), dtype=complex128, numpy=
array([[1.+0.j],
[1.+0.j]])>


Note that these functions are experimental, and only a subset of common functionality is supported. Furthermore, the names and behaviour of these functions may differ from similar functions in common frameworks; please refer to the function docstrings for more details.

* The gradient methods in tape mode now fully separate the quantum and classical processing. Rather than returning the evaluated gradients directly, they now return a tuple containing the required quantum and classical processing steps. [(840)](https://github.com/PennyLaneAI/pennylane/pull/840)

python
def gradient_method(idx, param, **options):
generate the quantum tapes that must be computed
to determine the quantum gradient
tapes = quantum_gradient_tapes(self)

def processing_fn(results):
perform classical processing on the evaluated tapes
returning the evaluated quantum gradient
return classical_processing(results)

return tapes, processing_fn


The `JacobianTape.jacobian()` method has been similarly modified to accumulate all gradient quantum tapes and classical processing functions, evaluate all quantum tapes simultaneously, and then apply the post-processing functions to the evaluated tape results.

* The MultiRZ gate now has a defined generator, allowing it to be used in quantum natural gradient optimization. [(912)](https://github.com/PennyLaneAI/pennylane/pull/912)

* The CRot gate now has a `decomposition` method, which breaks the gate down into rotations and CNOT gates. This allows `CRot` to be used on devices that do not natively support it. [(908)](https://github.com/PennyLaneAI/pennylane/pull/908)

* The classical processing in the `MottonenStatePreparation` template has been largely rewritten to use dense matrices and tensor manipulations wherever possible. This is in preparation to support differentiation through the template in the future. [(864)](https://github.com/PennyLaneAI/pennylane/pull/864)

* Device-based caching has replaced QNode caching. Caching is now accessed by passing a `cache` argument to the device. [(851)](https://github.com/PennyLaneAI/pennylane/pull/851)

The `cache` argument should be an integer specifying the size of the cache. For example, a cache of size 10 is created using:

pycon
>>> dev = qml.device("default.qubit", wires=2, cache=10)


* The `Operation`, `Tensor`, and `MeasurementProcess` classes now have the `__copy__` special method defined. [(840)](https://github.com/PennyLaneAI/pennylane/pull/840)

This allows us to ensure that, when a shallow copy is performed of an operation, the mutable list storing the operation parameters is *also* shallow copied. Both the old operation and the copied operation will continue to share the same parameter data,

pycon
>>> import copy
>>> op = qml.RX(0.2, wires=0)
>>> op2 = copy.copy(op)
>>> op.data[0] is op2.data[0]
True


however the *list container* is not a reference:

pycon
>>> op.data is op2.data
False


This allows the parameters of the copied operation to be modified, without mutating the parameters of the original operation.

* The `QuantumTape.copy` method has been tweaked so that [(840)](https://github.com/PennyLaneAI/pennylane/pull/840):

- Optionally, the tape's operations are shallow copied in addition to the tape by passing the `copy_operations=True` boolean flag. This allows the copied tape's parameters to be mutated without affecting the original tape's parameters. (Note: the two tapes will share parameter data *until* one of the tapes has their parameter list modified.)

- Copied tapes can be cast to another `QuantumTape` subclass by passing the `tape_cls` keyword argument.

<h3>Breaking changes</h3>

* Updated how parameter-shift gradient recipes are defined for operations, allowing for gradient recipes that are specified as an arbitrary number of terms. [(909)](https://github.com/PennyLaneAI/pennylane/pull/909)

Previously, `Operation.grad_recipe` was restricted to two-term parameter-shift formulas. With this change, the gradient recipe now contains elements of the form `[c_i, a_i, s_i]`, resulting in a gradient recipe of `\frac{\partial}{\partial\phi_k}f(\phi_k) = \sum_{i} c_i f(a_i \phi_k + s_i )`.

As this is a breaking change, all custom operations with defined gradient recipes must be updated to continue working with PennyLane 0.13. Note though that if `grad_recipe = None`, the default gradient recipe remains unchanged, and corresponds to the two terms `[c_0, a_0, s_0]=[1/2, 1, \pi/2]` and `[c_1, a_1, s_1]=[-1/2, 1, -\pi/2]` for every parameter.

- The `VQECost` class has been renamed to `ExpvalCost` to reflect its general applicability beyond VQE. Use of `VQECost` is still possible but will result in a deprecation warning. [(913)](https://github.com/PennyLaneAI/pennylane/pull/913)

<h3>Bug fixes</h3>

* The `default.qubit.tf` device is updated to handle TensorFlow objects (e.g., `tf.Variable`) as gate parameters correctly when using the `MultiRZ` and `CRot` operations. [(921)](https://github.com/PennyLaneAI/pennylane/pull/921)

* PennyLane tensor objects are now unwrapped in BaseQNode when passed as a keyword argument to the quantum function. [(903)](https://github.com/PennyLaneAI/pennylane/pull/903) [(#893)](https://github.com/PennyLaneAI/pennylane/pull/893)

* The new tape mode now prevents multiple observables from being evaluated on the same wire if the observables are not qubit-wise commuting Pauli words. [(882)](https://github.com/PennyLaneAI/pennylane/pull/882)

* Fixes a bug in `default.qubit` whereby inverses of common gates were not being applied via efficient gate-specific methods, instead falling back to matrix-vector multiplication. The following gates were affected: `PauliX`, `PauliY`, `PauliZ`, `Hadamard`, `SWAP`, `S`, `T`, `CNOT`, `CZ`. [(872)](https://github.com/PennyLaneAI/pennylane/pull/872)

* The `PauliRot` operation now gracefully handles single-qubit Paulis, and all-identity Paulis [(860)](https://github.com/PennyLaneAI/pennylane/pull/860).

* Fixes a bug whereby binary Python operators were not properly propagating the `requires_grad` attribute to the output tensor. [(889)](https://github.com/PennyLaneAI/pennylane/pull/889)

* Fixes a bug which prevents `TorchLayer` from doing `backward` when CUDA is enabled. [(899)](https://github.com/PennyLaneAI/pennylane/pull/899)

* Fixes a bug where multi-threaded execution of `QNodeCollection` sometimes fails because of simultaneous queuing. This is fixed by adding thread locking during queuing. [(910)](https://github.com/PennyLaneAI/pennylane/pull/918)

* Fixes a bug in `QuantumTape.set_parameters()`. The previous implementation assumed that the `self.trainable_parms` set would always be iterated over in increasing integer order. However, this is not guaranteed behaviour, and can lead to the incorrect tape parameters being set if this is not the case. [(923)](https://github.com/PennyLaneAI/pennylane/pull/923)

* Fixes broken error message if a QNode is instantiated with an unknown exception. [(930)](https://github.com/PennyLaneAI/pennylane/pull/930)

<h3>Contributors</h3>

This release contains contributions from (in alphabetical order):

Juan Miguel Arrazola, Thomas Bromley, Christina Lee, Alain Delgado Gran, Olivia Di Matteo, Anthony Hayes, Theodor Isacsson, Josh Izaac, Soran Jahangiri, Nathan Killoran, Shumpei Kobayashi, Romain Moyard, Zeyue Niu, Maria Schuld, Antal Száva.

0.12.0

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

<h4>New and improved simulators</h4>

* PennyLane now supports a new device, `default.mixed`, designed for simulating mixed-state quantum computations. This enables native support for implementing noisy channels in a circuit, which generally map pure states to mixed states. [(794)](https://github.com/PennyLaneAI/pennylane/pull/794) [(#807)](https://github.com/PennyLaneAI/pennylane/pull/807) [(#819)](https://github.com/PennyLaneAI/pennylane/pull/819)

The device can be initialized as
pycon
>>> dev = qml.device("default.mixed", wires=1)


This allows the construction of QNodes that include non-unitary operations, such as noisy channels:

pycon
>>> qml.qnode(dev)
... def circuit(params):
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.AmplitudeDamping(0.5, wires=0)
... return qml.expval(qml.PauliZ(0))
>>> print(circuit([0.54, 0.12]))
0.9257702929524184
>>> print(circuit([0, np.pi]))
0.0


<h4>New tools for optimizing measurements</h4>

* The new `grouping` module provides functionality for grouping simultaneously measurable Pauli word observables. [(761)](https://github.com/PennyLaneAI/pennylane/pull/761) [(#850)](https://github.com/PennyLaneAI/pennylane/pull/850) [(#852)](https://github.com/PennyLaneAI/pennylane/pull/852)

- The `optimize_measurements` function will take as input a list of Pauli word observables and their corresponding coefficients (if any), and will return the partitioned Pauli terms diagonalized in the measurement basis and the corresponding diagonalizing circuits.

python
from pennylane.grouping import optimize_measurements
h, nr_qubits = qml.qchem.molecular_hamiltonian("h2", "h2.xyz")
rotations, grouped_ops, grouped_coeffs = optimize_measurements(h.ops, h.coeffs, grouping="qwc")


The diagonalizing circuits of `rotations` correspond to the diagonalized Pauli word groupings of `grouped_ops`.

- Pauli word partitioning utilities are performed by the `PauliGroupingStrategy` class. An input list of Pauli words can be partitioned into mutually commuting, qubit-wise-commuting, or anticommuting groupings.

For example, partitioning Pauli words into anticommutative groupings by the Recursive Largest First (RLF) graph colouring heuristic:

python
from pennylane import PauliX, PauliY, PauliZ, Identity
from pennylane.grouping import group_observables
pauli_words = [
Identity('a') Identity('b'),
Identity('a') PauliX('b'),
Identity('a') PauliY('b'),
PauliZ('a') PauliX('b'),
PauliZ('a') PauliY('b'),
PauliZ('a') PauliZ('b')
]
groupings = group_observables(pauli_words, grouping_type='anticommuting', method='rlf')


- Various utility functions are included for obtaining and manipulating Pauli words in the binary symplectic vector space representation.

For instance, two Pauli words may be converted to their binary vector representation:

pycon
>>> from pennylane.grouping import pauli_to_binary
>>> from pennylane.wires import Wires
>>> wire_map = {Wires('a'): 0, Wires('b'): 1}
>>> pauli_vec_1 = pauli_to_binary(qml.PauliX('a') qml.PauliY('b'))
>>> pauli_vec_2 = pauli_to_binary(qml.PauliZ('a') qml.PauliZ('b'))
>>> pauli_vec_1
[1. 1. 0. 1.]
>>> pauli_vec_2
[0. 0. 1. 1.]


Their product up to a phase may be computed by taking the sum of their binary vector representations, and returned in the operator representation.

pycon
>>> from pennylane.grouping import binary_to_pauli
>>> binary_to_pauli((pauli_vec_1 + pauli_vec_2) % 2, wire_map)
Tensor product ['PauliY', 'PauliX']: 0 params, wires ['a', 'b']


For more details on the grouping module, see the [grouping module documentation](https://pennylane.readthedocs.io/en/stable/code/qml_grouping.html)


<h4>Returning the quantum state from simulators</h4>

* The quantum state of a QNode can now be returned using the `qml.state()` return function. [(818)](https://github.com/XanaduAI/pennylane/pull/818)

python
import pennylane as qml

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

qml.qnode(dev)
def qfunc(x, y):
qml.RZ(x, wires=0)
qml.CNOT(wires=[0, 1])
qml.RY(y, wires=1)
qml.CNOT(wires=[0, 2])
return qml.state()

>>> qfunc(0.56, 0.1)
array([0.95985437-0.27601028j, 0. +0.j ,
0.04803275-0.01381203j, 0. +0.j ,
0. +0.j , 0. +0.j ,
0. +0.j , 0. +0.j ])


Differentiating the state is currently available when using the classical backpropagation differentiation method (`diff_method="backprop"`) with a compatible device, and when using the new tape mode.

<h4>New operations and channels</h4>

* PennyLane now includes standard channels such as the Amplitude-damping, Phase-damping, and Depolarizing channels, as well as the ability to make custom qubit channels. [(760)](https://github.com/PennyLaneAI/pennylane/pull/760) [(#766)](https://github.com/PennyLaneAI/pennylane/pull/766) [(#778)](https://github.com/PennyLaneAI/pennylane/pull/778)

* The controlled-Y operation is now available via `qml.CY`. For devices that do not natively support the controlled-Y operation, it will be decomposed into `qml.RY`, `qml.CNOT`, and `qml.S` operations. [(806)](https://github.com/PennyLaneAI/pennylane/pull/806)

<h4>Preview the next-generation PennyLane QNode</h4>

* The new PennyLane `tape` module provides a re-formulated QNode class, rewritten from the ground-up, that uses a new `QuantumTape` object to represent the QNode's quantum circuit. Tape mode provides several advantages over the standard PennyLane QNode. [(785)](https://github.com/PennyLaneAI/pennylane/pull/785) [(#792)](https://github.com/PennyLaneAI/pennylane/pull/792) [(#796)](https://github.com/PennyLaneAI/pennylane/pull/796) [(#800)](https://github.com/PennyLaneAI/pennylane/pull/800) [(#803)](https://github.com/PennyLaneAI/pennylane/pull/803) [(#804)](https://github.com/PennyLaneAI/pennylane/pull/804) [(#805)](https://github.com/PennyLaneAI/pennylane/pull/805) [(#808)](https://github.com/PennyLaneAI/pennylane/pull/808) [(#810)](https://github.com/PennyLaneAI/pennylane/pull/810) [(#811)](https://github.com/PennyLaneAI/pennylane/pull/811) [(#815)](https://github.com/PennyLaneAI/pennylane/pull/815) [(#820)](https://github.com/PennyLaneAI/pennylane/pull/820) [(#823)](https://github.com/PennyLaneAI/pennylane/pull/823) [(#824)](https://github.com/PennyLaneAI/pennylane/pull/824) [(#829)](https://github.com/PennyLaneAI/pennylane/pull/829)

- Support for in-QNode classical processing: Tape mode allows for differentiable classical processing within the QNode.

- No more Variable wrapping: In tape mode, QNode arguments no longer become `Variable` objects within the QNode.

- Less restrictive QNode signatures: There is no longer any restriction on the QNode signature; the QNode can be defined and called following the same rules as standard Python functions.

- Unifying all QNodes: The tape-mode QNode merges all QNodes (including the `JacobianQNode` and the `PassthruQNode`) into a single unified QNode, with identical behaviour regardless of the differentiation type.

- Optimizations: Tape mode provides various performance optimizations, reducing pre- and post-processing overhead, and reduces the number of quantum evaluations in certain cases.

Note that tape mode is **experimental**, and does not currently have feature-parity with the existing QNode. [Feedback and bug reports](https://github.com/PennyLaneAI/pennylane/issues) are encouraged and will help improve the new tape mode.

Tape mode can be enabled globally via the `qml.enable_tape` function, without changing your PennyLane code:

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

qml.qnode(dev, interface="tf")
def circuit(p):
print("Parameter value:", p)
qml.RX(tf.sin(p[0])**2 + p[1], wires=0)
return qml.expval(qml.PauliZ(0))


For more details, please see the [tape mode documentation](https://pennylane.readthedocs.io/en/stable/code/qml_tape.html).

<h3>Improvements</h3>

* QNode caching has been introduced, allowing the QNode to keep track of the results of previous device executions and reuse those results in subsequent calls. Note that QNode caching is only supported in the new and experimental tape-mode. [(817)](https://github.com/PennyLaneAI/pennylane/pull/817)

Caching is available by passing a `caching` argument to the QNode:

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

qml.qnode(dev, caching=10) cache up to 10 evaluations
def qfunc(x):
qml.RX(x, wires=0)
qml.RX(0.3, wires=1)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(1))

qfunc(0.1) first evaluation executes on the device
qfunc(0.1) second evaluation accesses the cached result


* Sped up the application of certain gates in `default.qubit` by using array/tensor manipulation tricks. The following gates are affected: `PauliX`, `PauliY`, `PauliZ`, `Hadamard`, `SWAP`, `S`, `T`, `CNOT`, `CZ`. [(772)](https://github.com/PennyLaneAI/pennylane/pull/772)

* The computation of marginal probabilities has been made more efficient for devices with a large number of wires, achieving in some cases a 5x speedup. [(799)](https://github.com/PennyLaneAI/pennylane/pull/799)

* Adds arithmetic operations (addition, tensor product, subtraction, and scalar multiplication) between `Hamiltonian`, `Tensor`, and `Observable` objects, and inline arithmetic operations between Hamiltonians and other observables. [(765)](https://github.com/PennyLaneAI/pennylane/pull/765)

Hamiltonians can now easily be defined as sums of observables:

pycon3
>>> H = 3 * qml.PauliZ(0) - (qml.PauliX(0) qml.PauliX(1)) + qml.Hamiltonian([4], [qml.PauliZ(0)])
>>> print(H)
(7.0) [Z0] + (-1.0) [X0 X1]


* Adds `compare()` method to `Observable` and `Hamiltonian` classes, which allows for comparison between observable quantities. [(765)](https://github.com/PennyLaneAI/pennylane/pull/765)

pycon3
>>> H = qml.Hamiltonian([1], [qml.PauliZ(0)])
>>> obs = qml.PauliZ(0) qml.Identity(1)
>>> print(H.compare(obs))
True


pycon3
>>> H = qml.Hamiltonian([2], [qml.PauliZ(0)])
>>> obs = qml.PauliZ(1) qml.Identity(0)
>>> print(H.compare(obs))
False


* Adds `simplify()` method to the `Hamiltonian` class. [(765)](https://github.com/PennyLaneAI/pennylane/pull/765)

pycon3
>>> H = qml.Hamiltonian([1, 2], [qml.PauliZ(0), qml.PauliZ(0) qml.Identity(1)])
>>> H.simplify()
>>> print(H)
(3.0) [Z0]


* Added a new bit-flip mixer to the `qml.qaoa` module. [(774)](https://github.com/PennyLaneAI/pennylane/pull/774)

* Summation of two `Wires` objects is now supported and will return a `Wires` object containing the set of all wires defined by the terms in the summation. [(812)](https://github.com/PennyLaneAI/pennylane/pull/812)

<h3>Breaking changes</h3>

* The PennyLane NumPy module now returns scalar (zero-dimensional) arrays where Python scalars were previously returned. [(820)](https://github.com/PennyLaneAI/pennylane/pull/820) [(#833)](https://github.com/PennyLaneAI/pennylane/pull/833)

For example, this affects array element indexing, and summation:

pycon
>>> x = np.array([1, 2, 3], requires_grad=False)
>>> x[0]
tensor(1, requires_grad=False)
>>> np.sum(x)
tensor(6, requires_grad=True)


This may require small updates to user code. A convenience method, `np.tensor.unwrap()`, has been added to help ease the transition. This converts PennyLane NumPy tensors to standard NumPy arrays and Python scalars:

pycon
>>> x = np.array(1.543, requires_grad=False)
>>> x.unwrap()
1.543


Note, however, that information regarding array differentiability will be lost.

* The device capabilities dictionary has been redesigned, for clarity and robustness. In particular, the capabilities dictionary is now inherited from the parent class, various keys have more expressive names, and all keys are now defined in the base device class. For more details, please [refer to the developer documentation](https://pennylane.readthedocs.io/en/stable/development/plugins.html#device-capabilities). [(781)](https://github.com/PennyLaneAI/pennylane/pull/781/files)

<h3>PennyLane-QChem</h3>

* The functions `one_particle` and `two_particle` have been implemented to extend PennyLane-QChem capabilities to construct observables of many-body quantum systems. These functions can be used in conjunction with the `observable` function to construct electronic structure hamiltonians involving one- and two-particle operators. [(809)](https://github.com/PennyLaneAI/pennylane/pull/809)

* The function `observable` in the `obs` module has been generalized to build many-body observables combining one- and two-particle operators (e.g., Hamiltonians) [(791)](https://github.com/PennyLaneAI/pennylane/pull/791)

* Fix calculation of the contribution of core orbitals to two-particle operators in the function two_particle. [(825)](https://github.com/PennyLaneAI/pennylane/pull/825)

<h3>Bug fixes</h3>

* Changed to use lists for storing variable values inside `BaseQNode` allowing complex matrices to be passed to `QubitUnitary`. [(773)](https://github.com/PennyLaneAI/pennylane/pull/773)

* Fixed a bug within `default.qubit`, resulting in greater efficiency when applying a state vector to all wires on the device. [(849)](https://github.com/PennyLaneAI/pennylane/pull/849)

<h3>Documentation</h3>

* Equations have been added to the `qml.sample` and `qml.probs` docstrings to clarify the mathematical foundation of the performed measurements. [(843)](https://github.com/PennyLaneAI/pennylane/pull/843)

<h3>Contributors</h3>

This release contains contributions from (in alphabetical order):

Aroosa Ijaz, Juan Miguel Arrazola, Thomas Bromley, Jack Ceroni, Alain Delgado Gran, Josh Izaac, Soran Jahangiri, Nathan Killoran, Robert Lang, Cedric Lin, Olivia Di Matteo, Nicolás Quesada, Maria Schuld, Antal Száva.

0.11.0

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

<h4>New and improved simulators</h4>

* Added a new device, `default.qubit.autograd`, a pure-state qubit simulator written using Autograd. This device supports classical backpropagation (`diff_method="backprop"`); this can be faster than the parameter-shift rule for computing quantum gradients when the number of parameters to be optimized is large. [(721)](https://github.com/XanaduAI/pennylane/pull/721)

pycon
>>> dev = qml.device("default.qubit.autograd", wires=1)
>>> qml.qnode(dev, diff_method="backprop")
... def circuit(x):
... qml.RX(x[1], wires=0)
... qml.Rot(x[0], x[1], x[2], wires=0)
... return qml.expval(qml.PauliZ(0))
>>> weights = np.array([0.2, 0.5, 0.1])
>>> grad_fn = qml.grad(circuit)
>>> print(grad_fn(weights))
array([-2.25267173e-01, -1.00864546e+00, 6.93889390e-18])


See the [device documentation](https://pennylane.readthedocs.io/en/stable/code/api/pennylane.devices.default_qubit_autograd.DefaultQubitAutograd.html) for more details.

* A new experimental C++ state-vector simulator device is now available, `lightning.qubit`. It uses the C++ Eigen library to perform fast linear algebra calculations for simulating quantum state-vector evolution.

`lightning.qubit` is currently in beta; it can be installed via `pip`:

console
$ pip install pennylane-lightning


Once installed, it can be used as a PennyLane device:

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


For more details, please see the [lightning qubit documentation](https://pennylane-lightning.readthedocs.io).

<h4>New algorithms and templates</h4>

* Added built-in QAOA functionality via the new `qml.qaoa` module. [(712)](https://github.com/PennyLaneAI/pennylane/pull/712) [(#718)](https://github.com/PennyLaneAI/pennylane/pull/718) [(#741)](https://github.com/PennyLaneAI/pennylane/pull/741) [(#720)](https://github.com/PennyLaneAI/pennylane/pull/720)

This includes the following features:

* New `qml.qaoa.x_mixer` and `qml.qaoa.xy_mixer` functions for defining Pauli-X and XY mixer Hamiltonians.

* MaxCut: The `qml.qaoa.maxcut` function allows easy construction of the cost Hamiltonian and recommended mixer Hamiltonian for solving the MaxCut problem for a supplied graph.

* Layers: `qml.qaoa.cost_layer` and `qml.qaoa.mixer_layer` take cost and mixer Hamiltonians, respectively, and apply the corresponding QAOA cost and mixer layers to the quantum circuit

For example, using PennyLane to construct and solve a MaxCut problem with QAOA:

python
wires = range(3)
graph = Graph([(0, 1), (1, 2), (2, 0)])
cost_h, mixer_h = qaoa.maxcut(graph)

def qaoa_layer(gamma, alpha):
qaoa.cost_layer(gamma, cost_h)
qaoa.mixer_layer(alpha, mixer_h)

def antatz(params, **kwargs):

for w in wires:
qml.Hadamard(wires=w)

repeat the QAOA layer two times
qml.layer(qaoa_layer, 2, params[0], params[1])

dev = qml.device('default.qubit', wires=len(wires))
cost_function = qml.VQECost(ansatz, cost_h, dev)


* Added an `ApproxTimeEvolution` template to the PennyLane templates module, which can be used to implement Trotterized time-evolution under a Hamiltonian. [(710)](https://github.com/XanaduAI/pennylane/pull/710)

<img src="https://pennylane.readthedocs.io/en/latest/_static/templates/subroutines/approx_time_evolution.png" width=50%/>

* Added a `qml.layer` template-constructing function, which takes a unitary, and repeatedly applies it on a set of wires to a given depth. [(723)](https://github.com/PennyLaneAI/pennylane/pull/723)

python
def subroutine():
qml.Hadamard(wires=[0])
qml.CNOT(wires=[0, 1])
qml.PauliX(wires=[1])

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

qml.qnode(dev)
def circuit():
qml.layer(subroutine, 3)
return [qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))]


This creates the following circuit:
pycon
>>> circuit()
>>> print(circuit.draw())
0: ──H──╭C──X──H──╭C──X──H──╭C──X──┤ ⟨Z⟩
1: ─────╰X────────╰X────────╰X─────┤ ⟨Z⟩


* Added the `qml.utils.decompose_hamiltonian` function. This function can be used to decompose a Hamiltonian into a linear combination of Pauli operators. [(671)](https://github.com/XanaduAI/pennylane/pull/671)

pycon
>>> A = np.array(
... [[-2, -2+1j, -2, -2],
... [-2-1j, 0, 0, -1],
... [-2, 0, -2, -1],
... [-2, -1, -1, 0]])
>>> coeffs, obs_list = decompose_hamiltonian(A)


<h4>New device features</h4>

* It is now possible to specify custom wire labels, such as `['anc1', 'anc2', 0, 1, 3]`, where the labels can be strings or numbers. [(666)](https://github.com/XanaduAI/pennylane/pull/666)

Custom wire labels are defined by passing a list to the ``wires`` argument when creating the device:

pycon
>>> dev = qml.device("default.qubit", wires=['anc1', 'anc2', 0, 1, 3])


Quantum operations should then be invoked with these custom wire labels:

pycon
>>> qml.qnode(dev)
>>> def circuit():
... qml.Hadamard(wires='anc2')
... qml.CNOT(wires=['anc1', 3])
... ...


The existing behaviour, in which the number of wires is specified on device initialization, continues to work as usual. This gives a default behaviour where wires are labelled by consecutive integers.

pycon
>>> dev = qml.device("default.qubit", wires=5)


* An integrated device test suite has been added, which can be used to run basic integration tests on core or external devices. [(695)](https://github.com/PennyLaneAI/pennylane/pull/695) [(#724)](https://github.com/PennyLaneAI/pennylane/pull/724) [(#733)](https://github.com/PennyLaneAI/pennylane/pull/733)

The test can be invoked against a particular device by calling the ``pl-device-test`` command line program:

console
$ pl-device-test --device=default.qubit --shots=1234 --analytic=False


If the tests are run on external devices, the device and its dependencies must be installed locally. For more details, please see the [plugin test documentation](http://pennylane.readthedocs.io/en/latest/code/api/pennylane.devices.tests.html).

<h3>Improvements</h3>

* Added support for TensorFlow 2.3 and PyTorch 1.6. [(725)](https://github.com/PennyLaneAI/pennylane/pull/725)

* Returning probabilities is now supported from photonic QNodes. As with qubit QNodes, photonic QNodes returning probabilities are end-to-end differentiable. [(699)](https://github.com/XanaduAI/pennylane/pull/699/)

pycon
>>> dev = qml.device("strawberryfields.fock", wires=2, cutoff_dim=5)
>>> qml.qnode(dev)
... def circuit(a):
... qml.Displacement(a, 0, wires=0)
... return qml.probs(wires=0)
>>> print(circuit(0.5))
[7.78800783e-01 1.94700196e-01 2.43375245e-02 2.02812704e-03 1.26757940e-04]


<h3>Breaking changes</h3>

* The `pennylane.plugins` and `pennylane.beta.plugins` folders have been renamed to `pennylane.devices` and `pennylane.beta.devices`, to reflect their content better. [(726)](https://github.com/XanaduAI/pennylane/pull/726)

<h3>Bug fixes</h3>

* The PennyLane interface conversion functions can now convert QNodes with pre-existing interfaces. [(707)](https://github.com/XanaduAI/pennylane/pull/707)

<h3>Documentation</h3>

* The interfaces section of the documentation has been renamed to 'Interfaces and training', and updated with the latest variable handling details. [(753)](https://github.com/PennyLaneAI/pennylane/pull/753)

<h3>Contributors</h3>

This release contains contributions from (in alphabetical order):

Juan Miguel Arazzola, Thomas Bromley, Jack Ceroni, Alain Delgado Gran, Shadab Hussain, Theodor Isacsson, Josh Izaac, Nathan Killoran, Maria Schuld, Antal Száva, Nicola Vitucci.

0.10.0

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

<h4>New and improved simulators</h4>

* Added a new device, `default.qubit.tf`, a pure-state qubit simulator written using TensorFlow. As a result, it supports classical backpropagation as a means to compute the Jacobian. This can be faster than the parameter-shift rule for computing quantum gradients when the number of parameters to be optimized is large.

`default.qubit.tf` is designed to be used with end-to-end classical backpropagation (`diff_method="backprop"`) with the TensorFlow interface. This is the default method of differentiation when creating a QNode with this device.

Using this method, the created QNode is a 'white-box' that is tightly integrated with your TensorFlow computation, including [AutoGraph](https://www.tensorflow.org/guide/function) support:

pycon
>>> dev = qml.device("default.qubit.tf", wires=1)
>>> tf.function
... qml.qnode(dev, interface="tf", diff_method="backprop")
... def circuit(x):
... qml.RX(x[1], wires=0)
... qml.Rot(x[0], x[1], x[2], wires=0)
... return qml.expval(qml.PauliZ(0))
>>> weights = tf.Variable([0.2, 0.5, 0.1])
>>> with tf.GradientTape() as tape:
... res = circuit(weights)
>>> print(tape.gradient(res, weights))
tf.Tensor([-2.2526717e-01 -1.0086454e+00 1.3877788e-17], shape=(3,), dtype=float32)


See the `default.qubit.tf` [documentation](https://pennylane.ai/en/stable/code/api/pennylane.beta.plugins.DefaultQubitTF.html) for more details.

* The [default.tensor plugin](https://github.com/XanaduAI/pennylane/blob/master/pennylane/beta/plugins/default_tensor.py) has been significantly upgraded. It now allows two different tensor network representations to be used: `"exact"` and `"mps"`. The former uses a exact factorized representation of quantum states, while the latter uses a matrix product state representation. ([#572](https://github.com/XanaduAI/pennylane/pull/572)) ([#599](https://github.com/XanaduAI/pennylane/pull/599))

<h4>New machine learning functionality and integrations</h4>

* PennyLane QNodes can now be converted into Torch layers, allowing for creation of quantum and hybrid models using the `torch.nn` API. [(588)](https://github.com/XanaduAI/pennylane/pull/588)

A PennyLane QNode can be converted into a `torch.nn` layer using the `qml.qnn.TorchLayer` class:

pycon
>>> qml.qnode(dev)
... def qnode(inputs, weights_0, weight_1):
... define the circuit
... ...

>>> weight_shapes = {"weights_0": 3, "weight_1": 1}
>>> qlayer = qml.qnn.TorchLayer(qnode, weight_shapes)


A hybrid model can then be easily constructed:

pycon
>>> model = torch.nn.Sequential(qlayer, torch.nn.Linear(2, 2))


* Added a new "reversible" differentiation method which can be used in simulators, but not hardware.

The reversible approach is similar to backpropagation, but trades off extra computation for enhanced memory efficiency. Where backpropagation caches the state tensors at each step during a simulated evolution, the reversible method only caches the final pre-measurement state.

Compared to the parameter-shift method, the reversible method can be faster or slower, depending on the density and location of parametrized gates in a circuit (circuits with higher density of parametrized gates near the end of the circuit will see a benefit). [(670)](https://github.com/XanaduAI/pennylane/pull/670)

pycon
>>> dev = qml.device("default.qubit", wires=2)
... qml.qnode(dev, diff_method="reversible")
... def circuit(x):
... qml.RX(x, wires=0)
... qml.RX(x, wires=0)
... qml.CNOT(wires=[0,1])
... return qml.expval(qml.PauliZ(0))
>>> qml.grad(circuit)(0.5)
(array(-0.47942554),)


<h4>New templates and cost functions</h4>

* Added the new templates `UCCSD`, `SingleExcitationUnitary`, and`DoubleExcitationUnitary`, which together implement the Unitary Coupled-Cluster Singles and Doubles (UCCSD) ansatz to perform VQE-based quantum chemistry simulations using PennyLane-QChem. [(622)](https://github.com/XanaduAI/pennylane/pull/622) [(#638)](https://github.com/XanaduAI/pennylane/pull/638) [(#654)](https://github.com/XanaduAI/pennylane/pull/654) [(#659)](https://github.com/XanaduAI/pennylane/pull/659) [(#622)](https://github.com/XanaduAI/pennylane/pull/622)

* Added module `pennylane.qnn.cost` with class `SquaredErrorLoss`. The module contains classes to calculate losses and cost functions on circuits with trainable parameters. [(642)](https://github.com/XanaduAI/pennylane/pull/642)

<h3>Improvements</h3>

* A significant improvement with respect to how QNodes and interfaces mark quantum function arguments as differentiable when using Autograd, designed to improve performance and make QNodes more intuitive. [(648)](https://github.com/XanaduAI/pennylane/pull/648) [(#650)](https://github.com/XanaduAI/pennylane/pull/650)

In particular, the following changes have been made:

- A new `ndarray` subclass `pennylane.numpy.tensor`, which extends NumPy arrays with the keyword argument and attribute `requires_grad`. Tensors which have `requires_grad=False` are treated as non-differentiable by the Autograd interface.

- A new subpackage `pennylane.numpy`, which wraps `autograd.numpy` such that NumPy functions accept the `requires_grad` keyword argument, and allows Autograd to differentiate `pennylane.numpy.tensor` objects.

- The `argnum` argument to `qml.grad` is now optional; if not provided, arguments explicitly marked as `requires_grad=False` are excluded for the list of differentiable arguments. The ability to pass `argnum` has been retained for backwards compatibility, and if present the old behaviour persists.

* The QNode Torch interface now inspects QNode positional arguments. If any argument does not have the attribute `requires_grad=True`, it is automatically excluded from quantum gradient computations. [(652)](https://github.com/XanaduAI/pennylane/pull/652) [(#660)](https://github.com/XanaduAI/pennylane/pull/660)

* The QNode TF interface now inspects QNode positional arguments. If any argument is not being watched by a `tf.GradientTape()`, it is automatically excluded from quantum gradient computations. [(655)](https://github.com/XanaduAI/pennylane/pull/655) [(#660)](https://github.com/XanaduAI/pennylane/pull/660)

* QNodes have two new public methods: `QNode.set_trainable_args()` and `QNode.get_trainable_args()`. These are designed to be called by interfaces, to specify to the QNode which of its input arguments are differentiable. Arguments which are non-differentiable will not be converted to PennyLane Variable objects within the QNode. [(660)](https://github.com/XanaduAI/pennylane/pull/660)

* Added `decomposition` method to PauliX, PauliY, PauliZ, S, T, Hadamard, and PhaseShift gates, which decomposes each of these gates into rotation gates. [(668)](https://github.com/XanaduAI/pennylane/pull/668)

* The `CircuitGraph` class now supports serializing contained circuit operations and measurement basis rotations to an OpenQASM2.0 script via the new `CircuitGraph.to_openqasm()` method. [(623)](https://github.com/XanaduAI/pennylane/pull/623)

<h3>Breaking changes</h3>

* Removes support for Python 3.5. [(639)](https://github.com/XanaduAI/pennylane/pull/639)

<h3>Documentation</h3>

* Various small typos were fixed.

<h3>Contributors</h3>

This release contains contributions from (in alphabetical order):

Thomas Bromley, Jack Ceroni, Alain Delgado Gran, Theodor Isacsson, Josh Izaac, Nathan Killoran, Maria Schuld, Antal Száva, Nicola Vitucci.

0.9.0

<h3>New features</h3>

* Catalyst now supports the specification of shot-vectors when used with `qml.sample` measurements on the `lightning.qubit` device. [(1051)](https://github.com/PennyLaneAI/catalyst/pull/1051)

Shot-vectors allow shots to be specified as a list of shots, `[20, 1, 100]`, or as a tuple of the form `((num_shots, repetitions), ...)` such that `((20, 3), (1, 100))` is equivalent to `shots=[20, 20, 20, 1, 1, ..., 1]`.

This can result in more efficient quantum execution, as a single job representing the total number of shots is executed on the quantum device, with the measurement post-processing then coarse-grained with respect to the shot-vector.

For example,

python
dev = qml.device("lightning.qubit", wires=1, shots=((5, 2), 7))

qjit
qml.qnode(dev)
def circuit():
qml.Hadamard(0)
return qml.sample()


pycon
>>> circuit()
(Array([[0], [1], [0], [1], [1]], dtype=int64),
Array([[0], [1], [1], [0], [1]], dtype=int64),
Array([[1], [0], [1], [1], [0], [1], [0]], dtype=int64))


Note that other measurement types, such as `expval` and `probs`, currently do not support shot-vectors.

* A new function `catalyst.pipeline` allows the quantum-circuit-transformation pass pipeline for QNodes within a qjit-compiled workflow to be configured. [(1131)](https://github.com/PennyLaneAI/catalyst/pull/1131) [(#1240)](https://github.com/PennyLaneAI/catalyst/pull/1240)

python
import pennylane as qml
from catalyst import pipeline, qjit

my_passes = {
"cancel_inverses": {},
"my_circuit_transformation_pass": {"my-option" : "my-option-value"},
}

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

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

qjit
def fn(x):
return jnp.sin(circuit(x ** 2))


`pipeline` can also be used to specify different pass pipelines for different parts of the same qjit-compiled workflow:

python
my_pipeline = {
"cancel_inverses": {},
"my_circuit_transformation_pass": {"my-option" : "my-option-value"},
}

my_other_pipeline = {"cancel_inverses": {}}

qjit
def fn(x):
circuit_pipeline = pipeline(my_pipeline)(circuit)
circuit_other = pipeline(my_other_pipeline)(circuit)
return jnp.abs(circuit_pipeline(x) - circuit_other(x))


The pass pipeline order and options can be configured *globally* for a qjit-compiled function, by using the `circuit_transform_pipeline` argument of the `qjit` decorator.

python
my_passes = {
"cancel_inverses": {},
"my_circuit_transformation_pass": {"my-option" : "my-option-value"},
}

qjit(circuit_transform_pipeline=my_passes)
def fn(x):
return jnp.sin(circuit(x ** 2))


Global and local (via `pipeline`) configurations can coexist, however local pass pipelines will always take precedence over global pass pipelines.

The available MLIR passes are listed and documented in the [passes module documentation](https://docs.pennylane.ai/projects/catalyst/en/stable/code/__init__.html#module-catalyst.passes).

* A peephole merge rotations pass, which acts similarly to the Python-based [PennyLane merge rotations transform](https://docs.pennylane.ai/en/stable/code/api/pennylane.transforms.merge_rotations.html), is now available in MLIR and can be applied to QNodes within a qjit-compiled function. [(#1162)](https://github.com/PennyLaneAI/catalyst/pull/1162) [(#1205)](https://github.com/PennyLaneAI/catalyst/pull/1205) [(#1206)](https://github.com/PennyLaneAI/catalyst/pull/1206)

The `merge_rotations` pass can be provided to the `catalyst.pipeline` decorator:

python
from catalyst import pipeline, qjit

my_passes = {
"merge_rotations": {}
}

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

qjit
pipeline(my_passes)
qml.qnode(dev)
def g(x: float):
qml.RX(x, wires=0)
qml.RX(x, wires=0)
qml.Hadamard(wires=0)
return qml.expval(qml.PauliX(0))


It can also be applied directly to qjit-compiled QNodes via the `catalyst.passes.merge_rotations` Python decorator:

python
from catalyst.passes import merge_rotations

qjit
merge_rotations
qml.qnode(dev)
def g(x: float):
qml.RX(x, wires=0)
qml.RX(x, wires=0)
qml.Hadamard(wires=0)
return qml.expval(qml.PauliX(0))


* Static arguments of a qjit-compiled function can now be indicated by name via a `static_argnames` argument to the `qjit` decorator. [(1158)](https://github.com/PennyLaneAI/catalyst/pull/1158)

Specified static argument names will be treated as compile-time static values, allowing any hashable Python object to be passed to this function argument during compilation.

pycon
>>> qjit(static_argnames="y")
... def f(x, y):
... print(f"Compiling with y={y}")
... return x + y
>>> f(0.5, 0.3)
Compiling with y=0.3


The function will only be re-compiled if the hash values of the static arguments change. Otherwise, re-using previous static argument values will result in no re-compilation:

pycon
Array(0.8, dtype=float64)
>>> f(0.1, 0.3) no re-compilation occurs
Array(0.4, dtype=float64)
>>> f(0.1, 0.4) y changes, re-compilation
Compiling with y=0.4
Array(0.5, dtype=float64)


* Catalyst Autograph now supports updating a single index or a slice of JAX arrays using Python's array assignment operator syntax. [(769)](https://github.com/PennyLaneAI/catalyst/pull/769) [(#1143)](https://github.com/PennyLaneAI/catalyst/pull/1143)

Using operator assignment syntax in favor of `at...op` expressions is now possible for the following operations:

- `x[i] += y` in favor of `x.at[i].add(y)`
- `x[i] -= y` in favor of `x.at[i].add(-y)`
- `x[i] *= y` in favor of `x.at[i].multiply(y)`
- `x[i] /= y` in favor of `x.at[i].divide(y)`
- `x[i] **= y` in favor of `x.at[i].power(y)`

python
qjit(autograph=True)
def f(x):
first_dim = x.shape[0]
result = jnp.copy(x)

for i in range(first_dim):
result[i] *= 2 This is now supported

return result


pycon
>>> f(jnp.array([1, 2, 3]))
Array([2, 4, 6], dtype=int64)


* Catalyst now has a standalone compiler tool called `catalyst-cli` that quantum-compiles MLIR input files into an object file independent of the Python frontend. [(1208)](https://github.com/PennyLaneAI/catalyst/pull/1208) [(#1255)](https://github.com/PennyLaneAI/catalyst/pull/1255)

This compiler tool combines three stages of compilation:

1. `quantum-opt`: Performs the MLIR-level optimizations and lowers the input dialect to the LLVM dialect.
2. `mlir-translate`: Translates the input in the LLVM dialect into LLVM IR.
3. `llc`: Performs lower-level optimizations and creates the object file.

`catalyst-cli` runs all three stages under the hood by default, but it also has the ability to run each stage individually. For example:

console
Creates both the optimized IR and an object file
catalyst-cli input.mlir -o output.o

Only performs MLIR optimizations
catalyst-cli --tool=opt input.mlir -o llvm-dialect.mlir

Only lowers LLVM dialect MLIR input to LLVM IR
catalyst-cli --tool=translate llvm-dialect.mlir -o llvm-ir.ll

Only performs lower-level optimizations and creates object file
catalyst-cli --tool=llc llvm-ir.ll -o output.o


Note that `catalyst-cli` is only available when Catalyst is built from source, and is not included when installing Catalyst via pip or from wheels.

* Experimental integration of the PennyLane capture module is available. It currently only supports quantum gates, without control flow. [(1109)](https://github.com/PennyLaneAI/catalyst/pull/1109)

To trigger the PennyLane pipeline for capturing the program as a Jaxpr, simply set `experimental_capture=True` in the qjit decorator.

python
import pennylane as qml
from catalyst import qjit

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

qjit(experimental_capture=True)
qml.qnode(dev)
def circuit():
qml.Hadamard(0)
qml.CNOT([0, 1])
return qml.expval(qml.Z(0))


<h3>Improvements</h3>

* Multiple `qml.sample` calls can now be returned from the same program, and can be structured using Python containers. For example, a program can return a dictionary of the form `return {"first": qml.sample(), "second": qml.sample()}`. [(1051)](https://github.com/PennyLaneAI/catalyst/pull/1051)

* Catalyst now ships with `null.qubit`, a Catalyst runtime plugin that mocks out all functions in the QuantumDevice interface. This device is provided as a convenience for testing and benchmarking purposes. [(1179)](https://github.com/PennyLaneAI/catalyst/pull/1179)

python
qml.device("null.qubit", wires=1)

qml.qjit
qml.qnode(dev)
def g(x):
qml.RX(x, wires=0)
return qml.probs(wires=[0])


* Setting the `seed` argument in the `qjit` decorator will now seed sampled results, in addition to mid-circuit measurement results. [(1164)](https://github.com/PennyLaneAI/catalyst/pull/1164)

python
dev = qml.device("lightning.qubit", wires=1, shots=10)

qml.qnode(dev)
def circuit(x):
qml.RX(x, wires=0)
m = catalyst.measure(0)

if m:
qml.Hadamard(0)

return qml.sample()

qml.qjit(seed=37, autograph=True)
def workflow(x):
return jnp.squeeze(jnp.stack([circuit(x) for i in range(4)]))


pycon
>>> workflow(1.8)
Array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 1, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 1, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 0, 1, 1]], dtype=int64)
>>> workflow(1.8)
Array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 1, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 1, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 0, 1, 1]], dtype=int64)


Note that statistical measurement processes such as `expval`, `var`, and `probs` are currently not affected by seeding when shot noise is present.

* The `cancel_inverses` MLIR compilation pass (`-remove-chained-self-inverse`) now supports cancelling all Hermitian gates, as well as adjoints of arbitrary unitary operations. [(1136)](https://github.com/PennyLaneAI/catalyst/pull/1136) [(#1186)](https://github.com/PennyLaneAI/catalyst/pull/1186) [(#1211)](https://github.com/PennyLaneAI/catalyst/pull/1211)

For the full list of supported Hermitian gates please see the `cancel_inverses` documentation in `catalyst.passes`.

* Support is expanded for backend devices that exclusively return samples in the measurement basis. Pre- and post-processing now allows `qjit` to be used on these devices with `qml.expval`, `qml.var` and `qml.probs` measurements in addition to `qml.sample`, using the `measurements_from_samples` transform. [(1106)](https://github.com/PennyLaneAI/catalyst/pull/1106)

* Scalar tensors are eliminated from control flow operations in the program, and are replaced with bare scalars instead. This improves compilation time and memory usage at runtime by avoiding heap allocations and reducing the amount of instructions. [(1075)](https://github.com/PennyLaneAI/catalyst/pull/1075)

* Catalyst now supports NumPy 2.0. [(1119)](https://github.com/PennyLaneAI/catalyst/pull/1119) [(#1182)](https://github.com/PennyLaneAI/catalyst/pull/1182)

* Compiling QNodes to asynchronous functions will no longer print to `stderr` in case of an error. [(645)](https://github.com/PennyLaneAI/catalyst/pull/645)

* Gradient computations have been made more efficient, as calling gradients twice (with the same gradient parameters) will now only lower to a single MLIR function. [(1172)](https://github.com/PennyLaneAI/catalyst/pull/1172)

* `qml.sample()` and `qml.counts()` on `lightning.qubit`/`kokkos` can now be seeded with `qjit(seed=...)`. [(1164)](https://github.com/PennyLaneAI/catalyst/pull/1164) [(#1248)](https://github.com/PennyLaneAI/catalyst/pull/1248)

* The compiler pass `-remove-chained-self-inverse` can now also cancel adjoints of arbitrary unitary operations (in addition to the named Hermitian gates). [(1186)](https://github.com/PennyLaneAI/catalyst/pull/1186) [(#1211)](https://github.com/PennyLaneAI/catalyst/pull/1211)

* Add Lightning-GPU support to Catalyst docs and update tests. [(1254)](https://github.com/PennyLaneAI/catalyst/pull/1254)

<h3>Breaking changes</h3>

* The `static_size` field in the `AbstractQreg` class has been removed. [(1113)](https://github.com/PennyLaneAI/catalyst/pull/1113)

This reverts a previous breaking change.

* Nesting QNodes within one another now raises an error. [(1176)](https://github.com/PennyLaneAI/catalyst/pull/1176)

* The `debug.compile_from_mlir` function has been removed; please use `debug.replace_ir` instead. [(1181)](https://github.com/PennyLaneAI/catalyst/pull/1181)

* The `compiler.last_compiler_output` function has been removed; please use `compiler.get_output_of("last", workspace)` instead. [(1208)](https://github.com/PennyLaneAI/catalyst/pull/1208)

<h3>Bug fixes</h3>

* Fixes a bug where the second execution of a function with abstracted axes is failing. [(1247)](https://github.com/PennyLaneAI/catalyst/pull/1247)

* Fixes a bug in `catalyst.mitigate_with_zne` that would lead to incorrectly extrapolated results. [(1213)](https://github.com/PennyLaneAI/catalyst/pull/1213)

* Fixes a bug preventing the target of `qml.adjoint` and `qml.ctrl` calls from being transformed by AutoGraph. [(1212)](https://github.com/PennyLaneAI/catalyst/pull/1212)

* Resolves a bug where `mitigate_with_zne` does not work properly with shots and devices supporting only counts and samples (e.g., Qrack). [(1165)](https://github.com/PennyLaneAI/catalyst/pull/1165)

* Resolves a bug in the `vmap` function when passing shapeless values to the target. [(1150)](https://github.com/PennyLaneAI/catalyst/pull/1150)

* Fixes a bug that resulted in an error message when using `qml.cond` on callables with arguments. [(1151)](https://github.com/PennyLaneAI/catalyst/pull/1151)

* Fixes a bug that prevented taking the gradient of nested accelerate callbacks. [(1156)](https://github.com/PennyLaneAI/catalyst/pull/1156)

* Fixes some small issues with scatter lowering: [(1216)](https://github.com/PennyLaneAI/catalyst/pull/1216) [(#1217)](https://github.com/PennyLaneAI/catalyst/pull/1217)

- Registers the func dialect as a requirement for running the scatter lowering pass.
- Emits error if `%input`, `%update` and `%result` are not of length 1 instead of segfaulting.

* Fixes a performance issue with `catalyst.vmap`, where the root cause was in the lowering of the scatter operation. [(1214)](https://github.com/PennyLaneAI/catalyst/pull/1214)

* Fixes a bug where conditional-ed single gates cannot be used in qjit, e.g. `qml.cond(x > 1, qml.Hadamard)(wires=0)`. [(1232)](https://github.com/PennyLaneAI/catalyst/pull/1232)

<h3>Internal changes</h3>

* Removes deprecated PennyLane code across the frontend. [(1168)](https://github.com/PennyLaneAI/catalyst/pull/1168)

* Updates Enzyme to version `v0.0.149`. [(1142)](https://github.com/PennyLaneAI/catalyst/pull/1142)

* Adjoint canonicalization is now available in MLIR for `CustomOp` and `MultiRZOp`. It can be used with the `--canonicalize` pass in `quantum-opt`. [(1205)](https://github.com/PennyLaneAI/catalyst/pull/1205)

* Removes the `MemMemCpyOptPass` in llvm O2 (applied for Enzyme), which reduces bugs when running gradient-like functions. [(1063)](https://github.com/PennyLaneAI/catalyst/pull/1063)

* Bufferization of `gradient.ForwardOp` and `gradient.ReverseOp` now requires three steps: `gradient-preprocessing`, `gradient-bufferize`, and `gradient-postprocessing`. `gradient-bufferize` has a new rewrite for `gradient.ReturnOp`. [(1139)](https://github.com/PennyLaneAI/catalyst/pull/1139)

* A new MLIR pass `detensorize-scf` is added that works in conjunction with the existing `linalg-detensorize` pass to detensorize input programs. The IR generated by JAX wraps all values in the program in tensors, including scalars, leading to unnecessary memory allocations for programs compiled to CPU via the MLIR-to-LLVM pipeline. [(1075)](https://github.com/PennyLaneAI/catalyst/pull/1075)

* Importing Catalyst will now pollute less of JAX's global variables by using `LoweringParameters`. [(1152)](https://github.com/PennyLaneAI/catalyst/pull/1152)

* Cached primitive lowerings is used instead of a custom cache structure. [(1159)](https://github.com/PennyLaneAI/catalyst/pull/1159)

* Functions with multiple tapes are now split with a new mlir pass `--split-multiple-tapes`, with one tape per function. The reset routine that makes a measurement between tapes and inserts an X gate if measured one is no longer used. [(1017)](https://github.com/PennyLaneAI/catalyst/pull/1017) [(#1130)](https://github.com/PennyLaneAI/catalyst/pull/1130)

* Prefer creating new `qml.devices.ExecutionConfig` objects over using the global `qml.devices.DefaultExecutionConfig`. Doing so helps avoid unexpected bugs and test failures in case the `DefaultExecutionConfig` object becomes modified from its original state. [(1137)](https://github.com/PennyLaneAI/catalyst/pull/1137)

* Remove the old `QJITDevice` API. [(1138)](https://github.com/PennyLaneAI/catalyst/pull/1138)

* The device-capability loading mechanism has been moved into the `QJITDevice` constructor. [(1141)](https://github.com/PennyLaneAI/catalyst/pull/1141)

* Several functions related to device capabilities have been refactored. [(1149)](https://github.com/PennyLaneAI/catalyst/pull/1149)

In particular, the signatures of `get_device_capability`, `catalyst_decompose`, `catalyst_acceptance`, and `QJITDevice.__init__` have changed, and the `pennylane_operation_set` function has been removed entirely.

* Catalyst now generates nested modules denoting quantum programs. [(1144)](https://github.com/PennyLaneAI/catalyst/pull/1144)

Similar to MLIR's `gpu.launch_kernel` function, Catalyst, now supports a `call_function_in_module`. This allows Catalyst to call functions in modules and have modules denote a quantum kernel. This will allow for device-specific optimizations and compilation pipelines.

At the moment, no one is using this. This is just the necessary scaffolding to support device-specific transformations. As such, the module will be inlined to preserve current semantics. However, in the future, we will explore lowering this nested module into other IRs/binary formats and lowering `call_function_in_module` to something that can dispatch calls to another runtime/VM.


<h3>Contributors</h3>

This release contains contributions from (in alphabetical order):

Joey Carter,
Spencer Comin,
Amintor Dusko,
Lillian M.A. Frederiksen,
Sengthai Heng,
David Ittah,
Mehrdad Malekmohammadi,
Vincent Michaud-Rioux,
Romain Moyard,
Erick Ochoa Lopez,
Daniel Strano,
Raul Torres,
Paul Haochen Wang.

Page 8 of 11

© 2024 Safety CLI Cybersecurity Inc. All Rights Reserved.