Skip to content

Commit

Permalink
Make BitArray.{slice_bits,slice_shots,__getitem__} raise `IndexErro…
Browse files Browse the repository at this point in the history
…r` when indices are not valid (backport #12755) (#12844)

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

* Make BitArray.{slice_bits,slice_shots} raise IndexError when indices are out of bounds

* update __getitem__

(cherry picked from commit bfd2eea)

# Conflicts:
#	qiskit/primitives/containers/bit_array.py

* Update bit_array.py

---------

Co-authored-by: Takashi Imamichi <[email protected]>
Co-authored-by: Elena Peña Tapia <[email protected]>
  • Loading branch information
3 people authored Jul 29, 2024
1 parent f97a620 commit 4f09f57
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 12 deletions.
21 changes: 13 additions & 8 deletions qiskit/primitives/containers/bit_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,15 @@ def __repr__(self):

def __getitem__(self, indices):
"""Slices the array along an existing axis of the array."""
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 @@ -428,13 +433,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 @@ -455,13 +460,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 @@ -527,6 +527,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 @@ -571,9 +585,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 @@ -621,9 +635,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

0 comments on commit 4f09f57

Please sign in to comment.