From 247599aea8b35d0ab899bd76524ad23cf8310d7c Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Thu, 6 Aug 2026 11:53:15 +0800 Subject: [PATCH 1/3] Preserve CLEAR tracker identity precision --- .../evaluation/tracking_metrics/_clear_identity.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py b/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py index 46f898a67..13e36b9c7 100644 --- a/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py +++ b/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py @@ -11,6 +11,7 @@ from ._data import TrackingSequence, unit_interval_scalar _EPS = np.finfo(float).eps +_UNMATCHED_ID = -1 @dataclass(frozen=True) @@ -39,8 +40,8 @@ def evaluate_clear(data: TrackingSequence, *, threshold: float) -> ClearCounts: return ClearCounts(0, data.num_tracker_detections, 0, 0, 0.0) tp = fp = fn = switches = 0 motp_sum = 0.0 - previous_id = np.full(data.num_gt_ids, np.nan) - previous_timestep_id = np.full(data.num_gt_ids, np.nan) + previous_id = np.full(data.num_gt_ids, _UNMATCHED_ID, dtype=int) + previous_timestep_id = np.full(data.num_gt_ids, _UNMATCHED_ID, dtype=int) for gt_ids, tracker_ids, similarity in zip( data.gt_ids, data.tracker_ids, data.similarity_scores, strict=True ): @@ -60,9 +61,14 @@ def evaluate_clear(data: TrackingSequence, *, threshold: float) -> ClearCounts: matched_gt = gt_ids[match_rows] matched_tracker = tracker_ids[match_cols] previous = previous_id[matched_gt] - switches += int(np.sum((~np.isnan(previous)) & (matched_tracker != previous))) + switches += int( + np.sum( + (previous != _UNMATCHED_ID) + & (matched_tracker != previous) + ) + ) previous_id[matched_gt] = matched_tracker - previous_timestep_id[:] = np.nan + previous_timestep_id[:] = _UNMATCHED_ID previous_timestep_id[matched_gt] = matched_tracker matches = len(match_rows) tp += matches From 9c2aa67cb7b7c4780ea71584d6ea74bf11e98994 Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Thu, 6 Aug 2026 11:53:39 +0800 Subject: [PATCH 2/3] Test large CLEAR tracker identities --- tests/evaluation/test_tracking_metrics.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/evaluation/test_tracking_metrics.py b/tests/evaluation/test_tracking_metrics.py index c98d47119..b98735415 100644 --- a/tests/evaluation/test_tracking_metrics.py +++ b/tests/evaluation/test_tracking_metrics.py @@ -82,6 +82,21 @@ def test_identity_switch_reduces_association_metrics() -> None: assert finalize_identity(identity_counts)["idf1"] == pytest.approx(0.5) +def test_clear_preserves_large_tracker_identity_precision() -> None: + large_tracker_id = 2**53 + 1 + data = _sequence( + [[0], [0]], + [[large_tracker_id], [large_tracker_id - 1]], + [[[1.0]], [[1.0]]], + num_gt_ids=1, + num_tracker_ids=large_tracker_id + 1, + ) + + counts = evaluate_clear(data, threshold=0.5) + + assert (counts.tp, counts.fp, counts.fn, counts.id_switches) == (2, 0, 0, 1) + + def test_hota_uses_multiple_localization_thresholds() -> None: data = _sequence( [[0]], From 636ab6693ce452ca2fbf19d74238224f12a2ad27 Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Thu, 6 Aug 2026 11:54:11 +0800 Subject: [PATCH 3/3] Format CLEAR precision fix --- src/pyrecest/evaluation/tracking_metrics/_clear_identity.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py b/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py index 13e36b9c7..4f56f3147 100644 --- a/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py +++ b/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py @@ -62,10 +62,7 @@ def evaluate_clear(data: TrackingSequence, *, threshold: float) -> ClearCounts: matched_tracker = tracker_ids[match_cols] previous = previous_id[matched_gt] switches += int( - np.sum( - (previous != _UNMATCHED_ID) - & (matched_tracker != previous) - ) + np.sum((previous != _UNMATCHED_ID) & (matched_tracker != previous)) ) previous_id[matched_gt] = matched_tracker previous_timestep_id[:] = _UNMATCHED_ID