Repository: Qiskit/qiskit

Issue:
Recently added z2symmetry in quantum_info does not implement the loops as expected
### Environment

- **Qiskit Terra version**: 0.23.0
- **Python version**: 3.9
- **Operating system**: MacOs


### What is happening?

I recently implemented a version of the Z2symmetry class working with `SparsePauliOp`. In an effort to avoid duplicate lines in the `find_z2_symmetries` class, we refactored how it runs through all three symmetry cases 'Z_or_I','Y_or_I', 'X_or_I'.
I'm realising that only the main case 'Z_or_I' was being tested and that one of the latest commit of the original PR introduced errors in the other cases (not tested).
In practice, an error is being raised when using these method for certain qubit operators

### How can we reproduce the issue?

```
from qiskit.quantum_info import Pauli, PauliList, SparsePauliOp
from qiskit.quantum_info.analysis.z2_symmetries import Z2Symmetries

qubit_op = SparsePauliOp.from_list(
    [
        ("IIXZ", -1.0537076071291125),
        ("IZXY", 0.393983679438514),
        ("ZIYY", -0.39398367943851387),
        ("ZZIZ", -0.01123658523318205),
        ("XXYI", 0.1812888082114961),
    ]
)
z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op)
```
```
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-1-3fd82654c195> in <module>
     11     ]
     12 )
---> 13 z2_symmetries = Z2Symmetries.find_z2_symmetries(qubit_op)

~/Documents/own_repo/qiskit-terra/qiskit/quantum_info/analysis/z2_symmetries.py in find_z2_symmetries(cls, operator)
    285                             Pauli((np.zeros(half_symm_shape), np.zeros(half_symm_shape)))
    286                         )
--> 287                         sq_paulis[row].z[col] = pauli_bool[key][0]
    288                         sq_paulis[row].x[col] = pauli_bool[key][1]
    289                         sq_list.append(col)

IndexError: list index out of range
```

### What should happen?

The find_z2_symmetries method should produce sq_list and sq_paulis objet with the same size as the number of symmetries.

### Any suggestions?

This is due to a mistake in the use of break to escape a for loop. This cannot be seen from the test but from a comparison with the working implementation of `find_Z2_symmetries` for `PauliSumOp`.


Discussion:

Resolving patch:
diff --git a/qiskit/quantum_info/analysis/z2_symmetries.py b/qiskit/quantum_info/analysis/z2_symmetries.py
--- a/qiskit/quantum_info/analysis/z2_symmetries.py
+++ b/qiskit/quantum_info/analysis/z2_symmetries.py
@@ -270,14 +270,16 @@ def _test_symmetry_row_col(row: int, col: int, idx_test: list, row_test: list) -
                     )
                 )
             )
-
+            # Try all cases for the symmetries other than row: Z or I, Y or I, X or I on col qubit.
+            # One test will return true.
+            # Build the single-qubit Pauli accordingly.
+            # Build the index list accordingly.
             for col in range(half_symm_shape):
-                # Try all cases for the symmetries other than row: Z or I, Y or I, X or I on col qubit.
-                # One test will return true.
-                # Build the single-qubit Pauli accordingly.
-                # Build the index list accordingly.
                 for key in ("Z_or_I", "X_or_I", "Y_or_I"):
-                    if _test_symmetry_row_col(row, col, test_idx[key], test_row[key]):
+                    current_test_result = _test_symmetry_row_col(
+                        row, col, test_idx[key], test_row[key]
+                    )
+                    if current_test_result:
                         sq_paulis.append(
                             Pauli((np.zeros(half_symm_shape), np.zeros(half_symm_shape)))
                         )
@@ -285,7 +287,9 @@ def _test_symmetry_row_col(row: int, col: int, idx_test: list, row_test: list) -
                         sq_paulis[row].x[col] = pauli_bool[key][1]
                         sq_list.append(col)
                         break
-                break
+                if current_test_result:
+                    # We break out of the loop over columns only when one valid test is identified.
+                    break
 
         return cls(PauliList(pauli_symmetries), PauliList(sq_paulis), sq_list, None)
 


Test patch:
diff --git a/test/python/quantum_info/test_sparse_z2_symmetries.py b/test/python/quantum_info/test_sparse_z2_symmetries.py
--- a/test/python/quantum_info/test_sparse_z2_symmetries.py
+++ b/test/python/quantum_info/test_sparse_z2_symmetries.py
@@ -14,13 +14,13 @@
 
 import unittest
 
-from test.python.opflow import QiskitOpflowTestCase
+from qiskit.test import QiskitTestCase
 
-from qiskit.quantum_info import Pauli, SparsePauliOp
+from qiskit.quantum_info import Pauli, PauliList, SparsePauliOp
 from qiskit.quantum_info.analysis.z2_symmetries import Z2Symmetries
 
 
-class TestSparseZ2Symmetries(QiskitOpflowTestCase):
+class TestSparseZ2Symmetries(QiskitTestCase):
     """Z2Symmetries tests."""
 
     def test_find_z2_symmetries(self):
@@ -120,6 +120,48 @@ def test_twostep_tapering(self):
             tapered_op = z2_symmetries.taper(qubit_op)
             self.assertEqual(tapered_op, tapered_op_secondstep)
 
+    def test_find_z2_symmetries_X_or_I(self):
+        """Testing a more complex cases of the find_z2_symmetries method to reach the X or I case."""
+
+        qubit_op = SparsePauliOp.from_list(
+            [
+                ("IIXZ", -1.0537076071291125),
+                ("IZXY", 0.393983679438514),
+                ("ZIYY", -0.39398367943851387),
+                ("ZZIZ", -0.01123658523318205),
+                ("XXYI", 0.1812888082114961),
+            ]
+        )
+
+        z2_symmetries_ref = Z2Symmetries(
+            symmetries=PauliList(["ZZII", "XXIZ", "XIYX"]),
+            sq_paulis=PauliList(["IXII", "IIIX", "IIIZ"]),
+            sq_list=[2, 0, 0],
+            tapering_values=None,
+        )
+
+        expected_op = SparsePauliOp.from_list(
+            [
+                ("XX", -1.05370761),
+                ("YX", -0.39398368),
+                ("ZI", -0.39398368),
+                ("IY", 0.01123659),
+                ("XY", 0.18128881),
+            ]
+        )
+
+        z2_symmetries = Z2Symmetries.find_z2_symmetries(qubit_op)
+        self.assertEqual(z2_symmetries.symmetries, z2_symmetries_ref.symmetries)
+        self.assertEqual(z2_symmetries.sq_paulis, z2_symmetries_ref.sq_paulis)
+        self.assertEqual(z2_symmetries.sq_list, z2_symmetries_ref.sq_list)
+        self.assertEqual(z2_symmetries.tapering_values, z2_symmetries_ref.tapering_values)
+
+        tapered_op = z2_symmetries.taper(qubit_op)[1]
+        tapered_op_ref = z2_symmetries_ref.taper(qubit_op)[1]
+
+        self.assertEqual(tapered_op, expected_op)
+        self.assertEqual(tapered_op_ref, expected_op)
+
 
 if __name__ == "__main__":
     unittest.main()