Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix {Pauli,SparsePauliOp}.apply_layout to raise an error with negative or duplicate indices (backport #12385) #12386

Merged
merged 1 commit into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions qiskit/quantum_info/operators/symplectic/pauli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
8 changes: 5 additions & 3 deletions qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""
Expand All @@ -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)

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
12 changes: 12 additions & 0 deletions test/python/quantum_info/operators/symplectic/test_pauli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Loading