Repository: aeon-toolkit/aeon
Pull request #535 (2023-07-04 16:19:31)

[DOC] fixed path of image
Fixed an image path for the deep learning notebook.

review-notebook-app[bot]: Check out this pull request on&nbsp; <a href="https://app.reviewnb.com/aeon-toolkit/aeon/pull/535"><img align="absmiddle"  alt="ReviewNB" height="28" class="BotMessageButtonImage" src="https://raw.githubusercontent.com/ReviewNB/support/master/images/button_reviewnb.png"/></a> 

 See visual diffs & provide feedback on Jupyter Notebooks. 

---

 <i>Powered by <a href='https://www.reviewnb.com/?utm_source=gh'>ReviewNB</a></i>
TonyBagnall: for the other folders, I have created an img directory in the sub dir and moved pictures there, so that img/H-Inception.png would work. Might be better to duplicate this structure for networks
hadifawaz1999: > for the other folders, I have created an img directory in the sub dir and moved pictures there, so that img/H-Inception.png would work. Might be better to duplicate this structure for networks

Oh okay will do that then thanks ! do you use the H-Inception image in some notebooks in root ? if not i can move it instead of duplicate the image.
TonyBagnall: > > for the other folders, I have created an img directory in the sub dir and moved pictures there, so that img/H-Inception.png would work. Might be better to duplicate this structure for networks
> 
> Oh okay will do that then thanks ! do you use the H-Inception image in some notebooks in root ? if not i can move it instead of duplicate the image.

move it rather than copy, dont think its used elsewhere, will check after
hadifawaz1999: > > > for the other folders, I have created an img directory in the sub dir and moved pictures there, so that img/H-Inception.png would work. Might be better to duplicate this structure for networks
> > 
> > 
> > Oh okay will do that then thanks ! do you use the H-Inception image in some notebooks in root ? if not i can move it instead of duplicate the image.
> 
> move it rather than copy, dont think its used elsewhere, will check after

Should be good now, let me know. I checked and its not used in other notebooks.
hadifawaz1999: Should i wait till we fix the kalman stuff and other packages that were updated @TonyBagnall @MatthewMiddlehurst ? because the fails are because of that.

Patch:
diff --git a/aeon/clustering/metrics/averaging/_barycenter_averaging.py b/aeon/clustering/metrics/averaging/_barycenter_averaging.py
index f788db62..15cca346 100644
--- a/aeon/clustering/metrics/averaging/_barycenter_averaging.py
+++ b/aeon/clustering/metrics/averaging/_barycenter_averaging.py
@@ -110,7 +110,6 @@ def _ba_update(
 ) -> Tuple[np.ndarray, float]:
     X_size, X_dims, X_timepoints = X.shape
     sum = np.zeros(X_timepoints)
-
     alignment = np.zeros((X_dims, X_timepoints))
     cost = 0.0
     for i in range(X_size):
@@ -134,7 +133,9 @@ def _ba_update(
                 curr_ts, center, window, independent, c
             )
         else:
-            raise ValueError(f"Metric must be a known string, got {metric}")
+            # When numba version > 0.57 add more informative error with what metric
+            # was passed.
+            raise ValueError("Metric parameter invalid")
         for j, k in curr_alignment:
             alignment[:, k] += curr_ts[:, j]
             sum[k] += 1
diff --git a/aeon/distances/_distance.py b/aeon/distances/_distance.py
index c2da8f19..6674a685 100644
--- a/aeon/distances/_distance.py
+++ b/aeon/distances/_distance.py
@@ -132,7 +132,9 @@ def distance(
     elif metric == "lcss":
         return lcss_distance(x, y, kwargs.get("window"), kwargs.get("epsilon", 1.0))
     elif metric == "erp":
-        return erp_distance(x, y, kwargs.get("window"), kwargs.get("g", 0.0))
+        return erp_distance(
+            x, y, kwargs.get("window"), kwargs.get("g", 0.0), kwargs.get("g_arr", None)
+        )
     elif metric == "edr":
         return edr_distance(x, y, kwargs.get("window"), kwargs.get("epsilon"))
     elif metric == "twe":
@@ -243,7 +245,9 @@ def pairwise_distance(
             x, y, kwargs.get("window"), kwargs.get("epsilon", 1.0)
         )
     elif metric == "erp":
-        return erp_pairwise_distance(x, y, kwargs.get("window"), kwargs.get("g", 0.0))
+        return erp_pairwise_distance(
+            x, y, kwargs.get("window"), kwargs.get("g", 0.0), kwargs.get("g_arr", None)
+        )
     elif metric == "edr":
         return edr_pairwise_distance(x, y, kwargs.get("window"), kwargs.get("epsilon"))
     elif metric == "twe":
@@ -374,7 +378,9 @@ def alignment_path(
             x, y, kwargs.get("window"), kwargs.get("epsilon", 1.0)
         )
     elif metric == "erp":
-        return erp_alignment_path(x, y, kwargs.get("window"), kwargs.get("g", 0.0))
+        return erp_alignment_path(
+            x, y, kwargs.get("window"), kwargs.get("g", 0.0), kwargs.get("g_arr", None)
+        )
     elif metric == "edr":
         return edr_alignment_path(x, y, kwargs.get("window"), kwargs.get("epsilon"))
     elif metric == "twe":
@@ -460,7 +466,9 @@ def cost_matrix(
     elif metric == "lcss":
         return lcss_cost_matrix(x, y, kwargs.get("window"), kwargs.get("epsilon", 1.0))
     elif metric == "erp":
-        return erp_cost_matrix(x, y, kwargs.get("window"), kwargs.get("g", 0.0))
+        return erp_cost_matrix(
+            x, y, kwargs.get("window"), kwargs.get("g", 0.0), kwargs.get("g_arr", None)
+        )
     elif metric == "edr":
         return edr_cost_matrix(x, y, kwargs.get("window"), kwargs.get("epsilon"))
     elif metric == "twe":
diff --git a/aeon/distances/_erp.py b/aeon/distances/_erp.py
index 56e966ee..fdf426b6 100644
--- a/aeon/distances/_erp.py
+++ b/aeon/distances/_erp.py
@@ -34,7 +34,8 @@ def erp_distance(
     x: np.ndarray,
     y: np.ndarray,
     window: float = None,
-    g: Union[float, np.ndarray] = 0.0,
+    g: float = 0.0,
+    g_arr: np.ndarray = None,
 ) -> float:
     """Compute the ERP distance between two time series.
 
@@ -58,10 +59,10 @@ def erp_distance(
     window: float, defaults=None
         The window to use for the bounding matrix. If None, no bounding matrix
         is used.
-    g: float or np.ndarray of shape (n_channels), defaults=0.
-        The reference value to penalise gaps. The default is 0. If it is an array
-        then it must be the length of the number of channels in x and y. If a single
-        value is provided then that value is used across each channel
+    g: float.
+        The reference value to penalise gaps. The default is 0.
+    g_arr: np.ndarray of shape (n_channels), defaults=None
+        Numpy array that must be the length of the number of channels in x and y.
 
     Returns
     -------
@@ -91,10 +92,10 @@ def erp_distance(
         _x = x.reshape((1, x.shape[0]))
         _y = y.reshape((1, y.shape[0]))
         bounding_matrix = create_bounding_matrix(_x.shape[1], _y.shape[1], window)
-        return _erp_distance(_x, _y, bounding_matrix, g)
+        return _erp_distance(_x, _y, bounding_matrix, g, g_arr)
     if x.ndim == 2 and y.ndim == 2:
         bounding_matrix = create_bounding_matrix(x.shape[1], y.shape[1], window)
-        return _erp_distance(x, y, bounding_matrix, g)
+        return _erp_distance(x, y, bounding_matrix, g, g_arr)
     raise ValueError("x and y must be 1D or 2D")
 
 
@@ -104,6 +105,7 @@ def erp_cost_matrix(
     y: np.ndarray,
     window: float = None,
     g: Union[float, np.ndarray] = 0.0,
+    g_arr: np.ndarray = None,
 ) -> np.ndarray:
     """Compute the ERP cost matrix between two time series.
 
@@ -121,10 +123,10 @@ def erp_cost_matrix(
     window: float, defaults=None
         The window to use for the bounding matrix. If None, no bounding matrix
         is used.
-    g: float or np.ndarray of shape (n_channels), defaults=0.
-        The reference value to penalise gaps. The default is 0. If it is an array
-        then it must be the length of the number of channels in x and y. If a single
-        value is provided then that value is used across each channel.
+    g: float.
+        The reference value to penalise gaps. The default is 0.
+    g_arr: np.ndarray of shape (n_channels), defaults=None
+        Numpy array that must be the length of the number of channels in x and y.
 
     Returns
     -------
@@ -158,10 +160,10 @@ def erp_cost_matrix(
         _x = x.reshape((1, x.shape[0]))
         _y = y.reshape((1, y.shape[0]))
         bounding_matrix = create_bounding_matrix(_x.shape[1], _y.shape[1], window)
-        return _erp_cost_matrix(_x, _y, bounding_matrix, g)
+        return _erp_cost_matrix(_x, _y, bounding_matrix, g, g_arr)
     if x.ndim == 2 and y.ndim == 2:
         bounding_matrix = create_bounding_matrix(x.shape[1], y.shape[1], window)
-        return _erp_cost_matrix(x, y, bounding_matrix, g)
+        return _erp_cost_matrix(x, y, bounding_matrix, g, g_arr)
     raise ValueError("x and y must be 1D or 2D")
 
 
@@ -170,9 +172,12 @@ def _erp_distance(
     x: np.ndarray,
     y: np.ndarray,
     bounding_matrix: np.ndarray,
-    g: Union[float, np.ndarray],
+    g: float,
+    g_arr: np.ndarray,
 ) -> float:
-    return _erp_cost_matrix(x, y, bounding_matrix, g)[x.shape[1] - 1, y.shape[1] - 1]
+    return _erp_cost_matrix(x, y, bounding_matrix, g, g_arr)[
+        x.shape[1] - 1, y.shape[1] - 1
+    ]
 
 
 @njit(cache=True, fastmath=True)
@@ -180,15 +185,16 @@ def _erp_cost_matrix(
     x: np.ndarray,
     y: np.ndarray,
     bounding_matrix: np.ndarray,
-    g: Union[float, np.ndarray],
+    g: float,
+    g_arr: np.ndarray,
 ) -> np.ndarray:
     x_size = x.shape[1]
     y_size = y.shape[1]
 
     cost_matrix = np.zeros((x_size + 1, y_size + 1))
 
-    gx_distance, x_sum = _precompute_g(x, g)
-    gy_distance, y_sum = _precompute_g(y, g)
+    gx_distance, x_sum = _precompute_g(x, g, g_arr)
+    gy_distance, y_sum = _precompute_g(y, g, g_arr)
 
     cost_matrix[1:, 0] = x_sum
     cost_matrix[0, 1:] = y_sum
@@ -208,15 +214,15 @@ def _erp_cost_matrix(
 
 @njit(cache=True, fastmath=True)
 def _precompute_g(
-    x: np.ndarray, g: Union[float, np.ndarray]
+    x: np.ndarray, g: float, g_array: np.ndarray
 ) -> Tuple[np.ndarray, float]:
     gx_distance = np.zeros(x.shape[1])
-    if isinstance(g, float):
+    if g_array is None:
         g_arr = np.full(x.shape[0], g)
     else:
-        if g.shape[0] != x.shape[0]:
+        if g_array.shape[0] != x.shape[0]:
             raise ValueError("g must be a float or an array with shape (x.shape[0],)")
-        g_arr = g
+        g_arr = g_array
     x_sum = 0
 
     for i in range(x.shape[1]):
@@ -231,7 +237,8 @@ def erp_pairwise_distance(
     X: np.ndarray,
     y: np.ndarray = None,
     window: float = None,
-    g: Union[float, np.ndarray] = 0.0,
+    g: float = 0.0,
+    g_arr: np.ndarray = None,
 ) -> np.ndarray:
     """Compute the erp pairwise distance between a set of time series.
 
@@ -251,10 +258,10 @@ def erp_pairwise_distance(
     window: float, default=None
         The window to use for the bounding matrix. If None, no bounding matrix
         is used.
-    g: float or np.ndarray of shape (n_channels), defaults=0
-        The reference value to penalise gaps. The default is 0. If it is an array
-        then it must be the length of the number of channels in x and y. If a single
-        value is provided then that value is used across each channel.
+    g: float.
+        The reference value to penalise gaps. The default is 0.
+    g_arr: np.ndarray of shape (n_channels), defaults=None
+        Numpy array that must be the length of the number of channels in x and y.
 
     Returns
     -------
@@ -297,18 +304,21 @@ def erp_pairwise_distance(
     if y is None:
         # To self
         if X.ndim == 3:
-            return _erp_pairwise_distance(X, window, g)
+            return _erp_pairwise_distance(X, window, g, g_arr)
         if X.ndim == 2:
             _X = X.reshape((X.shape[0], 1, X.shape[1]))
-            return _erp_pairwise_distance(_X, window, g)
+            return _erp_pairwise_distance(_X, window, g, g_arr)
         raise ValueError("x and y must be 2D or 3D arrays")
     _x, _y = reshape_pairwise_to_multiple(X, y)
-    return _erp_from_multiple_to_multiple_distance(_x, _y, window, g)
+    return _erp_from_multiple_to_multiple_distance(_x, _y, window, g, g_arr)
 
 
 @njit(cache=True, fastmath=True)
 def _erp_pairwise_distance(
-    X: np.ndarray, window: float, g: Union[float, np.ndarray]
+    X: np.ndarray,
+    window: float,
+    g: float,
+    g_arr: np.ndarray,
 ) -> np.ndarray:
     n_instances = X.shape[0]
     distances = np.zeros((n_instances, n_instances))
@@ -316,7 +326,7 @@ def _erp_pairwise_distance(
 
     for i in range(n_instances):
         for j in range(i + 1, n_instances):
-            distances[i, j] = _erp_distance(X[i], X[j], bounding_matrix, g)
+            distances[i, j] = _erp_distance(X[i], X[j], bounding_matrix, g, g_arr)
             distances[j, i] = distances[i, j]
 
     return distances
@@ -324,7 +334,11 @@ def _erp_pairwise_distance(
 
 @njit(cache=True, fastmath=True)
 def _erp_from_multiple_to_multiple_distance(
-    x: np.ndarray, y: np.ndarray, window: float, g: Union[float, np.ndarray]
+    x: np.ndarray,
+    y: np.ndarray,
+    window: float,
+    g: float,
+    g_arr: np.ndarray,
 ) -> np.ndarray:
     n_instances = x.shape[0]
     m_instances = y.shape[0]
@@ -333,7 +347,7 @@ def _erp_from_multiple_to_multiple_distance(
 
     for i in range(n_instances):
         for j in range(m_instances):
-            distances[i, j] = _erp_distance(x[i], y[j], bounding_matrix, g)
+            distances[i, j] = _erp_distance(x[i], y[j], bounding_matrix, g, g_arr)
     return distances
 
 
@@ -342,7 +356,8 @@ def erp_alignment_path(
     x: np.ndarray,
     y: np.ndarray,
     window: float = None,
-    g: Union[float, np.ndarray] = 0.0,
+    g: float = 0.0,
+    g_arr: np.ndarray = None,
 ) -> Tuple[List[Tuple[int, int]], float]:
     """Compute the erp alignment path between two time series.
 
@@ -360,10 +375,10 @@ def erp_alignment_path(
     window: float, default=None
         The window to use for the bounding matrix. If None, no bounding matrix
         is used.
-    g: float or np.ndarray of shape (n_channels), defaults=0.
-        The reference value to penalise gaps. The default is 0. If it is an array
-        then it must be the length of the number of channels in x and y. If a single
-        value is provided then that value is used across each channel.
+    g: float.
+        The reference value to penalise gaps. The default is 0.
+    g_arr: np.ndarray of shape (n_channels), defaults=None
+        Numpy array that must be the length of the number of channels in x and y.
 
     Returns
     -------
@@ -390,7 +405,7 @@ def erp_alignment_path(
     """
     bounding_matrix = create_bounding_matrix(x.shape[-1], y.shape[-1], window)
     cost_matrix = _add_inf_to_out_of_bounds_cost_matrix(
-        erp_cost_matrix(x, y, window, g), bounding_matrix
+        erp_cost_matrix(x, y, window, g, g_arr), bounding_matrix
     )
     return (
         compute_min_return_path(cost_matrix),
diff --git a/examples/networks/deep_learning.ipynb b/examples/networks/deep_learning.ipynb
index 273b4b3c..ed24364a 100644
--- a/examples/networks/deep_learning.ipynb
+++ b/examples/networks/deep_learning.ipynb
@@ -91,6 +91,7 @@
    ]
   },
   {
+   "attachments": {},
    "cell_type": "markdown",
    "metadata": {},
    "source": [
@@ -99,7 +100,7 @@
     "#### InceptionTime\n",
     "\n",
     "The InceptionTime model is an ensemble of multiple (by default five) Inception models. Each Inception model is a Convolutional Neural Network made of six Inception modules as seen in the Figure below. Each Inception module is composed of multiple (by default three) convolution layer in parallel and a max-pooling operation as well.\n",
-    "![InceptionTime](img/Inception.png)"
+    "![InceptionTime](./img/Inception.png)"
    ]
   },
   {
@@ -141,13 +142,14 @@
    ]
   },
   {
+   "attachments": {},
    "cell_type": "markdown",
    "metadata": {},
    "source": [
     "#### H-InceptionTime\n",
     "\n",
     "Just as InceptionTime, H-InceptionTime is an ensemble of multiple H-Inception models. The model can be seen in the figure below, where the additional custom filters are added in parallel to the first Inception module.\n",
-    "![H-InceptionTime](img/H-Inception.png)"
+    "![H-InceptionTime](./img/H-Inception.png)"
    ]
   },
   {


Test patch:
diff --git a/aeon/distances/tests/test_numba_distance_parameters.py b/aeon/distances/tests/test_numba_distance_parameters.py
index cded18a7..808f5014 100644
--- a/aeon/distances/tests/test_numba_distance_parameters.py
+++ b/aeon/distances/tests/test_numba_distance_parameters.py
@@ -33,7 +33,9 @@ def _test_distance_params(
         curr_results = []
         for x, y in test_ts:
             if g_none:
-                param_dict["g"] = np.std([x, y], axis=0).sum(axis=1)
+                param_dict["g_arr"] = np.std([x, y], axis=0).sum(axis=1)
+                if "g" in param_dict:
+                    del param_dict["g"]
             results = []
             results.append(distance_func(x, y, **param_dict))
             results.append(distance(x, y, metric=distance_str, **param_dict))