From e257a261181c5bb2ea4d5f884fb64af0f1651ed2 Mon Sep 17 00:00:00 2001 From: chrisholder Date: Thu, 7 Aug 2025 16:05:24 +0100 Subject: [PATCH 1/4] minor msm bug fix --- aeon/distances/elastic/_msm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aeon/distances/elastic/_msm.py b/aeon/distances/elastic/_msm.py index 2b0c835f7d..b4d2417aa0 100644 --- a/aeon/distances/elastic/_msm.py +++ b/aeon/distances/elastic/_msm.py @@ -272,7 +272,7 @@ def _independent_cost_matrix( for i in range(1, y_size): if bounding_matrix[0, i]: - cost = _cost_independent(y[i], y[i - 1], x[0], c) + cost = _cost_independent(y[i], x[0], y[i - 1], c) cost_matrix[0][i] = cost_matrix[0][i - 1] + cost for i in range(1, x_size): @@ -302,7 +302,7 @@ def _msm_dependent_cost_matrix( cost_matrix[i][0] = cost_matrix[i - 1][0] + cost for i in range(1, y_size): if bounding_matrix[0, i]: - cost = _cost_dependent(y[:, i], y[:, i - 1], x[:, 0], c) + cost = _cost_dependent(y[:, i], x[:, 0], y[:, i - 1], c) cost_matrix[0][i] = cost_matrix[0][i - 1] + cost for i in range(1, x_size): From f281038fc17dd8c124b2b1d346ddc1f69c7f606d Mon Sep 17 00:00:00 2001 From: chrisholder Date: Wed, 19 Nov 2025 01:53:45 +0000 Subject: [PATCH 2/4] msm bug fixes --- aeon/distances/elastic/_msm.py | 42 +++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/aeon/distances/elastic/_msm.py b/aeon/distances/elastic/_msm.py index 8ca3d8a188..7fbe8ab1c6 100644 --- a/aeon/distances/elastic/_msm.py +++ b/aeon/distances/elastic/_msm.py @@ -267,19 +267,19 @@ def _independent_cost_matrix( for i in range(1, x_size): if bounding_matrix[i, 0]: cost = _cost_independent(x[i], x[i - 1], y[0], c) - cost_matrix[i][0] = cost_matrix[i - 1][0] + cost + cost_matrix[i, 0] = cost_matrix[i - 1, 0] + cost - for i in range(1, y_size): - if bounding_matrix[0, i]: - cost = _cost_independent(y[i], x[0], y[i - 1], c) - cost_matrix[0][i] = cost_matrix[0][i - 1] + cost + for j in range(1, y_size): + if bounding_matrix[0, j]: + cost = _cost_independent(y[j], x[0], y[j - 1], c) + cost_matrix[0, j] = cost_matrix[0, j - 1] + cost for i in range(1, x_size): for j in range(1, y_size): if bounding_matrix[i, j]: d1 = cost_matrix[i - 1][j - 1] + np.abs(x[i] - y[j]) - d2 = cost_matrix[i - 1][j] + _cost_independent(x[i], x[i - 1], y[j], c) - d3 = cost_matrix[i][j - 1] + _cost_independent(y[j], x[i], y[j - 1], c) + d2 = cost_matrix[i - 1, j] + _cost_independent(x[i], x[i - 1], y[j], c) + d3 = cost_matrix[i, j - 1] + _cost_independent(y[j], x[i], y[j - 1], c) cost_matrix[i, j] = min(d1, d2, d3) @@ -292,40 +292,44 @@ def _msm_dependent_cost_matrix( ) -> np.ndarray: x_size = x.shape[1] y_size = y.shape[1] + cost_matrix = np.full((x_size, y_size), np.inf) - cost_matrix[0, 0] = np.sum(np.abs(x[:, 0] - y[:, 0])) + cost_matrix[0, 0] = _univariate_squared_distance(x[:, 0], y[:, 0]) for i in range(1, x_size): if bounding_matrix[i, 0]: cost = _cost_dependent(x[:, i], x[:, i - 1], y[:, 0], c) - cost_matrix[i][0] = cost_matrix[i - 1][0] + cost - for i in range(1, y_size): - if bounding_matrix[0, i]: - cost = _cost_dependent(y[:, i], x[:, 0], y[:, i - 1], c) - cost_matrix[0][i] = cost_matrix[0][i - 1] + cost + cost_matrix[i, 0] = cost_matrix[i - 1, 0] + cost + + for j in range(1, y_size): + if bounding_matrix[0, j]: + cost = _cost_dependent(y[:, j], x[:, 0], y[:, j - 1], c) + cost_matrix[0, j] = cost_matrix[0, j - 1] + cost for i in range(1, x_size): for j in range(1, y_size): if bounding_matrix[i, j]: - d1 = cost_matrix[i - 1][j - 1] + np.sum(np.abs(x[:, i] - y[:, j])) - d2 = cost_matrix[i - 1][j] + _cost_dependent( + d1 = cost_matrix[i - 1, j - 1] + _univariate_squared_distance( + x[:, i], y[:, j] + ) + d2 = cost_matrix[i - 1, j] + _cost_dependent( x[:, i], x[:, i - 1], y[:, j], c ) - d3 = cost_matrix[i][j - 1] + _cost_dependent( + d3 = cost_matrix[i, j - 1] + _cost_dependent( y[:, j], x[:, i], y[:, j - 1], c ) - cost_matrix[i, j] = min(d1, d2, d3) + return cost_matrix @njit(cache=True, fastmath=True) def _cost_dependent(x: np.ndarray, y: np.ndarray, z: np.ndarray, c: float) -> float: diameter = _univariate_squared_distance(y, z) - mid = (y + z) / 2 + mid = (y + z) / 2.0 distance_to_mid = _univariate_squared_distance(mid, x) - if distance_to_mid <= (diameter / 2): + if distance_to_mid <= (diameter / 4.0): return c else: dist_to_q_prev = _univariate_squared_distance(y, x) From 2902c0bd3f503f238504f77ba9eb3c8750915504 Mon Sep 17 00:00:00 2001 From: chrisholder Date: Wed, 19 Nov 2025 02:05:10 +0000 Subject: [PATCH 3/4] updated tests --- aeon/distances/elastic/tests/test_distance_correctness.py | 4 ++-- aeon/testing/expected_results/expected_distance_results.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aeon/distances/elastic/tests/test_distance_correctness.py b/aeon/distances/elastic/tests/test_distance_correctness.py index 6aa1c57684..9206324ef9 100644 --- a/aeon/distances/elastic/tests/test_distance_correctness.py +++ b/aeon/distances/elastic/tests/test_distance_correctness.py @@ -60,7 +60,7 @@ "wddtw": [38144.53125, 19121.4927, 1.34957], "twe": [4536.0, 3192.0220, 3030.036000000001], "msm_ind": [1515.0, 1517.8000000000004, 1557.0], # msm with independent distance - "msm_dep": [1897.0, 1898.6000000000001, 1921.0], # msm with dependent distance + "msm_dep": [190547.0, 190549.800000000020, 190589.0], # msm with dependent distance } basic_motions_distances = { "euclidean": 27.51835240, @@ -78,7 +78,7 @@ # msm with independent distance "msm_ind": [84.36021099999999, 140.13788899999997, 262.6939920000001], # msm with dependent distance - "msm_dep": [33.06825, 71.1408, 190.7397], + "msm_dep": [192.24477562339214, 205.82382238128477, 277.7315058567359], } diff --git a/aeon/testing/expected_results/expected_distance_results.py b/aeon/testing/expected_results/expected_distance_results.py index 7126c5c624..5eb5107fdb 100644 --- a/aeon/testing/expected_results/expected_distance_results.py +++ b/aeon/testing/expected_results/expected_distance_results.py @@ -166,7 +166,7 @@ "msm": [ [2.5687181410313746, 28.97170437295012], [2.5687181410313746, 28.97170437295012], - [2.5687181410313746, 28.657118461088324], + [1.0924085990342982, 13.072037194954508], [1.8756413986565008, 22.362537814430787], ], "adtw": [ From 7b82f4634b145463fdcf9c23b419e46ca71c738e Mon Sep 17 00:00:00 2001 From: chrisholder Date: Wed, 19 Nov 2025 02:08:28 +0000 Subject: [PATCH 4/4] remove redundent distance call --- aeon/distances/elastic/_msm.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/aeon/distances/elastic/_msm.py b/aeon/distances/elastic/_msm.py index 7fbe8ab1c6..c1221fa3f7 100644 --- a/aeon/distances/elastic/_msm.py +++ b/aeon/distances/elastic/_msm.py @@ -246,12 +246,10 @@ def _msm_independent_cost_matrix( x_size = x.shape[1] y_size = y.shape[1] cost_matrix = np.zeros((x_size, y_size)) - distance = 0 min_instances = min(x.shape[0], y.shape[0]) for i in range(min_instances): curr_cost_matrix = _independent_cost_matrix(x[i], y[i], bounding_matrix, c) cost_matrix = np.add(cost_matrix, curr_cost_matrix) - distance += curr_cost_matrix[-1, -1] return cost_matrix