diff --git a/src/mouse_tracking/matching/vectorized_features.py b/src/mouse_tracking/matching/vectorized_features.py index a3ed4c97..526a2e11 100644 --- a/src/mouse_tracking/matching/vectorized_features.py +++ b/src/mouse_tracking/matching/vectorized_features.py @@ -35,6 +35,10 @@ def __init__(self, detections: list[Detection]): def _extract_poses(self, detections: list[Detection]) -> np.ndarray: """Extract pose data into a vectorized array.""" + if len(detections) == 0: + # Return properly shaped empty array + return np.zeros((0, 12, 2), dtype=np.float64) + poses = [] for det in detections: if det.pose is not None: diff --git a/tests/matching/vectorized_features/test_compute_vectorized_detection_features.py b/tests/matching/vectorized_features/test_compute_vectorized_detection_features.py index e516a170..48a2ac31 100644 --- a/tests/matching/vectorized_features/test_compute_vectorized_detection_features.py +++ b/tests/matching/vectorized_features/test_compute_vectorized_detection_features.py @@ -33,11 +33,9 @@ def test_init_empty_detections(self): assert features.n_detections == 0 assert features.detections == [] - assert features.poses.shape == (0,) # Empty array has shape (0,) + assert features.poses.shape == (0, 12, 2) # Properly shaped empty array assert features.embeddings.shape == (0, 0) # Empty embeddings - assert ( - features.valid_pose_masks.shape == () - ) # Empty array results in scalar shape + assert features.valid_pose_masks.shape == (0, 12) # Properly shaped empty mask assert features.valid_embed_masks.shape == (0,) def test_init_mixed_valid_invalid(self, detection_factory): diff --git a/tests/matching/vectorized_features/test_compute_vectorized_pose_distances.py b/tests/matching/vectorized_features/test_compute_vectorized_pose_distances.py index 553235e3..370a2272 100644 --- a/tests/matching/vectorized_features/test_compute_vectorized_pose_distances.py +++ b/tests/matching/vectorized_features/test_compute_vectorized_pose_distances.py @@ -174,15 +174,25 @@ def test_pose_distances_different_sizes(self, features_factory): assert distances.shape == (3, 2) assert not np.any(np.isnan(distances)) # All should be valid - def test_pose_distances_empty_features(self): + @pytest.mark.parametrize("n_features1, n_features2", [(0, 0), (0, 1), (1, 0)]) + def test_pose_distances_empty_features( + self, n_features1, n_features2, features_factory + ): """Test pose distance computation with empty features.""" - features1 = VectorizedDetectionFeatures([]) - features2 = VectorizedDetectionFeatures([]) + example_pose_config = [{"has_pose": True, "center": (0, 0)}] + features1 = features_factory( + n_detections=n_features1, pose_configs=example_pose_config + ) + features2 = features_factory( + n_detections=n_features2, pose_configs=example_pose_config + ) - # This will likely crash due to empty array indexing - mark as expected behavior - # TODO: This reveals a bug in the function with empty features - with pytest.raises(IndexError): - compute_vectorized_pose_distances(features1, features2) + # Should handle empty features gracefully + distances = compute_vectorized_pose_distances(features1, features2) + + # Should return empty distance matrix with correct shape + assert distances.shape == (n_features1, n_features2) + assert distances.dtype == np.float64 def test_pose_distances_single_detection(self, features_factory): """Test pose distance computation with single detection.""" diff --git a/tests/matching/vectorized_features/test_get_rotated_poses.py b/tests/matching/vectorized_features/test_get_rotated_poses.py index 522b6192..72fef7f2 100644 --- a/tests/matching/vectorized_features/test_get_rotated_poses.py +++ b/tests/matching/vectorized_features/test_get_rotated_poses.py @@ -115,8 +115,8 @@ def test_get_rotated_poses_empty_detections(self): # Should not call rotate_pose assert mock_rotate.call_count == 0 - # Should return empty array matching poses shape - assert rotated_poses.shape == (0,) + # Should return properly shaped empty array + assert rotated_poses.shape == (0, 12, 2) assert np.array_equal(rotated_poses, features.poses) def test_get_rotated_poses_uses_detection_rotate_pose(self, detection_factory):