From 828c1ec34e672ef4b654bd1e5d354ce86b158ba5 Mon Sep 17 00:00:00 2001 From: lillian542 <38584660+lillian542@users.noreply.github.com> Date: Fri, 22 Nov 2024 12:59:06 -0500 Subject: [PATCH] Opmath docs (#6589) **Context:** A number of documentation changes and especially type hint changes already went in to master with the primary PR removing operator arithmetic, but we left the larger documentation sections (unifying docstring messaging surrounding qml.Hamiltonian/qml.ops.LinearCombination, updating the guidelines page for new operator arithmetic) for a separate PR. **Description of the Change:** - There is now a single docstring for LinearCombionation/qml.Hamiltonian. It references using `qml.Hamiltonian` as an access point. - The opmath page guiding users in transitioning from legacy operator arithmetic in the docs is updated to reflect the removal - A little bit of cleaning up to remove the more obvious instances where we refer to legacy operators in docstrings that should now refer to opmath operators. Since "tensor" and "Hamiltonian" are common words outside of class names, it's hard to do a thorough search, but we got a lot of the the easy-to-find ones here. **Benefits:** Clear documentation surrounding the current operator functionality in the code base after the removal of legacy operator arithmetic. [sc-77523] --------- Co-authored-by: Isaac De Vlugt <34751083+isaacdevlugt@users.noreply.github.com> Co-authored-by: Yushao Chen (Jerry) --- doc/conf.py | 3 +- doc/news/new_opmath.rst | 188 ++---------------- doc/releases/changelog-dev.md | 1 + pennylane/devices/_qubit_device.py | 2 +- pennylane/operation.py | 2 +- pennylane/ops/functions/generator.py | 4 +- pennylane/ops/op_math/linear_combination.py | 9 + pennylane/ops/qubit/observables.py | 4 +- pennylane/optimize/shot_adaptive.py | 2 +- pennylane/pauli/conversion.py | 4 +- .../subroutines/approx_time_evolution.py | 2 +- pennylane/templates/subroutines/qdrift.py | 6 +- pennylane/templates/subroutines/trotter.py | 6 +- tests/ops/functions/test_generator.py | 2 - tests/ops/qubit/test_qchem_ops.py | 3 +- tests/pauli/test_pauli_utils.py | 4 - .../templates/test_subroutines/test_qdrift.py | 6 +- .../test_subroutines/test_trotter.py | 2 +- tests/test_qaoa.py | 1 - 19 files changed, 52 insertions(+), 199 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 193c7b91270..a4ff3cb3bf7 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -113,7 +113,8 @@ # built documents. import pennylane -pennylane.Hamiltonian = pennylane.ops.op_math.linear_combination.Hamiltonian + +pennylane.Hamiltonian = pennylane.ops.op_math.linear_combination.LinearCombination # The full version, including alpha/beta/rc tags. diff --git a/doc/news/new_opmath.rst b/doc/news/new_opmath.rst index 20f86fb05fa..b0a64f63a7e 100644 --- a/doc/news/new_opmath.rst +++ b/doc/news/new_opmath.rst @@ -32,15 +32,12 @@ Summary of the update .. rst-class:: admonition tip - The opt-in feature ``qml.operation.enable_new_opmath()`` is now the default. Ideally, your code should not break. - If it still does, it likely only requires some minor changes. For that, see the :ref:`Troubleshooting_opmath` section. - You can still opt-out and run legacy code via ``qml.operation.disable_new_opmath()``, though it is deprecated, and thus, - not recommended. - -.. warning:: - - In PennyLane v0.39, legacy operator arithmetic is deprecated and will be removed in v0.40. - + After a period of deprecation, the legacy behaviour for operators was removed in PennyLane version 0.40. + Anyone using the latest PennyLane will automatically use the updated operator arithmetic. Ideally, your code + should not break when making this update. If it still does, it likely only requires some minor changes. + For that, see the :ref:`Troubleshooting_opmath` section. If you were using any of the functions explictly + provided to continue using the deprecated behaviour, like ``qml.operation.disable_new_opmath()``, that + code will need to be removed. * The underlying system for performing arithmetic with operators has been changed. Arithmetic can be carried out using standard Python operations like ``+``, ``*`` and ``@`` or via arithmetic functions located in :mod:`~.op_math`. @@ -65,7 +62,7 @@ Summary of the update >>> type(op.pauli_rep) pennylane.pauli.pauli_arithmetic.PauliSentence - You can transform the :class:`~.pennylane.pauli.PauliSentence` back to a suitable :class:`~.pennylane.operation.Operator` via the :meth:`~pennylane.pauli.PauliSentence.operation` or :meth:`~pennylane.pauli.PauliSentence.hamiltonian` method. + You can transform the :class:`~.pennylane.pauli.PauliSentence` back to a suitable :class:`~.pennylane.operation.Operator` via the :meth:`~pennylane.pauli.PauliSentence.operation` method. >>> op.pauli_rep.operation() X(0) + Y(0) @@ -166,28 +163,16 @@ Summary of the update **qml.Hamiltonian** - The legacy classes :class:`~.pennylane.operation.Tensor` and :class:`~.pennylane.Hamiltonian` will soon be deprecated. - :class:`~.ops.op_math.LinearCombination` offers the same API as :class:`~.pennylane.Hamiltonian` but works well with new opmath classes. - - Depending on whether or not new opmath is active, ``qml.Hamiltonian`` will return either of the two classes. + The classes :class:`~.pennylane.operation.Tensor` and :class:`~.pennylane.ops.Hamiltonian` have been removed. + The familiar ``qml.Hamiltonian`` can still be used, which dispatches to ``LinearCombination`` and offers the same + usage and functionality but with different implementation details. >>> import pennylane as qml >>> from pennylane import X - >>> qml.operation.active_new_opmath() - True >>> H = qml.Hamiltonian([0.5, 0.5], [X(0), X(1)]) >>> type(H) pennylane.ops.op_math.linear_combination.LinearCombination - >>> qml.operation.disable_new_opmath() - >>> qml.operation.active_new_opmath() - False - >>> H = qml.Hamiltonian([0.5, 0.5], [X(0), X(1)]) - >>> type(H) - pennylane.ops.qubit.hamiltonian.Hamiltonian - - Both classes offer the same API and functionality, so a user does not have to worry about those implementation details. - .. _Troubleshooting_opmath: Troubleshooting @@ -200,8 +185,7 @@ To help identify a fix, select the option below that describes your situation. :title: My old PennyLane script does not run anymore :href: old-script-broken - A quick-and-dirty fix for this issue is to deactivate new opmath at the beginning of the script via ``qml.operation.disable_new_opmath()``. - We recommend to do the following checks instead + We recommend to do the following checks: * Check explicit use of the legacy :class:`~Tensor` class. If you find it in your script it can just be changed from ``Tensor(*terms)`` to ``qml.prod(*terms)`` with the same call signature. @@ -209,24 +193,12 @@ To help identify a fix, select the option below that describes your situation. .. code-block:: python - # new opmath enabled (default) op = X(0) @ X(1) assert op.operands == (X(0), X(1)) - - with qml.operation.disable_new_opmath_cm(): - # context manager that disables new opmath temporarilly - op = X(0) @ X(1) - assert op.obs == [X(0), X(1)] * Check explicit use of ``qml.ops.Hamiltonian``. In that case, simply change to ``qml.Hamiltonian``. - - >>> op = qml.ops.Hamiltonian([0.5, 0.5], [X(0) @ X(1), X(1) @ X(2)]) - ValueError: Could not create circuits. Some or all observables are not valid. - >>> op = qml.Hamiltonian([0.5, 0.5], [X(0) @ X(1), X(1) @ X(2)]) - >>> isinstance(op, qml.ops.LinearCombination) - True - - * Check if you are explicitly enabling and disabling new opmath somewhere in your script. Mixing both systems is not supported. + This will dispatch to the ``LinearCombination`` class, which offers the same API and functionality + with different implementation details. If for some unexpected reason your script still breaks, please post on the PennyLane `discussion forum `_ or open a `bug report `_ @@ -236,141 +208,22 @@ To help identify a fix, select the option below that describes your situation. :title: Sharp bits about the qml.Hamiltonian dispatch :href: sharp-bits-hamiltonian - One of the reasons that :class:`~.ops.op_math.LinearCombination` exists is that the old Hamiltonian class is not compatible with new opmath tensor products. - We can try to instantiate an old ``qml.ops.Hamiltonian`` class with a ``X(0) @ X(1)`` tensor product, which returns a :class:`~.pennylane.ops.Prod` instance with new opmath enabled. + The API of :class:`~.ops.op_math.LinearCombination` is mostly identical to that of the removed ``qml.ops.Hamiltonian``. - >>> qml.operation.active_new_opmath() # confirm opmath is active (by default) - True - >>> qml.ops.Hamiltonian([0.5], [X(0) @ X(1)]) - PennyLaneDeprecationWarning: Using 'qml.ops.Hamiltonian' with new operator arithmetic is deprecated. Instead, use 'qml.Hamiltonian', or use 'qml.operation.disable_new_opmath()' to continue to access the legacy functionality. See https://docs.pennylane.ai/en/stable/development/deprecations.html for more details. - ValueError: Could not create circuits. Some or all observables are not valid. + One small difference is that ``Hamiltonian.simplify()`` no longer alters the instance in-place. Instead, you must do the - However, using ``qml.Hamiltonian`` works as expected. - - >>> qml.Hamiltonian([0.5], [X(0) @ X(1)]) - 0.5 * (X(0) @ X(1)) - - The API of :class:`~.ops.op_math.LinearCombination` is identical to that of :class:`~.Hamiltonian`. We can group observables upon initialization. - - >>> H1 = qml.Hamiltonian([0.5, 0.5, 0.5], [X(0) @ X(1), X(0), Y(0)], grouping_type="qwc") - >>> H2 = qml.ops.LinearCombination([0.5, 0.5, 0.5], [X(0) @ X(1), X(0), Y(0)], grouping_type="qwc") - >>> H1 == H2 - True - - One small difference is that ``ham.simplify()`` no longer alters the instance in-place. In either case (legacy/new opmath), the following works. + following: >>> H1 = qml.Hamiltonian([0.5, 0.5], [X(0) @ X(1), X(0) @ X(1)]) - >>> H1 = H1.simplify() # work for new and legacy opmath - -.. details:: - :title: I want to contribute to PennyLane and need to provide legacy support in tests - :href: PL-developer - - If you want to contribute a new feature to PennyLane or update an existing one, you likely also need to update the tests. - - .. note:: - Please refrain from explicitly using ``qml.operation.disable_new_opmath()`` and ``qml.operation.enable_new_opmath()`` anywhere in tests as that globally - changes the status of new opmath and thereby can affect other tests. - - .. code-block:: python3 - - def test_some_legacy_opmath_behavior(): - qml.operation.disable_new_opmath() # dont do this - # testing some legacy behavior things - - def test_some_new_opmath_behavior(): - assert qml.operation.active_new_opmath() - # will fail because the previous test globally disabled new opmath - - Instead, please use the fixtures below, or the context managers ``qml.operation.disable_new_opmath_cm()`` and ``qml.operation.enable_new_opmath_cm()``. - - >>> with qml.operation.disable_new_opmath_cm(): - ... op = qml.Hamiltonian([0.5], [X(0) @ X(1)]) - >>> assert isinstance(op, qml.ops.Hamiltonian) - - Our continuous integration (CI) test suite is running all tests with the new opmath enabled by default. - We also periodically run the CI test suite with new opmath disabled, as we support both the new and legacy systems for a limited time. - In case a test needs to be adopted for either case, you can use the following fixtures. - - * Use ``@pytest.mark.usefixtures("use_legacy_opmath")`` to test functionality that is explicitly only supported by legacy opmath (e.g., for backward compatibility). - - .. code-block:: python3 - - @pytest.mark.usefixtures("use_legacy_opmath") - def test_qml_hamiltonian_legacy_opmath(): - assert qml.Hamiltonian == qml.ops.Hamiltonian - - def test_qml_hamiltonian() - assert qml.Hamiltonian == qml.ops.LinearCombination - - * Use ``@pytest.mark.usefixtures("use_new_opmath")`` to test functionality that `only` works with new opmath. That is because for the intermittent period - of supporting both systems, we periodically run the test suite with new opmath disabled. - - .. code-block:: python3 - - @pytest.mark.usefixtures("use_new_opmath") - def test_qml_hamiltonian_new_opmath(): - assert qml.Hamiltonian == qml.ops.LinearCombination - - * Use ``@pytest.mark.usefixtures("use_legacy_and_new_opmath")`` if you want to test support for both systems in one single test. You can use ``qml.operation.active_new_opmath`` - inside the test to account for minor differences between both systems. - - .. code-block:: python3 - - @pytest.mark.usefixtures("use_legacy_and_new_opmath") - def test_qml_hamiltonian_new_opmath(): - if qml.operation.active_new_opmath(): - assert qml.Hamiltonian == qml.ops.LinearCombination - - if not qml.operation.active_new_opmath(): - assert qml.Hamiltonian == qml.ops.Hamiltonian - - One sharp bit about testing is that ``pytest`` runs collection and test execution separately. That means that instances generated outside the test, e.g., for parametrization, have been created - using the respective system. So you may need to also put that creation in the appropriate context manager. - - .. code-block:: python3 - - # in some test file - with qml.operation.disable_new_opmath_cm(): - legacy_ham_example = qml.Hamiltonian(coeffs, ops) # creates a Hamiltonian instance - - @pytest.mark.usefixtures("use_legacy_opmath") - @pytest.mark.parametrize("ham", [legacy_ham_example]) - def test_qml_hamiltonian_legacy_opmath(ham): - assert isinstance(ham, qml.Hamiltonian) # True - assert isinstance(ham, qml.ops.Hamiltonian) # True - - Alternatively, you can convert them back to legacy Hamiltonian instances using ``qml.operation.convert_to_legacy_H()``. - - .. code-block:: python3 - - ham_example = qml.Hamiltonian(coeffs, ops) # creates a LinearCombination instance - - @pytest.mark.usefixtures("use_new_opmath") - @pytest.mark.parametrize("ham", [ham_example]) - def test_qml_hamiltonian_new_opmath(ham): - assert isinstance(ham, qml.Hamiltonian) # True - assert not isinstance(ham, qml.ops.Hamiltonian) # True - - @pytest.mark.usefixtures("use_legacy_opmath") - @pytest.mark.parametrize("ham", [ham_example]) - def test_qml_hamiltonian_legacy_opmath(ham): - # Most likely you wanted to test things with a Hamiltonian instance - legacy_ham_example = convert_to_legacy_H(ham) - assert isinstance(legacy_ham_example, qml.ops.Hamiltonian) # True - assert isinstance(legacy_ham_example, qml.Hamiltonian) # True because we are in legacy opmath context - assert not isinstance(legacy_ham_example, qml.ops.LinearCombination) # True - - For all that, keep in mind that ``qml.Hamiltonian`` points to :class:`~pennylane.Hamiltonian` and :class:`LinearCombination` depending on the status of ``qml.operation.active_new_opmath()``. - So if you want to test something specifically for the old :class:`~pennylane.Hamiltonian`` class, use ``qml.ops.Hamiltonian`` instead. + >>> H1 = H1.simplify() .. details:: :title: Sharp bits about the nesting structure of new opmath instances :href: sharp-bits-nesting - The type of the final operator is determined by the outermost operation. The resulting object is a nested structure (sums of s/prods or s/prods of sums). + The type of the final operator is determined by the outermost operation. The resulting object is a nested + structure (sums of s/prods or s/prods of sums). - >>> qml.operation.enable_new_opmath() # default soon >>> op = 0.5 * (X(0) @ X(1)) + 0.5 * (Y(0) @ Y(1)) >>> type(op) pennylane.ops.op_math.sum.Sum @@ -402,7 +255,8 @@ To help identify a fix, select the option below that describes your situation. There is yet another way to construct the same, equivalent, operator. We can bring all of them to the same format by using ``op.simplify()``, which brings the operator down to - the form :math:`\sum_i c_i \hat{O}_i`, where :math:`c_i` is a scalar coefficient and :math:`\hat{O}_i` is a pure operator or tensor product of operators. + the form :math:`\sum_i c_i \hat{O}_i`, where :math:`c_i` is a scalar coefficient and :math:`\hat{O}_i` is a + pure operator or tensor product of operators. >>> op1 = 0.5 * (X(0) @ X(1)) + 0.5 * (Y(0) @ Y(1)) >>> op2 = (0.5 * X(0)) @ X(1) + (0.5 * Y(0)) @ Y(1) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 6eabafdebc2..b73d298f0cc 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -142,6 +142,7 @@ check out the [updated operator troubleshooting page](https://docs.pennylane.ai/en/stable/news/new_opmath.html). [(#6548)](https://github.com/PennyLaneAI/pennylane/pull/6548) [(#6602)](https://github.com/PennyLaneAI/pennylane/pull/6602) + [(#6589)](https://github.com/PennyLaneAI/pennylane/pull/6589) * The developer-facing `qml.utils` module has been removed. Specifically, the following 4 sets of functions have been either moved or removed[(#6588)](https://github.com/PennyLaneAI/pennylane/pull/6588): diff --git a/pennylane/devices/_qubit_device.py b/pennylane/devices/_qubit_device.py index 1bb2be4e4de..7ff009cccac 100644 --- a/pennylane/devices/_qubit_device.py +++ b/pennylane/devices/_qubit_device.py @@ -1630,7 +1630,7 @@ def adjoint_jacobian( * Cannot differentiate with respect to state-prep operations. * Does not work for parametrized observables like - :class:`~.Hamiltonian` or :class:`~.Hermitian`. + :class:`~.ops.LinearCombination` or :class:`~.Hermitian`. Args: tape (.QuantumTape): circuit that the function takes the gradient of diff --git a/pennylane/operation.py b/pennylane/operation.py index 10452589156..45156666227 100644 --- a/pennylane/operation.py +++ b/pennylane/operation.py @@ -1433,7 +1433,7 @@ def generator(self): # pylint: disable=no-self-use 0.5 * Y(0) + Z(0) @ X(1) The generator may also be provided in the form of a dense or sparse Hamiltonian - (using :class:`.Hamiltonian` and :class:`.SparseHamiltonian` respectively). + (using :class:`.LinearCombination` and :class:`.SparseHamiltonian` respectively). The default value to return is ``None``, indicating that the operation has no defined generator. diff --git a/pennylane/ops/functions/generator.py b/pennylane/ops/functions/generator.py index d9115808bc4..d93d503997b 100644 --- a/pennylane/ops/functions/generator.py +++ b/pennylane/ops/functions/generator.py @@ -133,10 +133,10 @@ def generator(op: qml.operation.Operator, format="prefactor"): * ``"observable"``: Return the generator as a single observable as directly defined by ``op``. Returned generators may be any type of observable, including - :class:`~.Hermitian`, :class:`~.SparseHamiltonian`, or :class:`~.Hamiltonian`. + :class:`~.Hermitian`, :class:`~.SparseHamiltonian`, or :class:`~.ops.LinearCombination`. * ``"hamiltonian"``: Similar to ``"observable"``, however the returned observable - will always be converted into :class:`~.Hamiltonian` regardless of how ``op`` + will always be converted into :class:`~.ops.LinearCombination` regardless of how ``op`` encodes the generator. * ``"arithmetic"``: Similar to ``"hamiltonian"``, however the returned observable diff --git a/pennylane/ops/op_math/linear_combination.py b/pennylane/ops/op_math/linear_combination.py index 9e897aa0739..bccc70da9c5 100644 --- a/pennylane/ops/op_math/linear_combination.py +++ b/pennylane/ops/op_math/linear_combination.py @@ -33,6 +33,10 @@ class LinearCombination(Sum): The ``LinearCombination`` is represented as a linear combination of other operators, e.g., :math:`\sum_{k=0}^{N-1} c_k O_k`, where the :math:`c_k` are trainable parameters. + .. note:: + + ``qml.Hamiltonian`` dispatches to :class:`~pennylane.ops.op_math.LinearCombination`. + Args: coeffs (tensor_like): coefficients of the ``LinearCombination`` expression observables (Iterable[Observable]): observables in the ``LinearCombination`` expression, of same length as ``coeffs`` @@ -59,6 +63,11 @@ class LinearCombination(Sum): >>> print(H) 0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ H(2)) + The same ``LinearCombination`` can be created using the ``qml.Hamiltonian`` alias: + + >>> H = qml.Hamiltonian(coeffs, obs) + >>> print(H) + 0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ H(2)) The coefficients can be a trainable tensor, for example: diff --git a/pennylane/ops/qubit/observables.py b/pennylane/ops/qubit/observables.py index 4fc4a98c092..da4e07c1d22 100644 --- a/pennylane/ops/qubit/observables.py +++ b/pennylane/ops/qubit/observables.py @@ -287,8 +287,8 @@ class SparseHamiltonian(Observable): Sparse Hamiltonians can be constructed directly with a SciPy-compatible sparse matrix. - Alternatively, you can construct your Hamiltonian as usual using :class:`~.Hamiltonian`, and then use - :meth:`~.Hamiltonian.sparse_matrix` to construct the sparse matrix that serves as the input + Alternatively, you can construct your Hamiltonian as usual using :class:`~.LinearCombination`, and then use + :meth:`~.LinearCombination.sparse_matrix` to construct the sparse matrix that serves as the input to ``SparseHamiltonian``: >>> wires = range(20) diff --git a/pennylane/optimize/shot_adaptive.py b/pennylane/optimize/shot_adaptive.py index ed8657184a1..8accc0c6810 100644 --- a/pennylane/optimize/shot_adaptive.py +++ b/pennylane/optimize/shot_adaptive.py @@ -62,7 +62,7 @@ class ShotAdaptiveOptimizer(GradientDescentOptimizer): **Example** For VQE/VQE-like problems, the objective function for the optimizer can be realized - as a :class:`~.QNode` object measuring the expectation of a :class:`~.Hamiltonian`. + as a :class:`~.QNode` object measuring the expectation of a :class:`~.ops.LinearCombination`. >>> from pennylane import numpy as np >>> coeffs = [2, 4, -1, 5, 2] diff --git a/pennylane/pauli/conversion.py b/pennylane/pauli/conversion.py index 859d6ac2670..52a20083b33 100644 --- a/pennylane/pauli/conversion.py +++ b/pennylane/pauli/conversion.py @@ -232,8 +232,8 @@ def pauli_decompose( check_hermitian (bool): check if the provided matrix is Hermitian if ``True``. Returns: - Union[~.Hamiltonian, ~.PauliSentence]: the matrix decomposed as a linear combination - of Pauli operators, returned either as a :class:`~.Hamiltonian` or :class:`~.PauliSentence` + Union[~.LinearCombination, ~.PauliSentence]: the matrix decomposed as a linear combination + of Pauli operators, returned either as a :class:`~.ops.LinearCombination` or :class:`~.PauliSentence` instance. **Example:** diff --git a/pennylane/templates/subroutines/approx_time_evolution.py b/pennylane/templates/subroutines/approx_time_evolution.py index 2272e37c057..38819490e70 100644 --- a/pennylane/templates/subroutines/approx_time_evolution.py +++ b/pennylane/templates/subroutines/approx_time_evolution.py @@ -66,7 +66,7 @@ class ApproxTimeEvolution(Operation): .. warning:: - The Trotter-Suzuki decomposition depends on the order of the summed observables. Two mathematically identical :class:`~.Hamiltonian` objects may undergo different time evolutions + The Trotter-Suzuki decomposition depends on the order of the summed observables. Two mathematically identical :class:`~.LinearCombination` objects may undergo different time evolutions due to the order in which those observables are stored. .. note:: diff --git a/pennylane/templates/subroutines/qdrift.py b/pennylane/templates/subroutines/qdrift.py index cf5132c2440..b74a1ac009c 100644 --- a/pennylane/templates/subroutines/qdrift.py +++ b/pennylane/templates/subroutines/qdrift.py @@ -23,9 +23,7 @@ def _check_hamiltonian_type(hamiltonian): if not isinstance(hamiltonian, Sum): - raise TypeError( - f"The given operator must be a PennyLane ~.Hamiltonian or ~.Sum, got {hamiltonian}" - ) + raise TypeError(f"The given operator must be a PennyLane ~.Sum, got {hamiltonian}") def _extract_hamiltonian_coeffs_and_ops(hamiltonian): @@ -106,7 +104,7 @@ class QDrift(Operation): seed (int): The seed for the random number generator. Raises: - TypeError: The ``hamiltonian`` is not of type :class:`~.Hamiltonian`, or :class:`~.Sum` + TypeError: The ``hamiltonian`` is not of type :class:`~.Sum` QuantumFunctionError: If the coefficients of ``hamiltonian`` are trainable and are used in a differentiable workflow. ValueError: If there is only one term in the Hamiltonian. diff --git a/pennylane/templates/subroutines/trotter.py b/pennylane/templates/subroutines/trotter.py index 2608d21d59f..5ec5680fcb3 100644 --- a/pennylane/templates/subroutines/trotter.py +++ b/pennylane/templates/subroutines/trotter.py @@ -101,7 +101,7 @@ class TrotterProduct(ErrorOperation, ResourcesOperation): check_hermitian (bool): A flag to enable the validation check to ensure this is a valid unitary operator Raises: - TypeError: The ``hamiltonian`` is not of type :class:`~.Hamiltonian`, or :class:`~.Sum`. + TypeError: The ``hamiltonian`` is not of type :class:`~.Sum`. ValueError: The ``hamiltonian`` must have atleast two terms. ValueError: One or more of the terms in ``hamiltonian`` are not Hermitian. ValueError: The ``order`` is not one or a positive even integer. @@ -132,7 +132,7 @@ def my_circ(): .. warning:: The Trotter-Suzuki decomposition depends on the order of the summed observables. Two - mathematically identical :class:`~.Hamiltonian` objects may undergo different time + mathematically identical :class:`~.LinearCombination` objects may undergo different time evolutions due to the order in which those observables are stored. The order of observables can be queried using the :meth:`~.Sum.terms` method. @@ -222,7 +222,7 @@ def __init__( # pylint: disable=too-many-arguments if not isinstance(hamiltonian, Sum): raise TypeError( - f"The given operator must be a PennyLane ~.Hamiltonian, ~.Sum or ~.SProd, got {hamiltonian}" + f"The given operator must be a PennyLane ~.Sum or ~.SProd, got {hamiltonian}" ) if check_hermitian: diff --git a/tests/ops/functions/test_generator.py b/tests/ops/functions/test_generator.py index 9c997204632..8fe72c512e0 100644 --- a/tests/ops/functions/test_generator.py +++ b/tests/ops/functions/test_generator.py @@ -390,8 +390,6 @@ def test_observable(self): assert isinstance(gen, qml.Hamiltonian) assert gen.compare(ObservableOp(0.5, wires=0).generator()) - # removed fixture to only run with legacy opmath - not clear why it was added, - # but we'll see once things are tidied up enough for tests to run def test_tensor_observable(self): """Test a generator that returns a tensor observable is correct""" gen = qml.generator(TensorOp, format="hamiltonian")(0.5, wires=[0, 1]) diff --git a/tests/ops/qubit/test_qchem_ops.py b/tests/ops/qubit/test_qchem_ops.py index 8b11969ffda..a95dfe60a6f 100644 --- a/tests/ops/qubit/test_qchem_ops.py +++ b/tests/ops/qubit/test_qchem_ops.py @@ -1237,8 +1237,7 @@ def test_label_method(op, label1, label2, label3): @pytest.mark.parametrize("op", PARAMETRIZED_QCHEM_OPERATIONS) def test_generators(op): """Check that the type of the generator returned by the qchem ops is - the same as the type pointed to by qml.Hamiltonian (either Hamiltonian - or LinearCombiantion) for both legacy and new opmath""" + the same as the type pointed to by LinearCombiantion""" if isinstance(op, (qml.ops.DoubleExcitationPlus, qml.ops.DoubleExcitationMinus)): pytest.skip(reason="Operator has SparseHamiltonian generator instead") diff --git a/tests/pauli/test_pauli_utils.py b/tests/pauli/test_pauli_utils.py index d493ab1c736..a52e0f1315d 100644 --- a/tests/pauli/test_pauli_utils.py +++ b/tests/pauli/test_pauli_utils.py @@ -225,8 +225,6 @@ def test_observables_to_binary_matrix_n_qubits_arg(self): ValueError, observables_to_binary_matrix, observables, n_qubits_invalid ) - # removed a fixture to only use legacy_opmath because its not clear why it there - # we'll see what happens when we are ready to run the tests def test_is_qwc(self): """Determining if two Pauli words are qubit-wise commuting.""" @@ -953,8 +951,6 @@ def test_diagonalize_qwc_pauli_words_catch_when_not_qwc(self, not_qwc_grouping): assert pytest.raises(ValueError, diagonalize_qwc_pauli_words, not_qwc_grouping) -# removed a fixture to only use legacy_opmath because its not clear why it there -# we'll see what happens when we are ready to run the tests class TestTapering: terms_bin_mat_data = [ diff --git a/tests/templates/test_subroutines/test_qdrift.py b/tests/templates/test_subroutines/test_qdrift.py index 33c168dc7a1..359f1266b33 100644 --- a/tests/templates/test_subroutines/test_qdrift.py +++ b/tests/templates/test_subroutines/test_qdrift.py @@ -101,9 +101,7 @@ def test_copy(self, coeffs, ops, time, n, seed): # pylint: disable=too-many-arg def test_error_type(self, hamiltonian, raise_error): """Test an error is raised of an incorrect type is passed""" if raise_error: - with pytest.raises( - TypeError, match="The given operator must be a PennyLane ~.Hamiltonian or ~.Sum" - ): + with pytest.raises(TypeError, match="The given operator must be a PennyLane ~.Sum"): qml.QDrift(hamiltonian, time=1.23) else: try: @@ -615,6 +613,6 @@ def test_error_func(h, time, n, expected_error): def test_error_func_type_error(): """Test that an error is raised if the wrong type is passed for hamiltonian""" - msg = "The given operator must be a PennyLane ~.Hamiltonian or ~.Sum" + msg = "The given operator must be a PennyLane ~.Sum" with pytest.raises(TypeError, match=msg): qml.QDrift.error(qml.PauliX(0), time=1.23, n=10) diff --git a/tests/templates/test_subroutines/test_trotter.py b/tests/templates/test_subroutines/test_trotter.py index ce9cd3f1760..6d027441905 100644 --- a/tests/templates/test_subroutines/test_trotter.py +++ b/tests/templates/test_subroutines/test_trotter.py @@ -356,7 +356,7 @@ def test_error_type(self, hamiltonian, raise_error): if raise_error: with pytest.raises( TypeError, - match="The given operator must be a PennyLane ~.Hamiltonian, ~.Sum or ~.SProd", + match="The given operator must be a PennyLane ~.Sum or ~.SProd", ): qml.TrotterProduct(hamiltonian, time=1.23) diff --git a/tests/test_qaoa.py b/tests/test_qaoa.py index 326b46297a3..5f31aff8d55 100644 --- a/tests/test_qaoa.py +++ b/tests/test_qaoa.py @@ -1094,7 +1094,6 @@ class TestUtils: """Tests that the utility functions are working properly""" # pylint: disable=protected-access - # removed a fixture to only use legacy opmath here for now, because I'm not sure why its relevant @pytest.mark.parametrize( ("hamiltonian", "value"), (