From 9142513b23f4c765fd5f689e76948931a9b66c0d Mon Sep 17 00:00:00 2001 From: Josh Carmichael Date: Tue, 28 May 2024 15:15:22 -0400 Subject: [PATCH 1/7] Use sklearn get_namespace to accomodate API change. --- src/aspire/numeric/complex_pca/complex_pca.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/aspire/numeric/complex_pca/complex_pca.py b/src/aspire/numeric/complex_pca/complex_pca.py index 5c8cd1e2d6..e38820c702 100644 --- a/src/aspire/numeric/complex_pca/complex_pca.py +++ b/src/aspire/numeric/complex_pca/complex_pca.py @@ -14,6 +14,7 @@ import numpy as np import scipy.sparse as sp from sklearn.decomposition import PCA +from sklearn.utils._array_api import get_namespace from .validation import check_array @@ -45,6 +46,8 @@ def _fit(self, X): allow_complex=True, ) + xp, is_array_api_compliant = get_namespace(X) + # Handle n_components==None if self.n_components is None: if self.svd_solver != "arpack": @@ -68,9 +71,9 @@ def _fit(self, X): # Call different fits for either full or truncated SVD if self._fit_svd_solver == "full": - return self._fit_full(X, n_components) + return self._fit_full(X, n_components, xp, is_array_api_compliant) elif self._fit_svd_solver in ["arpack", "randomized"]: - return self._fit_truncated(X, n_components, self._fit_svd_solver) + return self._fit_truncated(X, n_components, xp) else: raise ValueError( "Unrecognized svd_solver='{0}'" "".format(self._fit_svd_solver) From 2147dde9a2da8402bf93488f24be465804695540 Mon Sep 17 00:00:00 2001 From: Josh Carmichael Date: Tue, 28 May 2024 15:45:59 -0400 Subject: [PATCH 2/7] update pyproject.toml sklearn >= 1.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0e28ebad97..7a83384213 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ dependencies = [ "PyWavelets", "ray >= 2.9.2", "scipy >= 1.10.0", - "scikit-learn", + "scikit-learn >= 1.5", "scikit-image", "setuptools >= 0.41", "tqdm", From bb4a443a38f5879b7cc44d58cb6cabfecec88d7f Mon Sep 17 00:00:00 2001 From: Josh Carmichael Date: Tue, 28 May 2024 16:02:20 -0400 Subject: [PATCH 3/7] revert changes and pin sklearn. --- pyproject.toml | 2 +- src/aspire/numeric/complex_pca/complex_pca.py | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7a83384213..1da2bfb0ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ dependencies = [ "PyWavelets", "ray >= 2.9.2", "scipy >= 1.10.0", - "scikit-learn >= 1.5", + "scikit-learn <= 1.4.2", "scikit-image", "setuptools >= 0.41", "tqdm", diff --git a/src/aspire/numeric/complex_pca/complex_pca.py b/src/aspire/numeric/complex_pca/complex_pca.py index e38820c702..5c8cd1e2d6 100644 --- a/src/aspire/numeric/complex_pca/complex_pca.py +++ b/src/aspire/numeric/complex_pca/complex_pca.py @@ -14,7 +14,6 @@ import numpy as np import scipy.sparse as sp from sklearn.decomposition import PCA -from sklearn.utils._array_api import get_namespace from .validation import check_array @@ -46,8 +45,6 @@ def _fit(self, X): allow_complex=True, ) - xp, is_array_api_compliant = get_namespace(X) - # Handle n_components==None if self.n_components is None: if self.svd_solver != "arpack": @@ -71,9 +68,9 @@ def _fit(self, X): # Call different fits for either full or truncated SVD if self._fit_svd_solver == "full": - return self._fit_full(X, n_components, xp, is_array_api_compliant) + return self._fit_full(X, n_components) elif self._fit_svd_solver in ["arpack", "randomized"]: - return self._fit_truncated(X, n_components, xp) + return self._fit_truncated(X, n_components, self._fit_svd_solver) else: raise ValueError( "Unrecognized svd_solver='{0}'" "".format(self._fit_svd_solver) From e9d3cb23c37da3ac0bbb8e14d0dff6e7342f2825 Mon Sep 17 00:00:00 2001 From: Josh Carmichael Date: Wed, 29 May 2024 22:04:08 -0400 Subject: [PATCH 4/7] Workaround for py3.8 --- src/aspire/numeric/complex_pca/complex_pca.py | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/aspire/numeric/complex_pca/complex_pca.py b/src/aspire/numeric/complex_pca/complex_pca.py index 5c8cd1e2d6..1361aedd79 100644 --- a/src/aspire/numeric/complex_pca/complex_pca.py +++ b/src/aspire/numeric/complex_pca/complex_pca.py @@ -11,9 +11,12 @@ Unfortunately we need a complex valued PCA, so we wrap theirs for now. """ +import sys + import numpy as np import scipy.sparse as sp from sklearn.decomposition import PCA +from sklearn.utils._array_api import get_namespace from .validation import check_array @@ -45,6 +48,8 @@ def _fit(self, X): allow_complex=True, ) + xp, is_array_api_compliant = get_namespace(X) + # Handle n_components==None if self.n_components is None: if self.svd_solver != "arpack": @@ -66,11 +71,23 @@ def _fit(self, X): else: self._fit_svd_solver = "full" + # sci-kit changed `_fit_*()` API in latest release v1.5.0 + # which supports Python 3.9 - 3.12. This can be removed after + # our minimal support is Python 3.9. + py_version = sys.version_info + py_dep = py_version.major == 3 and py_version.minor < 9 + # Call different fits for either full or truncated SVD if self._fit_svd_solver == "full": - return self._fit_full(X, n_components) + if py_dep: + return self._fit_full(X, n_components) + else: + return self._fit_full(X, n_components, xp, is_array_api_compliant) elif self._fit_svd_solver in ["arpack", "randomized"]: - return self._fit_truncated(X, n_components, self._fit_svd_solver) + if py_dep: + return self._fit_truncated(X, n_components, self._fit_svd_solver) + else: + return self._fit_truncated(X, n_components, xp) else: raise ValueError( "Unrecognized svd_solver='{0}'" "".format(self._fit_svd_solver) From becc76ca8ed800f7690eddd2fbb6a44ec7dd0f63 Mon Sep 17 00:00:00 2001 From: Josh Carmichael Date: Thu, 30 May 2024 08:24:41 -0400 Subject: [PATCH 5/7] remove pin --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1da2bfb0ce..0e28ebad97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ dependencies = [ "PyWavelets", "ray >= 2.9.2", "scipy >= 1.10.0", - "scikit-learn <= 1.4.2", + "scikit-learn", "scikit-image", "setuptools >= 0.41", "tqdm", From 538620258c3a74493967e1ffa25edac6f4fbc701 Mon Sep 17 00:00:00 2001 From: Josh Carmichael Date: Thu, 30 May 2024 09:07:45 -0400 Subject: [PATCH 6/7] check sklearn version instead of python --- src/aspire/numeric/complex_pca/complex_pca.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/aspire/numeric/complex_pca/complex_pca.py b/src/aspire/numeric/complex_pca/complex_pca.py index 1361aedd79..c0476206c8 100644 --- a/src/aspire/numeric/complex_pca/complex_pca.py +++ b/src/aspire/numeric/complex_pca/complex_pca.py @@ -15,6 +15,8 @@ import numpy as np import scipy.sparse as sp +import sklearn +from packaging.version import Version from sklearn.decomposition import PCA from sklearn.utils._array_api import get_namespace @@ -74,17 +76,16 @@ def _fit(self, X): # sci-kit changed `_fit_*()` API in latest release v1.5.0 # which supports Python 3.9 - 3.12. This can be removed after # our minimal support is Python 3.9. - py_version = sys.version_info - py_dep = py_version.major == 3 and py_version.minor < 9 + API_dep = Version(sklearn.__version__) < Version("1.5.0") # Call different fits for either full or truncated SVD if self._fit_svd_solver == "full": - if py_dep: + if API_dep: return self._fit_full(X, n_components) else: return self._fit_full(X, n_components, xp, is_array_api_compliant) elif self._fit_svd_solver in ["arpack", "randomized"]: - if py_dep: + if API_dep: return self._fit_truncated(X, n_components, self._fit_svd_solver) else: return self._fit_truncated(X, n_components, xp) From 2ee4e5f380a39486afcac75194529984f062d3e0 Mon Sep 17 00:00:00 2001 From: Josh Carmichael Date: Thu, 30 May 2024 09:10:28 -0400 Subject: [PATCH 7/7] tox --- src/aspire/numeric/complex_pca/complex_pca.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/aspire/numeric/complex_pca/complex_pca.py b/src/aspire/numeric/complex_pca/complex_pca.py index c0476206c8..bd270ef64b 100644 --- a/src/aspire/numeric/complex_pca/complex_pca.py +++ b/src/aspire/numeric/complex_pca/complex_pca.py @@ -11,8 +11,6 @@ Unfortunately we need a complex valued PCA, so we wrap theirs for now. """ -import sys - import numpy as np import scipy.sparse as sp import sklearn