diff --git a/src/pyrecest/evaluation/get_distance_function.py b/src/pyrecest/evaluation/get_distance_function.py index 44a2cb3407..f5d2168fe2 100644 --- a/src/pyrecest/evaluation/get_distance_function.py +++ b/src/pyrecest/evaluation/get_distance_function.py @@ -255,7 +255,7 @@ def _euclidean_mtt_distance(x1, x2, *, cutoff_distance: float) -> float: return float(cutoff_distance * abs(first.shape[0] - second.shape[0])) deltas = first[:, None, :] - second[None, :, :] - costs = numpy.linalg.norm(deltas, axis=2) + costs = numpy.hypot.reduce(deltas, axis=2) costs = numpy.minimum(costs, float(cutoff_distance)) row_indices, column_indices = linear_sum_assignment(costs) matched_cost = float(costs[row_indices, column_indices].sum()) diff --git a/tests/evaluation/test_euclidean_mtt_distance_orientation.py b/tests/evaluation/test_euclidean_mtt_distance_orientation.py index 1bb01d276e..45682d5a76 100644 --- a/tests/evaluation/test_euclidean_mtt_distance_orientation.py +++ b/tests/evaluation/test_euclidean_mtt_distance_orientation.py @@ -41,3 +41,18 @@ def test_empty_target_dimension_disambiguates_small_dim_first_target_set(): np.testing.assert_allclose(distance(no_targets, dim_first_targets), 21.0) np.testing.assert_allclose(distance(dim_first_targets, no_targets), 21.0) + + +def test_euclidean_mtt_distance_preserves_extreme_finite_norm_below_cutoff(): + distance = get_distance_function( + "euclidean_mtt", + {"cutoff_distance": 1.5e308}, + ) + first = np.array([[1.0e308, 1.0e308]]) + second = np.array([[0.0, 0.0]]) + expected = np.hypot(1.0e308, 1.0e308) + + with np.errstate(over="raise", invalid="raise"): + result = distance(first, second) + + np.testing.assert_allclose(result, expected, rtol=1.0e-15)