From 497811a6f0a92efe70ebe0c50efd9310aae573aa Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Tue, 1 Feb 2022 15:51:07 +0100 Subject: [PATCH] Fix ``PauliSumOp.permute`` to not change the original object (#7339) * fix PauliSumOp.permute * black! * extend fix to general PauliSumOp * Revert "extend fix to general PauliSumOp" This reverts commit 6c4fa32dc7ac02c21698cdfa43066d4a7f9ebe0e. Co-authored-by: Ikko Hamamura Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- qiskit/opflow/primitive_ops/pauli_sum_op.py | 2 +- ...pauli-sum-op-permute-a9b742f3a2fad934.yaml | 7 ++++ test/python/opflow/test_pauli_sum_op.py | 32 ++++++++++++------- 3 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 releasenotes/notes/fix-pauli-sum-op-permute-a9b742f3a2fad934.yaml diff --git a/qiskit/opflow/primitive_ops/pauli_sum_op.py b/qiskit/opflow/primitive_ops/pauli_sum_op.py index 90c6708373e1..c514ad8be09c 100644 --- a/qiskit/opflow/primitive_ops/pauli_sum_op.py +++ b/qiskit/opflow/primitive_ops/pauli_sum_op.py @@ -210,7 +210,7 @@ def permute(self, permutation: List[int]) -> "PauliSumOp": if length > self.num_qubits: spop = self.primitive.tensor(SparsePauliOp(Pauli("I" * (length - self.num_qubits)))) else: - spop = self.primitive + spop = self.primitive.copy() permutation = [i for i in range(length) if i not in permutation] + permutation permu_arr = np.arange(length)[np.argsort(permutation)] diff --git a/releasenotes/notes/fix-pauli-sum-op-permute-a9b742f3a2fad934.yaml b/releasenotes/notes/fix-pauli-sum-op-permute-a9b742f3a2fad934.yaml new file mode 100644 index 000000000000..66e4c70868d2 --- /dev/null +++ b/releasenotes/notes/fix-pauli-sum-op-permute-a9b742f3a2fad934.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fix a bug in :meth:`qiskit.opflow.PauliSumOp.permute` where the original object on which + the method is called is permuted, instead of only returning a new, permuted copy. + This bug only occured for permutations that left the number of qubits in the operator + unchanged. diff --git a/test/python/opflow/test_pauli_sum_op.py b/test/python/opflow/test_pauli_sum_op.py index aacb88825965..34853311238a 100644 --- a/test/python/opflow/test_pauli_sum_op.py +++ b/test/python/opflow/test_pauli_sum_op.py @@ -10,11 +10,12 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -""" Test PauliSumOp """ +"""Test PauliSumOp.""" import unittest from itertools import product from test.python.opflow import QiskitOpflowTestCase +from ddt import ddt, data, unpack import numpy as np from scipy.sparse import csr_matrix @@ -41,6 +42,7 @@ from qiskit.quantum_info import Pauli, PauliTable, SparsePauliOp +@ddt class TestPauliSumOp(QiskitOpflowTestCase): """PauliSumOp tests.""" @@ -163,22 +165,28 @@ def test_tensor(self): expected = (Z ^ Z) + (Z ^ I) self.assertEqual(pauli_sum, expected) - def test_permute(self): - """permute test""" - pauli_sum = PauliSumOp(SparsePauliOp((X ^ Y ^ Z).primitive)) - expected = PauliSumOp(SparsePauliOp((X ^ I ^ Y ^ Z ^ I).primitive)) + @data(([1, 2, 4], "XIYZI"), ([2, 1, 0], "ZYX")) + @unpack + def test_permute(self, permutation, expected_pauli): + """Test the permute method.""" + pauli_sum = PauliSumOp(SparsePauliOp.from_list([("XYZ", 1)])) + expected = PauliSumOp(SparsePauliOp.from_list([(expected_pauli, 1)])) + permuted = pauli_sum.permute(permutation) - self.assertEqual(pauli_sum.permute([1, 2, 4]), expected) + with self.subTest(msg="test permutated object"): + self.assertEqual(permuted, expected) - pauli_sum = PauliSumOp(SparsePauliOp((X ^ Y ^ Z).primitive)) - expected = PauliSumOp(SparsePauliOp((Z ^ Y ^ X).primitive)) - self.assertEqual(pauli_sum.permute([2, 1, 0]), expected) + with self.subTest(msg="test original object is unchanged"): + original = PauliSumOp(SparsePauliOp.from_list([("XYZ", 1)])) + self.assertEqual(pauli_sum, original) - with self.assertRaises(OpflowError): - pauli_sum.permute([1, 2, 1]) + @data([1, 2, 1], [1, 2, -1]) + def test_permute_invalid(self, permutation): + """Test the permute method raises an error on invalid permutations.""" + pauli_sum = PauliSumOp(SparsePauliOp((X ^ Y ^ Z).primitive)) with self.assertRaises(OpflowError): - pauli_sum.permute([1, 2, -1]) + pauli_sum.permute(permutation) def test_compose(self): """compose test"""