Repository: aeon-toolkit/aeon
Pull request #1753 (2024-07-03 10:50:17)

[MNT] `mrsqm` and `pycatch22` bounds
#### What does this implement/fix? Explain your changes.

Relaxes the bound on these two dependencies as they have received updates since their breakages. Allows `mrsqm` installation on Unix so it is covered in the codecov tests.



aeon-actions-bot[bot]: 
## Thank you for contributing to `aeon`

I have added the following labels to this PR based on the title: **[ $\\color{#EC843A}{\\textsf{maintenance}}$ ]**.


The [Checks](https://github.com/aeon-toolkit/aeon/pull/1753/checks) tab will show the status of our automated tests. You can click on individual test runs in the tab or "Details" in the panel below to see more information if there is a failure.

If our `pre-commit` code quality check fails, any trivial fixes will automatically be pushed to your PR unless it is a draft.

Don't hesitate to ask questions on the `aeon` [Slack](https://join.slack.com/t/aeon-toolkit/shared_invite/zt-22vwvut29-HDpCu~7VBUozyfL_8j3dLA) channel if you have any.

### PR CI actions

These checkboxes will add labels to enable/disable CI functionality for this PR. This may not take effect immediately, and a new commit may be required to run the new configuration.

- [ ] Run `pre-commit` checks for all files
- [ ] Run all `pytest` tests and configurations
- [ ] Run all notebook example tests
- [ ] Run numba-disabled `codecov` tests
- [ ] Stop automatic `pre-commit` fixes (always disabled for drafts)
    

Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 13343d4f..d5b5d8d9 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -3,9 +3,11 @@
   "projectOwner": "aeon-toolkit",
   "repoType": "github",
   "repoHost": "https://github.com",
-  "files": ["CONTRIBUTORS.md"],
+  "files": [
+    "CONTRIBUTORS.md"
+  ],
   "imageSize": 80,
-  "commit": "false"
+  "commit": "false",
   "commitConvention": "atom",
   "contributorsPerLine": 8,
   "contributorsSortAlphabetically": true,
@@ -2436,5 +2438,5 @@
         "doc"
       ]
     }
-  ],
+  ]
 }
diff --git a/.github/workflows/pr_precommit.yml b/.github/workflows/pr_precommit.yml
index 41304f46..d9d60bdd 100644
--- a/.github/workflows/pr_precommit.yml
+++ b/.github/workflows/pr_precommit.yml
@@ -17,19 +17,8 @@ jobs:
     runs-on: ubuntu-20.04
 
     steps:
-      - name: Create app token
-        uses: actions/create-github-app-token@v1
-        id: app-token
-        with:
-          app-id: ${{ vars.PR_APP_ID }}
-          private-key: ${{ secrets.PR_APP_KEY }}
-
       - name: Checkout
         uses: actions/checkout@v4
-        with:
-          repository: ${{ github.event.pull_request.head.repo.full_name }}
-          ref: ${{ github.head_ref }}
-          token: ${{ steps.app-token.outputs.token }}
 
       - name: Setup Python 3.10
         uses: actions/setup-python@v5
@@ -43,6 +32,7 @@ jobs:
       - name: List changed files
         run: echo '${{ steps.changed-files.outputs.all_changed_files }}'
 
+      # only check the full repository if PR and correctly labelled
       - if: ${{ github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'full pre-commit') }}
         name: Full pre-commit
         uses: pre-commit/action@v3.0.1
@@ -54,6 +44,23 @@ jobs:
         with:
           extra_args: --files ${{ steps.changed-files.outputs.all_changed_files }}
 
+      # push fixes if pre-commit fails and PR is eligible
+      - if: ${{ failure() && github.event_name == 'pull_request_target' && !github.event.pull_request.draft && !contains(github.event.pull_request.labels.*.name, 'stop pre-commit fixes') }}
+        name: Create app token
+        uses: actions/create-github-app-token@v1
+        id: app-token
+        with:
+          app-id: ${{ vars.PR_APP_ID }}
+          private-key: ${{ secrets.PR_APP_KEY }}
+
+      - if: ${{ failure() && github.event_name == 'pull_request_target' && !github.event.pull_request.draft && !contains(github.event.pull_request.labels.*.name, 'stop pre-commit fixes') }}
+        name: Checkout
+        uses: actions/checkout@v4
+        with:
+          repository: ${{ github.event.pull_request.head.repo.full_name }}
+          ref: ${{ github.head_ref }}
+          token: ${{ steps.app-token.outputs.token }}
+
       - if: ${{ failure() && github.event_name == 'pull_request_target' && !github.event.pull_request.draft && !contains(github.event.pull_request.labels.*.name, 'stop pre-commit fixes') }}
         name: Push pre-commit fixes
         uses: stefanzweifel/git-auto-commit-action@v5
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
new file mode 100644
index 00000000..7117eebf
--- /dev/null
+++ b/.github/workflows/scorecard.yml
@@ -0,0 +1,50 @@
+# This workflow uses actions that are not certified by GitHub. They are provided
+# by a third-party and are governed by separate terms of service, privacy
+# policy, and support documentation.
+
+name: Scorecard supply-chain security
+on:
+  branch_protection_rule:
+  schedule:
+    - cron: '30 1 * * 7'
+  push:
+    branches: [ "main" ]
+
+permissions: read-all
+
+jobs:
+  analysis:
+    name: Scorecard analysis
+    runs-on: ubuntu-latest
+    permissions:
+      # Needed to upload the results to code-scanning dashboard.
+      security-events: write
+      # Needed to publish results and get a badge (see publish_results below).
+      id-token: write
+
+    steps:
+      - name: "Checkout code"
+        uses: actions/checkout@v4 # v4.1.1
+        with:
+          persist-credentials: false
+
+      - name: "Run analysis"
+        uses: ossf/scorecard-action@v4.13.1
+        with:
+          results_file: results.sarif
+          results_format: sarif
+          publish_results: true
+
+      # Upload the results as artifacts (optional).
+      - name: "Upload artifact"
+        uses: actions/upload-artifact@v3
+        with:
+          name: SARIF file
+          path: results.sarif
+          retention-days: 5
+
+      # Upload the results to GitHub's code scanning dashboard (optional).
+      - name: "Upload to code-scanning"
+        uses: github/codeql-action/upload-sarif@v2
+        with:
+          sarif_file: results.sarif
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 40a03785..80afe396 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -29,7 +29,7 @@ repos:
         args: [ "--create", "--python-folders", "aeon" ]
 
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.4.8
+    rev: v0.5.1
     hooks:
       - id: ruff
         args: [ "--fix"]
@@ -48,7 +48,7 @@ repos:
         args: [ "--profile=black", "--multi-line=3" ]
 
   - repo: https://github.com/pycqa/flake8
-    rev: 7.0.0
+    rev: 7.1.0
     hooks:
       - id: flake8
         additional_dependencies: [ flake8-bugbear, flake8-print, Flake8-pyproject ]
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 10541c02..0a2b990a 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -229,7 +229,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/dasgupsa"><img src="https://avatars2.githubusercontent.com/u/10398956?v=4?s=80" width="80px;" alt="Saurabh Dasgupta"/><br /><sub><b>Saurabh Dasgupta</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=dasgupsa" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/SebasKoel"><img src="https://avatars3.githubusercontent.com/u/66252156?v=4?s=80" width="80px;" alt="Sebastiaan Koel"/><br /><sub><b>Sebastiaan Koel</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=SebasKoel" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=SebasKoel" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/shagn"><img src="https://avatars.githubusercontent.com/u/16029092?v=4?s=80" width="80px;" alt="Sebastian Hagn"/><br /><sub><b>Sebastian Hagn</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=shagn" title="Documentation">📖</a></td>
-      <td align="center" valign="top" width="12.5%"><a href="https://github.com/codelionx"><img src="https://avatars.githubusercontent.com/u/10573700?v=4?s=80" width="80px;" alt="Sebastian Schmidl"/><br /><sub><b>Sebastian Schmidl</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Acodelionx" title="Bug reports">🐛</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=codelionx" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=codelionx" title="Documentation">📖</a> <a href="#research-codelionx" title="Research">🔬</a></td>
+      <td align="center" valign="top" width="12.5%"><a href="https://github.com/codelionx"><img src="https://avatars.githubusercontent.com/u/10573700?v=4?s=80" width="80px;" alt="Sebastian Schmidl"/><br /><sub><b>Sebastian Schmidl</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Acodelionx" title="Bug reports">🐛</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=codelionx" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=codelionx" title="Documentation">📖</a> <a href="#research-codelionx" title="Research">🔬</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=codelionx" title="Tests">⚠️</a> <a href="https://github.com/aeon-toolkit/aeon/pulls?q=is%3Apr+reviewed-by%3Acodelionx" title="Reviewed Pull Requests">👀</a> <a href="#data-codelionx" title="Data">🔣</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/AurumnPegasus"><img src="https://avatars.githubusercontent.com/u/54315149?v=4?s=80" width="80px;" alt="Shivansh Subramanian"/><br /><sub><b>Shivansh Subramanian</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=AurumnPegasus" title="Documentation">📖</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=AurumnPegasus" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://www.linkedin.com/in/solomon-botchway-a1383821b/"><img src="https://avatars.githubusercontent.com/u/62394255?v=4?s=80" width="80px;" alt="Solomon Botchway"/><br /><sub><b>Solomon Botchway</b></sub></a><br /><a href="#maintenance-snnbotchway" title="Maintenance">🚧</a></td>
     </tr>
diff --git a/README.md b/README.md
index be575cde..67de4d49 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ We strive to provide a broad library of time series algorithms including the
 latest advances, offer efficient implementations using numba, and interfaces with other
 time series packages to provide a single framework for algorithm comparison.
 
-The latest `aeon` release is `v0.9.0`. You can view the full changelog
+The latest `aeon` release is `v0.10.0`. You can view the full changelog
 [here](https://www.aeon-toolkit.org/en/stable/changelog.html).
 
 Our webpage and documentation is available at https://aeon-toolkit.org.
@@ -26,7 +26,7 @@ does not apply:
 
 | Overview      |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
 |---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **CI/CD**     | [![github-actions-release](https://img.shields.io/github/actions/workflow/status/aeon-toolkit/aeon/release.yml?logo=github&label=build%20%28release%29)](https://github.com/aeon-toolkit/aeon/actions/workflows/release.yml) [![github-actions-main](https://img.shields.io/github/actions/workflow/status/aeon-toolkit/aeon/pr_pytest.yml?logo=github&branch=main&label=build%20%28main%29)](https://github.com/aeon-toolkit/aeon/actions/workflows/pr_pytest.yml) [![github-actions-nightly](https://img.shields.io/github/actions/workflow/status/aeon-toolkit/aeon/periodic_tests.yml?logo=github&label=build%20%28nightly%29)](https://github.com/aeon-toolkit/aeon/actions/workflows/periodic_tests.yml) [![docs-main](https://img.shields.io/readthedocs/aeon-toolkit/stable?logo=readthedocs&label=docs%20%28stable%29)](https://www.aeon-toolkit.org/en/stable/) [![docs-main](https://img.shields.io/readthedocs/aeon-toolkit/latest?logo=readthedocs&label=docs%20%28latest%29)](https://www.aeon-toolkit.org/en/latest/) [![!codecov](https://img.shields.io/codecov/c/github/aeon-toolkit/aeon?label=codecov&logo=codecov)](https://codecov.io/gh/aeon-toolkit/aeon) |
+| **CI/CD**     | [![github-actions-release](https://img.shields.io/github/actions/workflow/status/aeon-toolkit/aeon/release.yml?logo=github&label=build%20%28release%29)](https://github.com/aeon-toolkit/aeon/actions/workflows/release.yml) [![github-actions-main](https://img.shields.io/github/actions/workflow/status/aeon-toolkit/aeon/pr_pytest.yml?logo=github&branch=main&label=build%20%28main%29)](https://github.com/aeon-toolkit/aeon/actions/workflows/pr_pytest.yml) [![github-actions-nightly](https://img.shields.io/github/actions/workflow/status/aeon-toolkit/aeon/periodic_tests.yml?logo=github&label=build%20%28nightly%29)](https://github.com/aeon-toolkit/aeon/actions/workflows/periodic_tests.yml) [![docs-main](https://img.shields.io/readthedocs/aeon-toolkit/stable?logo=readthedocs&label=docs%20%28stable%29)](https://www.aeon-toolkit.org/en/stable/) [![docs-main](https://img.shields.io/readthedocs/aeon-toolkit/latest?logo=readthedocs&label=docs%20%28latest%29)](https://www.aeon-toolkit.org/en/latest/) [![!codecov](https://img.shields.io/codecov/c/github/aeon-toolkit/aeon?label=codecov&logo=codecov)](https://codecov.io/gh/aeon-toolkit/aeon) [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/aeon-toolkit/aeon/badge)](https://scorecard.dev/viewer/?uri=github.com/aeon-toolkit/aeon)|
 | **Code**      | [![!pypi](https://img.shields.io/pypi/v/aeon?logo=pypi&color=blue)](https://pypi.org/project/aeon/) [![!conda](https://img.shields.io/conda/vn/conda-forge/aeon?logo=anaconda&color=blue)](https://anaconda.org/conda-forge/aeon) [![!python-versions](https://img.shields.io/pypi/pyversions/aeon?logo=python)](https://www.python.org/) [![!black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![license](https://img.shields.io/badge/license-BSD%203--Clause-green?logo=style)](https://github.com/aeon-toolkit/aeon/blob/main/LICENSE) [![binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/aeon-toolkit/aeon/main?filepath=examples)                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
 | **Community** | [![!slack](https://img.shields.io/static/v1?logo=slack&label=Slack&message=chat&color=lightgreen)](https://join.slack.com/t/aeon-toolkit/shared_invite/zt-22vwvut29-HDpCu~7VBUozyfL_8j3dLA) [![!linkedin](https://img.shields.io/static/v1?logo=linkedin&label=LinkedIn&message=news&color=lightblue)](https://www.linkedin.com/company/aeon-toolkit/) [![!twitter](https://img.shields.io/static/v1?logo=twitter&label=Twitter&message=news&color=lightblue)](https://twitter.com/aeon_toolkit)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 
diff --git a/aeon/__init__.py b/aeon/__init__.py
index 3d79daf0..b201632b 100644
--- a/aeon/__init__.py
+++ b/aeon/__init__.py
@@ -1,6 +1,6 @@
 """aeon toolkit."""
 
-__version__ = "0.9.0"
+__version__ = "0.10.0"
 
 __all__ = ["show_versions"]
 
diff --git a/aeon/classification/convolution_based/_arsenal.py b/aeon/classification/convolution_based/_arsenal.py
index 67110631..d1ec88cf 100644
--- a/aeon/classification/convolution_based/_arsenal.py
+++ b/aeon/classification/convolution_based/_arsenal.py
@@ -51,6 +51,17 @@ class Arsenal(BaseClassifier):
         Default of 0 means n_estimators is used.
     contract_max_n_estimators : int, default=100
         Max number of estimators when time_limit_in_minutes is set.
+    class_weight{“balanced”, “balanced_subsample”}, dict or list of dicts, default=None
+        From sklearn documentation:
+        If not given, all classes are supposed to have weight one.
+        The “balanced” mode uses the values of y to automatically adjust weights
+        inversely proportional to class frequencies in the input data as
+        n_samples / (n_classes * np.bincount(y))
+        The “balanced_subsample” mode is the same as “balanced” except that weights
+        are computed based on the bootstrap sample for every tree grown.
+        For multi-output, the weights of each column of y will be multiplied.
+        Note that these weights will be multiplied with sample_weight (passed through
+        the fit method) if sample_weight is specified.
     n_jobs : int, default=1
         The number of jobs to run in parallel for both `fit` and `predict`.
         ``-1`` means using all processors.
@@ -125,6 +136,7 @@ class Arsenal(BaseClassifier):
         n_features_per_kernel=4,
         time_limit_in_minutes=0.0,
         contract_max_n_estimators=100,
+        class_weight=None,
         n_jobs=1,
         random_state=None,
     ):
@@ -136,8 +148,9 @@ class Arsenal(BaseClassifier):
         self.time_limit_in_minutes = time_limit_in_minutes
         self.contract_max_n_estimators = contract_max_n_estimators
 
-        self.random_state = random_state
+        self.class_weight = class_weight
         self.n_jobs = n_jobs
+        self.random_state = random_state
 
         self.n_cases_ = 0
         self.n_channels_ = 0
@@ -355,7 +368,9 @@ class Arsenal(BaseClassifier):
         transformed_x = rocket.fit_transform(X)
         scaler = StandardScaler(with_mean=False)
         scaler.fit(transformed_x, y)
-        ridge = RidgeClassifierCV(alphas=np.logspace(-3, 3, 10))
+        ridge = RidgeClassifierCV(
+            alphas=np.logspace(-3, 3, 10), class_weight=self.class_weight
+        )
         ridge.fit(scaler.transform(transformed_x), y)
         return [
             make_pipeline(rocket, scaler, ridge),
@@ -380,7 +395,9 @@ class Arsenal(BaseClassifier):
 
         clf = make_pipeline(
             StandardScaler(with_mean=False),
-            RidgeClassifierCV(alphas=np.logspace(-3, 3, 10)),
+            RidgeClassifierCV(
+                alphas=np.logspace(-3, 3, 10), class_weight=self.class_weight
+            ),
         )
         clf.fit(Xt[idx][subsample], y[subsample])
         preds = clf.predict(Xt[idx][oob])
diff --git a/aeon/classification/convolution_based/_hydra.py b/aeon/classification/convolution_based/_hydra.py
index 1e53e891..289f4f80 100644
--- a/aeon/classification/convolution_based/_hydra.py
+++ b/aeon/classification/convolution_based/_hydra.py
@@ -25,6 +25,17 @@ class HydraClassifier(BaseClassifier):
         Number of kernels per group.
     n_groups : int, default=64
         Number of groups per dilation.
+    class_weight{“balanced”, “balanced_subsample”}, dict or list of dicts, default=None
+        From sklearn documentation:
+        If not given, all classes are supposed to have weight one.
+        The “balanced” mode uses the values of y to automatically adjust weights
+        inversely proportional to class frequencies in the input data as
+        n_samples / (n_classes * np.bincount(y))
+        The “balanced_subsample” mode is the same as “balanced” except that weights
+        are computed based on the bootstrap sample for every tree grown.
+        For multi-output, the weights of each column of y will be multiplied.
+        Note that these weights will be multiplied with sample_weight (passed through
+        the fit method) if sample_weight is specified.
     n_jobs : int, default=1
         The number of jobs to run in parallel for both `fit` and `predict`.
         ``-1`` means using all processors.
@@ -76,9 +87,12 @@ class HydraClassifier(BaseClassifier):
         "python_dependencies": "torch",
     }
 
-    def __init__(self, n_kernels=8, n_groups=64, n_jobs=1, random_state=None):
+    def __init__(
+        self, n_kernels=8, n_groups=64, class_weight=None, n_jobs=1, random_state=None
+    ):
         self.n_kernels = n_kernels
         self.n_groups = n_groups
+        self.class_weight = class_weight
         self.n_jobs = n_jobs
         self.random_state = random_state
 
@@ -95,7 +109,9 @@ class HydraClassifier(BaseClassifier):
         self._clf = make_pipeline(
             transform,
             _SparseScaler(),
-            RidgeClassifierCV(alphas=np.logspace(-3, 3, 10)),
+            RidgeClassifierCV(
+                alphas=np.logspace(-3, 3, 10), class_weight=self.class_weight
+            ),
         )
         self._clf.fit(X, y)
 
diff --git a/aeon/classification/convolution_based/_mr_hydra.py b/aeon/classification/convolution_based/_mr_hydra.py
index 0005168b..1c036edc 100644
--- a/aeon/classification/convolution_based/_mr_hydra.py
+++ b/aeon/classification/convolution_based/_mr_hydra.py
@@ -23,6 +23,17 @@ class MultiRocketHydraClassifier(BaseClassifier):
         Number of kernels per group for the Hydra transform.
     n_groups : int, default=64
         Number of groups per dilation for the Hydra transform.
+    class_weight{“balanced”, “balanced_subsample”}, dict or list of dicts, default=None
+        From sklearn documentation:
+        If not given, all classes are supposed to have weight one.
+        The “balanced” mode uses the values of y to automatically adjust weights
+        inversely proportional to class frequencies in the input data as
+        n_samples / (n_classes * np.bincount(y))
+        The “balanced_subsample” mode is the same as “balanced” except that weights
+        are computed based on the bootstrap sample for every tree grown.
+        For multi-output, the weights of each column of y will be multiplied.
+        Note that these weights will be multiplied with sample_weight (passed through
+        the fit method) if sample_weight is specified.
     n_jobs : int, default=1
         The number of jobs to run in parallel for both `fit` and `predict`.
         ``-1`` means using all processors.
@@ -70,9 +81,12 @@ class MultiRocketHydraClassifier(BaseClassifier):
         "python_dependencies": "torch",
     }
 
-    def __init__(self, n_kernels=8, n_groups=64, n_jobs=1, random_state=None):
+    def __init__(
+        self, n_kernels=8, n_groups=64, class_weight=None, n_jobs=1, random_state=None
+    ):
         self.n_kernels = n_kernels
         self.n_groups = n_groups
+        self.class_weight = class_weight
         self.n_jobs = n_jobs
         self.random_state = random_state
 
@@ -101,7 +115,9 @@ class MultiRocketHydraClassifier(BaseClassifier):
 
         Xt = np.concatenate((Xt_hydra, Xt_multirocket), axis=1)
 
-        self.classifier = RidgeClassifierCV(alphas=np.logspace(-3, 3, 10))
+        self.classifier = RidgeClassifierCV(
+            alphas=np.logspace(-3, 3, 10), class_weight=self.class_weight
+        )
         self.classifier.fit(Xt, y)
 
         return self
diff --git a/aeon/classification/convolution_based/_rocket_classifier.py b/aeon/classification/convolution_based/_rocket_classifier.py
index 8b68e74c..afe4db4b 100644
--- a/aeon/classification/convolution_based/_rocket_classifier.py
+++ b/aeon/classification/convolution_based/_rocket_classifier.py
@@ -45,14 +45,26 @@ class RocketClassifier(BaseClassifier):
     estimator : sklearn compatible classifier or None, default=None
         The estimator used. If None, a RidgeClassifierCV(alphas=np.logspace(-3, 3, 10))
         is used.
+    class_weight{“balanced”, “balanced_subsample”}, dict or list of dicts, default=None
+        Only applies if estimator is None and the default is used.
+        From sklearn documentation:
+        If not given, all classes are supposed to have weight one.
+        The “balanced” mode uses the values of y to automatically adjust weights
+        inversely proportional to class frequencies in the input data as
+        n_samples / (n_classes * np.bincount(y))
+        The “balanced_subsample” mode is the same as “balanced” except that weights
+        are computed based on the bootstrap sample for every tree grown.
+        For multi-output, the weights of each column of y will be multiplied.
+        Note that these weights will be multiplied with sample_weight (passed through
+        the fit method) if sample_weight is specified.
+    n_jobs : int, default=1
+        The number of jobs to run in parallel for both `fit` and `predict`.
+        ``-1`` means using all processors.
     random_state : int, RandomState instance or None, default=None
         If `int`, random_state is the seed used by the random number generator;
         If `RandomState` instance, random_state is the random number generator;
         If `None`, the random number generator is the `RandomState` instance used
         by `np.random`.
-    n_jobs : int, default=1
-        The number of jobs to run in parallel for both `fit` and `predict`.
-        ``-1`` means using all processors.
 
     Attributes
     ----------
@@ -105,16 +117,19 @@ class RocketClassifier(BaseClassifier):
         max_dilations_per_kernel=32,
         n_features_per_kernel=4,
         estimator=None,
-        random_state=None,
+        class_weight=None,
         n_jobs=1,
+        random_state=None,
     ):
         self.num_kernels = num_kernels
         self.rocket_transform = rocket_transform
         self.max_dilations_per_kernel = max_dilations_per_kernel
         self.n_features_per_kernel = n_features_per_kernel
-        self.random_state = random_state
         self.estimator = estimator
+
+        self.class_weight = class_weight
         self.n_jobs = n_jobs
+        self.random_state = random_state
 
         super().__init__()
 
@@ -168,7 +183,9 @@ class RocketClassifier(BaseClassifier):
         self._scaler = StandardScaler(with_mean=False)
         self._estimator = _clone_estimator(
             (
-                RidgeClassifierCV(alphas=np.logspace(-3, 3, 10))
+                RidgeClassifierCV(
+                    alphas=np.logspace(-3, 3, 10), class_weight=self.class_weight
+                )
                 if self.estimator is None
                 else self.estimator
             ),
diff --git a/aeon/classification/dictionary_based/_muse.py b/aeon/classification/dictionary_based/_muse.py
index 58946246..f2d0a42a 100644
--- a/aeon/classification/dictionary_based/_muse.py
+++ b/aeon/classification/dictionary_based/_muse.py
@@ -73,6 +73,17 @@ class MUSE(BaseClassifier):
         If set to True, a LogisticRegression will be trained, which does support
         predict_proba(), yet is slower and typically less accuracy. predict_proba() is
         needed for example in Early-Classification like TEASER.
+    class_weight{“balanced”, “balanced_subsample”}, dict or list of dicts, default=None
+        From sklearn documentation:
+        If not given, all classes are supposed to have weight one.
+        The “balanced” mode uses the values of y to automatically adjust weights
+        inversely proportional to class frequencies in the input data as
+        n_samples / (n_classes * np.bincount(y))
+        The “balanced_subsample” mode is the same as “balanced” except that weights
+        are computed based on the bootstrap sample for every tree grown.
+        For multi-output, the weights of each column of y will be multiplied.
+        Note that these weights will be multiplied with sample_weight (passed through
+        the fit method) if sample_weight is specified.
     n_jobs : int, default=1
         The number of jobs to run in parallel for both `fit` and `predict`.
         ``-1`` means using all processors.
@@ -136,6 +147,7 @@ class MUSE(BaseClassifier):
         feature_selection="chi2",
         p_threshold=0.05,
         support_probabilities=False,
+        class_weight=None,
         n_jobs=1,
         random_state=None,
     ):
@@ -150,18 +162,20 @@ class MUSE(BaseClassifier):
         self.word_lengths = [4, 6]
         self.bigrams = bigrams
         self.binning_strategies = ["equi-width", "equi-depth"]
-        self.random_state = random_state
         self.min_window = 6
         self.max_window = 100
         self.window_inc = window_inc
         self.window_sizes = []
         self.SFA_transformers = []
         self.clf = None
-        self.n_jobs = n_jobs
         self.support_probabilities = support_probabilities
         self.total_features_count = 0
         self.feature_selection = feature_selection
 
+        self.class_weight = class_weight
+        self.n_jobs = n_jobs
+        self.random_state = random_state
+
         super().__init__()
 
     def _fit(self, X, y):
@@ -242,13 +256,15 @@ class MUSE(BaseClassifier):
 
         # Ridge Classifier does not give probabilities
         if not self.support_probabilities:
-            self.clf = RidgeClassifierCV(alphas=np.logspace(-3, 3, 10))
+            self.clf = RidgeClassifierCV(
+                alphas=np.logspace(-3, 3, 10), class_weight=self.class_weight
+            )
         else:
             self.clf = LogisticRegression(
                 max_iter=5000,
                 solver="liblinear",
                 dual=True,
-                # class_weight="balanced",
+                class_weight=self.class_weight,
                 penalty="l2",
                 random_state=self.random_state,
                 n_jobs=self.n_jobs,
diff --git a/aeon/classification/dictionary_based/_weasel.py b/aeon/classification/dictionary_based/_weasel.py
index 38e2ca41..bb0ab99b 100644
--- a/aeon/classification/dictionary_based/_weasel.py
+++ b/aeon/classification/dictionary_based/_weasel.py
@@ -84,6 +84,17 @@ class WEASEL(BaseClassifier):
         If set to True, a LogisticRegression will be trained, which does support
         predict_proba(), yet is slower and typically less accurate. predict_proba() is
         needed for example in Early-Classification like TEASER.
+    class_weight{“balanced”, “balanced_subsample”}, dict or list of dicts, default=None
+        From sklearn documentation:
+        If not given, all classes are supposed to have weight one.
+        The “balanced” mode uses the values of y to automatically adjust weights
+        inversely proportional to class frequencies in the input data as
+        n_samples / (n_classes * np.bincount(y))
+        The “balanced_subsample” mode is the same as “balanced” except that weights
+        are computed based on the bootstrap sample for every tree grown.
+        For multi-output, the weights of each column of y will be multiplied.
+        Note that these weights will be multiplied with sample_weight (passed through
+        the fit method) if sample_weight is specified.
     random_state : int, RandomState instance or None, default=None
         If `int`, random_state is the seed used by the random number generator;
         If `RandomState` instance, random_state is the random number generator;
@@ -133,9 +144,10 @@ class WEASEL(BaseClassifier):
         window_inc=2,
         p_threshold=0.05,
         alphabet_size=4,
-        n_jobs=1,
         feature_selection="chi2",
         support_probabilities=False,
+        class_weight=None,
+        n_jobs=1,
         random_state=None,
     ):
         self.alphabet_size = alphabet_size
@@ -146,7 +158,6 @@ class WEASEL(BaseClassifier):
         self.word_lengths = [4, 6]
         self.bigrams = bigrams
         self.binning_strategy = binning_strategy
-        self.random_state = random_state
         self.min_window = 6
         self.max_window = 100
         self.feature_selection = feature_selection
@@ -157,9 +168,14 @@ class WEASEL(BaseClassifier):
         self.n_cases = 0
         self.SFA_transformers = []
         self.clf = None
-        self.n_jobs = n_jobs
         self.support_probabilities = support_probabilities
+
+        self.random_state = random_state
+        self.n_jobs = n_jobs
+        self.class_weight = class_weight
+
         set_num_threads(n_jobs)
+
         super().__init__()
 
     def _fit(self, X, y):
@@ -223,13 +239,15 @@ class WEASEL(BaseClassifier):
 
         # Ridge Classifier does not give probabilities
         if not self.support_probabilities:
-            self.clf = RidgeClassifierCV(alphas=np.logspace(-3, 3, 10))
+            self.clf = RidgeClassifierCV(
+                alphas=np.logspace(-3, 3, 10), class_weight=self.class_weight
+            )
         else:
             self.clf = LogisticRegression(
                 max_iter=5000,
                 solver="liblinear",
                 dual=True,
-                # class_weight="balanced",
+                class_weight=self.class_weight,
                 penalty="l2",
                 random_state=self.random_state,
                 n_jobs=self.n_jobs,
diff --git a/aeon/classification/dictionary_based/_weasel_v2.py b/aeon/classification/dictionary_based/_weasel_v2.py
index 01fbf8c9..43eb7198 100644
--- a/aeon/classification/dictionary_based/_weasel_v2.py
+++ b/aeon/classification/dictionary_based/_weasel_v2.py
@@ -80,6 +80,17 @@ class WEASEL_V2(BaseClassifier):
     max_feature_count : int, default=30_000
        size of the dictionary - number of words to use - if feature_selection set to
        "chi2" or "random". Else ignored.
+    class_weight{“balanced”, “balanced_subsample”}, dict or list of dicts, default=None
+        From sklearn documentation:
+        If not given, all classes are supposed to have weight one.
+        The “balanced” mode uses the values of y to automatically adjust weights
+        inversely proportional to class frequencies in the input data as
+        n_samples / (n_classes * np.bincount(y))
+        The “balanced_subsample” mode is the same as “balanced” except that weights
+        are computed based on the bootstrap sample for every tree grown.
+        For multi-output, the weights of each column of y will be multiplied.
+        Note that these weights will be multiplied with sample_weight (passed through
+        the fit method) if sample_weight is specified.
     random_state : int or None, default=None
         If `int`, random_state is the seed used by the random number generator;
         If `None`, the random number generator is the `RandomState` instance used
@@ -127,22 +138,21 @@ class WEASEL_V2(BaseClassifier):
         use_first_differences=(True, False),
         feature_selection="chi2_top_k",
         max_feature_count=30_000,
+        class_weight=None,
+        n_jobs=1,
         random_state=None,
-        n_jobs=4,
     ):
         self.norm_options = norm_options
         self.word_lengths = word_lengths
-
-        self.random_state = random_state
-
         self.min_window = min_window
-
         self.max_feature_count = max_feature_count
         self.use_first_differences = use_first_differences
         self.feature_selection = feature_selection
-
         self.clf = None
+
+        self.class_weight = class_weight
         self.n_jobs = n_jobs
+        self.random_state = random_state
 
         super().__init__()
 
@@ -178,7 +188,9 @@ class WEASEL_V2(BaseClassifier):
         words = self.transform.fit_transform(X, y)
 
         # use RidgeClassifierCV for classification
-        self.clf = RidgeClassifierCV(alphas=np.logspace(-1, 5, 10))
+        self.clf = RidgeClassifierCV(
+            alphas=np.logspace(-1, 5, 10), class_weight=self.class_weight
+        )
         self.clf.fit(words, y)
 
         if hasattr(self.clf, "best_score_"):
diff --git a/aeon/classification/interval_based/_quant.py b/aeon/classification/interval_based/_quant.py
index ea1ebe5c..ee513d51 100644
--- a/aeon/classification/interval_based/_quant.py
+++ b/aeon/classification/interval_based/_quant.py
@@ -36,6 +36,18 @@ class QUANTClassifier(BaseClassifier):
     estimator : sklearn estimator, default=None
         The estimator to use for classification. If None, an ExtraTreesClassifier
         with 200 estimators is used.
+    class_weight{“balanced”, “balanced_subsample”}, dict or list of dicts, default=None
+        Only applies if estimator is None, and the default ExtraTreesClassifier is used.
+        From sklearn documentation:
+        If not given, all classes are supposed to have weight one.
+        The “balanced” mode uses the values of y to automatically adjust weights
+        inversely proportional to class frequencies in the input data as
+        n_samples / (n_classes * np.bincount(y))
+        The “balanced_subsample” mode is the same as “balanced” except that weights
+        are computed based on the bootstrap sample for every tree grown.
+        For multi-output, the weights of each column of y will be multiplied.
+        Note that these weights will be multiplied with sample_weight (passed through
+        the fit method) if sample_weight is specified.
     random_state : int, RandomState instance or None, default=None
         If `int`, random_state is the seed used by the random number generator;
         If `RandomState` instance, random_state is the random number generator;
@@ -75,13 +87,18 @@ class QUANTClassifier(BaseClassifier):
     }
 
     def __init__(
-        self, interval_depth=6, quantile_divisor=4, estimator=None, random_state=None
+        self,
+        interval_depth=6,
+        quantile_divisor=4,
+        estimator=None,
+        class_weight=None,
+        random_state=None,
     ):
         self.interval_depth = interval_depth
         self.quantile_divisor = quantile_divisor
         self.estimator = estimator
+        self.class_weight = class_weight
         self.random_state = random_state
-
         super().__init__()
 
     def _fit(self, X, y):
@@ -107,7 +124,11 @@ class QUANTClassifier(BaseClassifier):
         self._estimator = _clone_estimator(
             (
                 ExtraTreesClassifier(
-                    n_estimators=200, max_features=0.1, criterion="entropy"
+                    n_estimators=200,
+                    max_features=0.1,
+                    criterion="entropy",
+                    class_weight=self.class_weight,
+                    random_state=self.random_state,
                 )
                 if self.estimator is None
                 else self.estimator
diff --git a/aeon/classification/shapelet_based/_rdst.py b/aeon/classification/shapelet_based/_rdst.py
index 7b4fe3d9..b5cdc971 100644
--- a/aeon/classification/shapelet_based/_rdst.py
+++ b/aeon/classification/shapelet_based/_rdst.py
@@ -68,6 +68,18 @@ class RDSTClassifier(BaseClassifier):
         `None` a default `RidgeClassifierCV` classifier is used with standard scalling.
     save_transformed_data : bool, default=False
         If True, the transformed training dataset for all classifiers will be saved.
+    class_weight{“balanced”, “balanced_subsample”}, dict or list of dicts, default=None
+        Only applies if estimator is None, and the default is used.
+        From sklearn documentation:
+        If not given, all classes are supposed to have weight one.
+        The “balanced” mode uses the values of y to automatically adjust weights
+        inversely proportional to class frequencies in the input data as
+        n_samples / (n_classes * np.bincount(y))
+        The “balanced_subsample” mode is the same as “balanced” except that weights
+        are computed based on the bootstrap sample for every tree grown.
+        For multi-output, the weights of each column of y will be multiplied.
+        Note that these weights will be multiplied with sample_weight (passed through
+        the fit method) if sample_weight is specified.
     n_jobs : int, default=1
         The number of jobs to run in parallel for both ``fit`` and ``predict``.
         `-1` means using all processors.
@@ -135,9 +147,10 @@ class RDSTClassifier(BaseClassifier):
         threshold_percentiles=None,
         alpha_similarity: float = 0.5,
         use_prime_dilations: bool = False,
+        distance: str = "manhattan",
         estimator=None,
         save_transformed_data: bool = False,
-        distance: str = "manhattan",
+        class_weight=None,
         n_jobs: int = 1,
         random_state: Union[int, Type[np.random.RandomState], None] = None,
     ) -> None:
@@ -150,8 +163,10 @@ class RDSTClassifier(BaseClassifier):
         self.distance = distance
         self.estimator = estimator
         self.save_transformed_data = save_transformed_data
+        self.class_weight = class_weight
         self.random_state = random_state
         self.n_jobs = n_jobs
+
         self.transformed_data_ = []
 
         self._transformer = None
@@ -195,6 +210,7 @@ class RDSTClassifier(BaseClassifier):
                 StandardScaler(with_mean=True),
                 RidgeClassifierCV(
                     alphas=np.logspace(-4, 4, 20),
+                    class_weight=self.class_weight,
                 ),
             )
         else:
diff --git a/aeon/networks/__init__.py b/aeon/networks/__init__.py
index 28e68570..4f56f2c4 100644
--- a/aeon/networks/__init__.py
+++ b/aeon/networks/__init__.py
@@ -13,7 +13,9 @@ __all__ = [
     "AEFCNNetwork",
     "AEResNetNetwork",
     "LITENetwork",
+    "AEBiGRUNetwork",
 ]
+from aeon.networks._ae_bgru import AEBiGRUNetwork
 from aeon.networks._ae_fcn import AEFCNNetwork
 from aeon.networks._ae_resnet import AEResNetNetwork
 from aeon.networks._cnn import CNNNetwork
diff --git a/aeon/networks/_ae_bgru.py b/aeon/networks/_ae_bgru.py
new file mode 100644
index 00000000..7fc2616f
--- /dev/null
+++ b/aeon/networks/_ae_bgru.py
@@ -0,0 +1,142 @@
+"""Implement Auto-Encoder based on Bidirectional GRUs."""
+
+from aeon.networks.base import BaseDeepLearningNetwork
+
+
+class AEBiGRUNetwork(BaseDeepLearningNetwork):
+    """
+    A class to implement an Auto-Encoder based on Bidirectional GRUs.
+
+    Parameters
+    ----------
+        latent_space_dim : int, default=128
+            Dimension of the latent space.
+        n_layers : int, default=None
+            Number of BiGRU layers. If None, defaults will be used.
+        n_units : list
+            Number of units in each BiGRU layer. If None, defaults will be used.
+        activation : Union[list, str]
+            Activation function(s) to use in each layer.
+            Can be a single string or a list.
+        temporal_latent_space : bool, default = False
+            Flag to choose whether the latent space is an MTS or Euclidean space.
+    """
+
+    _config = {
+        "python_dependencies": ["tensorflow"],
+        "python_version": "<3.12",
+        "structure": "auto-encoder",
+    }
+
+    def __init__(
+        self,
+        latent_space_dim=128,
+        n_layers=None,
+        n_units=None,
+        activation="relu",
+        temporal_latent_space=False,
+    ):
+        super().__init__()
+
+        self.latent_space_dim = latent_space_dim
+        self.activation = activation
+        self.n_layers = n_layers
+        self.n_units = n_units
+        self.temporal_latent_space = temporal_latent_space
+
+    def build_network(self, input_shape, **kwargs):
+        """Construct a network and return its input and output layers.
+
+        Parameters
+        ----------
+        input_shape : tuple of shape = (n_timepoints (m), n_channels (d))
+            The shape of the data fed into the input layer.
+
+        Returns
+        -------
+        encoder : a keras Model.
+        decoder : a keras Model.
+        """
+        import tensorflow as tf
+
+        if self.n_layers is None:
+            if self.n_units is not None:
+                raise ValueError(
+                    """Cannot pass number of units without specifying
+                            number of layers."""
+                )
+            elif self.n_units is None:
+                self._n_layers, self._n_units = 2, [50, self.latent_space_dim // 2]
+        elif self.n_layers is not None:
+            self._n_layers = self.n_layers
+            if self.n_units is None:
+                self._n_units = [50 for _ in range(self.n_layers)]
+                self._n_units[-1] = self.latent_space_dim // 2
+            elif self.n_units is not None:
+                if isinstance(self.n_units, list):
+                    self._n_units = self.n_units
+                    self._n_units[-1] = self.latent_space_dim // 2
+                    assert len(self.n_units) == self.n_layers
+                elif isinstance(self.n_units, int):
+                    self._n_units = [self.n_units for _ in range(self.n_layers)]
+                    self._n_units[-1] = self.latent_space_dim // 2
+
+        if isinstance(self.activation, str):
+            self._activation = [self.activation for _ in range(self._n_layers)]
+        else:
+            self._activation = self.activation
+            assert isinstance(self.activation, list)
+            assert len(self.activation) == self._n_layers
+
+        encoder_inputs = tf.keras.layers.Input(shape=input_shape, name="encoder_input")
+        x = encoder_inputs
+        for i in range(self._n_layers):
+            return_sequences = i < self._n_layers - 1
+            if self.temporal_latent_space:
+                return_sequences = i < self._n_layers
+            x = tf.keras.layers.Bidirectional(
+                tf.keras.layers.GRU(
+                    units=self._n_units[i],
+                    activation=self._activation[i],
+                    return_sequences=return_sequences,
+                ),
+                name=f"encoder_bgru_{i+1}",
+            )(x)
+
+        latent_space = tf.keras.layers.Dense(
+            self.latent_space_dim, activation="linear", name="latent_space"
+        )(x)
+        encoder_model = tf.keras.models.Model(
+            inputs=encoder_inputs, outputs=latent_space, name="encoder"
+        )
+
+        if not self.temporal_latent_space:
+            decoder_inputs = tf.keras.layers.Input(
+                shape=(self.latent_space_dim,), name="decoder_input"
+            )
+            x = tf.keras.layers.RepeatVector(input_shape[0], name="repeat_vector")(
+                decoder_inputs
+            )
+        elif self.temporal_latent_space:
+            decoder_inputs = tf.keras.layers.Input(
+                shape=latent_space.shape[1:], name="decoder_input"
+            )
+            x = decoder_inputs
+
+        for i in range(self._n_layers - 1, -1, -1):
+            x = tf.keras.layers.Bidirectional(
+                tf.keras.layers.GRU(
+                    units=self._n_units[i],
+                    activation=self._activation[i],
+                    return_sequences=True,
+                ),
+                name=f"decoder_bgru_{i+1}",
+            )(x)
+        decoder_outputs = tf.keras.layers.TimeDistributed(
+            tf.keras.layers.Dense(input_shape[1]), name="decoder_output"
+        )(x)
+        decoder_model = tf.keras.models.Model(
+            inputs=decoder_inputs, outputs=decoder_outputs, name="decoder"
+        )
+
+        return encoder_model, decoder_model
diff --git a/aeon/segmentation/base.py b/aeon/segmentation/base.py
index ea74127c..6bb6020c 100644
--- a/aeon/segmentation/base.py
+++ b/aeon/segmentation/base.py
@@ -16,49 +16,11 @@ from aeon.base._base_series import VALID_INPUT_TYPES
 class BaseSegmenter(BaseSeriesEstimator, ABC):
     """Base class for segmentation algorithms.
 
-    Segmenters take a single time series of length $m$ and returns a segmentation.
-    Series can be univariate (single series) or multivariate, with $d$ dimensions.
-
-    Input and internal data format
-        Univariate series:
-            Numpy array:
-            shape `(m,)`, `(m, 1)` or `(1, m)`. if ``self`` has no multivariate
-            capability, i.e.``self.get_tag(
-            ""capability:multivariate") == False``, all are converted to 1D
-            numpy `(m,)`
-            if ``self`` has multivariate capability, converted to 2D numpy `(m,1)` or
-            `(1, m)` depending on axis
-            pandas DataFrame or Series:
-            DataFrame single column shape `(m,1)`, `(1,m)` or Series shape `(m,)`
-            if ``self`` has no multivariate capability, all converted to Series `(m,)`
-            if ``self`` has multivariate capability, all converted to Pandas DataFrame
-            shape `(m,1)`, `(1,m)` depending on axis
-
-        Multivariate series:
-            Numpy array, shape `(m,d)` or `(d,m)`.
-            pandas DataFrame `(m,d)` or `(d,m)`
-
-    Conversion and axis resolution for multivariate
-
-        Conversion between numpy and pandas is handled by the base class. Sub classses
-        can assume the data is in the correct format (determined by
-        ``"X_inner_type"``, one of ``aeon.base._base_series.VALID_INNER_TYPES)`` and
-        represented with the expected
-        axis.
-
-        Multivariate series are segmented along an axis determined by ``self.axis``.
-        Axis plays two roles:
-
-        1) the axis the segmenter expects the data to be in for its internal methods
-        ``_fit`` and ``_predict``: 0 means each column is a time series, and the data is
-        shaped `(m,d)`, axis equal to 1 means each row is a time series, sometimes
-        called wide format, and the whole series is shape `(d,m)`. This should be set
-        for a given child class through the BaseSegmenter constructor.
-
-        2) The optional ``axis`` argument passed to the base class ``fit`` and
-        ``predict`` methods. If the data ``axis`` is different to the ``axis``
-        expected (i.e. value stored in ``self.axis``, then it is transposed in this
-        base class if self has multivariate capability.
+    Segmenters take a single time series of length ``n_timepoints`` and returns a
+    segmentation. Series can be univariate (single series) or multivariate,
+    with ``n_channels`` dimensions. If the segmenter can handle multivariate series,
+    if will have the tag ``"capability:multivariate"`` set to True. Multivariate
+    series are segmented along a the axis of time determined by ``self.axis``.
 
     Segmentation representation
 
@@ -66,7 +28,7 @@ class BaseSegmenter(BaseSeriesEstimator, ABC):
         and 8.
 
         The segmentation can be output in two forms:
-        a) A list of change points.
+        a) A list of change points (tag ``"returns_dense"`` is True).
             output example [4,8] for a series length 10 means three segments at
             positions (0,1,2,3), (4,5,6,7) and (8,9).
             This dense representation is the default behaviour, as it is the minimal
@@ -76,7 +38,8 @@ class BaseSegmenter(BaseSeriesEstimator, ABC):
             last less than the series length. If the last value is
             ``n_timepoints-1`` then the last point forms a single segment. An empty
             list indicates no change points.
-        b) A list of integers of length m indicating the segment of each time point:
+        b) A list of integers of length m indicating the segment of each time point (
+        tag ``"returns_dense"`` is False).
             output [0,0,0,0,1,1,1,1,2,2] or output [0,0,0,1,1,1,1,0,0,0]
             This sparse representation can be used to indicate shared segments
             indicating segment 1 is somehow the same (perhaps in generative process)
@@ -87,15 +50,16 @@ class BaseSegmenter(BaseSeriesEstimator, ABC):
 
     Parameters
     ----------
-    n_segments : int, default = 2
-        Number of segments to split the time series into. If None, then the number of
-        segments needs to be found in fit.
-    axis : int, default = 1
+    axis : int
         Axis along which to segment if passed a multivariate series (2D input). If axis
         is 0, it is assumed each column is a time series and each row is a
         timepoint. i.e. the shape of the data is ``(n_timepoints,n_channels)``.
         ``axis == 1`` indicates the time series are in rows, i.e. the shape of the data
-        is ``(n_channels, n_timepoints)`.
+        is ``(n_channels, n_timepoints)`. Each segmenter must specify the axis it
+        assumes in the constructor and pass it to the base class.
+    n_segments : int, default = 2
+        Number of segments to split the time series into. If None, then the number of
+        segments needs to be found in fit.
 
     """
 
@@ -124,7 +88,7 @@ class BaseSegmenter(BaseSeriesEstimator, ABC):
         Parameters
         ----------
         X : One of ``VALID_INPUT_TYPES``
-            Input time series
+            Input time series to fit a segmenter.
         y : One of ``VALID_INPUT_TYPES`` or None, default None
             Training time series, a labeled 1D series same length as X for supervised
             segmentation.
diff --git a/aeon/transformations/collection/base.py b/aeon/transformations/collection/base.py
index 623d13a4..a69f642c 100644
--- a/aeon/transformations/collection/base.py
+++ b/aeon/transformations/collection/base.py
@@ -205,7 +205,6 @@ class BaseCollectionTransformer(
         self.reset()
         X_inner = self._preprocess_collection(X)
         y_inner = y
-
         Xt = self._fit_transform(X=X_inner, y=y_inner)
 
         self._is_fitted = True
diff --git a/aeon/transformations/collection/convolution_based/_minirocket.py b/aeon/transformations/collection/convolution_based/_minirocket.py
index c92467ff..e413bb16 100644
--- a/aeon/transformations/collection/convolution_based/_minirocket.py
+++ b/aeon/transformations/collection/convolution_based/_minirocket.py
@@ -15,34 +15,47 @@ from aeon.transformations.collection import BaseCollectionTransformer
 class MiniRocket(BaseCollectionTransformer):
     """MINImally RandOm Convolutional KErnel Transform (MiniRocket).
 
-    MiniRocket [1]_ is an almost deterministic version of Rocket. It creates
-    convolutions of length 9 with weights restricted to two values, and uses 84 fixed
-    convolutions with six of one weight, three of the second weight to seed dilations.
+     MiniRocket [1]_ is an almost deterministic version of Rocket. It creates
+     convolutions of length 9 with weights restricted to two values, and uses 84 fixed
+     convolutions with six of one weight, three of the second weight to seed dilations.
 
 
     Parameters
     ----------
-    num_kernels : int, default=10,000
-       Number of random convolutional kernels.
-    max_dilations_per_kernel : int, default=32
-        Maximum number of dilations per kernel.
-    n_jobs : int, default=1
-        The number of jobs to run in parallel for `transform`. ``-1`` means using all
-        processors.
-    random_state : None or int, default = None
-        Seed for random number generation.
+     num_kernels : int, default=10,000
+        Number of random convolutional kernels. The number of kernels used is rounded
+        down to the nearest multiple of 84, unless a value of less than 84 is passec,
+        in which case it is set to 84.
+     max_dilations_per_kernel : int, default=32
+         Maximum number of dilations per kernel.
+     n_jobs : int, default=1
+         The number of jobs to run in parallel for `transform`. ``-1`` means using all
+         processors.
+     random_state : None or int, default = None
+         Seed for random number generation.
+
+    Attributes
+    ----------
+     self.parameters : Tuple (int32[:], int32[:], int32[:], int32[:], float32[:])
+         n_channels_per_comb, channel_indices, dilations, n_features_per_dilation,
+         biases
 
     See Also
     --------
-    MiniRocket, Rocket
+     Rocket, MultiRocket, Hydra
 
     References
     ----------
-    .. [1] Dempster, Angus and Schmidt, Daniel F and Webb, Geoffrey I,
-        "MINIROCKET: A Very Fast (Almost) Deterministic Transform for Time Series
-        Classification",2020,
-        https://dl.acm.org/doi/abs/10.1145/3447548.3467231,
-        https://arxiv.org/abs/2012.08791
+     .. [1] Dempster, Angus and Schmidt, Daniel F and Webb, Geoffrey I,
+         "MINIROCKET: A Very Fast (Almost) Deterministic Transform for Time Series
+         Classification",2020,
+         https://dl.acm.org/doi/abs/10.1145/3447548.3467231,
+         https://arxiv.org/abs/2012.08791
+
+    Notes
+    -----
+     Directly adapted from the original implementation
+     https://github.com/angus924/minirocket.
 
     Examples
     --------
@@ -101,8 +114,12 @@ class MiniRocket(BaseCollectionTransformer):
                 " zero pad shorter series so that n_timepoints == 9"
             )
         X = X.astype(np.float32)
+        if self.num_kernels < 84:
+            self.num_kernels_ = 84
+        else:
+            self.num_kernels_ = self.num_kernels
         self.parameters = _static_fit(
-            X, self.num_kernels, self.max_dilations_per_kernel, random_state
+            X, self.num_kernels_, self.max_dilations_per_kernel, random_state
         )
         return self
 
@@ -128,7 +145,11 @@ class MiniRocket(BaseCollectionTransformer):
         else:
             n_jobs = self.n_jobs
         set_num_threads(n_jobs)
-        X_ = _static_transform(X, self.parameters, MiniRocket._indices)
+        if n_channels == 1:
+            X = X.squeeze(1)
+            X_ = _static_transform_uni(X, self.parameters, MiniRocket._indices)
+        else:
+            X_ = _static_transform_multi(X, self.parameters, MiniRocket._indices)
         set_num_threads(prev_threads)
         return X_
 
@@ -215,6 +236,73 @@ def _PPV(a, b):
     return 0
 
 
+@njit(
+    "float32[:,:](float32[:,:],Tuple((int32[:],int32[:],int32[:],int32[:],float32["
+    ":])), int32[:,:])",
+    fastmath=True,
+    parallel=True,
+    cache=True,
+)
+def _static_transform_uni(X, parameters, indices):
+    """Transform a 2D collection of univariate time series.
+
+    Implemented separately to the multivariate version for numba efficiency reasons.
+    See issue #1778.
+    """
+    n_cases, n_timepoints = X.shape
+    (
+        _,
+        _,
+        dilations,
+        n_features_per_dilation,
+        biases,
+    ) = parameters
+    n_kernels = len(indices)
+    n_dilations = len(dilations)
+    f = n_kernels * np.sum(n_features_per_dilation)
+    features = np.zeros((n_cases, f), dtype=np.float32)
+    for i in prange(n_cases):
+        _X = X[i]
+        A = -_X
+        G = 3 * _X
+        f_start = 0
+        for j in range(n_dilations):
+            _padding0 = j % 2
+            dilation = dilations[j]
+            padding = (8 * dilation) // 2
+            n_features = n_features_per_dilation[j]
+            C_alpha = np.zeros(n_timepoints, dtype=np.float32)
+            C_alpha[:] = A
+            C_gamma = np.zeros((9, n_timepoints), dtype=np.float32)
+            C_gamma[4] = G
+            start = dilation
+            end = n_timepoints - padding
+            for gamma_index in range(4):
+                C_alpha[-end:] = C_alpha[-end:] + A[:end]
+                C_gamma[gamma_index, -end:] = G[:end]
+                end += dilation
+            for gamma_index in range(5, 9):
+                C_alpha[:-start] = C_alpha[:-start] + A[start:]
+                C_gamma[gamma_index, :-start] = G[start:]
+                start += dilation
+            for k in range(n_kernels):
+                f_end = f_start + n_features
+                _padding1 = (_padding0 + k) % 2
+                a, b, c = indices[k]
+                C = C_alpha + C_gamma[a] + C_gamma[b] + C_gamma[c]
+                if _padding1 == 0:
+                    for f in range(n_features):
+                        features[i, f_start + f] = _PPV(C, biases[f_start + f]).mean()
+                else:
+                    for f in range(n_features):
+                        features[i, f_start + f] = _PPV(
+                            C[padding:-padding], biases[f_start + f]
+                        ).mean()
+
+                f_start = f_end
+    return features
+
+
 @njit(
     "float32[:,:](float32[:,:,:],Tuple((int32[:],int32[:],int32[:],int32[:],float32["
     ":])), int32[:,:])",
@@ -222,8 +310,8 @@ def _PPV(a, b):
     parallel=True,
     cache=True,
 )
-def _static_transform(X, parameters, indices):
-    n_cases, n_columns, n_timepoints = X.shape
+def _static_transform_multi(X, parameters, indices):
+    n_cases, n_channels, n_timepoints = X.shape
     (
         n_channels_per_combination,
         channel_indices,
@@ -235,68 +323,62 @@ def _static_transform(X, parameters, indices):
     n_dilations = len(dilations)
     n_features = n_kernels * np.sum(n_features_per_dilation)
     features = np.zeros((n_cases, n_features), dtype=np.float32)
-    for example_index in prange(n_cases):
-        _X = X[example_index]
-        A = -_X  # A = alpha * X = -X
-        G = _X + _X + _X  # G = gamma * X = 3X
-        feature_index_start = 0
-        combination_index = 0
+    for i in prange(n_cases):
+        _X = X[i]
+        A = -_X
+        G = 3 * _X
+        f_start = 0
+        comb = 0
         n_channels_start = 0
-        for dilation_index in range(n_dilations):
-            _padding0 = dilation_index % 2
-            dilation = dilations[dilation_index]
-            padding = ((9 - 1) * dilation) // 2
-            n_features_this_dilation = n_features_per_dilation[dilation_index]
-            C_alpha = np.zeros((n_columns, n_timepoints), dtype=np.float32)
+        for j in range(n_dilations):
+            _padding0 = j % 2
+            dilation = dilations[j]
+            padding = (8 * dilation) // 2
+            n_features_this_dilation = n_features_per_dilation[j]
+            C_alpha = np.zeros((n_channels, n_timepoints), dtype=np.float32)
             C_alpha[:] = A
-            C_gamma = np.zeros((9, n_columns, n_timepoints), dtype=np.float32)
-            C_gamma[9 // 2] = G
+            C_gamma = np.zeros((9, n_channels, n_timepoints), dtype=np.float32)
+            C_gamma[4] = G
             start = dilation
             end = n_timepoints - padding
-            for gamma_index in range(9 // 2):
+            for gamma_index in range(4):
                 C_alpha[:, -end:] = C_alpha[:, -end:] + A[:, :end]
                 C_gamma[gamma_index, :, -end:] = G[:, :end]
                 end += dilation
 
-            for gamma_index in range(9 // 2 + 1, 9):
+            for gamma_index in range(5, 9):
                 C_alpha[:, :-start] = C_alpha[:, :-start] + A[:, start:]
                 C_gamma[gamma_index, :, :-start] = G[:, start:]
                 start += dilation
 
             for kernel_index in range(n_kernels):
-                feature_index_end = feature_index_start + n_features_this_dilation
-                n_channels_this_combination = n_channels_per_combination[
-                    combination_index
-                ]
-                num_channels_end = n_channels_start + n_channels_this_combination
-                channels_this_combination = channel_indices[
-                    n_channels_start:num_channels_end
-                ]
+                f_end = f_start + n_features_this_dilation
+                n_channels_this_combo = n_channels_per_combination[comb]
+                n_channels_end = n_channels_start + n_channels_this_combo
+                channels_this_combo = channel_indices[n_channels_start:n_channels_end]
                 _padding1 = (_padding0 + kernel_index) % 2
                 index_0, index_1, index_2 = indices[kernel_index]
                 C = (
-                    C_alpha[channels_this_combination]
-                    + C_gamma[index_0][channels_this_combination]
-                    + C_gamma[index_1][channels_this_combination]
-                    + C_gamma[index_2][channels_this_combination]
+                    C_alpha[channels_this_combo]
+                    + C_gamma[index_0][channels_this_combo]
+                    + C_gamma[index_1][channels_this_combo]
+                    + C_gamma[index_2][channels_this_combo]
                 )
                 C = np.sum(C, axis=0)
                 if _padding1 == 0:
                     for feature_count in range(n_features_this_dilation):
-                        features[example_index, feature_index_start + feature_count] = (
-                            _PPV(C, biases[feature_index_start + feature_count]).mean()
-                        )
+                        features[i, f_start + feature_count] = _PPV(
+                            C, biases[f_start + feature_count]
+                        ).mean()
                 else:
                     for feature_count in range(n_features_this_dilation):
-                        features[example_index, feature_index_start + feature_count] = (
-                            _PPV(
-                                C[padding:-padding],
-                                biases[feature_index_start + feature_count],
-                            ).mean()
-                        )
-                feature_index_start = feature_index_end
-                combination_index += 1
-                n_channels_start = num_channels_end
+                        features[i, f_start + feature_count] = _PPV(
+                            C[padding:-padding],
+                            biases[f_start + feature_count],
+                        ).mean()
+                f_start = f_end
+                comb += 1
+                n_channels_start = n_channels_end
     return features
 
 
diff --git a/aeon/transformations/collection/convolution_based/_rocket.py b/aeon/transformations/collection/convolution_based/_rocket.py
index 35922439..f8500a36 100644
--- a/aeon/transformations/collection/convolution_based/_rocket.py
+++ b/aeon/transformations/collection/convolution_based/_rocket.py
@@ -113,13 +113,13 @@ class Rocket(BaseCollectionTransformer):
 
         Parameters
         ----------
-        X : 3D np.ndarray of shape = [n_cases, n_channels, n_timepoints]
+        X : 3D np.ndarray of shape = (n_cases, n_channels, n_timepoints)
             collection of time series to transform
         y : ignored argument for interface compatibility
 
         Returns
         -------
-        np.ndarray [n_cases, num_kernels], transformed features
+        np.ndarray (n_cases, num_kernels), transformed features
         """
         if self.normalise:
             X = (X - X.mean(axis=-1, keepdims=True)) / (
@@ -221,7 +221,7 @@ def _apply_kernel_univariate(X, weights, length, bias, dilation, padding):
     output_length = (n_timepoints + (2 * padding)) - ((length - 1) * dilation)
 
     _ppv = 0
-    _max = np.NINF
+    _max = -np.inf
 
     end = (n_timepoints + padding) - ((length - 1) * dilation)
 
@@ -254,28 +254,20 @@ def _apply_kernel_multivariate(
     output_length = (n_timepoints + (2 * padding)) - ((length - 1) * dilation)
 
     _ppv = 0
-    _max = np.NINF
-
+    _max = -np.inf
     end = (n_timepoints + padding) - ((length - 1) * dilation)
-
     for i in range(-padding, end):
         _sum = bias
-
         index = i
-
         for j in range(length):
             if index > -1 and index < n_timepoints:
                 for k in range(num_channel_indices):
                     _sum = _sum + weights[k, j] * X[channel_indices[k], index]
-
             index = index + dilation
-
         if _sum > _max:
             _max = _sum
-
         if _sum > 0:
             _ppv += 1
-
     return np.float32(_ppv / output_length), np.float32(_max)
 
 
diff --git a/build_tools/pr_labeler.py b/build_tools/pr_labeler.py
index d4293aef..35e781ef 100644
--- a/build_tools/pr_labeler.py
+++ b/build_tools/pr_labeler.py
@@ -31,17 +31,17 @@ elif "[bot]" in pr.user.login:
 title = pr.title
 
 title_regex_to_labels = [
-    (r"\bENH\b", "enhancement"),
-    (r"\bMNT\b", "maintenance"),
-    (r"\bBUG\b", "bug"),
-    (r"\bDOC\b", "documentation"),
-    (r"\bREF\b", "refactor"),
-    (r"\bDEP\b", "deprecation"),
-    (r"\bGOV\b", "governance"),
+    (r"\benh\b", "enhancement"),
+    (r"\bmnt\b", "maintenance"),
+    (r"\bbug\b", "bug"),
+    (r"\bdoc\b", "documentation"),
+    (r"\bref\b", "refactor"),
+    (r"\bdep\b", "deprecation"),
+    (r"\bgov\b", "governance"),
 ]
 
 title_labels = [
-    label for regex, label in title_regex_to_labels if re.search(regex, title)
+    label for regex, label in title_regex_to_labels if re.search(regex, title.lower())
 ]
 title_labels_to_add = list(set(title_labels) - set(labels))
 
diff --git a/docs/changelog.md b/docs/changelog.md
index a47cfeff..0efb119d 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -1,14 +1,15 @@
 # Changelog
 
 All notable changes to this project will be documented in this file. The format is
-based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and we adhere
+based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and we adhere
 to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The source code for
 all [releases](https://github.com/aeon-toolkit/aeon/releases) is available on GitHub.
 
-To stay up-to-date with aeon releases, subscribe to aeon
+To stay up to date with aeon releases, subscribe to aeon
 [here](https://libraries.io/pypi/aeon) or follow us on
 [Twitter](https://twitter.com/aeon_toolbox).
 
+- [Version 0.10.0](changelogs/v0.10.md)
 - [Version 0.9.0](changelogs/v0.9.md)
 - [Version 0.8.0](changelogs/v0.8.md)
 - [Version 0.7.0](changelogs/v0.7.md)
diff --git a/docs/changelogs/v0.10.md b/docs/changelogs/v0.10.md
new file mode 100644
index 00000000..31dbe01f
--- /dev/null
+++ b/docs/changelogs/v0.10.md
@@ -0,0 +1,307 @@
+# v0.10.0
+
+July 2024
+
+## Highlights
+
+- Dropped support for Python 3.8
+- Announcement of deprecations for v1.0.0, includes removal and rework of the current forecasting and transformation frameworks
+- New anomaly detection methods: DWT-MLEAD, K-Means, and an adapter for PyOD ({user}`CodeLionX`)
+- New data loaders for anomaly detection and segmentation benchmark archives ({user}`CodeLionX`, {user}`ermshaua`)
+- New Proximity Tree classifier using aeon distances, Proximity Forest to follow. ({user}`itsdivya1309`)
+- New feature-based and dummy clusterers ({user}`MatthewMiddlehurst`, {user}`aadya940`)
+- New FLUSS and BinSeg segmenters ({user}`patrickzib`)
+- Addition of visualisation tools for shapelets ({user}`baraline`)
+
+## Anomaly Detection
+
+### Documentation
+
+- [DOC] Improve anomaly detector documentation ({pr}`1647`) {user}`CodeLionX`
+- [DOC] added reference to docstring of MERLIN anomaly detection ({pr}`1707`) {user}`adm-unl`
+
+### Enhancements
+
+- [MNT] Move haar wavelet transform to aeon.utils.numba package ({pr}`1579`) {user}`CodeLionX`
+- [ENH] Convert stray and add max iterations for MERLIN ({pr}`1571`) {user}`MatthewMiddlehurst`
+- [ENH] DWT-MLEAD anomaly detection method ({pr}`1580`) {user}`CodeLionX`
+- [ENH] Add sliding window utils for anomaly detection module ({pr}`1605`) {user}`CodeLionX`
+- [ENH] K-Means anomaly detector ({pr}`1607`) {user}`CodeLionX`
+- [ENH] Loader for TimeEval (anomaly detection) datasets ({pr}`1588`) {user}`CodeLionX`
+- [ENH] Add PyOD adapter for anomaly detection ({pr}`1586`) {user}`CodeLionX`
+
+## Classification
+
+### Bug Fixes
+
+- [BUG] Fixing wrong output activation in MLPClassifier ({pr}`1597`) {user}`hadifawaz1999`
+- [ENH,BUG] LearnedShapelets interfaced functions ({pr}`1687`) {user}`TonyBagnall`
+- [BUG] Adding modelcheckpoint callback by default to deep learners when user chooses their own callbacks list ({pr}`1763`) {user}`hadifawaz1999`
+- [BUG] Store n_timepoints and n_channels in fit to check in transform ({pr}`1758`) {user}`TonyBagnall`
+
+### Deprecation
+
+- [DEP] Rocket,RotationForest and FreshPrince deprecations (plus a bug fix) ({pr}`1648`) {user}`TonyBagnall`
+
+### Documentation
+
+- [DOC] remove ProximityTree from distance classifier notebook results display ({pr}`1745`) {user}`TonyBagnall`
+- [DOC] typo in convolutions notebook ({pr}`1769`) {user}`TonyBagnall`
+
+### Enhancements
+
+- [ENH,BUG] LearnedShapelets interfaced functions ({pr}`1687`) {user}`TonyBagnall`
+- [ENH] Tidy, deprecation actions and testing for sklearn estimators ({pr}`1701`) {user}`MatthewMiddlehurst`
+- [ENH] Implement Proximity Tree classifier using aeon distances ({pr}`1566`) {user}`itsdivya1309`
+- [ENH] REDCOMETS tweaks / fixes ({pr}`1722`) {user}`zy18811`
+- [ENH] change input type for MrSQMClassifier and deprecate prior to moving package ({pr}`1735`) {user}`TonyBagnall`
+- [ENH] Adds class_weight to those classifier that support it. Required for imbalanced datasets. ({pr}`1776`) {user}`patrickzib`
+
+## Clustering
+
+### Bug Fixes
+
+- [BUG] Remove feature extraction from `TSFreshClusterer` ({pr}`1716`) {user}`MatthewMiddlehurst`
+- [BUG] Cluster predict proba edge cases ({pr}`1739`) {user}`chrisholder`
+- [BUG] Adding modelcheckpoint callback by default to deep learners when user chooses their own callbacks list ({pr}`1763`) {user}`hadifawaz1999`
+
+### Documentation
+
+- [DOC] Wrong number of reference in Clara ({pr}`1640`) {user}`futuer-szd`
+
+### Enhancements
+
+- [ENH] Add DummyClusterer ({pr}`1567`) {user}`aadya940`
+- [ENH] Simple feature based clusterers ({pr}`1548`) {user}`MatthewMiddlehurst`
+- [ENH] removed unused attribute from k-means ({pr}`1727`) {user}`chrisholder`
+
+## Datasets
+
+### Bug Fixes
+
+- [BUG] Fix TSAD data loading tests and example notebooks ({pr}`1695`) {user}`CodeLionX`
+
+### Enhancements
+
+- [ENH] Loader for TimeEval (anomaly detection) datasets ({pr}`1588`) {user}`CodeLionX`
+- [ENH] Time Series Segmentation Benchmark + Human Activity Segmentation Challenge data loaders ({pr}`1755`) {user}`ermshaua`
+
+### Maintenance
+
+- [MNT] Set segmentation data loaders for overnight tests only ({pr}`1772`) {user}`TonyBagnall`
+
+## Distances
+
+### Bug Fixes
+
+- [BUG] lcss bounded below to 0 ({pr}`1610`) {user}`TonyBagnall`
+- [BUG] Bugfix MinDist doctests by setting word_length to 8 ({pr}`1690`) {user}`patrickzib`
+
+### Enhancements
+
+- [ENH] Lower Bounding Distances for SAX and SFA ({pr}`1622`) {user}`patrickzib`
+
+## Forecasting
+
+WARNING: The current forecasting framework is being removed in v1.0.0. To be replaced
+with a new framework. See the index page for more information.
+
+### Bug Fixes
+
+- [BUG] remove none argument for coerce to period ({pr}`1514`) {user}`TonyBagnall`
+- [BUG] unexclude mock forecaster ({pr}`1609`) {user}`TonyBagnall`
+
+## Networks
+
+### Deprecation
+
+- [DEP] Rename `BaseDeepNetwork` and deprecate inheritance of `BaseObject` ({pr}`1524`) {user}`MatthewMiddlehurst`
+
+### Maintenance
+
+- [MNT] Enhance networks module testing suite ({pr}`1631`) {user}`aadya940`
+
+## Regression
+
+### Bug Fixes
+
+- [BUG] Remove squaring distances in KNN regression ({pr}`1697`) {user}`TonyBagnall`
+- [BUG] Adding modelcheckpoint callback by default to deep learners when user chooses their own callbacks list ({pr}`1763`) {user}`hadifawaz1999`
+
+### Deprecation
+
+- [DEP] Rocket,RotationForest and FreshPrince deprecations (plus a bug fix) ({pr}`1648`) {user}`TonyBagnall`
+
+### Documentation
+
+- [DOC] Added All Regressors (2nd Attempt) ({pr}`1663`) {user}`Moonzyyy`
+
+### Enhancements
+
+- [ENH] Tidy, deprecation actions and testing for sklearn estimators ({pr}`1701`) {user}`MatthewMiddlehurst`
+
+## Segmentation
+
+### Enhancements
+
+- [ENH] `axis=1` function default and removal of axis class default for series transformation and segmentation ({pr}`1625`) {user}`MatthewMiddlehurst`
+- [ENH] Add FLUSS segmenter from stumpy ({pr}`1693`) {user}`patrickzib`
+- [ENH] ClaSP: Adds parallelization for distance computations and numbarize function calls ({pr}`1692`) {user}`patrickzib`
+- [ENH] Adds BinSeg Segmenter from Ruptures library ({pr}`1694`) {user}`patrickzib`
+- [ENH] Time Series Segmentation Benchmark + Human Activity Segmentation Challenge data loaders ({pr}`1755`) {user}`ermshaua`
+
+## Similarity Search
+
+### Enhancements
+
+- [ENH] Update similarity search with new base classes : Query Search ({pr}`1508`) {user}`baraline`
+
+## Transformations
+
+WARNING: The current `BaseTransformer` framework is being removed in v1.0.0. To be
+replaced with individual frameworks for collection and series transformations. See the
+index page for more information.
+
+### Bug Fixes
+
+- [BUG] Convert rockets to only use 32 bit floats internally ({pr}`1612`) {user}`TonyBagnall`
+- [BUG] add check y to BaseSeriesTransformer ({pr}`1624`) {user}`TonyBagnall`
+- [BUG] removed njit test exclusions ({pr}`1598`) {user}`TonyBagnall`
+- [BUG] fix padder fit_values ({pr}`1752`) {user}`TonyBagnall`
+- [BUG] Hydra bugfix ({pr}`1771`) {user}`MatthewMiddlehurst`
+
+### Deprecation
+
+- [DEP] Tidy up BaseTransformer testing ({pr}`1541`) {user}`TonyBagnall`
+- [DEP] Convert clear sky transformer to new base class ({pr}`1565`) {user}`MatthewMiddlehurst`
+- [DEP] Rocket,RotationForest and FreshPrince deprecations (plus a bug fix) ({pr}`1648`) {user}`TonyBagnall`
+- [DEP] deprecate PandasAdaptor ({pr}`1614`) {user}`TonyBagnall`
+- [DEP] remove Differencer ({pr}`1645`) {user}`TonyBagnall`
+- [DEP] Remove augmenters, binning, cos, sqrt ({pr}`1668`) {user}`TonyBagnall`
+- [DEP] Remove kalman filter and time since ({pr}`1669`) {user}`TonyBagnall`
+- [DEP] Remove ClearSky ({pr}`1673`) {user}`TonyBagnall`
+- [DEP] make BoxCox legacy ({pr}`1672`) {user}`TonyBagnall`
+- [DEP] remove PCA ({pr}`1674`) {user}`TonyBagnall`
+- [DEP] v0.10 move ColumnSelect and IndexSelect to legacy ({pr}`1675`) {user}`TonyBagnall`
+- [DEP] deprecate compose ({pr}`1679`) {user}`TonyBagnall`
+- [DEP] V0.10 remove ACF/PACF ({pr}`1678`) {user}`TonyBagnall`
+- [DEP] Dep fest ({pr}`1680`) {user}`TonyBagnall`
+- [DEP] dep fest2 ({pr}`1681`) {user}`TonyBagnall`
+- [DEP] dep fest3 ({pr}`1682`) {user}`TonyBagnall`
+- [ENH] Add missing import for deprecation ({pr}`1721`) {user}`TonyBagnall`
+- [DEP] V0.10 Move DOBIN to legacy ({pr}`1731`) {user}`TonyBagnall`
+- [DEP] Deprecate the update function in BaseCollectionTransformer ({pr}`1744`) {user}`TonyBagnall`
+- [DEP] Exclusion list  ({pr}`1730`) {user}`TonyBagnall`
+
+### Documentation
+
+- [DOC] Add SlidingWindowSegmenter to API reference ({pr}`1600`) {user}`CodeLionX`
+- [Doc] Images for "Transformations"  ({pr}`1736`) {user}`Abhash297`
+- [DOC] Improve BaseCollectionTransformer docstrings ({pr}`1733`) {user}`TonyBagnall`
+
+### Enhancements
+
+- [MNT] Move haar wavelet transform to aeon.utils.numba package ({pr}`1579`) {user}`CodeLionX`
+- [ENH] Lower Bounding Distances for SAX and SFA ({pr}`1622`) {user}`patrickzib`
+- [ENH] `axis=1` function default and removal of axis class default for series transformation and segmentation ({pr}`1625`) {user}`MatthewMiddlehurst`
+- [ENH] Remove two  hard coded arrays from minirocket ({pr}`1698`) {user}`TonyBagnall`
+- [ENH] Merge MiniRocket and MiniRocketMultivariate ({pr}`1708`) {user}`TonyBagnall`
+- [ENH] Merge MultiRocket and MultiRocketMultivariate ({pr}`1711`) {user}`TonyBagnall`
+- [ENH] Channel selection rocket wrapper ({pr}`1504`) {user}`TonyBagnall`
+- [ENH] Shapelet visualization tools ({pr}`1715`) {user}`baraline`
+- [ENH] Revert mini rocket to separate functions for univariate and multivariate ({pr}`1781`) {user}`TonyBagnall`
+
+## Unit Testing
+
+### Bug Fixes
+
+- [BUG] Fix TSAD data loading tests and example notebooks ({pr}`1695`) {user}`CodeLionX`
+- [BUG] Use almost equal in random state testing of deep learning ({pr}`1773`) {user}`hadifawaz1999`
+
+### Deprecation
+
+- [ENH] Exclude deprecated estimators ({pr}`1547`) {user}`TonyBagnall`
+
+### Enhancements
+
+- [ENH] Exclude deprecated estimators ({pr}`1547`) {user}`TonyBagnall`
+- [ENH] Improve and refactor collection test data generation utilities ({pr}`1564`) {user}`MatthewMiddlehurst`
+- [ENH] Moves a test file  ({pr}`1665`) {user}`TonyBagnall`
+- [ENH] Rework series test data generators ({pr}`1592`) {user}`MatthewMiddlehurst`
+
+### Maintenance
+
+- [MNT] Add threads limit for numba and TF ({pr}`1604`) {user}`baraline`
+- [MNT] Drop Python 3.8 ({pr}`1659`) {user}`MatthewMiddlehurst`
+- [MNT] Replace Intel macOS runners with m1 macOS runners in CI ({pr}`1585`) {user}`chrisholder`
+- [MNT] Unit testing revamp part 1: `check_estimator` ({pr}`1479`) {user}`MatthewMiddlehurst`
+
+### Refactored
+
+- [ENH] Improve and refactor collection test data generation utilities ({pr}`1564`) {user}`MatthewMiddlehurst`
+- [REF] Refactor `testing.utils.data_gen` into `testing.data_generation` ({pr}`1589`) {user}`MatthewMiddlehurst`
+
+## Visualisations
+
+### Enhancements
+
+- [ENH] Shapelet visualization tools ({pr}`1715`) {user}`baraline`
+
+## Other
+
+### Bug Fixes
+
+- [BUG] Fix broken import causing CI to fail ({pr}`1717`) {user}`MatthewMiddlehurst`
+
+### Deprecation
+
+- [DEP] Remove probablistic class based metrics ({pr}`1630`) {user}`TonyBagnall`
+- [DEP] remove public VectorizedDF ({pr}`1666`) {user}`TonyBagnall`
+- [DEP] Remove _serialize ({pr}`1667`) {user}`TonyBagnall`
+- [DEP] v0.10 move ThetaLinesTransformer to legacy ({pr}`1676`) {user}`TonyBagnall`
+
+### Documentation
+
+- [DOC] Fixed a typo in mentoring.md ({pr}`1700`) {user}`futuer-szd`
+- [MNT,DOC] Remove `extension_templates` ({pr}`1657`) {user}`MatthewMiddlehurst`
+- [DOCS] Add any papers ({pr}`1526`) {user}`TonyBagnall`
+- [DOC,MNT] Documentation updates and deprecation warning for `v1.0.0` ({pr}`1743`) {user}`MatthewMiddlehurst`
+
+### Maintenance
+
+- [MNT] Remove stale branches ({pr}`1543`) {user}`MatthewMiddlehurst`
+- [MNT] Fix `pre-commit` pushes for forks (hopefully) and easier CI label interactions ({pr}`1601`) {user}`MatthewMiddlehurst`
+- [MNT] Change pre-commit trigger type ({pr}`1661`) {user}`MatthewMiddlehurst`
+- [MNT] Disable `pytest` threading by default for local runs ({pr}`1656`) {user}`MatthewMiddlehurst`
+- [MNT,DOC] Remove `extension_templates` ({pr}`1657`) {user}`MatthewMiddlehurst`
+- [MNT] Exclude `docs` and `examples` from release source ({pr}`1658`) {user}`MatthewMiddlehurst`
+- [MNT] Change `pre-commit` workflow checkout ref ({pr}`1704`) {user}`MatthewMiddlehurst`
+- [MNT] Set `keras` bound to fix CI ({pr}`1723`) {user}`MatthewMiddlehurst`
+- [DOC,MNT] Documentation updates and deprecation warning for `v1.0.0` ({pr}`1743`) {user}`MatthewMiddlehurst`
+- [MNT] Removing `tensorflow_addons` dependency ({pr}`1421`) {user}`MatthewMiddlehurst`
+- [MNT] Fix certain workflow actions for forks and add button for resetting CI ({pr}`1764`) {user}`MatthewMiddlehurst`
+
+### Other
+
+- [DEP] Simple removals for deprecation list for 0.10 ({pr}`1644`) {user}`TonyBagnall`
+- [MNT] Raise tensorflow bound to >2.13 ({pr}`1765`) {user}`TonyBagnall`
+
+## Contributors
+
+The following have contributed to this release through a collective 107 GitHub Pull Requests:
+
+{user}`aadya940`,
+{user}`Abhash297`,
+{user}`adm-unl`,
+{user}`baraline`,
+{user}`chrisholder`,
+{user}`CodeLionX`,
+{user}`ermshaua`,
+{user}`futuer-szd`,
+{user}`hadifawaz1999`,
+{user}`itsdivya1309`,
+{user}`MatthewMiddlehurst`,
+{user}`Moonzyyy`,
+{user}`patrickzib`,
+{user}`TonyBagnall`,
+{user}`zy18811`
diff --git a/pyproject.toml b/pyproject.toml
index 36847d5b..1ebe7a58 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
 
 [project]
 name = "aeon"
-version = "0.9.0"
+version = "0.10.0"
 description = "A toolkit for machine learning from time series"
 authors = [
     {name = "aeon developers", email = "contact@aeon-toolkit.org"},
@@ -83,7 +83,7 @@ all_extras = [
     "pyod>=1.1.3",
 
     # dependency of tensorflow, see issue #1724
-    "keras<3.4",
+    "keras<3.4.0",
     # for some reason, a heirarchical dask test fails on some Python versions with the
     # later versions of pyarrow and dask
     "dask[dataframe]<2024.3.0; python_version < '3.11'",
@@ -92,13 +92,13 @@ all_extras = [
 ]
 dl = [
     "keras-self-attention",
+    "tensorflow>=2.14; python_version < '3.12'",
     # dependency of tensorflow, see issue #1724
-    "keras<3.4",
-    "tensorflow>=2.12; python_version < '3.12'",
+    "keras<3.4.0",
 ]
 unstable_extras = [
-    "mrsqm>=0.0.1,<0.1.0; platform_system == 'Darwin' and python_version < '3.12'",  # requires gcc and fftw to be installed for Windows and some other OS (see http://www.fftw.org/index.html)
-    "pycatch22<=0.4.3",  # known to fail installation on some setups
+    "mrsqm>=0.0.7,<0.1.0; platform_system != 'Windows' and python_version < '3.12'",  # requires gcc and fftw to be installed for Windows and some other OS (see http://www.fftw.org/index.html)
+    "pycatch22",  # known to fail installation on some setups
     "pyfftw>=0.12.0; python_version < '3.12'",  # requires fftw to be installed for Windows and some other OS (see http://www.fftw.org/index.html)
 ]
 dev = [


Test patch:
diff --git a/aeon/networks/tests/test_ae_bgru.py b/aeon/networks/tests/test_ae_bgru.py
new file mode 100644
index 00000000..de842616
--- /dev/null
+++ b/aeon/networks/tests/test_ae_bgru.py
@@ -0,0 +1,54 @@
+"""Tests for the AEBiGRU Model."""
+
+import random
+
+import pytest
+
+from aeon.networks import AEBiGRUNetwork
+from aeon.utils.validation._dependencies import _check_soft_dependencies
+
+
+@pytest.mark.skipif(
+    not _check_soft_dependencies(["tensorflow"], severity="none"),
+    reason="Tensorflow soft dependency unavailable.",
+)
+@pytest.mark.parametrize(
+    "latent_space_dim,n_layers,temporal_latent_space",
+    [
+        (32, 1, True),
+        (128, 2, False),
+        (256, 3, True),
+        (64, 4, False),
+    ],
+)
+def test_aebigrunetwork_init(latent_space_dim, n_layers, temporal_latent_space):
+    """Test whether AEBiGRUNetwork initializes correctly for various parameters."""
+    aebigru = AEBiGRUNetwork(
+        latent_space_dim=latent_space_dim,
+        n_layers=n_layers,
+        temporal_latent_space=temporal_latent_space,
+        activation=random.choice(["relu", "tanh"]),
+        n_units=[random.choice([50, 25, 100]) for _ in range(n_layers)],
+    )
+    encoder, decoder = aebigru.build_network((1000, 5))
+    assert encoder is not None
+    assert decoder is not None
+
+
+@pytest.mark.skipif(
+    not _check_soft_dependencies(["tensorflow"], severity="none"),
+    reason="Tensorflow soft dependency unavailable.",
+)
+@pytest.mark.parametrize("activation", ["relu", "tanh"])
+def test_aebigrunetwork_activations(activation):
+    """Test whether AEBiGRUNetwork initializes correctly with different activations."""
+    aebigru = AEBiGRUNetwork(
+        latent_space_dim=64,
+        n_layers=2,
+        temporal_latent_space=True,
+        activation=activation,
+        n_units=[50, 50],
+    )
+    encoder, decoder = aebigru.build_network((1000, 5))
+    assert encoder is not None
+    assert decoder is not None
diff --git a/aeon/transformations/collection/channel_selection/tests/test_channel_scorer.py b/aeon/transformations/collection/channel_selection/tests/test_channel_scorer.py
index c9ee3bcb..5607be3a 100644
--- a/aeon/transformations/collection/channel_selection/tests/test_channel_scorer.py
+++ b/aeon/transformations/collection/channel_selection/tests/test_channel_scorer.py
@@ -1,5 +1,6 @@
 """Test channel scorer channel selector."""
 
+import numpy as np
 import pytest
 
 from aeon.testing.data_generation import make_example_3d_numpy
@@ -11,10 +12,11 @@ def test_channel_scorer():
     """Test the channel scorer."""
     # Test selects the correct number of channels
     cs = ChannelScorer(classifier=MockClassifierFullTags(), proportion=0.5)
-    X, y = make_example_3d_numpy(n_channels=10)
+    X, _ = make_example_3d_numpy(n_cases=20, n_channels=10)
+    y = np.array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
     cs.fit(X, y)
     assert len(cs.channels_selected_) == 5
-    X, y = make_example_3d_numpy(n_channels=9)
+    X, _ = make_example_3d_numpy(n_cases=20, n_channels=9)
     assert len(cs.channels_selected_) == 5
     with pytest.raises(ValueError, match="proportion must be in the range 0-1"):
         cs = ChannelScorer(classifier=MockClassifierFullTags(), proportion=1.1)