Repository: PennyLaneAI/pennylane
Pull request #6979 (2025-02-19 15:42:13)

`poly_to_angles` fixing #6978
### Before submitting

Please complete the following checklist when submitting a PR:

- [x] All new features must include a unit test.
      If you've fixed a bug or added code that should be tested, add a test to the
      test directory!

- [x] All new functions and code must be clearly commented and documented.
      If you do make documentation changes, make sure that the docs build and
      render correctly by running `make docs`.

- [x] Ensure that the test suite passes, by running `make test`.

- [x] Add a new entry to the `doc/releases/changelog-dev.md` file, summarizing the
      change, and including a link back to the PR.

- [x] The PennyLane source code conforms to
      [PEP8 standards](https://www.python.org/dev/peps/pep-0008/).
      We check all of our code against [Pylint](https://www.pylint.org/).
      To lint modified files, simply `pip install pylint`, and then
      run `pylint pennylane/path/to/file.py`.

When all the above are checked, delete everything above the dashed
line and fill in the pull request template.

------------------------------------------------------------------------------------------------------------

**Context:**

[sc-84735]

**Description of the Change:**

Now we copy the input into a list 

**Benefits:**

It works with any interface

**Possible Drawbacks:**

**Related GitHub Issues:**

#6978 


github-actions[bot]: Hello. You may have forgotten to update the changelog!
Please edit [`doc/releases/changelog-dev.md`](/PennyLaneAI/pennylane/blob/master/doc/releases/changelog-dev.md) with:
* A one-to-two sentence description of the change. You may include a small working example for new features.
* A link back to this PR.
* Your name (or GitHub username) in the contributors section.
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/6979?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.59%. Comparing base [(`b0b77fb`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/b0b77fbf791e0b332ea197cce05bbac529d3f4f1?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) to head [(`70d9d34`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/70d9d3497103203619867e816ad24fa23009b4ad?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    #6979   +/-   ##
=======================================
  Coverage   99.59%   99.59%           
=======================================
  Files         481      481           
  Lines       45784    45785    +1     
=======================================
+ Hits        45599    45600    +1     
  Misses        185      185           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/6979?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/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index a6af21f7f..dbe8fb476 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -443,6 +443,10 @@
   passed to the `QNode`, instead of assuming the method is always `deferred`.
   [(#6903)](https://github.com/PennyLaneAI/pennylane/pull/6903)
 
+* The `poly_to_angles` function has been improved to correctly work with different interfaces and
+  no longer manipulate the input angles tensor internally.
+  [(#6979)](https://github.com/PennyLaneAI/pennylane/pull/6979)
+
 * The `QROM` template is upgraded to decompose more efficiently when `work_wires` are not used.
   [#6967)](https://github.com/PennyLaneAI/pennylane/pull/6967)
 
diff --git a/pennylane/templates/subroutines/qsvt.py b/pennylane/templates/subroutines/qsvt.py
index 2898de207..49625cb13 100644
--- a/pennylane/templates/subroutines/qsvt.py
+++ b/pennylane/templates/subroutines/qsvt.py
@@ -365,7 +365,7 @@ class QSVT(Operation):
 
         .. code-block::
 
-            poly = [0, -1, 0, 0.5, 0, 0.5]
+            poly = np.array([0, -1, 0, 0.5, 0, 0.5])
             angles = qml.poly_to_angles(poly, "QSVT")
             input_matrix = np.array([[0.2, 0.1], [0.1, -0.1]])
 
@@ -825,7 +825,7 @@ def transform_angles(angles, routine1, routine2):
 
         .. code-block::
 
-            poly = [0, 1.0, 0, -1/2, 0, 1/3]
+            poly = np.array([0, 1.0, 0, -1/2, 0, 1/3])
 
             qsp_angles = qml.poly_to_angles(poly, "QSP")
             qsvt_angles = qml.transform_angles(qsp_angles, "QSP", "QSVT")
@@ -911,7 +911,7 @@ def poly_to_angles(poly, routine, angle_solver: Literal["root-finding"] = "root-
 
     .. code-block::
 
-        >>> poly = [0, 1.0, 0, -1/2, 0, 1/3]
+        >>> poly = np.array([0, 1.0, 0, -1/2, 0, 1/3])
         >>> qsvt_angles = qml.poly_to_angles(poly, "QSVT")
         >>> print(qsvt_angles)
         [-5.49778714  1.57079633  1.57079633  0.5833829   1.61095884  0.74753829]
@@ -925,7 +925,7 @@ def poly_to_angles(poly, routine, angle_solver: Literal["root-finding"] = "root-
 
         .. code-block::
 
-            poly = [0, 1.0, 0, -1/2, 0, 1/3]
+            poly = np.array([0, 1.0, 0, -1/2, 0, 1/3])
 
             qsvt_angles = qml.poly_to_angles(poly, "QSVT")
 
@@ -953,11 +953,7 @@ def poly_to_angles(poly, routine, angle_solver: Literal["root-finding"] = "root-
 
     """
 
-    # Trailing zeros are removed from the array
-    for _ in range(len(poly)):
-        if not np.isclose(poly[-1], 0.0):
-            break
-        poly.pop()
+    poly = qml.math.trim_zeros(qml.math.array(poly, like="numpy"), trim="b")
 
     if len(poly) == 1:
         raise AssertionError("The polynomial must have at least degree 1.")


Test patch:
diff --git a/tests/templates/test_subroutines/test_qsvt.py b/tests/templates/test_subroutines/test_qsvt.py
index fe0efc8ae..e82626438 100644
--- a/tests/templates/test_subroutines/test_qsvt.py
+++ b/tests/templates/test_subroutines/test_qsvt.py
@@ -792,3 +792,66 @@ class TestRootFindingSolver:
 
         with pytest.raises(AssertionError, match=msg_match):
             _ = qml.poly_to_angles(poly, routine, angle_solver)
+
+    def test_immutable_input(self):
+        """Test `poly_to_angles` does not modify the input"""
+
+        poly = [0, 1.0, 0, -1 / 2, 0, 1 / 3, 0]
+        poly_copy = poly.copy()
+        qml.poly_to_angles(poly, "QSVT")
+
+        assert len(poly) == len(poly_copy)
+        assert np.allclose(poly, poly_copy)
+
+    def test_interface_numpy(self):
+        """Test `poly_to_angles` works with numpy"""
+
+        poly = [0, 1.0, 0, -1 / 2, 0, 1 / 3, 0]
+        angles = qml.poly_to_angles(poly, "QSVT")
+
+        poly_numpy = np.array(poly)
+        angles_numpy = qml.poly_to_angles(poly_numpy, "QSVT")
+
+        assert qml.math.allclose(angles, angles_numpy)
+
+    @pytest.mark.jax
+    def test_interface_jax(self):
+        """Test `poly_to_angles` works with jax"""
+
+        import jax
+
+        poly = [0, 1.0, 0, -1 / 2, 0, 1 / 3, 0]
+        angles = qml.poly_to_angles(poly, "QSVT")
+
+        poly_jax = jax.numpy.array(poly)
+        angles_jax = qml.poly_to_angles(poly_jax, "QSVT")
+
+        assert qml.math.allclose(angles, angles_jax)
+
+    @pytest.mark.torch
+    def test_interface_torch(self):
+        """Test `poly_to_angles` works with torch"""
+
+        import torch
+
+        poly = [0, 1.0, 0, -1 / 2, 0, 1 / 3, 0]
+        angles = qml.poly_to_angles(poly, "QSVT")
+
+        poly_torch = torch.tensor(poly)
+        angles_torch = qml.poly_to_angles(poly_torch, "QSVT")
+
+        assert qml.math.allclose(angles, angles_torch)
+
+    @pytest.mark.tf
+    def test_interface_tf(self):
+        """Test `poly_to_angles` works with tensorflow"""
+
+        import tensorflow as tf
+
+        poly = [0, 1.0, 0, -1 / 2, 0, 1 / 3, 0]
+        angles = qml.poly_to_angles(poly, "QSVT")
+
+        poly_tf = tf.Variable(poly)
+        angles_tf = qml.poly_to_angles(poly_tf, "QSVT")
+
+        assert qml.math.allclose(angles, angles_tf)