diff --git a/doc/releases/changelog-0.19.0.md b/doc/releases/changelog-0.19.0.md new file mode 100644 index 00000000000..2e36beddff2 --- /dev/null +++ b/doc/releases/changelog-0.19.0.md @@ -0,0 +1,1083 @@ +:orphan: + +# Release 0.19.0 (current release) + +

New features since last release

+ +* Error mitigation using the zero-noise extrapolation method is now available through the + `transforms.mitigate_with_zne` transform. This transform can integrate with the + [Mitiq](https://mitiq.readthedocs.io/en/stable/) package for unitary folding and extrapolation + functionality. + [(#1813)](https://github.com/PennyLaneAI/pennylane/pull/1813) + + Consider the following noisy device: + + ```python + import pennylane as qml + + noise_strength = 0.05 + + dev = qml.device("default.mixed", wires=2) + dev = qml.transforms.insert(qml.AmplitudeDamping, noise_strength)(dev) + ``` + + We can mitigate the effects of this noise for circuits run on this device by using the added + transform: + + ```python + from pennylane import numpy as np + from pennylane.beta import qnode + + from mitiq.zne.scaling import fold_global + from mitiq.zne.inference import RichardsonFactory + + n_wires = 2 + n_layers = 2 + + shapes = qml.SimplifiedTwoDesign.shape(n_wires, n_layers) + np.random.seed(0) + w1, w2 = [np.random.random(s) for s in shapes] + + @qml.transforms.mitigate_with_zne([1, 2, 3], fold_global, RichardsonFactory.extrapolate) + @qnode(dev) + def circuit(w1, w2): + qml.SimplifiedTwoDesign(w1, w2, wires=range(2)) + return qml.expval(qml.PauliZ(0)) + ``` + + Now, executing `circuit` will be mitigated: + + ```pycon + >>> circuit(w1, w2) + 0.19113067083636542 + ``` + +* A differentiable Hartree-Fock (HF) solver has been added. It can be used to construct molecular Hamiltonians + that can be differentiated with respect to nuclear coordinates and basis-set parameters. + [(#1610)](https://github.com/PennyLaneAI/pennylane/pull/1610) + + The HF solver computes the integrals over basis functions, constructs the relevant matrices, and + performs self-consistent-field iterations to obtain a set of optimized molecular orbital + coefficients. These coefficients and the computed integrals over basis functions are used to + construct the one- and two-body electron integrals in the molecular orbital basis which can be + used to generate a differentiable second-quantized Hamiltonian in the fermionic and qubit basis. + + The following code shows the construction of the Hamiltonian for the hydrogen molecule where the + geometry of the molecule and the basis set parameters are all differentiable. + + ```python + import pennylane as qml + from pennylane import numpy as np + + symbols = ["H", "H"] + geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 2.0]], requires_grad=True) + alpha = np.array([[3.42525091, 0.62391373, 0.1688554], + [3.42525091, 0.62391373, 0.1688554]], requires_grad = True) + coeff = np.array([[0.15432897, 0.53532814, 0.44463454], + [0.15432897, 0.53532814, 0.44463454]], requires_grad = True) + + # we create a molecule object with differentiable atomic coordinates and basis set parameters + # alpha and coeff are the exponentents and contraction coefficients of the Gaussian functions + mol = qml.hf.Molecule(symbols, geometry, alpha=alpha, coeff=coeff) + args = [geometry, alpha, coeff] # initial values of the differentiable parameters + + hamiltonian = qml.hf.generate_hamiltonian(mol)(*args) + ``` + + The generated Hamiltonian can be used in a circuit where the molecular geometry, the basis set + parameters and the circuit parameters are optimized simultaneously. + + ```python + import autograd + + params = [np.array([0.0], requires_grad=True)] + dev = qml.device("default.qubit", wires=4) + hf_state = np.array([1, 1, 0, 0]) + + def generate_circuit(mol): + @qml.qnode(dev) + def circuit(*args): + qml.BasisState(hf_state, wires=[0, 1, 2, 3]) + qml.DoubleExcitation(*args[0][0], wires=[0, 1, 2, 3]) + return qml.expval(hf.generate_hamiltonian(mol)(*args[1:])) + return circuit + + for n in range(10): # geometry and parameter optimization loop + + # we create a molecule object with differentiable atomic coordinates and basis set parameters + # alpha and coeff are the exponentents and contraction coefficients of the Gaussian functions + mol = hf.Molecule(symbols, geometry, alpha=alpha, coeff=coeff) + args_ = [params, *args] # initial values of the differentiable parameters + + # compute gradients with respect to the circuit parameters and update the parameters + g_params = autograd.grad(generate_circuit(mol), argnum = 0)(*args_) + params = params - 0.1 * g_params[0] + + # compute gradients with respect to the nuclear coordinates and update geometry + forces = autograd.grad(generate_circuit(mol), argnum = 1)(*args_) + geometry = geometry - 0.5 * forces + + # compute gradients with respect to the Gaussian exponents and update the exponents + g_alpha = autograd.grad(generate_circuit(mol), argnum = 2)(*args_) + alpha = alpha - 0.1 * g_alpha + + # compute gradients with respect to the Gaussian contraction coefficients and update them + g_coeff = autograd.grad(generate_circuit(mol), argnum = 3)(*args_) + coeff = coeff - 0.1 * g_coeff + ``` + + The components of the HF solver can also be differentiated individually. For instance, the overlap + integral can be differentiated with respect to the basis set parameters as + + ```python + symbols = ["H", "H"] + geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 2.0]], requires_grad=False) + alpha = np.array([[3.42525091, 0.62391373, 0.1688554], + [3.42525091, 0.62391373, 0.1688554]], requires_grad = True) + coeff = np.array([[0.15432897, 0.53532814, 0.44463454], + [0.15432897, 0.53532814, 0.44463454]], requires_grad = True) + + mol = qml.hf.Molecule(symbols, geometry, alpha=alpha, coeff=coeff) + args = [alpha, coeff] + + a = mol.basis_set[0] + b = mol.basis_set[1] + + g_alpha = autograd.grad(qml.hf.generate_overlap(a, b), argnum = 0)(*args) + g_coeff = autograd.grad(qml.hf.generate_overlap(a, b), argnum = 1)(*args) + ``` + +* The `insert` transform has now been added, providing a way to insert single-qubit operations into + a quantum circuit. The transform can apply to quantum functions, tapes, and devices. + [(#1795)](https://github.com/PennyLaneAI/pennylane/pull/1795) + + The following QNode can be transformed to add noise to the circuit: + + ```python + from pennylane.transforms import insert + + dev = qml.device("default.mixed", wires=2) + + @qml.qnode(dev) + @insert(qml.AmplitudeDamping, 0.2, position="end") + def f(w, x, y, z): + qml.RX(w, wires=0) + qml.RY(x, wires=1) + qml.CNOT(wires=[0, 1]) + qml.RY(y, wires=0) + qml.RX(z, wires=1) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + ``` + + Executions of this circuit will differ from the noise-free value: + + ```pycon + >>> f(0.9, 0.4, 0.5, 0.6) + tensor(0.754847, requires_grad=True) + >>> print(qml.draw(f)(0.9, 0.4, 0.5, 0.6)) + 0: ──RX(0.9)──╭C──RY(0.5)──AmplitudeDamping(0.2)──╭┤ ⟨Z ⊗ Z⟩ + 1: ──RY(0.4)──╰X──RX(0.6)──AmplitudeDamping(0.2)──╰┤ ⟨Z ⊗ Z⟩ + ``` + +* A new class has been added to store operator attributes, such as `self_inverses`, + and `composable_rotation`, as a list of operation names. + [(#1763)](https://github.com/PennyLaneAI/pennylane/pull/1763) + + A number of such attributes, for the purpose of compilation transforms, can be found + in `ops/qubit/attributes.py`, but the class can also be used to create your own. For + example, we can create a new Attribute, `pauli_ops`, like so: + + ```pycon + >>> from pennylane.ops.qubits.attributes import Attribute + >>> pauli_ops = Attribute(["PauliX", "PauliY", "PauliZ"]) + ``` + + We can check either a string or an Operation for inclusion in this set: + + ```pycon + >>> qml.PauliX(0) in pauli_ops + True + >>> "Hadamard" in pauli_ops + False + ``` + + We can also dynamically add operators to the sets at runtime. This is useful + for adding custom operations to the attributes such as `composable_rotations` + and ``self_inverses`` that are used in compilation transforms. For example, + suppose you have created a new Operation, `MyGate`, which you know to be its + own inverse. Adding it to the set, like so + + ```pycon + >>> from pennylane.ops.qubits.attributes import self_inverses + >>> self_inverses.add("MyGate") + ``` + + will enable the gate to be considered by the `cancel_inverses` compilation + transform if two such gates are adjacent in a circuit. + +* Common tape expansion functions are now available in `qml.transforms`, + alongside a new `create_expand_fn` function for easily creating expansion functions + from stopping criteria. + [(#1734)](https://github.com/PennyLaneAI/pennylane/pull/1734) + [(#1760)](https://github.com/PennyLaneAI/pennylane/pull/1760) + + `create_expand_fn` takes the default depth to which the expansion function + should expand a tape, a stopping criterion, an optional device, and a docstring to be set for the + created function. + The stopping criterion must take a queuable object and return a boolean. + +* A new transform, `@qml.batch_params`, has been added, that makes QNodes + handle a batch dimension in trainable parameters. + [(#1710)](https://github.com/PennyLaneAI/pennylane/pull/1710) + [(#1761)](https://github.com/PennyLaneAI/pennylane/pull/1761) + + This transform will create multiple circuits, one per batch dimension. + As a result, it is both simulator and hardware compatible. + + ```python + @qml.batch_params + @qml.beta.qnode(dev) + def circuit(x, weights): + qml.RX(x, wires=0) + qml.RY(0.2, wires=1) + qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1, 2]) + return qml.expval(qml.Hadamard(0)) + ``` + + The `qml.batch_params` decorator allows us to pass arguments `x` and `weights` + that have a batch dimension. For example, + + ```pycon + >>> batch_size = 3 + >>> x = np.linspace(0.1, 0.5, batch_size) + >>> weights = np.random.random((batch_size, 10, 3, 3)) + ``` + + If we evaluate the QNode with these inputs, we will get an output + of shape ``(batch_size,)``: + + ```pycon + >>> circuit(x, weights) + [-0.30773348 0.23135516 0.13086565] + ``` + +* The new `qml.fourier.qnode_spectrum` function extends the former + `qml.fourier.spectrum` function + and takes classical processing of QNode arguments into account. + The frequencies are computed per (requested) QNode argument instead + of per gate `id`. The gate `id`s are ignored. + [(#1681)](https://github.com/PennyLaneAI/pennylane/pull/1681) + [(#1720)](https://github.com/PennyLaneAI/pennylane/pull/1720) + + Consider the following example, which uses non-trainable inputs `x`, `y` and `z` + as well as trainable parameters `w` as arguments to the QNode. + + ```python + import pennylane as qml + import numpy as np + + n_qubits = 3 + dev = qml.device("default.qubit", wires=n_qubits) + + @qml.qnode(dev) + def circuit(x, y, z, w): + for i in range(n_qubits): + qml.RX(0.5*x[i], wires=i) + qml.Rot(w[0,i,0], w[0,i,1], w[0,i,2], wires=i) + qml.RY(2.3*y[i], wires=i) + qml.Rot(w[1,i,0], w[1,i,1], w[1,i,2], wires=i) + qml.RX(z, wires=i) + return qml.expval(qml.PauliZ(wires=0)) + + x = np.array([1., 2., 3.]) + y = np.array([0.1, 0.3, 0.5]) + z = -1.8 + w = np.random.random((2, n_qubits, 3)) + ``` + + This circuit looks as follows: + + ```pycon + >>> print(qml.draw(circuit)(x, y, z, w)) + 0: ──RX(0.5)──Rot(0.598, 0.949, 0.346)───RY(0.23)──Rot(0.693, 0.0738, 0.246)──RX(-1.8)──┤ ⟨Z⟩ + 1: ──RX(1)────Rot(0.0711, 0.701, 0.445)──RY(0.69)──Rot(0.32, 0.0482, 0.437)───RX(-1.8)──┤ + 2: ──RX(1.5)──Rot(0.401, 0.0795, 0.731)──RY(1.15)──Rot(0.756, 0.38, 0.38)─────RX(-1.8)──┤ + ``` + + Applying the `qml.fourier.qnode_spectrum` function to the circuit for the non-trainable + parameters, we obtain: + + ```pycon + >>> spec = qml.fourier.qnode_spectrum(circuit, encoding_args={"x", "y", "z"})(x, y, z, w) + >>> for inp, freqs in spec.items(): + ... print(f"{inp}: {freqs}") + "x": {(0,): [-0.5, 0.0, 0.5], (1,): [-0.5, 0.0, 0.5], (2,): [-0.5, 0.0, 0.5]} + "y": {(0,): [-2.3, 0.0, 2.3], (1,): [-2.3, 0.0, 2.3], (2,): [-2.3, 0.0, 2.3]} + "z": {(): [-3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0]} + ``` + + We can see that all three parameters in the QNode arguments ``x`` and ``y`` + contribute the spectrum of a Pauli rotation ``[-1.0, 0.0, 1.0]``, rescaled with the + prefactor of the respective parameter in the circuit. + The three ``RX`` rotations using the parameter ``z`` accumulate, yielding a more + complex frequency spectrum. + + For details on how to control for which parameters the spectrum is computed, + a comparison to `qml.fourier.circuit_spectrum`, and other usage details, please see the + [fourier.qnode_spectrum docstring](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.fourier.qnode_spectrum.html). + +* There is a new utility function `qml.math.is_independent` that checks whether + a callable is independent of its arguments. + [(#1700)](https://github.com/PennyLaneAI/pennylane/pull/1700) + + **Warning** + + This function is experimental and might behave differently than expected. + Also, it might be subject to change. + + **Disclaimer** + + Note that the test relies on both numerical and analytical checks, except + when using the PyTorch interface which only performs a numerical check. + It is known that there are edge cases on which this test will yield wrong + results, in particular non-smooth functions may be problematic. + For details, please refer to the + [is_indpendent docstring](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.math.is_independent.html). + +* Support for differentiable execution of batches of circuits has been + extended to the JAX interface for scalar functions, via the beta + `pennylane.interfaces.batch` module. + [(#1634)](https://github.com/PennyLaneAI/pennylane/pull/1634) + [(#1685)](https://github.com/PennyLaneAI/pennylane/pull/1685) + + For example using the `execute` function from the `pennylane.interfaces.batch` module: + + ```python + from pennylane.interfaces.batch import execute + + def cost_fn(x): + with qml.tape.JacobianTape() as tape1: + qml.RX(x[0], wires=[0]) + qml.RY(x[1], wires=[1]) + qml.CNOT(wires=[0, 1]) + qml.var(qml.PauliZ(0) @ qml.PauliX(1)) + + with qml.tape.JacobianTape() as tape2: + qml.RX(x[0], wires=0) + qml.RY(x[0], wires=1) + qml.CNOT(wires=[0, 1]) + qml.probs(wires=1) + + result = execute( + [tape1, tape2], dev, + gradient_fn=qml.gradients.param_shift, + interface="autograd" + ) + return (result[0] + result[1][0, 0])[0] + + res = jax.grad(cost_fn)(params) + ``` + +* The unitary matrix corresponding to a quantum circuit can now be generated using the new + `get_unitary_matrix()` transform. + [(#1609)](https://github.com/PennyLaneAI/pennylane/pull/1609) + [(#1786)](https://github.com/PennyLaneAI/pennylane/pull/1786) + + This transform is fully differentiable across all supported PennyLane autodiff frameworks. + + ```python + def circuit(theta): + qml.RX(theta, wires=1) + qml.PauliZ(wires=0) + qml.CNOT(wires=[0, 1]) + ``` + + ```pycon + >>> theta = torch.tensor(0.3, requires_grad=True) + >>> matrix = qml.transforms.get_unitary_matrix(circuit)(theta) + >>> print(matrix) + tensor([[ 0.9888+0.0000j, 0.0000+0.0000j, 0.0000-0.1494j, 0.0000+0.0000j], + [ 0.0000+0.0000j, 0.0000+0.1494j, 0.0000+0.0000j, -0.9888+0.0000j], + [ 0.0000-0.1494j, 0.0000+0.0000j, 0.9888+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, -0.9888+0.0000j, 0.0000+0.0000j, 0.0000+0.1494j]], + grad_fn=) + >>> loss = torch.real(torch.trace(matrix)) + >>> loss.backward() + >>> theta.grad + tensor(-0.1494) + ``` + +* Arbitrary two-qubit unitaries can now be decomposed into elementary gates. This + functionality has been incorporated into the `qml.transforms.unitary_to_rot` transform, and is + available separately as `qml.transforms.two_qubit_decomposition`. + [(#1552)](https://github.com/PennyLaneAI/pennylane/pull/1552) + + As an example, consider the following randomly-generated matrix and circuit that uses it: + + ```python + U = np.array([ + [-0.03053706-0.03662692j, 0.01313778+0.38162226j, 0.4101526 -0.81893687j, -0.03864617+0.10743148j], + [-0.17171136-0.24851809j, 0.06046239+0.1929145j, -0.04813084-0.01748555j, -0.29544883-0.88202604j], + [ 0.39634931-0.78959795j, -0.25521689-0.17045233j, -0.1391033 -0.09670952j, -0.25043606+0.18393466j], + [ 0.29599198-0.19573188j, 0.55605806+0.64025769j, 0.06140516+0.35499559j, 0.02674726+0.1563311j ] + ]) + + dev = qml.device('default.qubit', wires=2) + + @qml.qnode(dev) + @qml.transforms.unitary_to_rot + def circuit(x, y): + qml.RX(x, wires=0) + qml.QubitUnitary(U, wires=[0, 1]) + qml.RY(y, wires=0) + return qml.expval(qml.PauliZ(wires=0)) + ``` + + If we run the circuit, we can see the new decomposition: + + ```pycon + >>> circuit(0.3, 0.4) + tensor(-0.70520073, requires_grad=True) + >>> print(qml.draw(circuit)(0.3, 0.4)) + 0: ──RX(0.3)─────────────────Rot(-3.5, 0.242, 0.86)──╭X──RZ(0.176)───╭C─────────────╭X──Rot(5.56, 0.321, -2.09)───RY(0.4)──┤ ⟨Z⟩ + 1: ──Rot(-1.64, 2.69, 1.58)──────────────────────────╰C──RY(-0.883)──╰X──RY(-1.47)──╰C──Rot(-1.46, 0.337, 0.587)───────────┤ + ``` + +* The transform for the Jacobian of the classical preprocessing within a QNode, + `qml.transforms.classical_jacobian`, now takes a keyword argument `argnum` to specify + the QNode argument indices with respect to which the Jacobian is computed. + [(#1645)](https://github.com/PennyLaneAI/pennylane/pull/1645) + + An example for the usage of ``argnum`` is + + ```python + @qml.qnode(dev) + def circuit(x, y, z): + qml.RX(qml.math.sin(x), wires=0) + qml.CNOT(wires=[0, 1]) + qml.RY(y ** 2, wires=1) + qml.RZ(1 / z, wires=1) + return qml.expval(qml.PauliZ(0)) + + jac_fn = qml.transforms.classical_jacobian(circuit, argnum=[1, 2]) + ``` + + The Jacobian can then be computed at specified parameters. + + ```pycon + >>> x, y, z = np.array([0.1, -2.5, 0.71]) + >>> jac_fn(x, y, z) + (array([-0., -5., -0.]), array([-0. , -0. , -1.98373339])) + ``` + + The returned arrays are the derivatives of the three parametrized gates in the circuit + with respect to `y` and `z` respectively. + + There also are explicit tests for `classical_jacobian` now, which previously was tested + implicitly via its use in the `metric_tensor` transform. + + For more usage details, please see the + [classical Jacobian docstring](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.transforms.classical_jacobian.html). + +* Added a new operation `OrbitalRotation`, which implements the spin-adapted spatial orbital rotation gate. + [(#1665)](https://github.com/PennyLaneAI/pennylane/pull/1665) + + An example circuit that uses `OrbitalRotation` operation is: + + ```python + dev = qml.device('default.qubit', wires=4) + @qml.qnode(dev) + def circuit(phi): + qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3]) + qml.OrbitalRotation(phi, wires=[0, 1, 2, 3]) + return qml.state() + ``` + + If we run this circuit, we will get the following output + + ```pycon + >>> circuit(0.1) + array([ 0. +0.j, 0. +0.j, 0. +0.j, + 0.00249792+0.j, 0. +0.j, 0. +0.j, + -0.04991671+0.j, 0. +0.j, 0. +0.j, + -0.04991671+0.j, 0. +0.j, 0. +0.j, + 0.99750208+0.j, 0. +0.j, 0. +0.j, + 0. +0.j]) + ``` + +* A new, experimental QNode has been added, that adds support for batch execution of circuits, + custom quantum gradient support, and arbitrary order derivatives. This QNode is available via + `qml.beta.QNode`, and `@qml.beta.qnode`. + [(#1642)](https://github.com/PennyLaneAI/pennylane/pull/1642) + [(#1646)](https://github.com/PennyLaneAI/pennylane/pull/1646) + [(#1651)](https://github.com/PennyLaneAI/pennylane/pull/1651) + + It differs from the standard QNode in several ways: + + - Custom gradient transforms can be specified as the differentiation method: + + ```python + @qml.gradients.gradient_transform + def my_gradient_transform(tape): + ... + return tapes, processing_fn + + @qml.beta.qnode(dev, diff_method=my_gradient_transform) + def circuit(): + ``` + + - Arbitrary :math:`n`-th order derivatives are supported on hardware using + gradient transforms such as the parameter-shift rule. To specify that an :math:`n`-th + order derivative of a QNode will be computed, the `max_diff` argument should be set. + By default, this is set to 1 (first-order derivatives only). + + - Internally, if multiple circuits are generated for execution simultaneously, they + will be packaged into a single job for execution on the device. This can lead to + significant performance improvement when executing the QNode on remote + quantum hardware. + + - When decomposing the circuit, the default decomposition strategy will prioritize + decompositions that result in the smallest number of parametrized operations + required to satisfy the differentiation method. Additional decompositions required + to satisfy the native gate set of the quantum device will be performed later, by the + device at execution time. While this may lead to a slight increase in classical processing, + it significantly reduces the number of circuit evaluations needed to compute + gradients of complex unitaries. + + In an upcoming release, this QNode will replace the existing one. If you come across any bugs + while using this QNode, please let us know via a [bug + report](https://github.com/PennyLaneAI/pennylane/issues/new?assignees=&labels=bug+%3Abug%3A&template=bug_report.yml&title=%5BBUG%5D) + on our GitHub bug tracker. + + Currently, this beta QNode does not support the following features: + + - Non-mutability via the `mutable` keyword argument + - Viewing specifications with `qml.specs` + - The `reversible` QNode differentiation method + - The ability to specify a `dtype` when using PyTorch and TensorFlow. + + It is also not tested with the `qml.qnn` module. + +* Two new methods were added to the Device API, allowing PennyLane devices + increased control over circuit decompositions. + [(#1651)](https://github.com/PennyLaneAI/pennylane/pull/1651) + + - `Device.expand_fn(tape) -> tape`: expands a tape such that it is supported by the device. By + default, performs the standard device-specific gate set decomposition done in the default + QNode. Devices may overwrite this method in order to define their own decomposition logic. + + Note that the numerical result after applying this method should remain unchanged; PennyLane + will assume that the expanded tape returns exactly the same value as the original tape when + executed. + + - `Device.batch_transform(tape) -> (tapes, processing_fn)`: preprocesses the tape in the case + where the device needs to generate multiple circuits to execute from the input circuit. The + requirement of a post-processing function makes this distinct to the `expand_fn` method above. + + By default, this method applies the transform + + .. math:: \left\langle \sum_i c_i h_i\right\rangle -> \sum_i c_i \left\langle h_i \right\rangle + + if `expval(H)` is present on devices that do not natively support Hamiltonians with + non-commuting terms. + +* Added a new template `GateFabric`, which implements a local, expressive, quantum-number-preserving + ansatz proposed by Anselmetti *et al.* in [arXiv:2104.05692](https://arxiv.org/abs/2104.05695). + [(#1687)](https://github.com/PennyLaneAI/pennylane/pull/1687) + + An example of a circuit using `GateFabric` template is: + + ```python + coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614]) + H, qubits = qml.qchem.molecular_hamiltonian(["H", "H"], coordinates) + ref_state = qml.qchem.hf_state(electrons=2, qubits) + + dev = qml.device('default.qubit', wires=qubits) + @qml.qnode(dev) + def ansatz(weights): + qml.templates.GateFabric(weights, wires=[0,1,2,3], + init_state=ref_state, include_pi=True) + return qml.expval(H) + ``` + + For more details, see the [GateFabric documentation](../code/api/pennylane.templates.layers.GateFabric.html). + +* Added a new template `kUpCCGSD`, which implements a unitary coupled cluster ansatz with + generalized singles and pair doubles excitation operators, proposed by Joonho Lee *et al.* + in [arXiv:1810.02327](https://arxiv.org/abs/1810.02327). + [(#1743)](https://github.com/PennyLaneAI/pennylane/pull/1743) + + An example of a circuit using `kUpCCGSD` template is: + + ```python + coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614]) + H, qubits = qml.qchem.molecular_hamiltonian(["H", "H"], coordinates) + ref_state = qml.qchem.hf_state(electrons=2, qubits) + + dev = qml.device('default.qubit', wires=qubits) + @qml.qnode(dev) + def ansatz(weights): + qml.templates.kUpCCGSD(weights, wires=[0,1,2,3], k=0, delta_sz=0, + init_state=ref_state) + return qml.expval(H) + ``` + + +

Improvements

+ +* The default for an `Operation`'s `control_wires` attribute is now an empty `Wires` + object instead of the attribute raising a `NonImplementedError`. + [(#1821)](https://github.com/PennyLaneAI/pennylane/pull/1821) + +* `qml.circuit_drawer.MPLDrawer` will now automatically rotate and resize text to fit inside + the rectangle created by the `box_gate` method. + [(#1764)](https://github.com/PennyLaneAI/pennylane/pull/1764) + +* Quantum function transforms and batch transforms can now be applied to devices. + Once applied to a device, any quantum function executed on the + modified device will be transformed prior to execution. + [(#1809)](https://github.com/PennyLaneAI/pennylane/pull/1809) + [(#1810)](https://github.com/PennyLaneAI/pennylane/pull/1810) + + ```python + dev = qml.device("default.mixed", wires=1) + dev = qml.transforms.merge_rotations()(dev) + + @qml.beta.qnode(dev) + def f(w, x, y, z): + qml.RX(w, wires=0) + qml.RX(x, wires=0) + qml.RX(y, wires=0) + qml.RX(z, wires=0) + return qml.expval(qml.PauliZ(0)) + ``` + + ```pycon + >>> print(f(0.9, 0.4, 0.5, 0.6)) + -0.7373937155412453 + >>> print(qml.draw(f, expansion_strategy="device")(0.9, 0.4, 0.5, 0.6)) + 0: ──RX(2.4)──┤ ⟨Z⟩ + ``` + +* The `ApproxTimeEvolution` template can now be used with Hamiltonians that have + trainable coefficients. + [(#1789)](https://github.com/PennyLaneAI/pennylane/pull/1789) + + Resulting QNodes can be differentiated with respect to both the time parameter + *and* the Hamiltonian coefficients. + + ```python + dev = qml.device('default.qubit', wires=2) + obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)] + + @qml.qnode(dev) + def circuit(coeffs, t): + H = qml.Hamiltonian(coeffs, obs) + qml.templates.ApproxTimeEvolution(H, t, 2) + return qml.expval(qml.PauliZ(0)) + ``` + + ```pycon + >>> t = np.array(0.54, requires_grad=True) + >>> coeffs = np.array([-0.6, 2.0], requires_grad=True) + >>> qml.grad(circuit)(coeffs, t) + (array([-1.07813375, -1.07813375]), array(-2.79516158)) + ``` + + All differentiation methods, including backpropagation and the parameter-shift + rule, are supported. + +* Templates are now top level imported and can be used directly e.g. `qml.QFT(wires=0)`. + [(#1779)](https://github.com/PennyLaneAI/pennylane/pull/1779) + +* Operators now have a `label` method to determine how they are drawn. This will + eventually override the `RepresentationResolver` class. + [(#1678)](https://github.com/PennyLaneAI/pennylane/pull/1678) + +* The operation `label` method now supports string variables. + [(#1815)](https://github.com/PennyLaneAI/pennylane/pull/1815) + +* It is now possible to draw QNodes that have been transformed by a 'batch transform'; that is, + a transform that maps a single QNode into multiple circuits under the hood. Examples of + batch transforms include `@qml.metric_tensor` and `@qml.gradients`. + [(#1762)](https://github.com/PennyLaneAI/pennylane/pull/1762) + + For example, consider the parameter-shift rule, which generates two circuits per parameter; + one circuit that has the parameter shifted forward, and another that has the parameter shifted + backwards: + + ```python + dev = qml.device("default.qubit", wires=2) + + @qml.gradients.param_shift + @qml.beta.qnode(dev) + def circuit(x): + qml.RX(x, wires=0) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(wires=0)) + ``` + + ```pycon + >>> print(qml.draw(circuit)(0.6)) + 0: ──RX(2.17)──╭C──┤ ⟨Z⟩ + 1: ────────────╰X──┤ + + 0: ──RX(-0.971)──╭C──┤ ⟨Z⟩ + 1: ──────────────╰X──┤ + ``` + +* All qubit operations have been re-written to use the `qml.math` framework + for internal classical processing and the generation of their matrix representations. + As a result these representations are now fully differentiable, and the + framework-specific device classes no longer need to maintain framework-specific + versions of these matrices. + [(#1749)](https://github.com/PennyLaneAI/pennylane/pull/1749) + +* A new utility class `qml.BooleanFn` is introduced. It wraps a function that takes a single + argument and returns a Boolean. + [(#1734)](https://github.com/PennyLaneAI/pennylane/pull/1734) + + After wrapping, `qml.BooleanFn` can be called like the wrapped function, and + multiple instances can be manipulated and combined with the bitwise operators + `&`, `|` and `~`. + +* `qml.probs` now accepts an attribute `op` that allows to rotate the computational basis and get the + probabilities in the rotated basis. + [(#1692)](https://github.com/PennyLaneAI/pennylane/pull/1692) + +* The `qml.beta.QNode` now supports the `qml.qnn` module. + [(#1748)](https://github.com/PennyLaneAI/pennylane/pull/1748) + +* `@qml.beta.QNode` now supports the `qml.specs` transform. + [(#1739)](https://github.com/PennyLaneAI/pennylane/pull/1739) + +* `qml.circuit_drawer.drawable_layers` and `qml.circuit_drawer.drawable_grid` process a list of + operations to layer positions for drawing. + [(#1639)](https://github.com/PennyLaneAI/pennylane/pull/1639) + +* `qml.transforms.batch_transform` now accepts `expand_fn`s that take additional arguments and + keyword arguments. In fact, `expand_fn` and `transform_fn` now **must** have the same signature. + [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) + +* The `qml.batch_transform` decorator is now ignored during Sphinx builds, allowing + the correct signature to display in the built documentation. + [(#1733)](https://github.com/PennyLaneAI/pennylane/pull/1733) + +* The use of `expval(H)`, where `H` is a cost Hamiltonian generated by the `qaoa` module, + has been sped up. This was achieved by making PennyLane decompose a circuit with an `expval(H)` + measurement into subcircuits if the `Hamiltonian.grouping_indices` attribute is set, and setting + this attribute in the relevant `qaoa` module functions. + [(#1718)](https://github.com/PennyLaneAI/pennylane/pull/1718) + +* The tests for qubit operations are split into multiple files. + [(#1661)](https://github.com/PennyLaneAI/pennylane/pull/1661) + +* The `qml.metric_tensor` transform has been improved with regards to + both function and performance. + [(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638) + [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) + + - If the underlying device supports batch execution of circuits, the quantum circuits required to + compute the metric tensor elements will be automatically submitted as a batched job. This can + lead to significant performance improvements for devices with a non-trivial job submission + overhead. + + - Previously, the transform would only return the metric tensor with respect to gate arguments, + and ignore any classical processing inside the QNode, even very trivial classical processing + such as parameter permutation. The metric tensor now takes into account classical processing, + and returns the metric tensor with respect to QNode arguments, not simply gate arguments: + + ```pycon + >>> @qml.qnode(dev) + ... def circuit(x): + ... qml.Hadamard(wires=1) + ... qml.RX(x[0], wires=0) + ... qml.CNOT(wires=[0, 1]) + ... qml.RY(x[1] ** 2, wires=1) + ... qml.RY(x[1], wires=0) + ... return qml.expval(qml.PauliZ(0)) + >>> x = np.array([0.1, 0.2], requires_grad=True) + >>> qml.metric_tensor(circuit)(x) + array([[0.25 , 0. ], + [0. , 0.28750832]]) + ``` + + To revert to the previous behaviour of returning the metric tensor with respect to gate + arguments, `qml.metric_tensor(qnode, hybrid=False)` can be passed. + + ```pycon + >>> qml.metric_tensor(circuit, hybrid=False)(x) + array([[0.25 , 0. , 0. ], + [0. , 0.25 , 0. ], + [0. , 0. , 0.24750832]]) + ``` + + - The metric tensor transform now works with a larger set of operations. In particular, + all operations that have a single variational parameter and define a generator are now + supported. In addition to a reduction in decomposition overhead, the change + also results in fewer circuit evaluations. + + +* ``qml.circuit_drawer.CircuitDrawer`` can accept a string for the ``charset`` keyword, instead of a ``CharSet`` object. + [(#1640)](https://github.com/PennyLaneAI/pennylane/pull/1640) + +* ``qml.math.sort`` will now return only the sorted torch tensor and not the corresponding indices, making sort consistent across interfaces. + [(#1691)](https://github.com/PennyLaneAI/pennylane/pull/1691) + +* Operations can now have gradient recipes that depend on the state of the operation. + [(#1674)](https://github.com/PennyLaneAI/pennylane/pull/1674) + + For example, this allows for gradient recipes that are parameter dependent: + + ```python + class RX(qml.RX): + + @property + def grad_recipe(self): + # The gradient is given by [f(2x) - f(0)] / (2 sin(x)), by subsituting + # shift = x into the two term parameter-shift rule. + x = self.data[0] + c = 0.5 / np.sin(x) + return ([[c, 0.0, 2 * x], [-c, 0.0, 0.0]],) + ``` + +* Shots can now be passed as a runtime argument to transforms that execute circuits in batches, similarly + to QNodes. + [(#1707)](https://github.com/PennyLaneAI/pennylane/pull/1707) + + An example of such a transform are the gradient transforms in the + `qml.gradients` module. As a result, we can now call gradient transforms + (such as `qml.gradients.param_shift`) and set the number of shots at runtime. + + ```pycon + >>> dev = qml.device("default.qubit", wires=1, shots=1000) + >>> @qml.beta.qnode(dev) + ... def circuit(x): + ... qml.RX(x, wires=0) + ... return qml.expval(qml.PauliZ(0)) + >>> grad_fn = qml.gradients.param_shift(circuit) + >>> grad_fn(0.564, shots=[(1, 10)]).T + array([[-1., -1., -1., -1., -1., 0., -1., 0., -1., 0.]]) + >>> grad_fn(0.1233, shots=None) + array([[-0.53457096]]) + ``` + +* Specific QNode execution options are now re-used by batch transforms + to execute transformed QNodes. + [(#1708)](https://github.com/PennyLaneAI/pennylane/pull/1708) + +* To standardize across all optimizers, `qml.optimize.AdamOptimizer` now also uses `accumulation` (in form of `collections.namedtuple`) to keep track of running quantities. Before it used three variables `fm`, `sm` and `t`. [(#1757)](https://github.com/PennyLaneAI/pennylane/pull/1757) + +

Breaking changes

+ +- The operator attributes `has_unitary_generator`, `is_composable_rotation`, + `is_self_inverse`, `is_symmetric_over_all_wires`, and + `is_symmetric_over_control_wires` have been removed as attributes from the + base class. They have been replaced by the sets that store the names of + operations with similar properties in `ops/qubit/attributes.py`. + [(#1763)](https://github.com/PennyLaneAI/pennylane/pull/1763) + +* The `qml.inv` function has been removed, `qml.adjoint` should be used + instead. + [(#1778)](https://github.com/PennyLaneAI/pennylane/pull/1778) + +* The input signature of an `expand_fn` used in a `batch_transform` + now **must** have the same signature as the provided `transform_fn`, + and vice versa. + [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) + +* The expansion rule in the `qml.metric_tensor` transform has been changed. + [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) + + If `hybrid=False`, the changed expansion rule might lead to a changed output. + +* The `qml.metric_tensor` keyword argument `diag_approx` is deprecated. + Approximations can be controlled with the more fine-grained `approx` + keyword argument, with `approx="block-diag"` (the default) reproducing + the old behaviour. + [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) + +* The `default.qubit.torch` device automatically determines if computations + should be run on a CPU or a GPU and doesn't take a `torch_device` argument + anymore. + [(#1705)](https://github.com/PennyLaneAI/pennylane/pull/1705) + +* The utility function `qml.math.requires_grad` now returns `True` when using Autograd + if and only if the `requires_grad=True` attribute is set on the NumPy array. Previously, + this function would return `True` for *all* NumPy arrays and Python floats, unless + `requires_grad=False` was explicitly set. + [(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638) + +* The operation `qml.Interferometer` has been renamed `qml.InterferometerUnitary` in order to + distinguish it from the template `qml.templates.Interferometer`. + [(#1714)](https://github.com/PennyLaneAI/pennylane/pull/1714) + +* The `qml.transforms.invisible` decorator has been replaced with `qml.tape.stop_recording`, which + may act as a context manager as well as a decorator to ensure that contained logic is + non-recordable or non-queueable within a QNode or quantum tape context. + [(#1754)](https://github.com/PennyLaneAI/pennylane/pull/1754) + +* Templates `SingleExcitationUnitary` and `DoubleExcitationUnitary` have been renamed + to `FermionicSingleExcitation` and `FermionicDoubleExcitation`, respectively. + [(#1822)](https://github.com/PennyLaneAI/pennylane/pull/1822) + +

Deprecations

+ +* The `template` decorator is now deprecated with a warning message and will be removed + in release `v0.20.0`. It has been removed from different PennyLane functions. + [(#1794)](https://github.com/PennyLaneAI/pennylane/pull/1794) + [(#1808)](https://github.com/PennyLaneAI/pennylane/pull/1808) + +* Allowing cost functions to be differentiated using `qml.grad` or + `qml.jacobian` without explicitly marking parameters as trainable is being + deprecated, and will be removed in the next release. + Please specify the `requires_grad` attribute for every argument, or specify + `argnum` when using `qml.grad` or `qml.jacobian`. + [(#1773)](https://github.com/PennyLaneAI/pennylane/pull/1773) + + The following raises a warning in v0.19.0 and will raise an error in + v0.20.0: + + ```python + import pennylane as qml + + dev = qml.device('default.qubit', wires=1) + + @qml.qnode(dev) + def test(x): + qml.RY(x, wires=[0]) + return qml.expval(qml.PauliZ(0)) + + par = 0.3 + qml.grad(test)(par) + ``` + + Preferred approaches include specifying the `requires_grad` attribute: + + ```python + import pennylane as qml + from pennylane import numpy as np + + dev = qml.device('default.qubit', wires=1) + + @qml.qnode(dev) + def test(x): + qml.RY(x, wires=[0]) + return qml.expval(qml.PauliZ(0)) + + par = np.array(0.3, requires_grad=True) + qml.grad(test)(par) + ``` + + Or specifying the `argnum` argument when using `qml.grad` or `qml.jacobian`: + + ```python + import pennylane as qml + + dev = qml.device('default.qubit', wires=1) + + @qml.qnode(dev) + def test(x): + qml.RY(x, wires=[0]) + return qml.expval(qml.PauliZ(0)) + + par = 0.3 + qml.grad(test, argnum=0)(par) + ``` + +* The `qml.fourier.spectrum` function has been renamed to `qml.fourier.circuit_spectrum`, + in order to clearly separate the new `qnode_spectrum` function from this one. + `qml.fourier.spectrum` is now an alias for `circuit_spectrum` but is flagged for + deprecation and will be removed soon. + [(#1681)](https://github.com/PennyLaneAI/pennylane/pull/1681) + +* The `init` module, which contains functions to generate random parameter tensors for + templates, is flagged for deprecation and will be removed in the next release cycle. + Instead, the templates' `shape` method can be used to get the desired shape of the tensor, + which can then be generated manually. + [(#1689)](https://github.com/PennyLaneAI/pennylane/pull/1689) + +* The `QNode.draw` method has been deprecated, and will be removed in an upcoming release. + Please use the `qml.draw` transform instead. + [(#1746)](https://github.com/PennyLaneAI/pennylane/pull/1746) + +* The `QNode.metric_tensor` method has been deprecated, and will be removed in an upcoming release. + Please use the `qml.metric_tensor` transform instead. + [(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638) + +* The `pad` parameter of the `qml.AmplitudeEmbedding` template has been removed. + It has instead been renamed to the `pad_with` parameter. + [(#1805)](https://github.com/PennyLaneAI/pennylane/pull/1805) + +

Bug fixes

+ +* Fixes a bug with the arrow width in the `measure` of `qml.circuit_drawer.MPLDrawer`. + [(#1823)](https://github.com/PennyLaneAI/pennylane/pull/1823) + +* The helper functions `qml.math.block_diag` and `qml.math.scatter_element_add` now are + entirely differentiable when using Autograd. + Previously only indexed entries of the block diagonal could be differentiated, while + the derivative w.r.t to the second argument of `qml.math.scatter_element_add` dispatched + to NumPy instead of Autograd. + [(#1816)](https://github.com/PennyLaneAI/pennylane/pull/1816) + [(#1818)](https://github.com/PennyLaneAI/pennylane/pull/1818) + +* Fixes a bug where the GPU cannot be used with `qml.qnn.TorchLayer`. + [(#1705)](https://github.com/PennyLaneAI/pennylane/pull/1705) + +* Fix a bug where the devices cache the same result for different observables return types. + [(#1719)](https://github.com/PennyLaneAI/pennylane/pull/1719) + +* Fixed a bug of the default circuit drawer where having more measurements + compared to the number of measurements on any wire raised a `KeyError`. + [(#1702)](https://github.com/PennyLaneAI/pennylane/pull/1702) + +* Fix a bug where it was not possible to use `jax.jit` on a `QNode` when using `QubitStateVector`. + [(#1683)](https://github.com/PennyLaneAI/pennylane/pull/1683) + +* The device suite tests can now execute successfully if no shots configuration variable is given. + [(#1641)](https://github.com/PennyLaneAI/pennylane/pull/1641) + +* Fixes a bug where the `qml.gradients.param_shift` transform would raise an error while attempting + to compute the variance of a QNode with ragged output. + [(#1646)](https://github.com/PennyLaneAI/pennylane/pull/1646) + +* Fixes a bug in `default.mixed`, to ensure that returned probabilities are always non-negative. + [(#1680)](https://github.com/PennyLaneAI/pennylane/pull/1680) + +* Fixes a bug where gradient transforms would fail to apply to QNodes + containing classical processing. + [(#1699)](https://github.com/PennyLaneAI/pennylane/pull/1699) + +* Fixes a bug where the the parameter-shift method was not correctly using the + fallback gradient function when *all* circuit parameters required the fallback. + [(#1782)](https://github.com/PennyLaneAI/pennylane/pull/1782) + +

Documentation

+ +* Adds a link to https://pennylane.ai/qml/demonstrations.html in the navbar. + [(#1624)](https://github.com/PennyLaneAI/pennylane/pull/1624) + +* Corrects the docstring of `ExpvalCost` by adding `wires` to the signature of the `ansatz` argument. [(#1715)](https://github.com/PennyLaneAI/pennylane/pull/1715) + +* Updates the 'Gradients and training' quickstart guide to provide information + on gradient transforms. + [(#1751)](https://github.com/PennyLaneAI/pennylane/pull/1751) + +* All instances of `qnode.draw()` have been updated to instead use the transform `qml.draw(qnode)`. + [(#1750)](https://github.com/PennyLaneAI/pennylane/pull/1750) + +* Add the `jax` interface in QNode Documentation. [(#1755)](https://github.com/PennyLaneAI/pennylane/pull/1755) + +* Reorganized all the templates related to quantum chemistry under a common header `Quantum Chemistry templates`. + [(#1822)](https://github.com/PennyLaneAI/pennylane/pull/1822) + +

Contributors

+ +This release contains contributions from (in alphabetical order): + +Juan Miguel Arrazola, Utkarsh Azad, Akash Narayanan B, Sam Banning, Thomas Bromley, Jack Ceroni, +Alain Delgado, Olivia Di Matteo, Andrew Gardhouse, David Ittah, Josh Izaac, Soran Jahangiri, +Christina Lee, Romain Moyard, Carrie-Anne Rubidge, Maria Schuld, Rishabh Singh, Jay Soni, +Ingrid Strandberg, Antal Száva, Teresa Tamayo-Mendoza, Rodrigo Vargas, Cody Wang, David Wierichs, +Moritz Willmann. diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index dc7f5a3d5c0..2da70eaccb0 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -1,1083 +1,20 @@ :orphan: -# Release 0.19.0-dev (development release) +# Release 0.20.0-dev (development release)

New features since last release

-* Error mitigation using the zero-noise extrapolation method is now available through the - `transforms.mitigate_with_zne` transform. This transform can integrate with the - [Mitiq](https://mitiq.readthedocs.io/en/stable/) package for unitary folding and extrapolation - functionality. - [(#1813)](https://github.com/PennyLaneAI/pennylane/pull/1813) - - Consider the following noisy device: - - ```python - import pennylane as qml - - noise_strength = 0.05 - - dev = qml.device("default.mixed", wires=2) - dev = qml.transforms.insert(qml.AmplitudeDamping, noise_strength)(dev) - ``` - - We can mitigate the effects of this noise for circuits run on this device by using the added - transform: - - ```python - from pennylane import numpy as np - from pennylane.beta import qnode - - from mitiq.zne.scaling import fold_global - from mitiq.zne.inference import RichardsonFactory - - n_wires = 2 - n_layers = 2 - - shapes = qml.SimplifiedTwoDesign.shape(n_wires, n_layers) - np.random.seed(0) - w1, w2 = [np.random.random(s) for s in shapes] - - @qml.transforms.mitigate_with_zne([1, 2, 3], fold_global, RichardsonFactory.extrapolate) - @qnode(dev) - def circuit(w1, w2): - qml.SimplifiedTwoDesign(w1, w2, wires=range(2)) - return qml.expval(qml.PauliZ(0)) - ``` - - Now, executing `circuit` will be mitigated: - - ```pycon - >>> circuit(w1, w2) - 0.19113067083636542 - ``` - -* A differentiable Hartree-Fock (HF) solver has been added. It can be used to construct molecular Hamiltonians - that can be differentiated with respect to nuclear coordinates and basis-set parameters. - [(#1610)](https://github.com/PennyLaneAI/pennylane/pull/1610) - - The HF solver computes the integrals over basis functions, constructs the relevant matrices, and - performs self-consistent-field iterations to obtain a set of optimized molecular orbital - coefficients. These coefficients and the computed integrals over basis functions are used to - construct the one- and two-body electron integrals in the molecular orbital basis which can be - used to generate a differentiable second-quantized Hamiltonian in the fermionic and qubit basis. - - The following code shows the construction of the Hamiltonian for the hydrogen molecule where the - geometry of the molecule and the basis set parameters are all differentiable. - - ```python - import pennylane as qml - from pennylane import numpy as np - - symbols = ["H", "H"] - geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 2.0]], requires_grad=True) - alpha = np.array([[3.42525091, 0.62391373, 0.1688554], - [3.42525091, 0.62391373, 0.1688554]], requires_grad = True) - coeff = np.array([[0.15432897, 0.53532814, 0.44463454], - [0.15432897, 0.53532814, 0.44463454]], requires_grad = True) - - # we create a molecule object with differentiable atomic coordinates and basis set parameters - # alpha and coeff are the exponentents and contraction coefficients of the Gaussian functions - mol = qml.hf.Molecule(symbols, geometry, alpha=alpha, coeff=coeff) - args = [geometry, alpha, coeff] # initial values of the differentiable parameters - - hamiltonian = qml.hf.generate_hamiltonian(mol)(*args) - ``` - - The generated Hamiltonian can be used in a circuit where the molecular geometry, the basis set - parameters and the circuit parameters are optimized simultaneously. - - ```python - import autograd - - params = [np.array([0.0], requires_grad=True)] - dev = qml.device("default.qubit", wires=4) - hf_state = np.array([1, 1, 0, 0]) - - def generate_circuit(mol): - @qml.qnode(dev) - def circuit(*args): - qml.BasisState(hf_state, wires=[0, 1, 2, 3]) - qml.DoubleExcitation(*args[0][0], wires=[0, 1, 2, 3]) - return qml.expval(hf.generate_hamiltonian(mol)(*args[1:])) - return circuit - - for n in range(10): # geometry and parameter optimization loop - - # we create a molecule object with differentiable atomic coordinates and basis set parameters - # alpha and coeff are the exponentents and contraction coefficients of the Gaussian functions - mol = hf.Molecule(symbols, geometry, alpha=alpha, coeff=coeff) - args_ = [params, *args] # initial values of the differentiable parameters - - # compute gradients with respect to the circuit parameters and update the parameters - g_params = autograd.grad(generate_circuit(mol), argnum = 0)(*args_) - params = params - 0.1 * g_params[0] - - # compute gradients with respect to the nuclear coordinates and update geometry - forces = autograd.grad(generate_circuit(mol), argnum = 1)(*args_) - geometry = geometry - 0.5 * forces - - # compute gradients with respect to the Gaussian exponents and update the exponents - g_alpha = autograd.grad(generate_circuit(mol), argnum = 2)(*args_) - alpha = alpha - 0.1 * g_alpha - - # compute gradients with respect to the Gaussian contraction coefficients and update them - g_coeff = autograd.grad(generate_circuit(mol), argnum = 3)(*args_) - coeff = coeff - 0.1 * g_coeff - ``` - - The components of the HF solver can also be differentiated individually. For instance, the overlap - integral can be differentiated with respect to the basis set parameters as - - ```python - symbols = ["H", "H"] - geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 2.0]], requires_grad=False) - alpha = np.array([[3.42525091, 0.62391373, 0.1688554], - [3.42525091, 0.62391373, 0.1688554]], requires_grad = True) - coeff = np.array([[0.15432897, 0.53532814, 0.44463454], - [0.15432897, 0.53532814, 0.44463454]], requires_grad = True) - - mol = qml.hf.Molecule(symbols, geometry, alpha=alpha, coeff=coeff) - args = [alpha, coeff] - - a = mol.basis_set[0] - b = mol.basis_set[1] - - g_alpha = autograd.grad(qml.hf.generate_overlap(a, b), argnum = 0)(*args) - g_coeff = autograd.grad(qml.hf.generate_overlap(a, b), argnum = 1)(*args) - ``` - -* The `insert` transform has now been added, providing a way to insert single-qubit operations into - a quantum circuit. The transform can apply to quantum functions, tapes, and devices. - [(#1795)](https://github.com/PennyLaneAI/pennylane/pull/1795) - - The following QNode can be transformed to add noise to the circuit: - - ```python - from pennylane.transforms import insert - - dev = qml.device("default.mixed", wires=2) - - @qml.qnode(dev) - @insert(qml.AmplitudeDamping, 0.2, position="end") - def f(w, x, y, z): - qml.RX(w, wires=0) - qml.RY(x, wires=1) - qml.CNOT(wires=[0, 1]) - qml.RY(y, wires=0) - qml.RX(z, wires=1) - return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - ``` - - Executions of this circuit will differ from the noise-free value: - - ```pycon - >>> f(0.9, 0.4, 0.5, 0.6) - tensor(0.754847, requires_grad=True) - >>> print(qml.draw(f)(0.9, 0.4, 0.5, 0.6)) - 0: ──RX(0.9)──╭C──RY(0.5)──AmplitudeDamping(0.2)──╭┤ ⟨Z ⊗ Z⟩ - 1: ──RY(0.4)──╰X──RX(0.6)──AmplitudeDamping(0.2)──╰┤ ⟨Z ⊗ Z⟩ - ``` - -* A new class has been added to store operator attributes, such as `self_inverses`, - and `composable_rotation`, as a list of operation names. - [(#1763)](https://github.com/PennyLaneAI/pennylane/pull/1763) - - A number of such attributes, for the purpose of compilation transforms, can be found - in `ops/qubit/attributes.py`, but the class can also be used to create your own. For - example, we can create a new Attribute, `pauli_ops`, like so: - - ```pycon - >>> from pennylane.ops.qubits.attributes import Attribute - >>> pauli_ops = Attribute(["PauliX", "PauliY", "PauliZ"]) - ``` - - We can check either a string or an Operation for inclusion in this set: - - ```pycon - >>> qml.PauliX(0) in pauli_ops - True - >>> "Hadamard" in pauli_ops - False - ``` - - We can also dynamically add operators to the sets at runtime. This is useful - for adding custom operations to the attributes such as `composable_rotations` - and ``self_inverses`` that are used in compilation transforms. For example, - suppose you have created a new Operation, `MyGate`, which you know to be its - own inverse. Adding it to the set, like so - - ```pycon - >>> from pennylane.ops.qubits.attributes import self_inverses - >>> self_inverses.add("MyGate") - ``` - - will enable the gate to be considered by the `cancel_inverses` compilation - transform if two such gates are adjacent in a circuit. - -* Common tape expansion functions are now available in `qml.transforms`, - alongside a new `create_expand_fn` function for easily creating expansion functions - from stopping criteria. - [(#1734)](https://github.com/PennyLaneAI/pennylane/pull/1734) - [(#1760)](https://github.com/PennyLaneAI/pennylane/pull/1760) - - `create_expand_fn` takes the default depth to which the expansion function - should expand a tape, a stopping criterion, an optional device, and a docstring to be set for the - created function. - The stopping criterion must take a queuable object and return a boolean. - -* A new transform, `@qml.batch_params`, has been added, that makes QNodes - handle a batch dimension in trainable parameters. - [(#1710)](https://github.com/PennyLaneAI/pennylane/pull/1710) - [(#1761)](https://github.com/PennyLaneAI/pennylane/pull/1761) - - This transform will create multiple circuits, one per batch dimension. - As a result, it is both simulator and hardware compatible. - - ```python - @qml.batch_params - @qml.beta.qnode(dev) - def circuit(x, weights): - qml.RX(x, wires=0) - qml.RY(0.2, wires=1) - qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1, 2]) - return qml.expval(qml.Hadamard(0)) - ``` - - The `qml.batch_params` decorator allows us to pass arguments `x` and `weights` - that have a batch dimension. For example, - - ```pycon - >>> batch_size = 3 - >>> x = np.linspace(0.1, 0.5, batch_size) - >>> weights = np.random.random((batch_size, 10, 3, 3)) - ``` - - If we evaluate the QNode with these inputs, we will get an output - of shape ``(batch_size,)``: - - ```pycon - >>> circuit(x, weights) - [-0.30773348 0.23135516 0.13086565] - ``` - -* The new `qml.fourier.qnode_spectrum` function extends the former - `qml.fourier.spectrum` function - and takes classical processing of QNode arguments into account. - The frequencies are computed per (requested) QNode argument instead - of per gate `id`. The gate `id`s are ignored. - [(#1681)](https://github.com/PennyLaneAI/pennylane/pull/1681) - [(#1720)](https://github.com/PennyLaneAI/pennylane/pull/1720) - - Consider the following example, which uses non-trainable inputs `x`, `y` and `z` - as well as trainable parameters `w` as arguments to the QNode. - - ```python - import pennylane as qml - import numpy as np - - n_qubits = 3 - dev = qml.device("default.qubit", wires=n_qubits) - - @qml.qnode(dev) - def circuit(x, y, z, w): - for i in range(n_qubits): - qml.RX(0.5*x[i], wires=i) - qml.Rot(w[0,i,0], w[0,i,1], w[0,i,2], wires=i) - qml.RY(2.3*y[i], wires=i) - qml.Rot(w[1,i,0], w[1,i,1], w[1,i,2], wires=i) - qml.RX(z, wires=i) - return qml.expval(qml.PauliZ(wires=0)) - - x = np.array([1., 2., 3.]) - y = np.array([0.1, 0.3, 0.5]) - z = -1.8 - w = np.random.random((2, n_qubits, 3)) - ``` - - This circuit looks as follows: - - ```pycon - >>> print(qml.draw(circuit)(x, y, z, w)) - 0: ──RX(0.5)──Rot(0.598, 0.949, 0.346)───RY(0.23)──Rot(0.693, 0.0738, 0.246)──RX(-1.8)──┤ ⟨Z⟩ - 1: ──RX(1)────Rot(0.0711, 0.701, 0.445)──RY(0.69)──Rot(0.32, 0.0482, 0.437)───RX(-1.8)──┤ - 2: ──RX(1.5)──Rot(0.401, 0.0795, 0.731)──RY(1.15)──Rot(0.756, 0.38, 0.38)─────RX(-1.8)──┤ - ``` - - Applying the `qml.fourier.qnode_spectrum` function to the circuit for the non-trainable - parameters, we obtain: - - ```pycon - >>> spec = qml.fourier.qnode_spectrum(circuit, encoding_args={"x", "y", "z"})(x, y, z, w) - >>> for inp, freqs in spec.items(): - ... print(f"{inp}: {freqs}") - "x": {(0,): [-0.5, 0.0, 0.5], (1,): [-0.5, 0.0, 0.5], (2,): [-0.5, 0.0, 0.5]} - "y": {(0,): [-2.3, 0.0, 2.3], (1,): [-2.3, 0.0, 2.3], (2,): [-2.3, 0.0, 2.3]} - "z": {(): [-3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0]} - ``` - - We can see that all three parameters in the QNode arguments ``x`` and ``y`` - contribute the spectrum of a Pauli rotation ``[-1.0, 0.0, 1.0]``, rescaled with the - prefactor of the respective parameter in the circuit. - The three ``RX`` rotations using the parameter ``z`` accumulate, yielding a more - complex frequency spectrum. - - For details on how to control for which parameters the spectrum is computed, - a comparison to `qml.fourier.circuit_spectrum`, and other usage details, please see the - [fourier.qnode_spectrum docstring](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.fourier.qnode_spectrum.html). - -* There is a new utility function `qml.math.is_independent` that checks whether - a callable is independent of its arguments. - [(#1700)](https://github.com/PennyLaneAI/pennylane/pull/1700) - - **Warning** - - This function is experimental and might behave differently than expected. - Also, it might be subject to change. - - **Disclaimer** - - Note that the test relies on both numerical and analytical checks, except - when using the PyTorch interface which only performs a numerical check. - It is known that there are edge cases on which this test will yield wrong - results, in particular non-smooth functions may be problematic. - For details, please refer to the - [is_indpendent docstring](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.math.is_independent.html). - -* Support for differentiable execution of batches of circuits has been - extended to the JAX interface for scalar functions, via the beta - `pennylane.interfaces.batch` module. - [(#1634)](https://github.com/PennyLaneAI/pennylane/pull/1634) - [(#1685)](https://github.com/PennyLaneAI/pennylane/pull/1685) - - For example using the `execute` function from the `pennylane.interfaces.batch` module: - - ```python - from pennylane.interfaces.batch import execute - - def cost_fn(x): - with qml.tape.JacobianTape() as tape1: - qml.RX(x[0], wires=[0]) - qml.RY(x[1], wires=[1]) - qml.CNOT(wires=[0, 1]) - qml.var(qml.PauliZ(0) @ qml.PauliX(1)) - - with qml.tape.JacobianTape() as tape2: - qml.RX(x[0], wires=0) - qml.RY(x[0], wires=1) - qml.CNOT(wires=[0, 1]) - qml.probs(wires=1) - - result = execute( - [tape1, tape2], dev, - gradient_fn=qml.gradients.param_shift, - interface="autograd" - ) - return (result[0] + result[1][0, 0])[0] - - res = jax.grad(cost_fn)(params) - ``` - -* The unitary matrix corresponding to a quantum circuit can now be generated using the new - `get_unitary_matrix()` transform. - [(#1609)](https://github.com/PennyLaneAI/pennylane/pull/1609) - [(#1786)](https://github.com/PennyLaneAI/pennylane/pull/1786) - - This transform is fully differentiable across all supported PennyLane autodiff frameworks. - - ```python - def circuit(theta): - qml.RX(theta, wires=1) - qml.PauliZ(wires=0) - qml.CNOT(wires=[0, 1]) - ``` - - ```pycon - >>> theta = torch.tensor(0.3, requires_grad=True) - >>> matrix = qml.transforms.get_unitary_matrix(circuit)(theta) - >>> print(matrix) - tensor([[ 0.9888+0.0000j, 0.0000+0.0000j, 0.0000-0.1494j, 0.0000+0.0000j], - [ 0.0000+0.0000j, 0.0000+0.1494j, 0.0000+0.0000j, -0.9888+0.0000j], - [ 0.0000-0.1494j, 0.0000+0.0000j, 0.9888+0.0000j, 0.0000+0.0000j], - [ 0.0000+0.0000j, -0.9888+0.0000j, 0.0000+0.0000j, 0.0000+0.1494j]], - grad_fn=) - >>> loss = torch.real(torch.trace(matrix)) - >>> loss.backward() - >>> theta.grad - tensor(-0.1494) - ``` - -* Arbitrary two-qubit unitaries can now be decomposed into elementary gates. This - functionality has been incorporated into the `qml.transforms.unitary_to_rot` transform, and is - available separately as `qml.transforms.two_qubit_decomposition`. - [(#1552)](https://github.com/PennyLaneAI/pennylane/pull/1552) - - As an example, consider the following randomly-generated matrix and circuit that uses it: - - ```python - U = np.array([ - [-0.03053706-0.03662692j, 0.01313778+0.38162226j, 0.4101526 -0.81893687j, -0.03864617+0.10743148j], - [-0.17171136-0.24851809j, 0.06046239+0.1929145j, -0.04813084-0.01748555j, -0.29544883-0.88202604j], - [ 0.39634931-0.78959795j, -0.25521689-0.17045233j, -0.1391033 -0.09670952j, -0.25043606+0.18393466j], - [ 0.29599198-0.19573188j, 0.55605806+0.64025769j, 0.06140516+0.35499559j, 0.02674726+0.1563311j ] - ]) - - dev = qml.device('default.qubit', wires=2) - - @qml.qnode(dev) - @qml.transforms.unitary_to_rot - def circuit(x, y): - qml.RX(x, wires=0) - qml.QubitUnitary(U, wires=[0, 1]) - qml.RY(y, wires=0) - return qml.expval(qml.PauliZ(wires=0)) - ``` - - If we run the circuit, we can see the new decomposition: - - ```pycon - >>> circuit(0.3, 0.4) - tensor(-0.70520073, requires_grad=True) - >>> print(qml.draw(circuit)(0.3, 0.4)) - 0: ──RX(0.3)─────────────────Rot(-3.5, 0.242, 0.86)──╭X──RZ(0.176)───╭C─────────────╭X──Rot(5.56, 0.321, -2.09)───RY(0.4)──┤ ⟨Z⟩ - 1: ──Rot(-1.64, 2.69, 1.58)──────────────────────────╰C──RY(-0.883)──╰X──RY(-1.47)──╰C──Rot(-1.46, 0.337, 0.587)───────────┤ - ``` - -* The transform for the Jacobian of the classical preprocessing within a QNode, - `qml.transforms.classical_jacobian`, now takes a keyword argument `argnum` to specify - the QNode argument indices with respect to which the Jacobian is computed. - [(#1645)](https://github.com/PennyLaneAI/pennylane/pull/1645) - - An example for the usage of ``argnum`` is - - ```python - @qml.qnode(dev) - def circuit(x, y, z): - qml.RX(qml.math.sin(x), wires=0) - qml.CNOT(wires=[0, 1]) - qml.RY(y ** 2, wires=1) - qml.RZ(1 / z, wires=1) - return qml.expval(qml.PauliZ(0)) - - jac_fn = qml.transforms.classical_jacobian(circuit, argnum=[1, 2]) - ``` - - The Jacobian can then be computed at specified parameters. - - ```pycon - >>> x, y, z = np.array([0.1, -2.5, 0.71]) - >>> jac_fn(x, y, z) - (array([-0., -5., -0.]), array([-0. , -0. , -1.98373339])) - ``` - - The returned arrays are the derivatives of the three parametrized gates in the circuit - with respect to `y` and `z` respectively. - - There also are explicit tests for `classical_jacobian` now, which previously was tested - implicitly via its use in the `metric_tensor` transform. - - For more usage details, please see the - [classical Jacobian docstring](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.transforms.classical_jacobian.html). - -* Added a new operation `OrbitalRotation`, which implements the spin-adapted spatial orbital rotation gate. - [(#1665)](https://github.com/PennyLaneAI/pennylane/pull/1665) - - An example circuit that uses `OrbitalRotation` operation is: - - ```python - dev = qml.device('default.qubit', wires=4) - @qml.qnode(dev) - def circuit(phi): - qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3]) - qml.OrbitalRotation(phi, wires=[0, 1, 2, 3]) - return qml.state() - ``` - - If we run this circuit, we will get the following output - - ```pycon - >>> circuit(0.1) - array([ 0. +0.j, 0. +0.j, 0. +0.j, - 0.00249792+0.j, 0. +0.j, 0. +0.j, - -0.04991671+0.j, 0. +0.j, 0. +0.j, - -0.04991671+0.j, 0. +0.j, 0. +0.j, - 0.99750208+0.j, 0. +0.j, 0. +0.j, - 0. +0.j]) - ``` - -* A new, experimental QNode has been added, that adds support for batch execution of circuits, - custom quantum gradient support, and arbitrary order derivatives. This QNode is available via - `qml.beta.QNode`, and `@qml.beta.qnode`. - [(#1642)](https://github.com/PennyLaneAI/pennylane/pull/1642) - [(#1646)](https://github.com/PennyLaneAI/pennylane/pull/1646) - [(#1651)](https://github.com/PennyLaneAI/pennylane/pull/1651) - - It differs from the standard QNode in several ways: - - - Custom gradient transforms can be specified as the differentiation method: - - ```python - @qml.gradients.gradient_transform - def my_gradient_transform(tape): - ... - return tapes, processing_fn - - @qml.beta.qnode(dev, diff_method=my_gradient_transform) - def circuit(): - ``` - - - Arbitrary :math:`n`-th order derivatives are supported on hardware using - gradient transforms such as the parameter-shift rule. To specify that an :math:`n`-th - order derivative of a QNode will be computed, the `max_diff` argument should be set. - By default, this is set to 1 (first-order derivatives only). - - - Internally, if multiple circuits are generated for execution simultaneously, they - will be packaged into a single job for execution on the device. This can lead to - significant performance improvement when executing the QNode on remote - quantum hardware. - - - When decomposing the circuit, the default decomposition strategy will prioritize - decompositions that result in the smallest number of parametrized operations - required to satisfy the differentiation method. Additional decompositions required - to satisfy the native gate set of the quantum device will be performed later, by the - device at execution time. While this may lead to a slight increase in classical processing, - it significantly reduces the number of circuit evaluations needed to compute - gradients of complex unitaries. - - In an upcoming release, this QNode will replace the existing one. If you come across any bugs - while using this QNode, please let us know via a [bug - report](https://github.com/PennyLaneAI/pennylane/issues/new?assignees=&labels=bug+%3Abug%3A&template=bug_report.yml&title=%5BBUG%5D) - on our GitHub bug tracker. - - Currently, this beta QNode does not support the following features: - - - Non-mutability via the `mutable` keyword argument - - Viewing specifications with `qml.specs` - - The `reversible` QNode differentiation method - - The ability to specify a `dtype` when using PyTorch and TensorFlow. - - It is also not tested with the `qml.qnn` module. - -* Two new methods were added to the Device API, allowing PennyLane devices - increased control over circuit decompositions. - [(#1651)](https://github.com/PennyLaneAI/pennylane/pull/1651) - - - `Device.expand_fn(tape) -> tape`: expands a tape such that it is supported by the device. By - default, performs the standard device-specific gate set decomposition done in the default - QNode. Devices may overwrite this method in order to define their own decomposition logic. - - Note that the numerical result after applying this method should remain unchanged; PennyLane - will assume that the expanded tape returns exactly the same value as the original tape when - executed. - - - `Device.batch_transform(tape) -> (tapes, processing_fn)`: preprocesses the tape in the case - where the device needs to generate multiple circuits to execute from the input circuit. The - requirement of a post-processing function makes this distinct to the `expand_fn` method above. - - By default, this method applies the transform - - .. math:: \left\langle \sum_i c_i h_i\right\rangle -> \sum_i c_i \left\langle h_i \right\rangle - - if `expval(H)` is present on devices that do not natively support Hamiltonians with - non-commuting terms. - -* Added a new template `GateFabric`, which implements a local, expressive, quantum-number-preserving - ansatz proposed by Anselmetti *et al.* in [arXiv:2104.05692](https://arxiv.org/abs/2104.05695). - [(#1687)](https://github.com/PennyLaneAI/pennylane/pull/1687) - - An example of a circuit using `GateFabric` template is: - - ```python - coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614]) - H, qubits = qml.qchem.molecular_hamiltonian(["H", "H"], coordinates) - ref_state = qml.qchem.hf_state(electrons=2, qubits) - - dev = qml.device('default.qubit', wires=qubits) - @qml.qnode(dev) - def ansatz(weights): - qml.templates.GateFabric(weights, wires=[0,1,2,3], - init_state=ref_state, include_pi=True) - return qml.expval(H) - ``` - - For more details, see the [GateFabric documentation](../code/api/pennylane.templates.layers.GateFabric.html). - -* Added a new template `kUpCCGSD`, which implements a unitary coupled cluster ansatz with - generalized singles and pair doubles excitation operators, proposed by Joonho Lee *et al.* - in [arXiv:1810.02327](https://arxiv.org/abs/1810.02327). - [(#1743)](https://github.com/PennyLaneAI/pennylane/pull/1743) - - An example of a circuit using `kUpCCGSD` template is: - - ```python - coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614]) - H, qubits = qml.qchem.molecular_hamiltonian(["H", "H"], coordinates) - ref_state = qml.qchem.hf_state(electrons=2, qubits) - - dev = qml.device('default.qubit', wires=qubits) - @qml.qnode(dev) - def ansatz(weights): - qml.templates.kUpCCGSD(weights, wires=[0,1,2,3], k=0, delta_sz=0, - init_state=ref_state) - return qml.expval(H) - ``` - -

Improvements

-* The default for an `Operation`'s `control_wires` attribute is now an empty `Wires` - object instead of the attribute raising a `NonImplementedError`. - [(#1821)](https://github.com/PennyLaneAI/pennylane/pull/1821) - -* `qml.circuit_drawer.MPLDrawer` will now automatically rotate and resize text to fit inside - the rectangle created by the `box_gate` method. - [(#1764)](https://github.com/PennyLaneAI/pennylane/pull/1764) - -* Quantum function transforms and batch transforms can now be applied to devices. - Once applied to a device, any quantum function executed on the - modified device will be transformed prior to execution. - [(#1809)](https://github.com/PennyLaneAI/pennylane/pull/1809) - [(#1810)](https://github.com/PennyLaneAI/pennylane/pull/1810) - - ```python - dev = qml.device("default.mixed", wires=1) - dev = qml.transforms.merge_rotations()(dev) - - @qml.beta.qnode(dev) - def f(w, x, y, z): - qml.RX(w, wires=0) - qml.RX(x, wires=0) - qml.RX(y, wires=0) - qml.RX(z, wires=0) - return qml.expval(qml.PauliZ(0)) - ``` - - ```pycon - >>> print(f(0.9, 0.4, 0.5, 0.6)) - -0.7373937155412453 - >>> print(qml.draw(f, expansion_strategy="device")(0.9, 0.4, 0.5, 0.6)) - 0: ──RX(2.4)──┤ ⟨Z⟩ - ``` - -* The `ApproxTimeEvolution` template can now be used with Hamiltonians that have - trainable coefficients. - [(#1789)](https://github.com/PennyLaneAI/pennylane/pull/1789) - - Resulting QNodes can be differentiated with respect to both the time parameter - *and* the Hamiltonian coefficients. - - ```python - dev = qml.device('default.qubit', wires=2) - obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)] - - @qml.qnode(dev) - def circuit(coeffs, t): - H = qml.Hamiltonian(coeffs, obs) - qml.templates.ApproxTimeEvolution(H, t, 2) - return qml.expval(qml.PauliZ(0)) - ``` - - ```pycon - >>> t = np.array(0.54, requires_grad=True) - >>> coeffs = np.array([-0.6, 2.0], requires_grad=True) - >>> qml.grad(circuit)(coeffs, t) - (array([-1.07813375, -1.07813375]), array(-2.79516158)) - ``` - - All differentiation methods, including backpropagation and the parameter-shift - rule, are supported. - -* Templates are now top level imported and can be used directly e.g. `qml.QFT(wires=0)`. - [(#1779)](https://github.com/PennyLaneAI/pennylane/pull/1779) - -* Operators now have a `label` method to determine how they are drawn. This will - eventually override the `RepresentationResolver` class. - [(#1678)](https://github.com/PennyLaneAI/pennylane/pull/1678) - -* The operation `label` method now supports string variables. - [(#1815)](https://github.com/PennyLaneAI/pennylane/pull/1815) - -* It is now possible to draw QNodes that have been transformed by a 'batch transform'; that is, - a transform that maps a single QNode into multiple circuits under the hood. Examples of - batch transforms include `@qml.metric_tensor` and `@qml.gradients`. - [(#1762)](https://github.com/PennyLaneAI/pennylane/pull/1762) - - For example, consider the parameter-shift rule, which generates two circuits per parameter; - one circuit that has the parameter shifted forward, and another that has the parameter shifted - backwards: - - ```python - dev = qml.device("default.qubit", wires=2) - - @qml.gradients.param_shift - @qml.beta.qnode(dev) - def circuit(x): - qml.RX(x, wires=0) - qml.CNOT(wires=[0, 1]) - return qml.expval(qml.PauliZ(wires=0)) - ``` - - ```pycon - >>> print(qml.draw(circuit)(0.6)) - 0: ──RX(2.17)──╭C──┤ ⟨Z⟩ - 1: ────────────╰X──┤ - - 0: ──RX(-0.971)──╭C──┤ ⟨Z⟩ - 1: ──────────────╰X──┤ - ``` - -* All qubit operations have been re-written to use the `qml.math` framework - for internal classical processing and the generation of their matrix representations. - As a result these representations are now fully differentiable, and the - framework-specific device classes no longer need to maintain framework-specific - versions of these matrices. - [(#1749)](https://github.com/PennyLaneAI/pennylane/pull/1749) - -* A new utility class `qml.BooleanFn` is introduced. It wraps a function that takes a single - argument and returns a Boolean. - [(#1734)](https://github.com/PennyLaneAI/pennylane/pull/1734) - - After wrapping, `qml.BooleanFn` can be called like the wrapped function, and - multiple instances can be manipulated and combined with the bitwise operators - `&`, `|` and `~`. - -* `qml.probs` now accepts an attribute `op` that allows to rotate the computational basis and get the - probabilities in the rotated basis. - [(#1692)](https://github.com/PennyLaneAI/pennylane/pull/1692) - -* The `qml.beta.QNode` now supports the `qml.qnn` module. - [(#1748)](https://github.com/PennyLaneAI/pennylane/pull/1748) - -* `@qml.beta.QNode` now supports the `qml.specs` transform. - [(#1739)](https://github.com/PennyLaneAI/pennylane/pull/1739) - -* `qml.circuit_drawer.drawable_layers` and `qml.circuit_drawer.drawable_grid` process a list of - operations to layer positions for drawing. - [(#1639)](https://github.com/PennyLaneAI/pennylane/pull/1639) - -* `qml.transforms.batch_transform` now accepts `expand_fn`s that take additional arguments and - keyword arguments. In fact, `expand_fn` and `transform_fn` now **must** have the same signature. - [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) - -* The `qml.batch_transform` decorator is now ignored during Sphinx builds, allowing - the correct signature to display in the built documentation. - [(#1733)](https://github.com/PennyLaneAI/pennylane/pull/1733) - -* The use of `expval(H)`, where `H` is a cost Hamiltonian generated by the `qaoa` module, - has been sped up. This was achieved by making PennyLane decompose a circuit with an `expval(H)` - measurement into subcircuits if the `Hamiltonian.grouping_indices` attribute is set, and setting - this attribute in the relevant `qaoa` module functions. - [(#1718)](https://github.com/PennyLaneAI/pennylane/pull/1718) - -* The tests for qubit operations are split into multiple files. - [(#1661)](https://github.com/PennyLaneAI/pennylane/pull/1661) - -* The `qml.metric_tensor` transform has been improved with regards to - both function and performance. - [(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638) - [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) - - - If the underlying device supports batch execution of circuits, the quantum circuits required to - compute the metric tensor elements will be automatically submitted as a batched job. This can - lead to significant performance improvements for devices with a non-trivial job submission - overhead. - - - Previously, the transform would only return the metric tensor with respect to gate arguments, - and ignore any classical processing inside the QNode, even very trivial classical processing - such as parameter permutation. The metric tensor now takes into account classical processing, - and returns the metric tensor with respect to QNode arguments, not simply gate arguments: - - ```pycon - >>> @qml.qnode(dev) - ... def circuit(x): - ... qml.Hadamard(wires=1) - ... qml.RX(x[0], wires=0) - ... qml.CNOT(wires=[0, 1]) - ... qml.RY(x[1] ** 2, wires=1) - ... qml.RY(x[1], wires=0) - ... return qml.expval(qml.PauliZ(0)) - >>> x = np.array([0.1, 0.2], requires_grad=True) - >>> qml.metric_tensor(circuit)(x) - array([[0.25 , 0. ], - [0. , 0.28750832]]) - ``` - - To revert to the previous behaviour of returning the metric tensor with respect to gate - arguments, `qml.metric_tensor(qnode, hybrid=False)` can be passed. - - ```pycon - >>> qml.metric_tensor(circuit, hybrid=False)(x) - array([[0.25 , 0. , 0. ], - [0. , 0.25 , 0. ], - [0. , 0. , 0.24750832]]) - ``` - - - The metric tensor transform now works with a larger set of operations. In particular, - all operations that have a single variational parameter and define a generator are now - supported. In addition to a reduction in decomposition overhead, the change - also results in fewer circuit evaluations. - - -* ``qml.circuit_drawer.CircuitDrawer`` can accept a string for the ``charset`` keyword, instead of a ``CharSet`` object. - [(#1640)](https://github.com/PennyLaneAI/pennylane/pull/1640) - -* ``qml.math.sort`` will now return only the sorted torch tensor and not the corresponding indices, making sort consistent across interfaces. - [(#1691)](https://github.com/PennyLaneAI/pennylane/pull/1691) - -* Operations can now have gradient recipes that depend on the state of the operation. - [(#1674)](https://github.com/PennyLaneAI/pennylane/pull/1674) - - For example, this allows for gradient recipes that are parameter dependent: - - ```python - class RX(qml.RX): - - @property - def grad_recipe(self): - # The gradient is given by [f(2x) - f(0)] / (2 sin(x)), by subsituting - # shift = x into the two term parameter-shift rule. - x = self.data[0] - c = 0.5 / np.sin(x) - return ([[c, 0.0, 2 * x], [-c, 0.0, 0.0]],) - ``` - -* Shots can now be passed as a runtime argument to transforms that execute circuits in batches, similarly - to QNodes. - [(#1707)](https://github.com/PennyLaneAI/pennylane/pull/1707) - - An example of such a transform are the gradient transforms in the - `qml.gradients` module. As a result, we can now call gradient transforms - (such as `qml.gradients.param_shift`) and set the number of shots at runtime. - - ```pycon - >>> dev = qml.device("default.qubit", wires=1, shots=1000) - >>> @qml.beta.qnode(dev) - ... def circuit(x): - ... qml.RX(x, wires=0) - ... return qml.expval(qml.PauliZ(0)) - >>> grad_fn = qml.gradients.param_shift(circuit) - >>> grad_fn(0.564, shots=[(1, 10)]).T - array([[-1., -1., -1., -1., -1., 0., -1., 0., -1., 0.]]) - >>> grad_fn(0.1233, shots=None) - array([[-0.53457096]]) - ``` - -* Specific QNode execution options are now re-used by batch transforms - to execute transformed QNodes. - [(#1708)](https://github.com/PennyLaneAI/pennylane/pull/1708) - -* To standardize across all optimizers, `qml.optimize.AdamOptimizer` now also uses `accumulation` (in form of `collections.namedtuple`) to keep track of running quantities. Before it used three variables `fm`, `sm` and `t`. [(#1757)](https://github.com/PennyLaneAI/pennylane/pull/1757) -

Breaking changes

-- The operator attributes `has_unitary_generator`, `is_composable_rotation`, - `is_self_inverse`, `is_symmetric_over_all_wires`, and - `is_symmetric_over_control_wires` have been removed as attributes from the - base class. They have been replaced by the sets that store the names of - operations with similar properties in `ops/qubit/attributes.py`. - [(#1763)](https://github.com/PennyLaneAI/pennylane/pull/1763) - -* The `qml.inv` function has been removed, `qml.adjoint` should be used - instead. - [(#1778)](https://github.com/PennyLaneAI/pennylane/pull/1778) - -* The input signature of an `expand_fn` used in a `batch_transform` - now **must** have the same signature as the provided `transform_fn`, - and vice versa. - [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) - -* The expansion rule in the `qml.metric_tensor` transform has been changed. - [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) - - If `hybrid=False`, the changed expansion rule might lead to a changed output. - -* The `qml.metric_tensor` keyword argument `diag_approx` is deprecated. - Approximations can be controlled with the more fine-grained `approx` - keyword argument, with `approx="block-diag"` (the default) reproducing - the old behaviour. - [(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721) - -* The `default.qubit.torch` device automatically determines if computations - should be run on a CPU or a GPU and doesn't take a `torch_device` argument - anymore. - [(#1705)](https://github.com/PennyLaneAI/pennylane/pull/1705) - -* The utility function `qml.math.requires_grad` now returns `True` when using Autograd - if and only if the `requires_grad=True` attribute is set on the NumPy array. Previously, - this function would return `True` for *all* NumPy arrays and Python floats, unless - `requires_grad=False` was explicitly set. - [(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638) - -* The operation `qml.Interferometer` has been renamed `qml.InterferometerUnitary` in order to - distinguish it from the template `qml.templates.Interferometer`. - [(#1714)](https://github.com/PennyLaneAI/pennylane/pull/1714) - -* The `qml.transforms.invisible` decorator has been replaced with `qml.tape.stop_recording`, which - may act as a context manager as well as a decorator to ensure that contained logic is - non-recordable or non-queueable within a QNode or quantum tape context. - [(#1754)](https://github.com/PennyLaneAI/pennylane/pull/1754) - -* Templates `SingleExcitationUnitary` and `DoubleExcitationUnitary` have been renamed - to `FermionicSingleExcitation` and `FermionicDoubleExcitation`, respectively. - [(#1822)](https://github.com/PennyLaneAI/pennylane/pull/1822) -

Deprecations

-* The `template` decorator is now deprecated with a warning message and will be removed - in release `v0.20.0`. It has been removed from different PennyLane functions. - [(#1794)](https://github.com/PennyLaneAI/pennylane/pull/1794) - [(#1808)](https://github.com/PennyLaneAI/pennylane/pull/1808) - -* Allowing cost functions to be differentiated using `qml.grad` or - `qml.jacobian` without explicitly marking parameters as trainable is being - deprecated, and will be removed in the next release. - Please specify the `requires_grad` attribute for every argument, or specify - `argnum` when using `qml.grad` or `qml.jacobian`. - [(#1773)](https://github.com/PennyLaneAI/pennylane/pull/1773) - - The following raises a warning in v0.19.0 and will raise an error in - v0.20.0: - - ```python - import pennylane as qml - - dev = qml.device('default.qubit', wires=1) - - @qml.qnode(dev) - def test(x): - qml.RY(x, wires=[0]) - return qml.expval(qml.PauliZ(0)) - - par = 0.3 - qml.grad(test)(par) - ``` - - Preferred approaches include specifying the `requires_grad` attribute: - - ```python - import pennylane as qml - from pennylane import numpy as np - - dev = qml.device('default.qubit', wires=1) - - @qml.qnode(dev) - def test(x): - qml.RY(x, wires=[0]) - return qml.expval(qml.PauliZ(0)) - - par = np.array(0.3, requires_grad=True) - qml.grad(test)(par) - ``` - - Or specifying the `argnum` argument when using `qml.grad` or `qml.jacobian`: - - ```python - import pennylane as qml - - dev = qml.device('default.qubit', wires=1) - - @qml.qnode(dev) - def test(x): - qml.RY(x, wires=[0]) - return qml.expval(qml.PauliZ(0)) - - par = 0.3 - qml.grad(test, argnum=0)(par) - ``` - -* The `qml.fourier.spectrum` function has been renamed to `qml.fourier.circuit_spectrum`, - in order to clearly separate the new `qnode_spectrum` function from this one. - `qml.fourier.spectrum` is now an alias for `circuit_spectrum` but is flagged for - deprecation and will be removed soon. - [(#1681)](https://github.com/PennyLaneAI/pennylane/pull/1681) - -* The `init` module, which contains functions to generate random parameter tensors for - templates, is flagged for deprecation and will be removed in the next release cycle. - Instead, the templates' `shape` method can be used to get the desired shape of the tensor, - which can then be generated manually. - [(#1689)](https://github.com/PennyLaneAI/pennylane/pull/1689) - -* The `QNode.draw` method has been deprecated, and will be removed in an upcoming release. - Please use the `qml.draw` transform instead. - [(#1746)](https://github.com/PennyLaneAI/pennylane/pull/1746) - -* The `QNode.metric_tensor` method has been deprecated, and will be removed in an upcoming release. - Please use the `qml.metric_tensor` transform instead. - [(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638) - -* The `pad` parameter of the `qml.AmplitudeEmbedding` template has been removed. - It has instead been renamed to the `pad_with` parameter. - [(#1805)](https://github.com/PennyLaneAI/pennylane/pull/1805) -

Bug fixes

-* Fixes a bug with the arrow width in the `measure` of `qml.circuit_drawer.MPLDrawer`. - [(#1823)](https://github.com/PennyLaneAI/pennylane/pull/1823) - -* The helper functions `qml.math.block_diag` and `qml.math.scatter_element_add` now are - entirely differentiable when using Autograd. - Previously only indexed entries of the block diagonal could be differentiated, while - the derivative w.r.t to the second argument of `qml.math.scatter_element_add` dispatched - to NumPy instead of Autograd. - [(#1816)](https://github.com/PennyLaneAI/pennylane/pull/1816) - [(#1818)](https://github.com/PennyLaneAI/pennylane/pull/1818) - -* Fixes a bug where the GPU cannot be used with `qml.qnn.TorchLayer`. - [(#1705)](https://github.com/PennyLaneAI/pennylane/pull/1705) - -* Fix a bug where the devices cache the same result for different observables return types. - [(#1719)](https://github.com/PennyLaneAI/pennylane/pull/1719) - -* Fixed a bug of the default circuit drawer where having more measurements - compared to the number of measurements on any wire raised a `KeyError`. - [(#1702)](https://github.com/PennyLaneAI/pennylane/pull/1702) - -* Fix a bug where it was not possible to use `jax.jit` on a `QNode` when using `QubitStateVector`. - [(#1683)](https://github.com/PennyLaneAI/pennylane/pull/1683) - -* The device suite tests can now execute successfully if no shots configuration variable is given. - [(#1641)](https://github.com/PennyLaneAI/pennylane/pull/1641) - -* Fixes a bug where the `qml.gradients.param_shift` transform would raise an error while attempting - to compute the variance of a QNode with ragged output. - [(#1646)](https://github.com/PennyLaneAI/pennylane/pull/1646) - -* Fixes a bug in `default.mixed`, to ensure that returned probabilities are always non-negative. - [(#1680)](https://github.com/PennyLaneAI/pennylane/pull/1680) - -* Fixes a bug where gradient transforms would fail to apply to QNodes - containing classical processing. - [(#1699)](https://github.com/PennyLaneAI/pennylane/pull/1699) - -* Fixes a bug where the the parameter-shift method was not correctly using the - fallback gradient function when *all* circuit parameters required the fallback. - [(#1782)](https://github.com/PennyLaneAI/pennylane/pull/1782) -

Documentation

-* Adds a link to https://pennylane.ai/qml/demonstrations.html in the navbar. - [(#1624)](https://github.com/PennyLaneAI/pennylane/pull/1624) - -* Corrects the docstring of `ExpvalCost` by adding `wires` to the signature of the `ansatz` argument. [(#1715)](https://github.com/PennyLaneAI/pennylane/pull/1715) - -* Updates the 'Gradients and training' quickstart guide to provide information - on gradient transforms. - [(#1751)](https://github.com/PennyLaneAI/pennylane/pull/1751) - -* All instances of `qnode.draw()` have been updated to instead use the transform `qml.draw(qnode)`. - [(#1750)](https://github.com/PennyLaneAI/pennylane/pull/1750) - -* Add the `jax` interface in QNode Documentation. [(#1755)](https://github.com/PennyLaneAI/pennylane/pull/1755) - -* Reorganized all the templates related to quantum chemistry under a common header `Quantum Chemistry templates`. - [(#1822)](https://github.com/PennyLaneAI/pennylane/pull/1822) -

Contributors

This release contains contributions from (in alphabetical order): -Juan Miguel Arrazola, Utkarsh Azad, Akash Narayanan B, Sam Banning, Thomas Bromley, Jack Ceroni, -Alain Delgado, Olivia Di Matteo, Andrew Gardhouse, David Ittah, Josh Izaac, Soran Jahangiri, -Christina Lee, Romain Moyard, Carrie-Anne Rubidge, Maria Schuld, Rishabh Singh, Jay Soni, -Ingrid Strandberg, Antal Száva, Teresa Tamayo-Mendoza, Rodrigo Vargas, Cody Wang, David Wierichs, -Moritz Willmann. diff --git a/pennylane/_version.py b/pennylane/_version.py index 6bfd882a0ba..dee77246337 100644 --- a/pennylane/_version.py +++ b/pennylane/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.19.0-dev" +__version__ = "0.20.0-dev" diff --git a/qchem/CHANGELOG.md b/qchem/CHANGELOG.md index 9b1d835440f..3b0aa288680 100644 --- a/qchem/CHANGELOG.md +++ b/qchem/CHANGELOG.md @@ -1,13 +1,7 @@ -# Release 0.19.0-dev +# Release 0.20.0-dev

New features

-* The ``dipole`` function has been added to the ``obs`` module - to construct the electric dipole operator of a molecule. - Currently, the implemented function relies on a PySCF functionality - to load the dipole matrix elements in the atomic basis. - [(#1698)](https://github.com/PennyLaneAI/pennylane/pull/1698) -

Improvements

Bug fixes

@@ -18,7 +12,21 @@ This release contains contributions from (in alphabetical order): -Alain Delgado +# Release 0.19.0 + +

New features

+ +* The ``dipole`` function has been added to the ``obs`` module + to construct the electric dipole operator of a molecule. + Currently, the implemented function relies on a PySCF functionality + to load the dipole matrix elements in the atomic basis. + [(#1698)](https://github.com/PennyLaneAI/pennylane/pull/1698) + +

Contributors

+ +This release contains contributions from (in alphabetical order): + +Juan Miguel Arrazola, Alain Delgado Gran, Soran Jahangiri. # Release 0.17.0 diff --git a/qchem/pennylane_qchem/_version.py b/qchem/pennylane_qchem/_version.py index 5f4c2479e1d..0ee01e99101 100644 --- a/qchem/pennylane_qchem/_version.py +++ b/qchem/pennylane_qchem/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.19.0-dev" +__version__ = "0.20.0-dev"