From 9c61cc7485422a1e8585f301ca729864b1248395 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Jun 2022 10:16:45 -0400 Subject: [PATCH] Daily rc sync to master 2022-06-17 (#2743) * Update phase decomp test (#2697) * Update interfaces.rst (#2698) * Allow templates to be decomposed (#2704) * Allow templates to be decomposed * Add TODO to clean * Update changelog * Fix pylint error Co-authored-by: Edward Jiang * Deprecate `qml.ExpvalCost` (#2571) * Add UserWarning to ExpvalCost and catch said warning in all tests containing ExpvalCost * added warning in doc string * added to the changelog in 0.23.1 * Update pennylane/vqe/vqe.py Co-authored-by: Josh Izaac * Update pennylane/vqe/vqe.py Co-authored-by: Josh Izaac * Update pennylane/vqe/vqe.py Co-authored-by: Josh Izaac * Update pennylane/vqe/vqe.py Co-authored-by: Josh Izaac * Update tests/optimize/test_qng.py Co-authored-by: Josh Izaac * Update tests/qchem/of_tests/test_convert.py Co-authored-by: Josh Izaac * Update tests/test_qaoa.py Co-authored-by: Josh Izaac * Update tests/test_vqe.py Co-authored-by: Josh Izaac * Update tests/transforms/test_adjoint_metric_tensor.py Co-authored-by: Josh Izaac * Update tests/optimize/test_optimize_shot_adapative.py Co-authored-by: Josh Izaac * overlooked to catch the new warning in test_dipole_of * switched to the right changelog Co-authored-by: Qottmann Co-authored-by: Josh Izaac Co-authored-by: Romain Moyard * Update JAX jit forward mode forward evaluation (#2700) * update logic * update logic * test case * test assertion Co-authored-by: Romain Moyard * Improve ising gates documentation (#2711) * Update doc * Update * Update pennylane/ops/qubit/parametric_ops.py Co-authored-by: antalszava * Apply suggestions from code review * CHange * Typo Co-authored-by: antalszava * Support classical fisher gradients when using Autograd (#2688) * Support classical fisher gradients when using Autograd * Update doc/releases/changelog-dev.md * added test for jax and autograd * black * added xfail tests * added comment in doc string about torch and tf not diffable Co-authored-by: Qottmann Co-authored-by: Romain Moyard * Support classical Fisher gradients when using TF and torch (#2710) * Support classical fisher gradients when using Autograd * Update doc/releases/changelog-dev.md * added test for jax and autograd * black * added xfail tests * added comment in doc string about torch and tf not diffable * Fix differentiability for tensorflow and torch * Remove warning * Fix TF not iterable error * Trigger CI * added example in doc-string about diffability * close-block becomes code-block lol * Update pennylane/qinfo/transforms.py Co-authored-by: Josh Izaac * Change pytest mark Co-authored-by: Josh Izaac Co-authored-by: Qottmann Co-authored-by: Romain Moyard * Remove `hardware` argument in `qml.qinfo.quantum_fisher` (#2695) * removed hardware argument, adapted doc string * updated tests * black * Update pennylane/qinfo/transforms.py Co-authored-by: Josh Izaac * Update pennylane/qinfo/transforms.py Co-authored-by: Josh Izaac * add default.qubit condition and change doc string Co-authored-by: Josh Izaac Co-authored-by: Romain Moyard * Add `qinfo` measurements in supported configurations docs (#2712) * Add documentation for new qinfo measurements * Add docs for finite diff * Fix JAX tests * Change param shift to red * Move entropy param shift tests Co-authored-by: Romain Moyard * Use access_state (#2719) Co-authored-by: Romain Moyard * Update docs v0.24 (#2724) * private func has no indices arg * update the circuit name in the example * reduced_dm doc update * correct Hamiltonian creation for classical Fisher * Delete exactly one space from reduced_dm docstring to correct rendering * Update outputting quantum_fisher example * Move summary to start (#2727) * added weights initialization example (#2735) * Wires not updated for a hamiltonian with in-place addition (#2738) * fixed hamiltonian wire bug * changelog * Cleanup docs (#2736) * Documentation changes for `batch_partial` (#2737) * Update docs * Add double backticks * Add other backtick :xd: Co-authored-by: Christina Lee * exclude files from pr Co-authored-by: antalszava Co-authored-by: Edward Jiang <34989448+eddddddy@users.noreply.github.com> Co-authored-by: Edward Jiang Co-authored-by: Korbinian Kottmann <43949391+Qottmann@users.noreply.github.com> Co-authored-by: Qottmann Co-authored-by: Josh Izaac Co-authored-by: Romain Moyard Co-authored-by: Qottmann Co-authored-by: Jay Soni Co-authored-by: Christina Lee Co-authored-by: GitHub Actions Bot <> Co-authored-by: David Ittah --- doc/code/qml_operation.rst | 1 + pennylane/math/quantum.py | 4 +- pennylane/measurements.py | 2 +- pennylane/ops/qubit/hamiltonian.py | 1 + pennylane/qinfo/transforms.py | 47 +++++++++++++----------- pennylane/qnn/torch.py | 40 ++++++++++++++++++-- pennylane/tape/tape.py | 2 +- pennylane/transforms/batch_partial.py | 15 ++++---- pennylane/transforms/broadcast_expand.py | 8 ++-- pennylane/vqe/vqe.py | 8 ++-- tests/ops/qubit/test_hamiltonian.py | 14 +++++++ 11 files changed, 97 insertions(+), 45 deletions(-) diff --git a/doc/code/qml_operation.rst b/doc/code/qml_operation.rst index 2c5e66b1ab6..d30f0df3cf7 100644 --- a/doc/code/qml_operation.rst +++ b/doc/code/qml_operation.rst @@ -36,5 +36,6 @@ new :class:`~pennylane.ops.qubit.attributes.Attribute` objects. ~ops.qubit.attributes.diagonal_in_z_basis ~ops.qubit.attributes.has_unitary_generator ~ops.qubit.attributes.self_inverses + ~ops.qubit.attributes.supports_broadcasting ~ops.qubit.attributes.symmetric_over_all_wires ~ops.qubit.attributes.symmetric_over_control_wires diff --git a/pennylane/math/quantum.py b/pennylane/math/quantum.py index 32805969ae3..f32320e8e74 100644 --- a/pennylane/math/quantum.py +++ b/pennylane/math/quantum.py @@ -501,11 +501,11 @@ def _compute_vn_entropy(density_matrix, base=None): **Example** >>> x = [[1/2, 0], [0, 1/2]] - >>> _compute_vn_entropy(x, indices=[0]) + >>> _compute_vn_entropy(x) 0.6931472 >>> x = [[1/2, 0], [0, 1/2]] - >>> _compute_vn_entropy(x, indices=[0], base=2) + >>> _compute_vn_entropy(x, base=2) 1.0 """ diff --git a/pennylane/measurements.py b/pennylane/measurements.py index c347829dc78..107aa1ae79d 100644 --- a/pennylane/measurements.py +++ b/pennylane/measurements.py @@ -870,7 +870,7 @@ def vn_entropy(wires, log_base=None): dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) - def circuit(x): + def circuit_entropy(x): qml.IsingXX(x, wires=[0, 1]) return qml.vn_entropy(wires=[0]) diff --git a/pennylane/ops/qubit/hamiltonian.py b/pennylane/ops/qubit/hamiltonian.py index ccf0e1e61eb..231c0460d9d 100644 --- a/pennylane/ops/qubit/hamiltonian.py +++ b/pennylane/ops/qubit/hamiltonian.py @@ -396,6 +396,7 @@ def simplify(self): self._coeffs = qml.math.stack(new_coeffs) if new_coeffs else [] self._ops = new_ops + self._wires = qml.wires.Wires.all_wires([op.wires for op in self.ops], sort=True) # reset grouping, since the indices refer to the old observables and coefficients self._grouping_indices = None diff --git a/pennylane/qinfo/transforms.py b/pennylane/qinfo/transforms.py index 2f1e37364ca..bc5c002bdd6 100644 --- a/pennylane/qinfo/transforms.py +++ b/pennylane/qinfo/transforms.py @@ -21,27 +21,28 @@ def reduced_dm(qnode, wires): - """Compute the reduced density matrix from a :class:`~.QNode` returning :func:`~.state`. + """Compute the reduced density matrix from a :class:`~.QNode` returning + :func:`~.state`. - Args: - qnode (QNode): A :class:`~.QNode` returning :func:`~.state`. - wires (Sequence(int)): List of wires in the considered subsystem. + Args: + qnode (QNode): A :class:`~.QNode` returning :func:`~.state`. + wires (Sequence(int)): List of wires in the considered subsystem. - Returns: - func: Function which wraps the QNode and accepts the same arguments. When called, this function will - return the density matrix. + Returns: + func: Function which wraps the QNode and accepts the same arguments. When called, this function will + return the density matrix. - **Example** + **Example** - .. code-block:: python + .. code-block:: python - import numpy as np + import numpy as np - dev = qml.device("default.qubit", wires=2) - @qml.qnode(dev) - def circuit(x): - qml.IsingXX(x, wires=[0,1]) - return qml.state() + dev = qml.device("default.qubit", wires=2) + @qml.qnode(dev) + def circuit(x): + qml.IsingXX(x, wires=[0,1]) + return qml.state() >>> reduced_dm(circuit, wires=[0])(np.pi/2) [[0.5+0.j 0.+0.j] @@ -332,7 +333,7 @@ def circ(x, y): .. code-block:: python - H = qml.Hamiltonian(coeffs = [0.5, 0.5], ops = [qml.PauliZ(0), qml.PauliZ(1)]) + H = qml.Hamiltonian(coeffs=[0.5, 0.5], observables=[qml.PauliZ(0), qml.PauliZ(1)]) @qml.qnode(dev) def circ(params): @@ -478,13 +479,15 @@ def circ(params): The natural gradient is then simply the QFIM multiplied by the gradient: >>> grad = qml.grad(circ)(params) - [ 0.59422561, -0.02615095, -0.05146226] - + >>> grad + array([ 0.59422561, -0.02615095, -0.05146226]) >>> qfim = qml.qinfo.quantum_fisher(circ)(params) - np.diag([1., 1., 0.77517241]) - - >>> q_nat_grad = qfim @ grad - [ 0.59422561 -0.02615095 -0.03989212] + >>> qfim + tensor([[1. , 0. , 0. ], + [0. , 1. , 0. ], + [0. , 0. , 0.77517241]], requires_grad=True) + >>> qfim @ grad + tensor([ 0.59422561, -0.02615095, -0.03989212], requires_grad=True) When using real hardware or finite shots, ``quantum_fisher`` is internally calling :func:`~.pennylane.metric_tensor`. To obtain the full QFIM, we need an auxilary wire to perform the Hadamard test. diff --git a/pennylane/qnn/torch.py b/pennylane/qnn/torch.py index cb99c53f117..2be440fa384 100644 --- a/pennylane/qnn/torch.py +++ b/pennylane/qnn/torch.py @@ -104,7 +104,10 @@ def qnode(inputs, weights_0, weight_1): **Initializing weights** - The optional ``init_method`` argument of :class:`~.TorchLayer` allows for the initialization + If ``init_method`` is not specified, weights are randomly initialized from the uniform + distribution on the interval :math:`[0, 2 \pi]`. + + Alternative a): The optional ``init_method`` argument of :class:`~.TorchLayer` allows for the initialization method of the QNode weights to be specified. The function passed to the argument must be from the `torch.nn.init `__ module. For example, weights can be randomly initialized from the normal distribution by passing: @@ -113,8 +116,39 @@ def qnode(inputs, weights_0, weight_1): init_method = torch.nn.init.normal_ - If ``init_method`` is not specified, weights are randomly initialized from the uniform - distribution on the interval :math:`[0, 2 \pi]`. + Alternative b): Two dictionaries ``weight_shapes`` and ``init_method`` are passed, whose ``keys`` match the ``args`` of the qnode. + + .. code-block:: + + @qml.qnode(dev) + def qnode(inputs, weights_0, weights_1, weights_2, weight_3, weight_4): + qml.templates.AngleEmbedding(inputs, wires=range(n_qubits)) + qml.templates.StronglyEntanglingLayers(weights_0, wires=range(n_qubits)) + qml.templates.BasicEntanglerLayers(weights_1, wires=range(n_qubits)) + qml.Rot(*weights_2, wires=0) + qml.RY(weight_3, wires=1) + qml.RZ(weight_4, wires=1) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)) + + + weight_shapes = { + "weights_0": (3, n_qubits, 3), + "weights_1": (3, n_qubits), + "weights_2": 3, + "weight_3": 1, + "weight_4": (1,), + } + + init_method = { + "weights_0": torch.nn.init.normal_, + "weights_1": torch.nn.init.uniform, + "weights_2": torch.tensor([1., 2., 3.]), + "weight_3": torch.tensor(1.), # scalar when shape is not an iterable and is <= 1 + "weight_4": torch.tensor([1.]), + } + + qlayer = qml.qnn.TorchLayer(qnode, weight_shapes=weight_shapes, init_method=init_method) **Full code example** diff --git a/pennylane/tape/tape.py b/pennylane/tape/tape.py index 503241901b4..0271d88d04a 100644 --- a/pennylane/tape/tape.py +++ b/pennylane/tape/tape.py @@ -1293,7 +1293,7 @@ def batch_size(self): .. seealso:: :attr:`~.Operator.batch_size` for details. Returns: - int: The batch size of the quantum tape. + int or None: The batch size of the quantum tape if present, else ``None``. """ return self._batch_size diff --git a/pennylane/transforms/batch_partial.py b/pennylane/transforms/batch_partial.py index 5c726a88060..2b07fe3c5d3 100644 --- a/pennylane/transforms/batch_partial.py +++ b/pennylane/transforms/batch_partial.py @@ -41,22 +41,23 @@ def batch_partial(qnode, all_operations=False, preprocess=None, **partial_kwargs """ Create a batched partial callable object from the QNode specified. - This transform provides functionality akin to `functools.partial` and + This transform provides functionality akin to ``functools.partial`` and allows batching the arguments used for calling the batched partial object. Args: qnode (pennylane.QNode): QNode to pre-supply arguments to all_operations (bool): If ``True``, a batch dimension will be added to *all* operations in the QNode, rather than just trainable QNode parameters. + preprocess (dict): If provided, maps every QNode argument name to a preprocessing + function. When the returned partial function is called, the arguments are + first passed to the preprocessing functions, and the return values are + passed to the QNode. partial_kwargs (dict): pre-supplied arguments to pass to the QNode. Returns: func: Function which wraps the QNode and accepts the same arguments minus the - pre-supplied arguments provided, and behaves the same as the QNode called with - both the pre-supplied arguments and the other arguments passed to this wrapper - function. However, the first dimension of each argument of the wrapper function - will be treated as a batch dimension. The function output will also contain - an initial batch dimension. + pre-supplied arguments provided. The first dimension of each argument of the + wrapper function will be treated as a batch dimension. **Example** @@ -101,7 +102,7 @@ def circuit(x, y): >>> x = np.array(0.1) >>> y_fn = lambda y0: y0 * 0.2 + 0.3 - >>> batched_lambda_circuit = qml.batch_partial(circuit, x=x, y=y_fn) + >>> batched_lambda_circuit = qml.batch_partial(circuit, x=x, preprocess={"y": y_fn}) The wrapped function ``batched_lambda_circuit`` also expects arguments to have an initial batch dimension: diff --git a/pennylane/transforms/broadcast_expand.py b/pennylane/transforms/broadcast_expand.py index fc6ce88bb60..66829498344 100644 --- a/pennylane/transforms/broadcast_expand.py +++ b/pennylane/transforms/broadcast_expand.py @@ -57,7 +57,7 @@ def broadcast_expand(tape): with broadcasting axis of length ``3`` passed to ``qml.RX``: >>> x = pnp.array([0.2, 0.6, 1.0], requires_grad=True) - >>> qml.draw(expanded_circuit)(x) + >>> print(qml.draw(expanded_circuit)(x)) 0: ──RX(0.20)─┤ 0: ──RX(0.60)─┤ 0: ──RX(1.00)─┤ @@ -71,13 +71,11 @@ def broadcast_expand(tape): We also can call the transform manually on a tape: >>> with qml.tape.QuantumTape() as tape: - >>> qml.RX(np.array([0.2, 0.6, 1.0], requires_grad=True), wires=0) + >>> qml.RX(pnp.array([0.2, 0.6, 1.0], requires_grad=True), wires=0) >>> qml.expval(qml.PauliZ(0)) >>> tapes, fn = qml.transforms.broadcast_expand(tape) >>> tapes - [, - , - ] + [, , ] >>> fn(qml.execute(tapes, qml.device("default.qubit", wires=1), None)) array([0.98006658, 0.82533561, 0.54030231]) """ diff --git a/pennylane/vqe/vqe.py b/pennylane/vqe/vqe.py index 2341baa4b41..e293dfa3f3c 100644 --- a/pennylane/vqe/vqe.py +++ b/pennylane/vqe/vqe.py @@ -25,6 +25,10 @@ class ExpvalCost: """ + Create a cost function that gives the expectation value of an input Hamiltonian. + + This cost function is useful for a range of problems including VQE and QAOA. + .. warning:: ``ExpvalCost`` is deprecated. Instead, it is recommended to simply pass Hamiltonians to the :func:`~.expval` function inside QNodes. @@ -38,10 +42,6 @@ def ansatz(params): In order to optimize the Hamiltonian evaluation taking into account commuting terms, use the ``grouping_type`` keyword in :class:`~.Hamiltonian`. - Create a cost function that gives the expectation value of an input Hamiltonian. - - This cost function is useful for a range of problems including VQE and QAOA. - Args: ansatz (callable): The ansatz for the circuit before the final measurement step. Note that the ansatz **must** have the following signature: diff --git a/tests/ops/qubit/test_hamiltonian.py b/tests/ops/qubit/test_hamiltonian.py index a4b64d8e0e5..a004d7cf164 100644 --- a/tests/ops/qubit/test_hamiltonian.py +++ b/tests/ops/qubit/test_hamiltonian.py @@ -266,6 +266,12 @@ np.array([qml.PauliX(0), qml.PauliZ(1), qml.PauliX(2), qml.PauliX(1)]), ), ), + # Case where the 1st hamiltonian doesn't contain all wires + ( + qml.Hamiltonian([1.23, -3.45], [qml.PauliX(0), qml.PauliY(1)]), + qml.Hamiltonian([6.78], [qml.PauliZ(2)]), + qml.Hamiltonian([1.23, -3.45, 6.78], [qml.PauliX(0), qml.PauliY(1), qml.PauliZ(2)]), + ), ] add_zero_hamiltonians = [ @@ -361,6 +367,12 @@ np.array([qml.PauliX(0), qml.PauliZ(1), qml.PauliX(2), qml.PauliX(1)]), ), ), + # Case where the 1st hamiltonian doesn't contain all wires + ( + qml.Hamiltonian([1.23, -3.45], [qml.PauliX(0), qml.PauliY(1)]), + qml.Hamiltonian([6.78], [qml.PauliZ(2)]), + qml.Hamiltonian([1.23, -3.45, -6.78], [qml.PauliX(0), qml.PauliY(1), qml.PauliZ(2)]), + ), ] mul_hamiltonians = [ @@ -808,6 +820,7 @@ def test_hamiltonian_iadd(self, H1, H2, H): """Tests that Hamiltonians are added inline correctly""" H1 += H2 assert H.compare(H1) + assert H.wires == H1.wires @pytest.mark.parametrize(("H1", "H2"), iadd_zero_hamiltonians) def test_hamiltonian_iadd_zero(self, H1, H2): @@ -830,6 +843,7 @@ def test_hamiltonian_isub(self, H1, H2, H): """Tests that Hamiltonians are subtracted inline correctly""" H1 -= H2 assert H.compare(H1) + assert H.wires == H1.wires def test_arithmetic_errors(self): """Tests that the arithmetic operations thrown the correct errors"""