Repository: PennyLaneAI/pennylane
Pull request #6023 (2024-07-22 16:08:03)

Updates to lie_closure
Fix https://github.com/PennyLaneAI/pennylane/issues/6018 and do some other maintenance upgrades

Aim is to allow lie closure to reliably handle cases where sums of paulis are input (e.g. Heisenberg model)

The problem was that sometimes a commutator would be 0 but require a simplify for that to show. Fixed that.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/6023?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.65%. Comparing base [(`3ad15d7`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/3ad15d7ee01b1c07b74d3d69f82c6c1699967076?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) to head [(`604ab3d`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/604ab3d392641e4cb041ae3712df46cd3110f4d6?dropdown=coverage&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    #6023      +/-   ##
==========================================
- Coverage   99.66%   99.65%   -0.01%     
==========================================
  Files         427      427              
  Lines       41057    40768     -289     
==========================================
- Hits        40919    40628     -291     
- Misses        138      140       +2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/6023?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).

Qottmann: [sc-69368]

Patch:
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 9fe507288..6b99fcbe0 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -210,6 +210,9 @@
 * `qml.AmplitudeEmbedding` has better support for features using low precision integer data types.
 [(#5969)](https://github.com/PennyLaneAI/pennylane/pull/5969)
 
+* `qml.lie_closure` works with sums of Paulis.
+  [(#6023)](https://github.com/PennyLaneAI/pennylane/pull/6023)
+
 
 <h3>Contributors ✍️</h3>
 
@@ -226,6 +229,7 @@ Emiliano Godinez,
 Renke Huang,
 Josh Izaac,
 Soran Jahangiri,
+Korbinian Kottmann,
 Christina Lee,
 Austin Huang,
 William Maxwell,
diff --git a/pennylane/pauli/dla/lie_closure.py b/pennylane/pauli/dla/lie_closure.py
index 931befcfd..7ed9a9393 100644
--- a/pennylane/pauli/dla/lie_closure.py
+++ b/pennylane/pauli/dla/lie_closure.py
@@ -14,6 +14,7 @@
 """A function to compute the Lie closure of a set of operators"""
 # pylint: disable=too-many-arguments
 import itertools
+import warnings
 from collections.abc import Iterable
 from copy import copy
 from functools import reduce
@@ -135,8 +136,11 @@ def lie_closure(
     while (new_length > old_length) and (epoch < max_iterations):
         if verbose:
             print(f"epoch {epoch+1} of lie_closure, DLA size is {new_length}")
+
         for ps1, ps2 in itertools.combinations(vspace.basis, 2):
             com = ps1.commutator(ps2)
+            com.simplify()
+
             if len(com) == 0:  # skip because operators commute
                 continue
 
@@ -144,6 +148,7 @@ def lie_closure(
             # remove common factor 2 with Pauli commutators
             for pw, val in com.items():
                 com[pw] = val.imag / 2
+
             vspace.add(com, tol=tol)
 
         # Updated number of linearly independent PauliSentences from previous and current step
@@ -151,6 +156,9 @@ def lie_closure(
         new_length = len(vspace)
         epoch += 1
 
+        if epoch == max_iterations:
+            warnings.warn(f"reached the maximum number of iterations {max_iterations}", UserWarning)
+
     if verbose > 0:
         print(f"After {epoch} epochs, reached a DLA size of {new_length}")
 


Test patch:
diff --git a/tests/pauli/dla/test_lie_closure.py b/tests/pauli/dla/test_lie_closure.py
index fc2f4361e..50babf8e0 100644
--- a/tests/pauli/dla/test_lie_closure.py
+++ b/tests/pauli/dla/test_lie_closure.py
@@ -344,7 +344,9 @@ class TestLieClosure:
             PauliSentence({PauliWord({i: "X", (i + 1) % n: "Z"}): 1.0}) for i in range(n - 1)
         ]
 
-        res = qml.pauli.lie_closure(generators, verbose=True, max_iterations=1)
+        with pytest.warns(UserWarning, match="reached the maximum number of iterations"):
+            res = qml.pauli.lie_closure(generators, verbose=True, max_iterations=1)
+
         captured = capsys.readouterr()
         assert (
             captured.out
@@ -501,6 +503,17 @@ class TestLieClosure:
         res = qml.pauli.lie_closure(generators)
         assert len(res) == 4 * ((2 ** (n - 2)) ** 2 - 1)
 
+    @pytest.mark.parametrize("n, res", [(3, 4), (4, 12)])
+    def test_lie_closure_heisenberg(self, n, res):
+        """Test the resulting DLA from Heisenberg model with summed generators"""
+        genXX = [X(i) @ X(i + 1) for i in range(n - 1)]
+        genYY = [Y(i) @ Y(i + 1) for i in range(n - 1)]
+        genZZ = [Z(i) @ Z(i + 1) for i in range(n - 1)]
+
+        generators = [qml.sum(XX + YY + ZZ) for XX, YY, ZZ in zip(genXX, genYY, genZZ)]
+        g = qml.lie_closure(generators)
+        assert len(g) == res
+
     def test_universal_gate_set(self):
         """Test universal gate set"""
         n = 3