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

Make BitArray.{slice_bits,slice_shots,__getitem__} raise IndexError when indices are not valid #12755

Merged
merged 2 commits into from
Jul 29, 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
21 changes: 13 additions & 8 deletions qiskit/primitives/containers/bit_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,15 @@ def __repr__(self):
return f"BitArray({desc})"

def __getitem__(self, indices):
if isinstance(indices, tuple) and len(indices) >= self.ndim + 2:
raise ValueError(
"BitArrays cannot be sliced along the bits axis, see slice_bits() instead."
)
if isinstance(indices, tuple):
if len(indices) == self.ndim + 1:
raise IndexError(
"BitArray cannot be sliced along the shots axis, use slice_shots() instead."
)
if len(indices) >= self.ndim + 2:
raise IndexError(
"BitArray cannot be sliced along the bits axis, use slice_bits() instead."
)
return BitArray(self._array[indices], self.num_bits)

@property
Expand Down Expand Up @@ -424,13 +429,13 @@ def slice_bits(self, indices: int | Sequence[int]) -> "BitArray":
A bit array sliced along the bit axis.

Raises:
ValueError: If there are any invalid indices of the bit axis.
IndexError: If there are any invalid indices of the bit axis.
"""
if isinstance(indices, int):
indices = (indices,)
for index in indices:
if index < 0 or index >= self.num_bits:
raise ValueError(
raise IndexError(
f"index {index} is out of bounds for the number of bits {self.num_bits}."
)
# This implementation introduces a temporary 8x memory overhead due to bit
Expand All @@ -451,13 +456,13 @@ def slice_shots(self, indices: int | Sequence[int]) -> "BitArray":
A bit array sliced along the shots axis.

Raises:
ValueError: If there are any invalid indices of the shots axis.
IndexError: If there are any invalid indices of the shots axis.
"""
if isinstance(indices, int):
indices = (indices,)
for index in indices:
if index < 0 or index >= self.num_shots:
raise ValueError(
raise IndexError(
f"index {index} is out of bounds for the number of shots {self.num_shots}."
)
arr = self._array
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
upgrade_primitives:
- |
:meth:`.BitArray.slice_bits` and :meth:`.BitArray.slice_shots`
will now raise ``IndexError`` when indices are out of bounds.
They used to raise ``ValueError`` in the case.
- |
:meth:`.BitArray.__getitem__` will now raise ``IndexError``
when indices are out of bounds or the number of dimensions
of indices does not match that of BitArray.
They used to raise ``ValueError`` in the case.
22 changes: 18 additions & 4 deletions test/python/primitives/containers/test_bit_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,20 @@ def test_getitem(self):
for j in range(2):
self.assertEqual(ba.get_counts((0, j, 2)), ba2.get_counts(j))

with self.subTest("errors"):
with self.assertRaisesRegex(IndexError, "index 2 is out of bounds"):
_ = ba[0, 2, 2]
with self.assertRaisesRegex(IndexError, "index -3 is out of bounds"):
_ = ba[0, -3, 2]
with self.assertRaisesRegex(
IndexError, "BitArray cannot be sliced along the shots axis"
):
_ = ba[0, 1, 2, 3]
with self.assertRaisesRegex(
IndexError, "BitArray cannot be sliced along the bits axis"
):
_ = ba[0, 1, 2, 3, 4]

def test_slice_bits(self):
"""Test the slice_bits method."""
# this creates incrementing bitstrings from 0 to 59
Expand Down Expand Up @@ -557,9 +571,9 @@ def test_slice_bits(self):
self.assertEqual(ba2.get_counts((i, j, k)), expect)

with self.subTest("errors"):
with self.assertRaisesRegex(ValueError, "index -1 is out of bounds"):
with self.assertRaisesRegex(IndexError, "index -1 is out of bounds"):
_ = ba.slice_bits(-1)
with self.assertRaisesRegex(ValueError, "index 9 is out of bounds"):
with self.assertRaisesRegex(IndexError, "index 9 is out of bounds"):
_ = ba.slice_bits(9)

def test_slice_shots(self):
Expand Down Expand Up @@ -607,9 +621,9 @@ def test_slice_shots(self):
self.assertEqual(ba2.get_bitstrings((i, j, k)), expected)

with self.subTest("errors"):
with self.assertRaisesRegex(ValueError, "index -1 is out of bounds"):
with self.assertRaisesRegex(IndexError, "index -1 is out of bounds"):
_ = ba.slice_shots(-1)
with self.assertRaisesRegex(ValueError, "index 10 is out of bounds"):
with self.assertRaisesRegex(IndexError, "index 10 is out of bounds"):
_ = ba.slice_shots(10)

def test_expectation_values(self):
Expand Down
Loading