diff --git a/qiskit/quantum_info/operators/symplectic/pauli.py b/qiskit/quantum_info/operators/symplectic/pauli.py index 1ccecc04a6c0..8187c1ee41e6 100644 --- a/qiskit/quantum_info/operators/symplectic/pauli.py +++ b/qiskit/quantum_info/operators/symplectic/pauli.py @@ -736,8 +736,11 @@ def apply_layout( n_qubits = num_qubits if layout is None: layout = list(range(self.num_qubits)) - elif any(x >= n_qubits for x in layout): - raise QiskitError("Provided layout contains indices outside the number of qubits.") + else: + if any(x < 0 or x >= n_qubits for x in layout): + raise QiskitError("Provided layout contains indices outside the number of qubits.") + if len(set(layout)) != len(layout): + raise QiskitError("Provided layout contains duplicate indices.") new_op = type(self)("I" * n_qubits) return new_op.compose(self, qargs=layout) diff --git a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py index dffe5b2396b2..cf51579bef8f 100644 --- a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +++ b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py @@ -1139,7 +1139,6 @@ def apply_layout( specified will be applied without any expansion. If layout is None, the operator will be expanded to the given number of qubits. - Returns: A new :class:`.SparsePauliOp` with the provided layout applied """ @@ -1159,10 +1158,13 @@ def apply_layout( f"applied to a {n_qubits} qubit operator" ) n_qubits = num_qubits - if layout is not None and any(x >= n_qubits for x in layout): - raise QiskitError("Provided layout contains indices outside the number of qubits.") if layout is None: layout = list(range(self.num_qubits)) + else: + if any(x < 0 or x >= n_qubits for x in layout): + raise QiskitError("Provided layout contains indices outside the number of qubits.") + if len(set(layout)) != len(layout): + raise QiskitError("Provided layout contains duplicate indices.") new_op = type(self)("I" * n_qubits) return new_op.compose(self, qargs=layout) diff --git a/releasenotes/notes/fix-apply-layout-duplicate-negative-indices-cf5517921fe52706.yaml b/releasenotes/notes/fix-apply-layout-duplicate-negative-indices-cf5517921fe52706.yaml new file mode 100644 index 000000000000..9fbe0ffd9c79 --- /dev/null +++ b/releasenotes/notes/fix-apply-layout-duplicate-negative-indices-cf5517921fe52706.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed :meth:`.SparsePauliOp.apply_layout` and :meth:`.Pauli.apply_layout` + to raise :exc:`.QiskitError` if duplicate indices or negative indices are provided + as part of a layout. diff --git a/test/python/quantum_info/operators/symplectic/test_pauli.py b/test/python/quantum_info/operators/symplectic/test_pauli.py index 875dd9237810..89324e8212e1 100644 --- a/test/python/quantum_info/operators/symplectic/test_pauli.py +++ b/test/python/quantum_info/operators/symplectic/test_pauli.py @@ -606,6 +606,18 @@ def test_apply_layout_null_layout_invalid_num_qubits(self): with self.assertRaises(QiskitError): op.apply_layout(layout=None, num_qubits=1) + def test_apply_layout_negative_indices(self): + """Test apply_layout with negative indices""" + op = Pauli("IZ") + with self.assertRaises(QiskitError): + op.apply_layout(layout=[-1, 0], num_qubits=3) + + def test_apply_layout_duplicate_indices(self): + """Test apply_layout with duplicate indices""" + op = Pauli("IZ") + with self.assertRaises(QiskitError): + op.apply_layout(layout=[0, 0], num_qubits=3) + if __name__ == "__main__": unittest.main() diff --git a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py index 330fd53bc35d..1149ef1f3466 100644 --- a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py +++ b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py @@ -1179,6 +1179,18 @@ def test_apply_layout_null_layout_invalid_num_qubits(self): with self.assertRaises(QiskitError): op.apply_layout(layout=None, num_qubits=1) + def test_apply_layout_negative_indices(self): + """Test apply_layout with negative indices""" + op = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)]) + with self.assertRaises(QiskitError): + op.apply_layout(layout=[-1, 0], num_qubits=3) + + def test_apply_layout_duplicate_indices(self): + """Test apply_layout with duplicate indices""" + op = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)]) + with self.assertRaises(QiskitError): + op.apply_layout(layout=[0, 0], num_qubits=3) + if __name__ == "__main__": unittest.main()