diff --git a/doc/releases/changelog-0.27.0.md b/doc/releases/changelog-0.27.0.md index 0094d58f45d..b1fa90337f1 100644 --- a/doc/releases/changelog-0.27.0.md +++ b/doc/releases/changelog-0.27.0.md @@ -4,145 +4,235 @@

New features since last release

-

(TODO: title) JAX JIT

+

An all-new data module πŸ’Ύ

-

(TODO: title) Qutrits

+* The `qml.data` module is now available, allowing users to download, load, and create quantum datasets. + [(#3156)](https://github.com/PennyLaneAI/pennylane/pull/3156) -* The `qml.GellMann` qutrit observable, the ternary generalization of the Pauli observables, is now available. - ([#3035](https://github.com/PennyLaneAI/pennylane/pull/3035)) + Datasets are hosted on Xanadu Cloud and can be downloaded by using `qml.data.load()`: - When using `qml.GellMann`, the `index` keyword argument determines which of the 8 Gell-Mann matrices is used. + ```pycon + >>> H2_datasets = qml.data.load( + ... data_name="qchem", molname="H2", basis="STO-3G", bondlength=1.1 + ... ) + >>> H2data = H2_datasets[0] + >>> H2data + + ``` - ```python - dev = qml.device("default.qutrit", wires=2) + - Datasets available to be downloaded can be listed with `qml.data.list_datasets()`. - @qml.qnode(dev) - def circuit(): - qml.TClock(wires=0) - qml.TShift(wires=1) - qml.TAdd(wires=[0, 1]) - return qml.expval(qml.GellMann(wires=0, index=8) + qml.GellMann(wires=1, index=3)) - ``` + - To download or load only specific properties of a dataset, we can specify the desired properties in `qml.data.load` with the `attributes` keyword argument: - ```pycon - >>> circuit() - -0.42264973081037416 - ``` + ```pycon + >>> H2_hamiltonian = qml.data.load( + ... data_name="qchem", molname="H2", basis="STO-3G", bondlength=1.1, + ... attributes=["molecule", "hamiltonian"] + ... )[0] + >>> H2_hamiltonian.hamiltonian + + ``` -* Controlled qutrit operations can now be performed with `qml.ControlledQutritUnitary`. - ([#2844](https://github.com/PennyLaneAI/pennylane/pull/2844)) + The available attributes can be found using `qml.data.list_attributes()`: - The control wires and values that define the operation are defined analogously to the qubit operation. + - To select data interactively, we can use `qml.data.load_interactive()`: - ```python - dev = qml.device("default.qutrit", wires=3) + ```pycon + >>> qml.data.load_interactive() + Please select a data name: + 1) qspin + 2) qchem + Choice [1-2]: 1 + Please select a sysname: + ... + Please select a periodicity: + ... + Please select a lattice: + ... + Please select a layout: + ... + Please select attributes: + ... + Force download files? (Default is no) [y/N]: N + Folder to download to? (Default is pwd, will download to /datasets subdirectory): + + Please confirm your choices: + dataset: qspin/Ising/open/rectangular/4x4 + attributes: ['parameters', 'ground_states'] + force: False + dest folder: datasets + Would you like to continue? (Default is yes) [Y/n]: + + ``` - @qml.qnode(dev) - def circuit(U): - qml.TShift(wires=0) - qml.TAdd(wires=[0, 1]) - qml.ControlledQutritUnitary(U, control_wires=[0, 1], control_values='12', wires=2) - return qml.state() + - Once a dataset is loaded, its properties can be accessed as follows: + + ```pycon + >>> dev = qml.device("default.qubit",wires=4) + >>> @qml.qnode(dev) + ... def circuit(): + ... qml.BasisState(H2data.hf_state, wires = [0, 1, 2, 3]) + ... for op in H2data.vqe_gates: + ... qml.apply(op) + ... return qml.expval(H2data.hamiltonian) + >>> print(circuit()) + -1.0791430411076344 + ``` + + It's also possible to create custom datasets with `qml.data.Dataset`: + + ```pycon + >>> example_hamiltonian = qml.Hamiltonian(coeffs=[1,0.5], observables=[qml.PauliZ(wires=0),qml.PauliX(wires=1)]) + >>> example_energies, _ = np.linalg.eigh(qml.matrix(example_hamiltonian)) + >>> example_dataset = qml.data.Dataset( + ... data_name = 'Example', hamiltonian=example_hamiltonian, energies=example_energies + ... ) + >>> example_dataset.data_name + 'Example' + >>> example_dataset.hamiltonian + (0.5) [X1] + + (1) [Z0] + >>> example_dataset.energies + array([-1.5, -0.5, 0.5, 1.5]) ``` + Custom datasets can be saved and read with the `qml.data.Dataset.write()` and `qml.data.Dataset.read()` methods, respectively. + ```pycon - >>> U = np.array([[1, 1, 0], [1, -1, 0], [0, 0, np.sqrt(2)]]) / np.sqrt(2) - >>> circuit(U) - tensor([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, - 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, - 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, - 0.+0.j, 0.+0.j, 0.+0.j], requires_grad=True) + >>> example_dataset.write('./path/to/dataset.dat') + >>> read_dataset = qml.data.Dataset() + >>> read_dataset.read('./path/to/dataset.dat') + >>> read_dataset.data_name + 'Example' + >>> read_dataset.hamiltonian + (0.5) [X1] + + (1) [Z0] + >>> read_dataset.energies + array([-1.5, -0.5, 0.5, 1.5]) ``` -

(TODO: title) QChem

+ We will continue to work on adding more datasets and features for `qml.data` in future releases. + +

Adaptive optimization πŸƒπŸ‹οΈπŸŠ

-* Grouped coefficients, observables, and basis rotation transformation matrices needed to construct a qubit Hamiltonian in the rotated basis of molecular orbitals are now calculable via `qml.qchem.basis_rotation()`. - ([#3011](https://github.com/PennyLaneAI/pennylane/pull/3011)) +* Optimizing quantum circuits can now be done *adaptively* with + `qml.AdaptiveOptimizer`. + [(#3192)](https://github.com/PennyLaneAI/pennylane/pull/3192) - ```pycon - >>> symbols = ['H', 'H'] - >>> geometry = np.array([[0.0, 0.0, 0.0], [1.398397361, 0.0, 0.0]], requires_grad = False) - >>> mol = qml.qchem.Molecule(symbols, geometry) - >>> core, one, two = qml.qchem.electron_integrals(mol)() - >>> coeffs, ops, unitaries = qml.qchem.basis_rotation(one, two, tol_factor=1.0e-5) - >>> unitaries - [tensor([[-1.00000000e+00, -5.46483514e-13], - [ 5.46483514e-13, -1.00000000e+00]], requires_grad=True), - tensor([[-1.00000000e+00, 3.17585063e-14], - [-3.17585063e-14, -1.00000000e+00]], requires_grad=True), - tensor([[-0.70710678, -0.70710678], - [-0.70710678, 0.70710678]], requires_grad=True), - tensor([[ 2.58789009e-11, 1.00000000e+00], - [-1.00000000e+00, 2.58789009e-11]], requires_grad=True)] + The `qml.AdaptiveOptimizer` takes an initial circuit and a collection of operators as input and adds a selected gate to the circuit at each optimization step. The process of growing the circuit can be repeated until the circuit gradients converge to zero within a given threshold. The adaptive optimizer can be used to implement algorithms such as ADAPT-VQE as shown in the following example. + + Firstly, we define some preliminary variables needed for VQE: + + ```python + symbols = ["H", "H", "H"] + geometry = np.array([[0.01076341, 0.04449877, 0.0], + [0.98729513, 1.63059094, 0.0], + [1.87262415, -0.00815842, 0.0]], requires_grad=False) + H, qubits = qml.qchem.molecular_hamiltonian(symbols, geometry, charge = 1) ``` -* Any gate operation can now be tapered according to :math:`\mathbb{Z}_2` symmetries of the Hamiltonian via `qml.qchem.taper_operation`. - [(#3002)](https://github.com/PennyLaneAI/pennylane/pull/3002) + The collection of gates to grow the circuit is built to contain all single and double excitations: - ```pycon - >>> symbols = ['He', 'H'] - >>> geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4589]]) - >>> mol = qml.qchem.Molecule(symbols, geometry, charge=1) - >>> H, n_qubits = qml.qchem.molecular_hamiltonian(symbols, geometry) - >>> generators = qml.qchem.symmetry_generators(H) - >>> paulixops = qml.qchem.paulix_ops(generators, n_qubits) - >>> paulix_sector = qml.qchem.optimal_sector(H, generators, mol.n_electrons) - >>> tap_op = qml.qchem.taper_operation(qml.SingleExcitation, generators, paulixops, - ... paulix_sector, wire_order=H.wires, op_wires=[0, 2]) - >>> tap_op(3.14159) - [Exp(1.570795j PauliY)] + ```python + n_electrons = 2 + singles, doubles = qml.qchem.excitations(n_electrons, qubits) + singles_excitations = [qml.SingleExcitation(0.0, x) for x in singles] + doubles_excitations = [qml.DoubleExcitation(0.0, x) for x in doubles] + operator_pool = doubles_excitations + singles_excitations ``` - Moreover, the obtained tapered operation can be used directly within a QNode. + Next, an initial circuit that prepares a Hartree-Fock state and returns the expectation value of the Hamiltonian is defined: - ```pycon - >>> dev = qml.device('default.qubit', wires=[0, 1]) - >>> @qml.qnode(dev) - ... def circuit(params): - ... tap_op(params[0]) - ... return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - >>> drawer = qml.draw(circuit, show_all_wires=True) - >>> print(drawer(params=[3.14159])) - 0: ──Exp(0.00+1.57j Y)── β•­ - 1: ───────────────────── β•° + ```python + hf_state = qml.qchem.hf_state(n_electrons, qubits) + dev = qml.device("default.qubit", wires=qubits) + @qml.qnode(dev) + def circuit(): + qml.BasisState(hf_state, wires=range(qubits)) + return qml.expval(H) ``` -

(TODO: title) New operators and optimizers

+ Finally, the optimizer is instantiated and then the circuit is created and optimized adaptively: -* Optimizing quantum circuits can now be done *adaptively* with `qml.AdaptiveOptimizer`. - [(#3192)](https://github.com/PennyLaneAI/pennylane/pull/3192) + ```python + opt = qml.optimize.AdaptiveOptimizer() + for i in range(len(operator_pool)): + circuit, energy, gradient = opt.step_and_cost(circuit, operator_pool, drain_pool=True) + print('Energy:', energy) + print(qml.draw(circuit)()) + print('Largest Gradient:', gradient) + print() + if gradient < 1e-3: + break + ``` - The `qml.AdaptiveOptimizer` optimizer takes an initial circuit and a collection of operators - as input and adds a selected gate to the circuits at each optimization step. The process of - growing the circuit can be repeated until the circuit gradients converge to zero within a given - threshold. The adaptive optimizer can be used to implement algorithms such as `ADAPT-VQE`. + ```pycon + Energy: -1.246549938420637 + 0: ─╭BasisState(M0)─╭GΒ²(0.20)── β•­<𝓗> + 1: β”€β”œBasisState(M0)β”€β”œGΒ²(0.20)── β”œ<𝓗> + 2: β”€β”œBasisState(M0)─│────────── β”œ<𝓗> + 3: β”€β”œBasisState(M0)─│────────── β”œ<𝓗> + 4: β”€β”œBasisState(M0)β”€β”œGΒ²(0.20)── β”œ<𝓗> + 5: ─╰BasisState(M0)─╰GΒ²(0.20)── β•°<𝓗> + Largest Gradient: 0.14399872776755085 + + Energy: -1.2613740231529604 + 0: ─╭BasisState(M0)─╭GΒ²(0.20)─╭GΒ²(0.19)── β•­<𝓗> + 1: β”€β”œBasisState(M0)β”€β”œGΒ²(0.20)β”€β”œGΒ²(0.19)── β”œ<𝓗> + 2: β”€β”œBasisState(M0)β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”œGΒ²(0.19)── β”œ<𝓗> + 3: β”€β”œBasisState(M0)─│─────────╰GΒ²(0.19)── β”œ<𝓗> + 4: β”€β”œBasisState(M0)β”€β”œGΒ²(0.20)──────────── β”œ<𝓗> + 5: ─╰BasisState(M0)─╰GΒ²(0.20)──────────── β•°<𝓗> + Largest Gradient: 0.1349349562423238 + + Energy: -1.2743971719780331 + 0: ─╭BasisState(M0)─╭GΒ²(0.20)─╭GΒ²(0.19)─────────── β•­<𝓗> + 1: β”€β”œBasisState(M0)β”€β”œGΒ²(0.20)β”€β”œGΒ²(0.19)─╭G(0.00)── β”œ<𝓗> + 2: β”€β”œBasisState(M0)β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”œGΒ²(0.19)─│───────── β”œ<𝓗> + 3: β”€β”œBasisState(M0)─│─────────╰GΒ²(0.19)─╰G(0.00)── β”œ<𝓗> + 4: β”€β”œBasisState(M0)β”€β”œGΒ²(0.20)───────────────────── β”œ<𝓗> + 5: ─╰BasisState(M0)─╰GΒ²(0.20)───────────────────── β•°<𝓗> + Largest Gradient: 0.00040841755397108586 + ``` - For a detailed breakdown of its implementation, check out [our demo!](https://pennylane.ai/qml/demos/tutorial_adaptive_circuits.html) + For a detailed breakdown of its implementation, check out the [Adaptive circuits for quantum chemistry + demo](https://pennylane.ai/qml/demos/tutorial_adaptive_circuits.html). -* The `IntegerComparator` arithmetic operation is now available. -[(#3113)](https://github.com/PennyLaneAI/pennylane/pull/3113) +

Automatic interface detection 🧩

- Given a basis state :math:`\vert n \rangle`, where :math:`n` is a positive integer, and a fixed positive integer :math:`L`, the `IntegerComparator` operator flips a target qubit if :math:`n \geq L`. Alternatively, the flipping condition can be :math:`n < L` as demonstrated below: +* QNodes now accept an `auto` interface argument which automatically detects the machine learning library to use. + [(#3132)](https://github.com/PennyLaneAI/pennylane/pull/3132) ```python + from pennylane import numpy as np + import torch + import tensorflow as tf + from jax import numpy as jnp + dev = qml.device("default.qubit", wires=2) + @qml.qnode(dev, interface="auto") + def circuit(weight): + qml.RX(weight[0], wires=0) + qml.RY(weight[1], wires=1) + return qml.expval(qml.PauliZ(0)) - @qml.qnode(dev) - def circuit(): - qml.BasisState(np.array([0, 1]), wires=range(2)) - qml.broadcast(qml.Hadamard, wires=range(2), pattern='single') - qml.IntegerComparator(2, geq=False, wires=[0, 1]) - return qml.state() + interface_tensors = [[0, 1], np.array([0, 1]), torch.Tensor([0, 1]), tf.Variable([0, 1], dtype=float), jnp.array([0, 1])] + for tensor in interface_tensors: + res = circuit(weight=tensor) + print(f"Result value: {res:.2f}; Result type: {type(res)}") ``` ```pycon - >>> circuit() - [-0.5+0.j 0.5+0.j -0.5+0.j 0.5+0.j] + Result value: 1.00; Result type: + Result value: 1.00; Result type: + Result value: 1.00; Result type: + Result value: 1.00; Result type: + Result value: 1.00; Result type: ``` -

(TODO: title) QNode QoL boosts

+

Upgraded JAX-JIT gradient support 🏎

-* Added support to the JAX-JIT interface for computing the gradient of QNodes that return a single vector of probabilities or multiple expectation values. +* JAX-JIT support for computing the gradient of QNodes that return a single vector of probabilities or multiple expectation values is now available. [(#3244)](https://github.com/PennyLaneAI/pennylane/pull/3244) [(#3261)](https://github.com/PennyLaneAI/pennylane/pull/3261) @@ -174,32 +264,183 @@ Note that this change depends on `jax.pure_callback`, which requires `jax>=0.3.17`. -* The `QNode` class now accepts an `auto` interface, which automatically detects the interface of the given input. - [(#3132)](https://github.com/PennyLaneAI/pennylane/pull/3132) +

Construct Pauli words and sentences πŸ”€

+ +* We've reorganized and grouped everything in PennyLane responsible for manipulating Pauli operators into a `pauli` module. The `grouping` module has been deprecated as a result, and logic was moved from `pennylane/grouping` to `pennylane/pauli/grouping`. + [(#3179)](https://github.com/PennyLaneAI/pennylane/pull/3179) +* `qml.pauli.PauliWord` and `qml.pauli.PauliSentence` can be used to represent tensor products and linear combinations of Pauli operators, respectively. These provide a more performant method to compute sums and products of Pauli operators. + [(#3195)](https://github.com/PennyLaneAI/pennylane/pull/3195) + + - `qml.pauli.PauliWord` represents tensor products of Pauli operators. We can efficiently multiply and extract the matrix of these operators using this representation. + + ```pycon + >>> pw1 = qml.pauli.PauliWord({0:"X", 1:"Z"}) + >>> pw2 = qml.pauli.PauliWord({0:"Y", 1:"Z"}) + >>> pw1, pw2 + (X(0) @ Z(1), Y(0) @ Z(1)) + >>> pw1 * pw2 + (Z(0), 1j) + >>> pw1.to_mat(wire_order=[0,1]) + array([[ 0, 0, 1, 0], + [ 0, 0, 0, -1], + [ 1, 0, 0, 0], + [ 0, -1, 0, 0]]) + ``` + + - `qml.pauli.PauliSentence` represents linear combinations of Pauli words. We can efficiently add, multiply and extract the matrix of these operators in this representation. + + ```pycon + >>> ps1 = qml.pauli.PauliSentence({pw1: 1.2, pw2: 0.5j}) + >>> ps2 = qml.pauli.PauliSentence({pw1: -1.2}) + >>> ps1 + 1.2 * X(0) @ Z(1) + + 0.5j * Y(0) @ Z(1) + >>> ps1 + ps2 + 0.0 * X(0) @ Z(1) + + 0.5j * Y(0) @ Z(1) + >>> ps1 * ps2 + -1.44 * I + + (-0.6+0j) * Z(0) + >>> (ps1 + ps2).to_mat(wire_order=[0,1]) + array([[ 0. +0.j, 0. +0.j, 0.5+0.j, 0. +0.j], + [ 0. +0.j, 0. +0.j, 0. +0.j, -0.5+0.j], + [-0.5+0.j, 0. +0.j, 0. +0.j, 0. +0.j], + [ 0. +0.j, 0.5+0.j, 0. +0.j, 0. +0.j]]) + ``` + +

(Experimental) More support for multi-measurement and gradient output types πŸ§ͺ

+ +* `qml.enable_return()` now supports QNodes returning multiple measurements, + including shots vectors, and gradient output types. + [(#2886)](https://github.com/PennyLaneAI/pennylane/pull/2886) + [(#3052)](https://github.com/PennyLaneAI/pennylane/pull/3052) + [(#3041)](https://github.com/PennyLaneAI/pennylane/pull/3041) + [(#3090)](https://github.com/PennyLaneAI/pennylane/pull/3090) + [(#3069)](https://github.com/PennyLaneAI/pennylane/pull/3069) + [(#3137)](https://github.com/PennyLaneAI/pennylane/pull/3137) + [(#3127)](https://github.com/PennyLaneAI/pennylane/pull/3127) + [(#3099)](https://github.com/PennyLaneAI/pennylane/pull/3099) + [(#3098)](https://github.com/PennyLaneAI/pennylane/pull/3098) + [(#3095)](https://github.com/PennyLaneAI/pennylane/pull/3095) + [(#3091)](https://github.com/PennyLaneAI/pennylane/pull/3091) + [(#3176)](https://github.com/PennyLaneAI/pennylane/pull/3176) + [(#3170)](https://github.com/PennyLaneAI/pennylane/pull/3170) + [(#3194)](https://github.com/PennyLaneAI/pennylane/pull/3194) + [(#3267)](https://github.com/PennyLaneAI/pennylane/pull/3267) + [(#3234)](https://github.com/PennyLaneAI/pennylane/pull/3234) + [(#3232)](https://github.com/PennyLaneAI/pennylane/pull/3232) + [(#3223)](https://github.com/PennyLaneAI/pennylane/pull/3223) + [(#3222)](https://github.com/PennyLaneAI/pennylane/pull/3222) + [(#3315)](https://github.com/PennyLaneAI/pennylane/pull/3315) + + In v0.25, we introduced `qml.enable_return()`, which separates measurements into their own tensors. The motivation of this change is the deprecation of ragged `ndarray` creation in NumPy. + + With this release, we're continuing to elevate this feature by adding support for: + + - Execution (`qml.execute`) + - Jacobian vector product (JVP) computation + - Gradient transforms (`qml.gradients.param_shift`, `qml.gradients.finite_diff`, `qml.gradients.hessian_transform`, `qml.gradients.param_shift_hessian`). + + - Interfaces (Autograd, TensorFlow, and JAX, although without JIT) + + With this added support, the JAX interface can handle multiple shots (shots vectors), measurements, and gradient output types with `qml.enable_return()`: + ```python - dev = qml.device("default.qubit", wires=2) - @qml.qnode(dev, interface="auto") - def circuit(weight): - qml.RX(weight[0], wires=0) - qml.RY(weight[1], wires=1) - return qml.expval(qml.PauliZ(0)) + import jax - interface_tensors = [[0, 1], np.array([0, 1]), torch.Tensor([0, 1]), tf.Variable([0, 1], dtype=float), jnp.array([0, 1])] - for tensor in interface_tensors: - res = circuit(weight=tensor) - print(f"Result value: {res:.2f}; Result type: {type(res)}") + qml.enable_return() + dev = qml.device("default.qubit", wires=2, shots=(1, 10000)) + + params = jax.numpy.array([0.1, 0.2]) + + @qml.qnode(dev, interface="jax", diff_method="parameter-shift", max_diff=2) + def circuit(x): + qml.RX(x[0], wires=[0]) + qml.RY(x[1], wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.var(qml.PauliZ(0) @ qml.PauliX(1)), qml.probs(wires=[0]) ``` ```pycon - Result value: 1.00; Result type: - Result value: 1.00; Result type: - Result value: 1.00; Result type: - Result value: 1.00; Result type: - Result value: 1.00; Result type: + >>> jax.hessian(circuit)(params) + ((DeviceArray([[ 0., 0.], + [ 2., -3.]], dtype=float32), + DeviceArray([[[-0.5, 0. ], + [ 0. , 0. ]], + [[ 0.5, 0. ], + [ 0. , 0. ]]], dtype=float32)), + (DeviceArray([[ 0.07677898, 0.0563341 ], + [ 0.07238522, -1.830669 ]], dtype=float32), + DeviceArray([[[-4.9707499e-01, 2.9999996e-04], + [-6.2500127e-04, 1.2500001e-04]], + [[ 4.9707499e-01, -2.9999996e-04], + [ 6.2500127e-04, -1.2500001e-04]]], dtype=float32))) + ``` + + For more details, please [refer to the documentation](https://docs.pennylane.ai/en/stable/code/api/pennylane.enable_return.html?highlight=enable_return#pennylane.enable_return). + +

New basis rotation and tapering features in qml.qchem πŸ€“

+ +* Grouped coefficients, observables, and basis rotation transformation matrices needed to construct a qubit Hamiltonian in the rotated basis of molecular orbitals are now calculable via `qml.qchem.basis_rotation()`. + ([#3011](https://github.com/PennyLaneAI/pennylane/pull/3011)) + + ```pycon + >>> symbols = ['H', 'H'] + >>> geometry = np.array([[0.0, 0.0, 0.0], [1.398397361, 0.0, 0.0]], requires_grad = False) + >>> mol = qml.qchem.Molecule(symbols, geometry) + >>> core, one, two = qml.qchem.electron_integrals(mol)() + >>> coeffs, ops, unitaries = qml.qchem.basis_rotation(one, two, tol_factor=1.0e-5) + >>> unitaries + [tensor([[-1.00000000e+00, -5.46483514e-13], + [ 5.46483514e-13, -1.00000000e+00]], requires_grad=True), + tensor([[-1.00000000e+00, 3.17585063e-14], + [-3.17585063e-14, -1.00000000e+00]], requires_grad=True), + tensor([[-0.70710678, -0.70710678], + [-0.70710678, 0.70710678]], requires_grad=True), + tensor([[ 2.58789009e-11, 1.00000000e+00], + [-1.00000000e+00, 2.58789009e-11]], requires_grad=True)] ``` +* Any gate operation can now be tapered according to :math:`\mathbb{Z}_2` symmetries of the Hamiltonian via `qml.qchem.taper_operation`. + [(#3002)](https://github.com/PennyLaneAI/pennylane/pull/3002) + [(#3121)](https://github.com/PennyLaneAI/pennylane/pull/3121) + + ```pycon + >>> symbols = ['He', 'H'] + >>> geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4589]]) + >>> mol = qml.qchem.Molecule(symbols, geometry, charge=1) + >>> H, n_qubits = qml.qchem.molecular_hamiltonian(symbols, geometry) + >>> generators = qml.qchem.symmetry_generators(H) + >>> paulixops = qml.qchem.paulix_ops(generators, n_qubits) + >>> paulix_sector = qml.qchem.optimal_sector(H, generators, mol.n_electrons) + >>> tap_op = qml.qchem.taper_operation(qml.SingleExcitation, generators, paulixops, + ... paulix_sector, wire_order=H.wires, op_wires=[0, 2]) + >>> tap_op(3.14159) + [Exp(1.5707949999999993j PauliY)] + ``` + + Moreover, the obtained tapered operation can be used directly within a QNode. + + ```pycon + >>> dev = qml.device('default.qubit', wires=[0, 1]) + >>> @qml.qnode(dev) + ... def circuit(params): + ... tap_op(params[0]) + ... return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + >>> drawer = qml.draw(circuit, show_all_wires=True) + >>> print(drawer(params=[3.14159])) + 0: ──Exp(0.00+1.57j Y)── β•­ + 1: ───────────────────── β•° + ``` + +* Functionality has been added to estimate the number of measurements required to compute an expectation value with a target error and estimate the error in computing an expectation value with a given number of measurements. + [(#3000)](https://github.com/PennyLaneAI/pennylane/pull/3000) + +

New functions, operations, and observables 🀩

+ * Wires of operators or entire QNodes can now be mapped to other wires via `qml.map_wires()`. + [(#3143)](https://github.com/PennyLaneAI/pennylane/pull/3143) [(#3145)](https://github.com/PennyLaneAI/pennylane/pull/3145) The `qml.map_wires()` function requires a dictionary representing a wire map. Use it with @@ -215,6 +456,9 @@ (RX(0.54, wires=[10]) + PauliX(wires=[11])) + (PauliZ(wires=[12]) @ RY(1.23, wires=[13])) ``` + A `map_wires` method has also been added to operators, which returns a copy + of the operator with its wires changed according to the given wire map. + - entire QNodes: ```python @@ -236,143 +480,84 @@ tensor([0.92885434, 0.07114566], requires_grad=True) >>> print(qml.draw(mapped_circuit)()) A: ──RX(0.54)── Probs - B: ──X───────── - C: ──Z───────── - D: ──RY(1.23)── + B: ──X───────── + C: ──Z───────── + D: ──RY(1.23)── ``` -

(TODO: title) Data Module

+* The `qml.IntegerComparator` arithmetic operation is now available. +[(#3113)](https://github.com/PennyLaneAI/pennylane/pull/3113) -* Added the `data` module to allow downloading, loading, and creating quantum datasets. + Given a basis state :math:`\vert n \rangle`, where :math:`n` is a positive integer, and a fixed positive integer :math:`L`, `qml.IntegerComparator` flips a target qubit if :math:`n \geq L`. Alternatively, the flipping condition can be :math:`n < L` as demonstrated below: -* Datasets hosted on the cloud can be downloaded with the `qml.data.load` function as follows: + ```python + dev = qml.device("default.qubit", wires=2) - ```pycon - >>> H2datasets = qml.data.load("qchem", molname="H2", basis="STO-3G", bondlength=1.1) - >>> print(H2datasets) - [] - >>> H2data = H2datasets[0] + @qml.qnode(dev) + def circuit(): + qml.BasisState(np.array([0, 1]), wires=range(2)) + qml.broadcast(qml.Hadamard, wires=range(2), pattern='single') + qml.IntegerComparator(2, geq=False, wires=[0, 1]) + return qml.state() ``` -* To see what datasets are available for download, we can call `qml.data.list_datasets`: - ```pycon - >>> available_data = qml.data.list_datasets() - >>> available_data.keys() - dict_keys(["qspin", "qchem"]) - >>> available_data["qchem"].keys() - dict_keys(["H2", "LiH", ...]) - >>> available_data['qchem']['H2'].keys() - dict_keys(["6-31G", "STO-3G"]) - >>> print(available_data['qchem']['H2']['STO-3G']) - ["0.5", "0.54", "0.62", "0.66", ...] + >>> circuit() + [-0.5+0.j 0.5+0.j -0.5+0.j 0.5+0.j] ``` -* To download or load only specific properties of a dataset, we can specify the desired attributes in `qml.data.load`: +* The `qml.GellMann` qutrit observable, the ternary generalization of the Pauli observables, is now available. + [(#3035)](https://github.com/PennyLaneAI/pennylane/pull/3035) - ```pycon - >>> part = qml.data.load("qchem", molname="H2", basis="STO-3G", bondlength=1.1, - ... attributes=["molecule", "fci_energy"])[0] - >>> part.molecule - - >>> part.fci_energy - -1.0791924385860894 - ``` + When using `qml.GellMann`, the `index` keyword argument determines which of the 8 Gell-Mann matrices is used. -* The available `attributes` can be found using `qml.data.list_attributes`: + ```python + dev = qml.device("default.qutrit", wires=2) - ```pycon - >>> qml.data.list_attributes(data_name='qchem') - ['molecule', - 'hamiltonian', - 'sparse_hamiltonian', - ... - 'tapered_hamiltonian', - 'full'] + @qml.qnode(dev) + def circuit(): + qml.TClock(wires=0) + qml.TShift(wires=1) + qml.TAdd(wires=[0, 1]) + return qml.expval(qml.GellMann(wires=0, index=8) + qml.GellMann(wires=1, index=3)) ``` -* To select data interactively by following a series of prompts, we can use `qml.data.load_interactive` as follows: - ```pycon - >>> qml.data.load_interactive() - Please select a data name: - 1) qspin - 2) qchem - Choice [1-2]: 1 - Please select a sysname: - ... - Please select a periodicity: - ... - Please select a lattice: - ... - Please select a layout: - ... - Please select attributes: - ... - Force download files? (Default is no) [y/N]: N - Folder to download to? (Default is pwd, will download to /datasets subdirectory): - - Please confirm your choices: - dataset: qspin/Ising/open/rectangular/4x4 - attributes: ['parameters', 'ground_states'] - force: False - dest folder: /Users/jovyan/Downloads/datasets - Would you like to continue? (Default is yes) [Y/n]: - - ``` + >>> circuit() + -0.42264973081037416 + ``` -* Once loaded, properties of a dataset can be accessed easily as follows: +* Controlled qutrit operations can now be performed with `qml.ControlledQutritUnitary`. + ([#2844](https://github.com/PennyLaneAI/pennylane/pull/2844)) - ```pycon - >>> dev = qml.device("default.qubit",wires=4) - >>> @qml.qnode(dev) - ... def circuit(): - ... qml.BasisState(H2_dataset.hf_state, wires = [0, 1, 2, 3]) - ... for op in H2_dataset.vqe_gates: - ... qml.apply(op) - ... return qml.expval(H2_dataset.hamiltonian) - >>> print(circuit()) - -1.0791430411076344 - ``` + The control wires and values that define the operation are defined analogously to the qubit operation. -* It is also possible to create custom datasets with `qml.data.Dataset` + ```python + dev = qml.device("default.qutrit", wires=3) - ```pycon - >>> coeffs = [1, 0.5] - >>> observables = [qml.PauliZ(wires=0), qml.PauliX(wires=1)] - >>> H = qml.Hamiltonian(coeffs, observables) - >>> energies, _ = np.linalg.eigh(qml.matrix(H)) #Calculate the energies - >>> dataset = qml.data.Dataset(data_name = "Example", hamiltonian=H, energies=energies) - >>> dataset.data_name - "Example" - >>> dataset.hamiltonian - (0.5) [X1] - + (1) [Z0] - >>> dataset.energies - array([-1.5, -0.5, 0.5, 1.5]) + @qml.qnode(dev) + def circuit(U): + qml.TShift(wires=0) + qml.TAdd(wires=[0, 1]) + qml.ControlledQutritUnitary(U, control_wires=[0, 1], control_values='12', wires=2) + return qml.state() ``` -* These custom datasets can be saved and read with the `Dataset.write` and `Dataset.read` functions as follows: - ```pycon - >>> dataset.write("./path/to/dataset.dat") - >>> read_dataset = qml.data.Dataset() - >>> read_dataset.read("./path/to/dataset.dat") - >>> read_dataset.data_name - 'Example' - >>> read_dataset.hamiltonian - (0.5) [X1] - + (1) [Z0] - >>> read_dataset.energies - array([-1.5, -0.5, 0.5, 1.5]) + >>> U = np.array([[1, 1, 0], [1, -1, 0], [0, 0, np.sqrt(2)]]) / np.sqrt(2) + >>> circuit(U) + tensor([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, + 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, + 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, + 0.+0.j, 0.+0.j, 0.+0.j], requires_grad=True) ```

Improvements

-* Adds a Python 3.11 classification to the PennyLane package. +* PennyLane now supports Python 3.11! [(#3297)](https://github.com/PennyLaneAI/pennylane/pull/3297) -* Added a `samples_computational_basis` attribute to the `MeasurementProcess` and `QuantumScript` classes to track if computational basis samples are being generated when `qml.sample` or `qml.counts` are called without specifying an observable. +* `qml.sample` and `qml.counts` work more efficiently and track if computational basis samples are being generated when they are called without specifying an observable. [(#3207)](https://github.com/PennyLaneAI/pennylane/pull/3207) * The parameters of a basis set containing a different number of Gaussian functions are now easier to differentiate. @@ -381,9 +566,6 @@ * Printing a `qml.MultiControlledX` operator now shows the `control_values` keyword argument. [(#3113)](https://github.com/PennyLaneAI/pennylane/pull/3113) -* The matrix passed to `qml.Hermitian` is now validated when creating the observable if the input is not abstract. - [(#3181)](https://github.com/PennyLaneAI/pennylane/pull/3181) - * `qml.simplify` and transforms like `qml.matrix`, `batch_transform`, `hamiltonian_expand`, and `split_non_commuting` now work with `QuantumScript` as well as `QuantumTape`. [(#3209)](https://github.com/PennyLaneAI/pennylane/pull/3209) @@ -391,37 +573,34 @@ * A redundant flipping of the initial state in the UCCSD and kUpCCGSD templates has been removed. [(#3148)](https://github.com/PennyLaneAI/pennylane/pull/3148) -* `Adjoint` now supports batching if the base operation supports batching. +* `qml.adjoint` now supports batching if the base operation supports batching. [(#3168)](https://github.com/PennyLaneAI/pennylane/pull/3168) -* `OrbitalRotation` is now decomposed into two `SingleExcitation` operations for faster execution and more efficient parameter-shift gradient calculations on devices that natively support `SingleExcitation`. +* `qml.OrbitalRotation` is now decomposed into two `qml.SingleExcitation` operations for faster execution and more efficient parameter-shift gradient calculations on devices that natively support `qml.SingleExcitation`. [(#3171)](https://github.com/PennyLaneAI/pennylane/pull/3171) -* Reorganized and grouped all functions in PennyLane responsible for manipulation of Pauli operators into a `pauli` - module. Deprecated the `grouping` module and moved logic from `pennylane/grouping` to `pennylane/pauli/grouping`. - [(#3179)](https://github.com/PennyLaneAI/pennylane/pull/3179) +* The `Exp` class decomposes into a `PauliRot` class if the coefficient is imaginary and the base operator is a Pauli Word. + [(#3249)](https://github.com/PennyLaneAI/pennylane/pull/3249) -* Added the `Operator` attributes `has_decomposition` and `has_adjoint` that indicate +* Added the operator attributes `has_decomposition` and `has_adjoint` that indicate whether a corresponding `decomposition` or `adjoint` method is available. [(#2986)](https://github.com/PennyLaneAI/pennylane/pull/2986) * Structural improvements are made to `QueuingManager`, formerly `QueuingContext`, and `AnnotatedQueue`. [(#2794)](https://github.com/PennyLaneAI/pennylane/pull/2794) [(#3061)](https://github.com/PennyLaneAI/pennylane/pull/3061) - - * `QueuingContext` is renamed to `QueuingManager`. - * `QueuingManager` should now be the global communication point for putting queuable objects into the active queue. - * `QueuingManager` is no longer an abstract base class. - * `AnnotatedQueue` and its children no longer inherit from `QueuingManager`. - * `QueuingManager` is no longer a context manager. - * Recording queues should start and stop recording via the `QueuingManager.add_active_queue` and - `QueueingContext.remove_active_queue` class methods instead of directly manipulating the `_active_contexts` property. - * `AnnotatedQueue` and its children no longer provide global information about actively recording queues. This information - is now only available through `QueuingManager`. - * `AnnotatedQueue` and its children no longer have the private `_append`, `_remove`, `_update_info`, `_safe_update_info`, - and `_get_info` methods. The public analogues should be used instead. - * `QueuingManager.safe_update_info` and `AnnotatedQueue.safe_update_info` are deprecated. Their functionality is moved to - `update_info`. + [(#3085)](https://github.com/PennyLaneAI/pennylane/pull/3085) + + - `QueuingContext` is renamed to `QueuingManager`. + - `QueuingManager` should now be the global communication point for putting queuable objects into the active queue. + - `QueuingManager` is no longer an abstract base class. + - `AnnotatedQueue` and its children no longer inherit from `QueuingManager`. + - `QueuingManager` is no longer a context manager. + - Recording queues should start and stop recording via the `QueuingManager.add_active_queue` and + `QueuingContext.remove_active_queue` class methods instead of directly manipulating the `_active_contexts` property. + - `AnnotatedQueue` and its children no longer provide global information about actively recording queues. This information is now only available through `QueuingManager`. + - `AnnotatedQueue` and its children no longer have the private `_append`, `_remove`, `_update_info`, `_safe_update_info`, and `_get_info` methods. The public analogues should be used instead. + - `QueuingManager.safe_update_info` and `AnnotatedQueue.safe_update_info` are deprecated. Their functionality is moved to `update_info`. * `qml.Identity` now accepts multiple wires. [(#3049)](https://github.com/PennyLaneAI/pennylane/pull/3049) @@ -448,14 +627,13 @@ * Modified the representation of `WireCut` by using `qml.draw_mpl`. [(#3067)](https://github.com/PennyLaneAI/pennylane/pull/3067) -* Improved the performance of the `qml.math.expand_matrix` function for dense matrices. - [(#3064)](https://github.com/PennyLaneAI/pennylane/pull/3064) - -* Improved the `qml.math.expand_matrix` method for sparse matrices. +* Improved the performance of `qml.math.expand_matrix` function for dense + and sparse matrices. [(#3060)](https://github.com/PennyLaneAI/pennylane/pull/3060) + [(#3064)](https://github.com/PennyLaneAI/pennylane/pull/3064) -* Support sums and products of `Operator` classes with scalar tensors of any interface - (numpy, jax, tensorflow, torch...). +* Added support for sums and products of operator classes with scalar tensors of any interface + (NumPy, JAX, Tensorflow, PyTorch...). [(#3149)](https://github.com/PennyLaneAI/pennylane/pull/3149) ```pycon @@ -470,7 +648,7 @@ performance of the `eigvals`, `diagonalizing_gates` and `Prod.matrix` methods. [(#3084)](https://github.com/PennyLaneAI/pennylane/pull/3084) -* Added the `map_wires` method to the `Operator` class, which returns a copy of the operator with +* Added the `map_wires` method to the operators, which returns a copy of the operator with its wires changed according to the given wire map. [(#3143)](https://github.com/PennyLaneAI/pennylane/pull/3143) @@ -496,34 +674,32 @@ * `default.qubit` favours decomposition and avoids matrix construction for `QFT` and `GroverOperator` at larger qubit numbers. [(#3193)](https://github.com/PennyLaneAI/pennylane/pull/3193) -* `ControlledQubitUnitary` now has a `control_values` property. +* `qml.ControlledQubitUnitary` now has a `control_values` property. [(#3206)](https://github.com/PennyLaneAI/pennylane/pull/3206) -* Remove `_wires` properties and setters from the `ControlledClass` and the `SymbolicClass`. - Stop using `op._wires = new_wires`, use `qml.map_wires(op, wire_map=dict(zip(op.wires, new_wires)))` - instead. - [(#3186)](https://github.com/PennyLaneAI/pennylane/pull/3186) - * Added a new `qml.tape.QuantumScript` class that contains all the non-queuing behavior of `QuantumTape`. Now, `QuantumTape` inherits from `QuantumScript` as well as `AnnotatedQueue`. [(#3097)](https://github.com/PennyLaneAI/pennylane/pull/3097) +* Extended the `qml.equal` function to MeasurementProcesses + [(#3189)](https://github.com/PennyLaneAI/pennylane/pull/3189) + +* `qml.drawer.draw.draw_mpl` now accepts a `style` kwarg to select a style for plotting, rather than calling + `qml.drawer.use_style(style)` before plotting. Setting a style for `draw_mpl` does not change the global + configuration for matplotlib plotting. If no `style` is passed, the function defaults + to plotting with the `black_white` style. + [(#3247)](https://github.com/PennyLaneAI/pennylane/pull/3247) +

Breaking changes

* `QuantumTape._par_info` is now a list of dictionaries, instead of a dictionary whose keys are integers starting from zero. [(#3185)](https://github.com/PennyLaneAI/pennylane/pull/3185) -* `QueuingContext` is renamed `QueuingManager`. +* `QueuingContext` has been renamed to `QueuingManager`. [(#3061)](https://github.com/PennyLaneAI/pennylane/pull/3061) -* `QueuingManager.safe_update_info` and `AnnotatedQueue.safe_update_info` are deprecated. Instead, `update_info` no longer raises errors - if the object isn't in the queue. - * Deprecation patches for the return types enum's location and `qml.utils.expand` are removed. [(#3092)](https://github.com/PennyLaneAI/pennylane/pull/3092) -* Extended `qml.equal` function to MeasurementProcesses - [(#3189)](https://github.com/PennyLaneAI/pennylane/pull/3189) - * `_multi_dispatch` functionality has been moved inside the `get_interface` function. This function can now be called with one or multiple tensors as arguments. [(#3136)](https://github.com/PennyLaneAI/pennylane/pull/3136) @@ -555,29 +731,17 @@ >>> qml.math.get_interface(torch_scalar, torch_tensor, numpy_tensor) 'torch' ``` - - Note that when passing lists or tuples without unpacking them, ``get_interface`` will always default to ``"numpy"``. - - ```pycon - >>> qml.math.get_interface([torch_scalar, torch_tensor, numpy_tensor]) - 'numpy' - ``` - - - -* `qml.drawer.draw.draw_mpl` now accepts a `style` kwarg to select a style for plotting, rather than calling - `qml.drawer.use_style(style)` before plotting. Setting a style for `draw_mpl` does not change the global - configuration for matplotlib plotting. If no `style` is passed, the function defaults - - to plotting with the `black_white` style. - [(#3247)](https://github.com/PennyLaneAI/pennylane/pull/3247) - + * `Operator.compute_terms` is removed. On a specific instance of an operator, `op.terms()` can be used instead. There is no longer a static method for this. [(#3215)](https://github.com/PennyLaneAI/pennylane/pull/3215)

Deprecations

+* `QueuingManager.safe_update_info` and `AnnotatedQueue.safe_update_info` are deprecated. Instead, `update_info` no longer raises errors + if the object isn't in the queue. + [(#3085)](https://github.com/PennyLaneAI/pennylane/pull/3085) + * `qml.tape.stop_recording` and `QuantumTape.stop_recording` have been moved to `qml.QueuingManager.stop_recording`. The old functions will still be available until v0.29. [(#3068)](https://github.com/PennyLaneAI/pennylane/pull/3068) @@ -604,7 +768,7 @@ * Added a "Deprecations" page to the developer documentation. [(#3093)](https://github.com/PennyLaneAI/pennylane/pull/3093) -* The example of the `FlipSign` template has been updated. +* The example of the `qml.FlipSign` template has been updated. [(#3219)](https://github.com/PennyLaneAI/pennylane/pull/3219)

Bug fixes

@@ -612,16 +776,9 @@ * `qml.SparseHamiltonian` now validates the size of the input matrix. [(#3278)](https://github.com/PennyLaneAI/pennylane/pull/3278) -* Fixed a bug where `qml.sample()` and `qml.counts()` would output incorrect results when mixed with measurements whose - operators do not qubit-wise commute with computational basis projectors. - [(#3207)](https://github.com/PennyLaneAI/pennylane/pull/3207) - * Users no longer see unintuitive errors when inputing sequences to `qml.Hermitian`. [(#3181)](https://github.com/PennyLaneAI/pennylane/pull/3181) -* `ControlledQubitUnitary.pow` now copies over the `control_values`. - [(#3206)](https://github.com/PennyLaneAI/pennylane/pull/3206) - * The evaluation of QNodes that return either `vn_entropy` or `mutual_info` raises an informative error message when using devices that define a vector of shots. [(#3180)](https://github.com/PennyLaneAI/pennylane/pull/3180) @@ -650,10 +807,7 @@ composite operator. [(#3204)](https://github.com/PennyLaneAI/pennylane/pull/3204) -* Fixed a bug where `qml.BasisStatePreparation` was not jit-compilable with JAX. - [(#3239)](https://github.com/PennyLaneAI/pennylane/pull/3239) - -* Fixed a bug where `qml.BasisEmbedding` was not jit-compilable with JAX. +* Fixed a bug where `qml.BasisStatePreparation` and `qml.BasisEmbedding` were not jit-compilable with JAX. [(#3239)](https://github.com/PennyLaneAI/pennylane/pull/3239) * Fixed a bug where `qml.MottonenStatePreparation` was not jit-compilable with JAX. @@ -673,16 +827,20 @@ This release contains contributions from (in alphabetical order): Kamal Mohamed Ali, Guillermo Alonso-Linaje, Juan Miguel Arrazola, -Albert Mitjans Coma, Utkarsh Azad, +Thomas Bromley, +Albert Mitjans Coma, Isaac De Vlugt, +Olivia Di Matteo, Amintor Dusko, Lillian M. A. Frederiksen, Diego Guala, +Josh Izaac, Soran Jahangiri, Edward Jiang, Korbinian Kottmann, Christina Lee, +Romain Moyard, Lee J. O'Riordan, Mudit Pandey, Matthew Silverman,