Skip to content

Commit 2d8e18e

Browse files
committed
fix: update pixel evaluator with NumPy 1.x compatible bit counting.
Signed-off-by: samiuc <[email protected]>
1 parent 507d55e commit 2d8e18e

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

docling_eval/evaluators/pixel/multi_label_confusion_matrix.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,27 @@
1414
_log = logging.getLogger(__name__)
1515

1616

17+
def _popcount(x: np.ndarray) -> np.ndarray:
18+
"""
19+
Count the number of 1-bits in each element of x.
20+
21+
Compatible with NumPy 1.x (falls back to vectorized bit counting)
22+
and NumPy 2.0+ (uses np.bitwise_count).
23+
"""
24+
if hasattr(np, "bitwise_count"):
25+
# NumPy 2.0+
26+
return np.bitwise_count(x)
27+
else:
28+
# NumPy 1.x fallback - vectorized popcount using lookup table
29+
# Works for uint64 by processing 8 bits at a time
30+
lookup = np.array([bin(i).count("1") for i in range(256)], dtype=np.uint8)
31+
x = x.astype(np.uint64)
32+
result = np.zeros_like(x, dtype=np.int64)
33+
for shift in range(0, 64, 8):
34+
result += lookup[(x >> shift) & 0xFF]
35+
return result
36+
37+
1738
def unpackbits(x: np.ndarray, num_bits: int):
1839
r"""
1940
Unpack num_bits bits of each element of the numpy array x
@@ -246,10 +267,10 @@ def _compute_confusion_matrix(
246267
)
247268

248269
# [num_pixels_with_extra_preds,]
249-
case2_gt_multiplier = np.bitwise_count(case2_gt_pixels)
270+
case2_gt_multiplier = _popcount(case2_gt_pixels)
250271

251272
# [num_pixels_with_extra_preds,]
252-
case2_preds_divider = np.bitwise_count(case2_preds_pixels)
273+
case2_preds_divider = _popcount(case2_preds_pixels)
253274

254275
# [num_pixels_with_extra_preds, num_categories, num_categories]
255276
case2_gain = case2_gt_multiplier[:, None, None] * case2_gt_diagonals
@@ -292,7 +313,7 @@ def _compute_confusion_matrix(
292313
case3_gt_preds_diff = unpackbits(case3_gt_preds_diff, num_categories)
293314

294315
# [num_pixels_with_additional_gt_labels,]
295-
case3_preds_divider = np.bitwise_count(case3_preds_pixels)
316+
case3_preds_divider = _popcount(case3_preds_pixels)
296317

297318
# [num_pixels_with_additional_gt_labels, num_categories, num_categories]
298319
case3_preds_diagonals = (
@@ -342,7 +363,7 @@ def _compute_confusion_matrix(
342363
case4_preds_pixels ^ case4_gt_pixels
343364
) & case4_preds_pixels
344365
if len(case4_preds_gt_diff) > 0:
345-
case4_divider = np.bitwise_count(case4_preds_gt_diff)
366+
case4_divider = _popcount(case4_preds_gt_diff)
346367
case4_preds_gt_diff = unpackbits(case4_preds_gt_diff, num_categories)
347368

348369
# [num_pixels_with_mutual_gt_pred_deltas, num_categories]
@@ -525,7 +546,7 @@ def _validate_contributions(
525546

526547
# Full sum check
527548
full_sum = np.sum(row_sum)
528-
expected_full_sum = np.sum(np.bitwise_count(selected_gt))
549+
expected_full_sum = np.sum(_popcount(selected_gt))
529550
if full_sum != expected_full_sum:
530551
self._handle_error(f"{info}: Wrong contributions full sums")
531552

0 commit comments

Comments
 (0)