From f02c2146642d835c3196cdcf157710ce75af350d Mon Sep 17 00:00:00 2001 From: Takashi Imamichi <31178928+t-imamichi@users.noreply.github.com> Date: Mon, 29 Jul 2024 23:10:19 +0900 Subject: [PATCH] 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 bfd2eea4807a894fa229cb55b3ad221a50fd31ee) # Conflicts: # qiskit/primitives/containers/bit_array.py --- qiskit/primitives/containers/bit_array.py | 20 +++++++++++++---- ...ray-slice-bits-shots-c9cb7e5d907722f5.yaml | 11 ++++++++++ .../primitives/containers/test_bit_array.py | 22 +++++++++++++++---- 3 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 releasenotes/notes/fix-bitarray-slice-bits-shots-c9cb7e5d907722f5.yaml diff --git a/qiskit/primitives/containers/bit_array.py b/qiskit/primitives/containers/bit_array.py index f52c852c35fd..3cf4de5ef2da 100644 --- a/qiskit/primitives/containers/bit_array.py +++ b/qiskit/primitives/containers/bit_array.py @@ -130,11 +130,23 @@ def __repr__(self): return f"BitArray({desc})" def __getitem__(self, indices): +<<<<<<< HEAD """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." + ) +>>>>>>> bfd2eea48 (Make `BitArray.{slice_bits,slice_shots,__getitem__}` raise `IndexError` when indices are not valid (#12755)) return BitArray(self._array[indices], self.num_bits) @property @@ -428,13 +440,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 @@ -455,13 +467,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 diff --git a/releasenotes/notes/fix-bitarray-slice-bits-shots-c9cb7e5d907722f5.yaml b/releasenotes/notes/fix-bitarray-slice-bits-shots-c9cb7e5d907722f5.yaml new file mode 100644 index 000000000000..56fd81012428 --- /dev/null +++ b/releasenotes/notes/fix-bitarray-slice-bits-shots-c9cb7e5d907722f5.yaml @@ -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. diff --git a/test/python/primitives/containers/test_bit_array.py b/test/python/primitives/containers/test_bit_array.py index 1c8d489b38e4..d4733388d87c 100644 --- a/test/python/primitives/containers/test_bit_array.py +++ b/test/python/primitives/containers/test_bit_array.py @@ -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 @@ -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): @@ -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):