Skip to content

Commit

Permalink
Fix BitArray.from_counts/from_samples to not fail for input with …
Browse files Browse the repository at this point in the history
…only `0` outcome and `num_bits=None` (#12800)

* interpret `0` as represented by 1 bit

* Test conversion of counts w only `0` outcome

* add release note
  • Loading branch information
aeddins-ibm authored Jul 26, 2024
1 parent 898fdec commit c40ce83
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 2 deletions.
7 changes: 5 additions & 2 deletions qiskit/primitives/containers/bit_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def from_counts(
Args:
counts: One or more counts-like mappings with the same number of shots.
num_bits: The desired number of bits per shot. If unset, the biggest value found sets
this value.
this value, with a minimum of one bit.
Returns:
A new bit array with shape ``()`` for single input counts, or ``(N,)`` for an iterable
Expand Down Expand Up @@ -277,7 +277,7 @@ def from_samples(
Args:
samples: A list of bitstrings, a list of integers, or a list of hexstrings.
num_bits: The desired number of bits per sample. If unset, the biggest sample provided
is used to determine this value.
is used to determine this value, with a minimum of one bit.
Returns:
A new bit array.
Expand All @@ -300,6 +300,9 @@ def from_samples(
# we are forced to prematurely look at every iterand in this case
ints = list(ints)
num_bits = max(map(int.bit_length, ints))
# convention: if the only value is 0, represent with one bit:
if num_bits == 0:
num_bits = 1

num_bytes = _min_num_bytes(num_bits)
data = b"".join(val.to_bytes(num_bytes, "big") for val in ints)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
Fixed a bug in :meth:`.BitArray.from_counts` and :meth:`.BitArray.from_samples`.
Previously these would raise an error if given data containing only zeros, and no
value for the optional argument ``num_bits``. Now they produce a :class:`.BitArray`
with :attr:`.BitArray.num_bits` set to 1.
14 changes: 14 additions & 0 deletions test/python/primitives/containers/test_bit_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ def convert(counts: Counts):

counts1 = convert(Counts({"0b101010": 2, "0b1": 3, "0x010203": 4}))
counts2 = convert(Counts({1: 3, 2: 6}))
counts3 = convert(Counts({0: 2}))

bit_array = BitArray.from_counts(counts1)
expected = BitArray(u_8([[0, 0, 42]] * 2 + [[0, 0, 1]] * 3 + [[1, 2, 3]] * 4), 17)
Expand All @@ -248,6 +249,10 @@ def convert(counts: Counts):
]
self.assertEqual(bit_array, BitArray(u_8(expected), 17))

bit_array = BitArray.from_counts(counts3)
expected = BitArray(u_8([[0], [0]]), 1)
self.assertEqual(bit_array, expected)

def test_from_samples_bitstring(self):
"""Test the from_samples static constructor."""
bit_array = BitArray.from_samples(["110", "1", "1111111111"])
Expand All @@ -256,6 +261,9 @@ def test_from_samples_bitstring(self):
bit_array = BitArray.from_samples(["110", "1", "1111111111"], 20)
self.assertEqual(bit_array, BitArray(u_8([[0, 0, 6], [0, 0, 1], [0, 3, 255]]), 20))

bit_array = BitArray.from_samples(["000", "0"])
self.assertEqual(bit_array, BitArray(u_8([[0], [0]]), 1))

def test_from_samples_hex(self):
"""Test the from_samples static constructor."""
bit_array = BitArray.from_samples(["0x01", "0x0a12", "0x0105"])
Expand All @@ -264,6 +272,9 @@ def test_from_samples_hex(self):
bit_array = BitArray.from_samples(["0x01", "0x0a12", "0x0105"], 20)
self.assertEqual(bit_array, BitArray(u_8([[0, 0, 1], [0, 10, 18], [0, 1, 5]]), 20))

bit_array = BitArray.from_samples(["0x0", "0x0"])
self.assertEqual(bit_array, BitArray(u_8([[0], [0]]), 1))

def test_from_samples_int(self):
"""Test the from_samples static constructor."""
bit_array = BitArray.from_samples([1, 2578, 261])
Expand All @@ -272,6 +283,9 @@ def test_from_samples_int(self):
bit_array = BitArray.from_samples([1, 2578, 261], 20)
self.assertEqual(bit_array, BitArray(u_8([[0, 0, 1], [0, 10, 18], [0, 1, 5]]), 20))

bit_array = BitArray.from_samples([0, 0, 0])
self.assertEqual(bit_array, BitArray(u_8([[0], [0], [0]]), 1))

def test_reshape(self):
"""Test the reshape method."""
# this creates incrementing bitstrings from 0 to 360 * 32 - 1
Expand Down

0 comments on commit c40ce83

Please sign in to comment.