Repository: PennyLaneAI/pennylane
Pull request #5677 (2024-05-10 20:01:50)

Deprecate `simplify` argument in `qml.ops.Hamiltonian` and `qml.LinearCombination`
**Context:** ***Part of  deprecations and removals for pennylane-0.37***

**Description of the Change:** Deprecating the ``simplify`` argument in ``qml.ops.Hamiltonian`` and ``qml.ops.LinearCombination`` in favour of ``qml.simplify()``.

[sc-59086]


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/5677?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 99.63%. Comparing base [(`be35a7b`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/be35a7b1780a1b1d818e9cfa300df214ce838f53?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) to head [(`d3e2f3f`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/5677?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).
> Report is 1 commits behind head on master.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #5677      +/-   ##
==========================================
- Coverage   99.68%   99.63%   -0.05%     
==========================================
  Files         414      414              
  Lines       38814    38541     -273     
==========================================
- Hits        38691    38400     -291     
- Misses        123      141      +18     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/5677?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).


Patch:
diff --git a/doc/development/deprecations.rst b/doc/development/deprecations.rst
index 5a8f0cbac..34c6e03b9 100644
--- a/doc/development/deprecations.rst
+++ b/doc/development/deprecations.rst
@@ -9,10 +9,17 @@ deprecations are listed below.
 Pending deprecations
 --------------------
 
+* The ``simplify`` argument in ``qml.Hamiltonian`` and ``qml.ops.LinearCombination`` is deprecated. 
+  Instead, ``qml.simplify()`` can be called on the constructed operator.
+
+  - Deprecated in v0.37
+  - Will be removed in v0.39
+
 * ``qml.transforms.map_batch_transform`` is deprecated, since transforms can be applied directly to a batch of tapes.
   See :func:`~.pennylane.transform` for more information.
 
   - Deprecated in v0.37
+  - Will be removed in v0.38
 
 New operator arithmetic deprecations
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 01db3008d..1a65146a5 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -92,10 +92,10 @@
 * `qml.is_commuting` no longer accepts the `wire_map` argument, which does not bring any functionality.
   [(#5660)](https://github.com/PennyLaneAI/pennylane/pull/5660)
 
-* ``qml.from_qasm_file`` has been removed. The user can open files and load their content using `qml.from_qasm`.
+* `qml.from_qasm_file` has been removed. The user can open files and load their content using `qml.from_qasm`.
   [(#5659)](https://github.com/PennyLaneAI/pennylane/pull/5659)
 
-* ``qml.load`` has been removed in favour of more specific functions, such as ``qml.from_qiskit``, etc.
+* `qml.load` has been removed in favour of more specific functions, such as `qml.from_qiskit`, etc.
   [(#5654)](https://github.com/PennyLaneAI/pennylane/pull/5654)
 
 <h4>Community contributions 🥳</h4>
@@ -105,7 +105,11 @@
 
 <h3>Deprecations 👋</h3>
 
-* ``qml.transforms.map_batch_transform`` is deprecated, since a transform can be applied directly to a batch of tapes.
+* The `simplify` argument in `qml.Hamiltonian` and `qml.ops.LinearCombination` is deprecated. 
+  Instead, `qml.simplify()` can be called on the constructed operator.
+  [(#5677)](https://github.com/PennyLaneAI/pennylane/pull/5677)
+
+* `qml.transforms.map_batch_transform` is deprecated, since a transform can be applied directly to a batch of tapes.
   [(#5676)](https://github.com/PennyLaneAI/pennylane/pull/5676)
 
 <h3>Documentation 📝</h3>
diff --git a/pennylane/operation.py b/pennylane/operation.py
index 7cb3d460d..4508e1745 100644
--- a/pennylane/operation.py
+++ b/pennylane/operation.py
@@ -2033,7 +2033,7 @@ class Observable(Operator):
         if isinstance(other, (qml.ops.Hamiltonian, qml.ops.LinearCombination)):
             return other + self
         if isinstance(other, (Observable, Tensor)):
-            return qml.Hamiltonian([1, 1], [self, other], simplify=True)
+            return qml.simplify(qml.Hamiltonian([1, 1], [self, other]))
 
         return super().__add__(other=other)
 
@@ -2045,7 +2045,7 @@ class Observable(Operator):
             return super().__mul__(other=a)
 
         if isinstance(a, (int, float)):
-            return qml.Hamiltonian([a], [self], simplify=True)
+            return qml.simplify(qml.Hamiltonian([a], [self]))
 
         return super().__mul__(other=a)
 
diff --git a/pennylane/ops/op_math/linear_combination.py b/pennylane/ops/op_math/linear_combination.py
index cde0c5cd8..ab00d9635 100644
--- a/pennylane/ops/op_math/linear_combination.py
+++ b/pennylane/ops/op_math/linear_combination.py
@@ -39,7 +39,7 @@ class LinearCombination(Sum):
         observables (Iterable[Observable]): observables in the ``LinearCombination`` expression, of same length as ``coeffs``
         simplify (bool): Specifies whether the ``LinearCombination`` is simplified upon initialization
                          (like-terms are combined). The default value is `False`. Note that ``coeffs`` cannot
-                         be differentiated when using the ``'torch'`` interface and ``simplify=True``.
+                         be differentiated when using the ``'torch'`` interface and ``simplify=True``. Use of this argument is deprecated.
         grouping_type (str): If not ``None``, compute and store information on how to group commuting
             observables upon initialization. This information may be accessed when a :class:`~.QNode` containing this
             ``LinearCombination`` is executed on devices. The string refers to the type of binary relation between Pauli words.
@@ -48,6 +48,10 @@ class LinearCombination(Sum):
             can be ``'lf'`` (Largest First) or ``'rlf'`` (Recursive Largest First). Ignored if ``grouping_type=None``.
         id (str): name to be assigned to this ``LinearCombination`` instance
 
+    .. warning::
+        The ``simplify`` argument is deprecated and will be removed in a future release.
+        Instead, you can call ``qml.simplify`` on the constructed operator.
+
     **Example:**
 
     A ``LinearCombination`` can be created by simply passing the list of coefficients
@@ -131,6 +135,13 @@ class LinearCombination(Sum):
             _pauli_rep = self._build_pauli_rep_static(coeffs, observables)
 
         if simplify:
+
+            warnings.warn(
+                "The simplify argument in qml.Hamiltonian and qml.ops.LinearCombination is deprecated. "
+                "Instead, you can call qml.simplify on the constructed operator.",
+                qml.PennyLaneDeprecationWarning,
+            )
+
             # simplify upon initialization changes ops such that they wouldnt be removed in self.queue() anymore
             if qml.QueuingManager.recording():
                 for o in observables:
diff --git a/pennylane/ops/qubit/hamiltonian.py b/pennylane/ops/qubit/hamiltonian.py
index 28ca22204..0d6a1d968 100644
--- a/pennylane/ops/qubit/hamiltonian.py
+++ b/pennylane/ops/qubit/hamiltonian.py
@@ -77,7 +77,7 @@ class Hamiltonian(Observable):
         coeffs (tensor_like): coefficients of the Hamiltonian expression
         observables (Iterable[Observable]): observables in the Hamiltonian expression, of same length as coeffs
         simplify (bool): Specifies whether the Hamiltonian is simplified upon initialization
-                         (like-terms are combined). The default value is `False`.
+                         (like-terms are combined). The default value is `False`. Use of this argument is deprecated.
         grouping_type (str): If not None, compute and store information on how to group commuting
             observables upon initialization. This information may be accessed when QNodes containing this
             Hamiltonian are executed on devices. The string refers to the type of binary relation between Pauli words.
@@ -86,6 +86,10 @@ class Hamiltonian(Observable):
             can be ``'lf'`` (Largest First) or ``'rlf'`` (Recursive Largest First). Ignored if ``grouping_type=None``.
         id (str): name to be assigned to this Hamiltonian instance
 
+    .. warning::
+        The ``simplify`` argument is deprecated and will be removed in a future release.
+        Instead, you can call ``qml.simplify`` on the constructed operator.
+
     **Example:**
 
     .. note::
@@ -279,6 +283,13 @@ class Hamiltonian(Observable):
         self._grouping_indices = None
 
         if simplify:
+
+            warn(
+                "The simplify argument in qml.Hamiltonian and qml.ops.LinearCombination is deprecated. "
+                "Instead, you can call qml.simplify on the constructed operator.",
+                qml.PennyLaneDeprecationWarning,
+            )
+
             # simplify upon initialization changes ops such that they wouldnt be
             # removed in self.queue() anymore, removing them here manually.
             if qml.QueuingManager.recording():
@@ -744,12 +755,12 @@ class Hamiltonian(Observable):
             coeffs = qml.math.kron(coeffs1, coeffs2)
             ops_list = itertools.product(ops1, ops2)
             terms = [qml.operation.Tensor(t[0], t[1]) for t in ops_list]
-            return Hamiltonian(coeffs, terms, simplify=True)
+            return qml.simplify(Hamiltonian(coeffs, terms))
 
         if isinstance(H, (Tensor, Observable)):
             terms = [op @ copy(H) for op in ops1]
 
-            return Hamiltonian(coeffs1, terms, simplify=True)
+            return qml.simplify(Hamiltonian(coeffs1, terms))
 
         return NotImplemented
 
@@ -766,7 +777,7 @@ class Hamiltonian(Observable):
         if isinstance(H, (Tensor, Observable)):
             terms = [copy(H) @ op for op in ops1]
 
-            return Hamiltonian(coeffs1, terms, simplify=True)
+            return qml.simplify(Hamiltonian(coeffs1, terms))
 
         return NotImplemented
 
@@ -781,14 +792,14 @@ class Hamiltonian(Observable):
         if isinstance(H, Hamiltonian):
             coeffs = qml.math.concatenate([self_coeffs, copy(H.coeffs)], axis=0)
             ops.extend(H.ops.copy())
-            return Hamiltonian(coeffs, ops, simplify=True)
+            return qml.simplify(Hamiltonian(coeffs, ops))
 
         if isinstance(H, (Tensor, Observable)):
             coeffs = qml.math.concatenate(
                 [self_coeffs, qml.math.cast_like([1.0], self_coeffs)], axis=0
             )
             ops.append(H)
-            return Hamiltonian(coeffs, ops, simplify=True)
+            return qml.simplify(Hamiltonian(coeffs, ops))
 
         return NotImplemented
 
diff --git a/pennylane/transforms/batch_transform.py b/pennylane/transforms/batch_transform.py
index 9d07f1d5e..9b1415345 100644
--- a/pennylane/transforms/batch_transform.py
+++ b/pennylane/transforms/batch_transform.py
@@ -72,9 +72,9 @@ def map_batch_transform(
     """
 
     warnings.warn(
-        "qml.transforms.map_batch_transform is deprecated."
-        "Instead, a transform can be applied directly to a batch of tapes."
-        "See :func:`~.pennylane.transform` for more details.",
+        "qml.transforms.map_batch_transform is deprecated. "
+        "Instead, a transform can be applied directly to a batch of tapes. "
+        "See qml.transform for more details.",
         qml.PennyLaneDeprecationWarning,
     )
 


Test patch:
diff --git a/tests/ops/op_math/test_linear_combination.py b/tests/ops/op_math/test_linear_combination.py
index 74e8ec64c..a1f59b887 100644
--- a/tests/ops/op_math/test_linear_combination.py
+++ b/tests/ops/op_math/test_linear_combination.py
@@ -564,6 +564,14 @@ dev = qml.device("default.qubit", wires=2)
 class TestLinearCombination:
     """Test the LinearCombination class"""
 
+    def test_deprecation_simplify_argument(self):
+        """Test that a deprecation warning is raised if the simplify argument is True."""
+        with pytest.warns(
+            qml.PennyLaneDeprecationWarning,
+            match="deprecated",
+        ):
+            _ = qml.ops.LinearCombination([1.0], [qml.X(0)], simplify=True)
+
     def test_error_if_observables_operator(self):
         """Test thatt an error is raised if an operator is provided to observables."""
 
@@ -588,7 +596,14 @@ class TestLinearCombination:
     @pytest.mark.parametrize("coeffs, ops, true_pauli", PAULI_REPS)
     def test_pauli_rep(self, coeffs, ops, true_pauli, simplify):
         """Test the pauli rep is correctly constructed"""
-        H = qml.ops.LinearCombination(coeffs, ops, simplify=simplify)
+        if simplify:
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                H = qml.ops.LinearCombination(coeffs, ops, simplify=simplify)
+        else:
+            H = qml.ops.LinearCombination(coeffs, ops, simplify=simplify)
         pr = H.pauli_rep
         if simplify:
             pr.simplify()
@@ -1629,7 +1644,11 @@ class TestLinearCombinationEvaluation:
             qml.RY(0.1, wires=0)
             return qml.expval(qml.ops.LinearCombination([1.0, 2.0], [X(1), X(1)], simplify=True))
 
-        circuit()
+        with pytest.warns(
+            qml.PennyLaneDeprecationWarning,
+            match="deprecated",
+        ):
+            circuit()
         pars = circuit.qtape.get_parameters(trainable_only=False)
         # simplify worked and added 1. and 2.
         assert pars == [0.1, 3.0]
@@ -1639,7 +1658,11 @@ class TestLinearCombinationEvaluation:
         """Tests that the base observables are correctly dequeued with simplify=True"""
 
         with qml.queuing.AnnotatedQueue() as q:
-            obs = qml.Hamiltonian([1, 1, 1], [qml.X(0), qml.X(0), qml.Z(0)], simplify=True)
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                obs = qml.Hamiltonian([1, 1, 1], [qml.X(0), qml.X(0), qml.Z(0)], simplify=True)
 
         assert len(q) == 1
         assert q.queue[0] == obs
@@ -1671,7 +1694,14 @@ class TestLinearCombinationDifferentiation:
             )
 
         grad_fn = qml.grad(circuit)
-        grad = grad_fn(coeffs, param)
+        if simplify:
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                grad = grad_fn(coeffs, param)
+        else:
+            grad = grad_fn(coeffs, param)
 
         # differentiating a cost that combines circuits with
         # measurements expval(Pauli)
@@ -1745,7 +1775,14 @@ class TestLinearCombinationDifferentiation:
             )
 
         grad_fn = qml.grad(circuit)
-        grad = grad_fn(coeffs, param)
+        if simplify:
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                grad = grad_fn(coeffs, param)
+        else:
+            grad = grad_fn(coeffs, param)
 
         # differentiating a cost that combines circuits with
         # measurements expval(Pauli)
@@ -1815,7 +1852,15 @@ class TestLinearCombinationDifferentiation:
             )
 
         grad_fn = jax.grad(circuit)
-        grad = grad_fn(coeffs, param)
+
+        if simplify:
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                grad = grad_fn(coeffs, param)
+        else:
+            grad = grad_fn(coeffs, param)
 
         # differentiating a cost that combines circuits with
         # measurements expval(Pauli)
@@ -1884,7 +1929,14 @@ class TestLinearCombinationDifferentiation:
                 )
             )
 
-        res = circuit(coeffs, param)
+        if simplify:
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                res = circuit(coeffs, param)
+        else:
+            res = circuit(coeffs, param)
         res.backward()  # pylint:disable=no-member
         grad = (coeffs.grad, param.grad)
 
@@ -1972,7 +2024,14 @@ class TestLinearCombinationDifferentiation:
             )
 
         with tf.GradientTape() as tape:
-            res = circuit(coeffs, param)
+            if simplify:
+                with pytest.warns(
+                    qml.PennyLaneDeprecationWarning,
+                    match="deprecated",
+                ):
+                    res = circuit(coeffs, param)
+            else:
+                res = circuit(coeffs, param)
         grad = tape.gradient(res, [coeffs, param])
 
         # differentiating a cost that combines circuits with
diff --git a/tests/ops/qubit/test_hamiltonian.py b/tests/ops/qubit/test_hamiltonian.py
index 945e8ac20..f208b1e4a 100644
--- a/tests/ops/qubit/test_hamiltonian.py
+++ b/tests/ops/qubit/test_hamiltonian.py
@@ -703,6 +703,15 @@ def test_deprecation_with_new_opmath(recwarn):
         assert len(recwarn) == 0
 
 
+def test_deprecation_simplify_argument():
+    """Test that a deprecation warning is raised if the simplify argument is True."""
+    with pytest.warns(
+        qml.PennyLaneDeprecationWarning,
+        match="deprecated",
+    ):
+        _ = qml.ops.Hamiltonian([1.0], [qml.X(0)], simplify=True)
+
+
 @pytest.mark.usefixtures("use_legacy_opmath")
 class TestHamiltonian:
     """Test the Hamiltonian class"""
@@ -1743,7 +1752,11 @@ class TestHamiltonianEvaluation:
                 qml.Hamiltonian([1.0, 2.0], [qml.PauliX(1), qml.PauliX(1)], simplify=True)
             )
 
-        circuit()
+        with pytest.warns(
+            qml.PennyLaneDeprecationWarning,
+            match="deprecated",
+        ):
+            circuit()
         pars = circuit.qtape.get_parameters(trainable_only=False)
         # simplify worked and added 1. and 2.
         assert pars == [0.1, 3.0]
@@ -1776,7 +1789,15 @@ class TestHamiltonianDifferentiation:
             )
 
         grad_fn = qml.grad(circuit)
-        grad = grad_fn(coeffs, param)
+
+        if simplify:
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                grad = grad_fn(coeffs, param)
+        else:
+            grad = grad_fn(coeffs, param)
 
         # differentiating a cost that combines circuits with
         # measurements expval(Pauli)
@@ -1850,7 +1871,15 @@ class TestHamiltonianDifferentiation:
             )
 
         grad_fn = qml.grad(circuit)
-        grad = grad_fn(coeffs, param)
+
+        if simplify:
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                grad = grad_fn(coeffs, param)
+        else:
+            grad = grad_fn(coeffs, param)
 
         # differentiating a cost that combines circuits with
         # measurements expval(Pauli)
@@ -1920,7 +1949,14 @@ class TestHamiltonianDifferentiation:
             )
 
         grad_fn = jax.grad(circuit)
-        grad = grad_fn(coeffs, param)
+        if simplify:
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                grad = grad_fn(coeffs, param)
+        else:
+            grad = grad_fn(coeffs, param)
 
         # differentiating a cost that combines circuits with
         # measurements expval(Pauli)
@@ -1988,7 +2024,15 @@ class TestHamiltonianDifferentiation:
                 )
             )
 
-        res = circuit(coeffs, param)
+        if simplify:
+            with pytest.warns(
+                qml.PennyLaneDeprecationWarning,
+                match="deprecated",
+            ):
+                res = circuit(coeffs, param)
+        else:
+            res = circuit(coeffs, param)
+
         res.backward()  # pylint:disable=no-member
         grad = (coeffs.grad, param.grad)
 
@@ -2076,7 +2120,15 @@ class TestHamiltonianDifferentiation:
             )
 
         with tf.GradientTape() as tape:
-            res = circuit(coeffs, param)
+            if simplify:
+                with pytest.warns(
+                    qml.PennyLaneDeprecationWarning,
+                    match="deprecated",
+                ):
+                    res = circuit(coeffs, param)
+            else:
+                res = circuit(coeffs, param)
+
         grad = tape.gradient(res, [coeffs, param])
 
         # differentiating a cost that combines circuits with