scikit-learn-intelex 2024.3.0__py312-none-manylinux1_x86_64.whl → 2024.4.0__py312-none-manylinux1_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of scikit-learn-intelex might be problematic. Click here for more details.

Files changed (33) hide show
  1. {scikit_learn_intelex-2024.3.0.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/METADATA +2 -2
  2. {scikit_learn_intelex-2024.3.0.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/RECORD +33 -30
  3. sklearnex/_device_offload.py +31 -4
  4. sklearnex/basic_statistics/__init__.py +2 -1
  5. sklearnex/basic_statistics/incremental_basic_statistics.py +288 -0
  6. sklearnex/basic_statistics/tests/test_incremental_basic_statistics.py +386 -0
  7. sklearnex/decomposition/pca.py +3 -6
  8. sklearnex/dispatcher.py +2 -2
  9. sklearnex/ensemble/_forest.py +68 -75
  10. sklearnex/linear_model/linear.py +275 -340
  11. sklearnex/linear_model/logistic_regression.py +50 -9
  12. sklearnex/linear_model/tests/test_linear.py +40 -5
  13. sklearnex/neighbors/_lof.py +53 -36
  14. sklearnex/neighbors/common.py +4 -1
  15. sklearnex/neighbors/knn_classification.py +37 -122
  16. sklearnex/neighbors/knn_regression.py +10 -117
  17. sklearnex/neighbors/knn_unsupervised.py +6 -78
  18. sklearnex/preview/cluster/k_means.py +5 -73
  19. sklearnex/preview/covariance/covariance.py +6 -5
  20. sklearnex/preview/covariance/tests/test_covariance.py +18 -5
  21. sklearnex/svm/_common.py +4 -7
  22. sklearnex/svm/nusvc.py +66 -50
  23. sklearnex/svm/nusvr.py +3 -49
  24. sklearnex/svm/svc.py +66 -51
  25. sklearnex/svm/svr.py +3 -49
  26. sklearnex/tests/_utils.py +14 -5
  27. sklearnex/tests/test_n_jobs_support.py +8 -2
  28. sklearnex/tests/test_patching.py +64 -54
  29. sklearnex/utils/__init__.py +2 -1
  30. sklearnex/utils/_namespace.py +97 -0
  31. {scikit_learn_intelex-2024.3.0.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/LICENSE.txt +0 -0
  32. {scikit_learn_intelex-2024.3.0.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/WHEEL +0 -0
  33. {scikit_learn_intelex-2024.3.0.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/top_level.txt +0 -0
sklearnex/svm/nusvr.py CHANGED
@@ -63,39 +63,6 @@ class NuSVR(sklearn_NuSVR, BaseSVR):
63
63
  )
64
64
 
65
65
  def fit(self, X, y, sample_weight=None):
66
- """
67
- Fit the SVM model according to the given training data.
68
-
69
- Parameters
70
- ----------
71
- X : {array-like, sparse matrix} of shape (n_samples, n_features) \
72
- or (n_samples, n_samples)
73
- Training vectors, where `n_samples` is the number of samples
74
- and `n_features` is the number of features.
75
- For kernel="precomputed", the expected shape of X is
76
- (n_samples, n_samples).
77
-
78
- y : array-like of shape (n_samples,)
79
- Target values (class labels in classification, real numbers in
80
- regression).
81
-
82
- sample_weight : array-like of shape (n_samples,), default=None
83
- Per-sample weights. Rescale C per sample. Higher weights
84
- force the classifier to put more emphasis on these points.
85
-
86
- Returns
87
- -------
88
- self : object
89
- Fitted estimator.
90
-
91
- Notes
92
- -----
93
- If X and y are not C-ordered and contiguous arrays of np.float64 and
94
- X is not a scipy.sparse.csr_matrix, X and/or y may be copied.
95
-
96
- If X is a dense array, then the other methods will not support sparse
97
- matrices as input.
98
- """
99
66
  if sklearn_check_version("1.2"):
100
67
  self._validate_params()
101
68
  if sklearn_check_version("1.0"):
@@ -115,22 +82,6 @@ class NuSVR(sklearn_NuSVR, BaseSVR):
115
82
 
116
83
  @wrap_output_data
117
84
  def predict(self, X):
118
- """
119
- Perform regression on samples in X.
120
-
121
- For an one-class model, +1 (inlier) or -1 (outlier) is returned.
122
-
123
- Parameters
124
- ----------
125
- X : {array-like, sparse matrix} of shape (n_samples, n_features)
126
- For kernel="precomputed", the expected shape of X is
127
- (n_samples_test, n_samples_train).
128
-
129
- Returns
130
- -------
131
- y_pred : ndarray of shape (n_samples,)
132
- The predicted values.
133
- """
134
85
  if sklearn_check_version("1.0"):
135
86
  self._check_feature_names(X, reset=False)
136
87
  return dispatch(
@@ -163,3 +114,6 @@ class NuSVR(sklearn_NuSVR, BaseSVR):
163
114
 
164
115
  def _onedal_predict(self, X, queue=None):
165
116
  return self._onedal_estimator.predict(X, queue=queue)
117
+
118
+ fit.__doc__ = sklearn_NuSVR.fit.__doc__
119
+ predict.__doc__ = sklearn_NuSVR.predict.__doc__
sklearnex/svm/svc.py CHANGED
@@ -17,11 +17,13 @@
17
17
  import numpy as np
18
18
  from scipy import sparse as sp
19
19
  from sklearn.exceptions import NotFittedError
20
+ from sklearn.metrics import accuracy_score
20
21
  from sklearn.svm import SVC as sklearn_SVC
21
22
  from sklearn.utils.validation import _deprecate_positional_args
22
23
 
23
24
  from daal4py.sklearn._n_jobs_support import control_n_jobs
24
25
  from daal4py.sklearn._utils import sklearn_check_version
26
+ from sklearnex.utils import get_namespace
25
27
 
26
28
  from .._device_offload import dispatch, wrap_output_data
27
29
  from .._utils import PatchingConditionsChain
@@ -34,7 +36,7 @@ from onedal.svm import SVC as onedal_SVC
34
36
 
35
37
 
36
38
  @control_n_jobs(
37
- decorated_methods=["fit", "predict", "_predict_proba", "decision_function"]
39
+ decorated_methods=["fit", "predict", "_predict_proba", "decision_function", "score"]
38
40
  )
39
41
  class SVC(sklearn_SVC, BaseSVC):
40
42
  __doc__ = sklearn_SVC.__doc__
@@ -81,39 +83,6 @@ class SVC(sklearn_SVC, BaseSVC):
81
83
  )
82
84
 
83
85
  def fit(self, X, y, sample_weight=None):
84
- """
85
- Fit the SVM model according to the given training data.
86
-
87
- Parameters
88
- ----------
89
- X : {array-like, sparse matrix} of shape (n_samples, n_features) \
90
- or (n_samples, n_samples)
91
- Training vectors, where `n_samples` is the number of samples
92
- and `n_features` is the number of features.
93
- For kernel="precomputed", the expected shape of X is
94
- (n_samples, n_samples).
95
-
96
- y : array-like of shape (n_samples,)
97
- Target values (class labels in classification, real numbers in
98
- regression).
99
-
100
- sample_weight : array-like of shape (n_samples,), default=None
101
- Per-sample weights. Rescale C per sample. Higher weights
102
- force the classifier to put more emphasis on these points.
103
-
104
- Returns
105
- -------
106
- self : object
107
- Fitted estimator.
108
-
109
- Notes
110
- -----
111
- If X and y are not C-ordered and contiguous arrays of np.float64 and
112
- X is not a scipy.sparse.csr_matrix, X and/or y may be copied.
113
-
114
- If X is a dense array, then the other methods will not support sparse
115
- matrices as input.
116
- """
117
86
  if sklearn_check_version("1.2"):
118
87
  self._validate_params()
119
88
  if sklearn_check_version("1.0"):
@@ -133,22 +102,6 @@ class SVC(sklearn_SVC, BaseSVC):
133
102
 
134
103
  @wrap_output_data
135
104
  def predict(self, X):
136
- """
137
- Perform regression on samples in X.
138
-
139
- For an one-class model, +1 (inlier) or -1 (outlier) is returned.
140
-
141
- Parameters
142
- ----------
143
- X : {array-like, sparse matrix} of shape (n_samples, n_features)
144
- For kernel="precomputed", the expected shape of X is
145
- (n_samples_test, n_samples_train).
146
-
147
- Returns
148
- -------
149
- y_pred : ndarray of shape (n_samples,)
150
- The predicted values.
151
- """
152
105
  if sklearn_check_version("1.0"):
153
106
  self._check_feature_names(X, reset=False)
154
107
  return dispatch(
@@ -161,6 +114,22 @@ class SVC(sklearn_SVC, BaseSVC):
161
114
  X,
162
115
  )
163
116
 
117
+ @wrap_output_data
118
+ def score(self, X, y, sample_weight=None):
119
+ if sklearn_check_version("1.0"):
120
+ self._check_feature_names(X, reset=False)
121
+ return dispatch(
122
+ self,
123
+ "score",
124
+ {
125
+ "onedal": self.__class__._onedal_score,
126
+ "sklearn": sklearn_SVC.score,
127
+ },
128
+ X,
129
+ y,
130
+ sample_weight=sample_weight,
131
+ )
132
+
164
133
  if sklearn_check_version("1.0"):
165
134
 
166
135
  @available_if(sklearn_SVC._check_proba)
@@ -193,6 +162,38 @@ class SVC(sklearn_SVC, BaseSVC):
193
162
  """
194
163
  return self._predict_proba(X)
195
164
 
165
+ @available_if(sklearn_SVC._check_proba)
166
+ def predict_log_proba(self, X):
167
+ """Compute log probabilities of possible outcomes for samples in X.
168
+
169
+ The model need to have probability information computed at training
170
+ time: fit with attribute `probability` set to True.
171
+
172
+ Parameters
173
+ ----------
174
+ X : array-like of shape (n_samples, n_features) or \
175
+ (n_samples_test, n_samples_train)
176
+ For kernel="precomputed", the expected shape of X is
177
+ (n_samples_test, n_samples_train).
178
+
179
+ Returns
180
+ -------
181
+ T : ndarray of shape (n_samples, n_classes)
182
+ Returns the log-probabilities of the sample for each class in
183
+ the model. The columns correspond to the classes in sorted
184
+ order, as they appear in the attribute :term:`classes_`.
185
+
186
+ Notes
187
+ -----
188
+ The probability model is created using cross validation, so
189
+ the results can be slightly different than those obtained by
190
+ predict. Also, it will produce meaningless results on very small
191
+ datasets.
192
+ """
193
+ xp, _ = get_namespace(X)
194
+
195
+ return xp.log(self.predict_proba(X))
196
+
196
197
  else:
197
198
 
198
199
  @property
@@ -200,6 +201,10 @@ class SVC(sklearn_SVC, BaseSVC):
200
201
  self._check_proba()
201
202
  return self._predict_proba
202
203
 
204
+ def _predict_log_proba(self, X):
205
+ xp, _ = get_namespace(X)
206
+ return xp.log(self.predict_proba(X))
207
+
203
208
  predict_proba.__doc__ = sklearn_SVC.predict_proba.__doc__
204
209
 
205
210
  @wrap_output_data
@@ -257,7 +262,7 @@ class SVC(sklearn_SVC, BaseSVC):
257
262
  if method_name == "fit":
258
263
  patching_status.and_conditions(conditions)
259
264
  return patching_status
260
- if method_name in ["predict", "predict_proba", "decision_function"]:
265
+ if method_name in ["predict", "predict_proba", "decision_function", "score"]:
261
266
  conditions.append(
262
267
  (hasattr(self, "_onedal_estimator"), "oneDAL model was not trained")
263
268
  )
@@ -307,3 +312,13 @@ class SVC(sklearn_SVC, BaseSVC):
307
312
 
308
313
  def _onedal_decision_function(self, X, queue=None):
309
314
  return self._onedal_estimator.decision_function(X, queue=queue)
315
+
316
+ def _onedal_score(self, X, y, sample_weight=None, queue=None):
317
+ return accuracy_score(
318
+ y, self._onedal_predict(X, queue=queue), sample_weight=sample_weight
319
+ )
320
+
321
+ fit.__doc__ = sklearn_SVC.fit.__doc__
322
+ predict.__doc__ = sklearn_SVC.predict.__doc__
323
+ decision_function.__doc__ = sklearn_SVC.decision_function.__doc__
324
+ score.__doc__ = sklearn_SVC.score.__doc__
sklearnex/svm/svr.py CHANGED
@@ -63,39 +63,6 @@ class SVR(sklearn_SVR, BaseSVR):
63
63
  )
64
64
 
65
65
  def fit(self, X, y, sample_weight=None):
66
- """
67
- Fit the SVM model according to the given training data.
68
-
69
- Parameters
70
- ----------
71
- X : {array-like, sparse matrix} of shape (n_samples, n_features) \
72
- or (n_samples, n_samples)
73
- Training vectors, where `n_samples` is the number of samples
74
- and `n_features` is the number of features.
75
- For kernel="precomputed", the expected shape of X is
76
- (n_samples, n_samples).
77
-
78
- y : array-like of shape (n_samples,)
79
- Target values (class labels in classification, real numbers in
80
- regression).
81
-
82
- sample_weight : array-like of shape (n_samples,), default=None
83
- Per-sample weights. Rescale C per sample. Higher weights
84
- force the classifier to put more emphasis on these points.
85
-
86
- Returns
87
- -------
88
- self : object
89
- Fitted estimator.
90
-
91
- Notes
92
- -----
93
- If X and y are not C-ordered and contiguous arrays of np.float64 and
94
- X is not a scipy.sparse.csr_matrix, X and/or y may be copied.
95
-
96
- If X is a dense array, then the other methods will not support sparse
97
- matrices as input.
98
- """
99
66
  if sklearn_check_version("1.2"):
100
67
  self._validate_params()
101
68
  if sklearn_check_version("1.0"):
@@ -116,22 +83,6 @@ class SVR(sklearn_SVR, BaseSVR):
116
83
 
117
84
  @wrap_output_data
118
85
  def predict(self, X):
119
- """
120
- Perform regression on samples in X.
121
-
122
- For an one-class model, +1 (inlier) or -1 (outlier) is returned.
123
-
124
- Parameters
125
- ----------
126
- X : {array-like, sparse matrix} of shape (n_samples, n_features)
127
- For kernel="precomputed", the expected shape of X is
128
- (n_samples_test, n_samples_train).
129
-
130
- Returns
131
- -------
132
- y_pred : ndarray of shape (n_samples,)
133
- The predicted values.
134
- """
135
86
  if sklearn_check_version("1.0"):
136
87
  self._check_feature_names(X, reset=False)
137
88
  return dispatch(
@@ -164,3 +115,6 @@ class SVR(sklearn_SVR, BaseSVR):
164
115
 
165
116
  def _onedal_predict(self, X, queue=None):
166
117
  return self._onedal_estimator.predict(X, queue=queue)
118
+
119
+ fit.__doc__ = sklearn_SVR.fit.__doc__
120
+ predict.__doc__ = sklearn_SVR.predict.__doc__
sklearnex/tests/_utils.py CHANGED
@@ -30,6 +30,7 @@ from sklearn.neighbors._base import KNeighborsMixin
30
30
 
31
31
  from onedal.tests.utils._dataframes_support import _convert_to_dataframe
32
32
  from sklearnex import get_patch_map, patch_sklearn, sklearn_is_patched, unpatch_sklearn
33
+ from sklearnex.linear_model import LogisticRegression
33
34
  from sklearnex.neighbors import (
34
35
  KNeighborsClassifier,
35
36
  KNeighborsRegressor,
@@ -95,6 +96,7 @@ SPECIAL_INSTANCES = {
95
96
  KNeighborsClassifier(algorithm="brute"),
96
97
  KNeighborsRegressor(algorithm="brute"),
97
98
  NearestNeighbors(algorithm="brute"),
99
+ LogisticRegression(solver="newton-cg"),
98
100
  ]
99
101
  }
100
102
 
@@ -102,10 +104,13 @@ SPECIAL_INSTANCES = {
102
104
  def gen_models_info(algorithms):
103
105
  output = []
104
106
  for i in algorithms:
105
- # split handles SPECIAL_INSTANCES or custom inputs
106
- # custom sklearn inputs must be a dict of estimators
107
- # with keys set by the __str__ method
108
- est = PATCHED_MODELS[i.split("(")[0]]
107
+
108
+ if i in PATCHED_MODELS:
109
+ est = PATCHED_MODELS[i]
110
+ elif i in SPECIAL_INSTANCES:
111
+ est = SPECIAL_INSTANCES[i].__class__
112
+ else:
113
+ raise KeyError(f"Unrecognized sklearnex estimator: {i}")
109
114
 
110
115
  methods = set()
111
116
  candidates = set(
@@ -116,7 +121,11 @@ def gen_models_info(algorithms):
116
121
  if issubclass(est, mixin):
117
122
  methods |= candidates & set(method)
118
123
 
119
- output += [[i, j] for j in methods]
124
+ output += [[i, j] for j in methods] if methods else [[i, None]]
125
+
126
+ # In the case that no methods are available, set method to None.
127
+ # This will allow estimators without mixins to still test the fit
128
+ # method in various tests.
120
129
  return output
121
130
 
122
131
 
@@ -84,10 +84,16 @@ def test_n_jobs_support(caplog, estimator_class, n_jobs):
84
84
  if method_name == "fit":
85
85
  continue
86
86
  method = getattr(estimator_instance, method_name)
87
- if len(inspect.signature(method).parameters) == 0:
87
+ argdict = inspect.signature(method).parameters
88
+ argnum = len(
89
+ [i for i in argdict if argdict[i].default == inspect.Parameter.empty]
90
+ )
91
+ if argnum == 0:
88
92
  check_method(method=method, caplog=caplog)
89
- else:
93
+ elif argnum == 1:
90
94
  check_method(X, method=method, caplog=caplog)
95
+ else:
96
+ check_method(X, Y, method=method, caplog=caplog)
91
97
  # check if correct methods were decorated
92
98
  check_methods_decoration(estimator_class)
93
99
  check_methods_decoration(estimator_instance)
@@ -26,24 +26,7 @@ from inspect import signature
26
26
  import numpy as np
27
27
  import numpy.random as nprnd
28
28
  import pytest
29
- from _utils import (
30
- DTYPES,
31
- PATCHED_FUNCTIONS,
32
- PATCHED_MODELS,
33
- SPECIAL_INSTANCES,
34
- UNPATCHED_FUNCTIONS,
35
- UNPATCHED_MODELS,
36
- gen_dataset,
37
- gen_models_info,
38
- )
39
- from sklearn.base import (
40
- BaseEstimator,
41
- ClassifierMixin,
42
- ClusterMixin,
43
- OutlierMixin,
44
- RegressorMixin,
45
- TransformerMixin,
46
- )
29
+ from sklearn.base import BaseEstimator
47
30
 
48
31
  from daal4py.sklearn._utils import sklearn_check_version
49
32
  from onedal.tests.utils._dataframes_support import (
@@ -53,21 +36,39 @@ from onedal.tests.utils._dataframes_support import (
53
36
  from sklearnex import is_patched_instance
54
37
  from sklearnex.dispatcher import _is_preview_enabled
55
38
  from sklearnex.metrics import pairwise_distances, roc_auc_score
39
+ from sklearnex.tests._utils import (
40
+ DTYPES,
41
+ PATCHED_FUNCTIONS,
42
+ PATCHED_MODELS,
43
+ SPECIAL_INSTANCES,
44
+ UNPATCHED_FUNCTIONS,
45
+ UNPATCHED_MODELS,
46
+ gen_dataset,
47
+ gen_models_info,
48
+ )
56
49
 
57
50
 
58
51
  @pytest.mark.parametrize("dtype", DTYPES)
59
- @pytest.mark.parametrize(
60
- "dataframe, queue", get_dataframes_and_queues(dataframe_filter_="numpy")
61
- )
52
+ @pytest.mark.parametrize("dataframe, queue", get_dataframes_and_queues())
62
53
  @pytest.mark.parametrize("metric", ["cosine", "correlation"])
63
54
  def test_pairwise_distances_patching(caplog, dataframe, queue, dtype, metric):
64
55
  with caplog.at_level(logging.WARNING, logger="sklearnex"):
56
+ if dtype == np.float16 and queue and not queue.sycl_device.has_aspect_fp16:
57
+ pytest.skip("Hardware does not support fp16 SYCL testing")
58
+ elif dtype == np.float64 and queue and not queue.sycl_device.has_aspect_fp64:
59
+ pytest.skip("Hardware does not support fp64 SYCL testing")
60
+ elif queue and queue.sycl_device.is_gpu:
61
+ pytest.skip("pairwise_distances does not support GPU queues")
62
+
65
63
  rng = nprnd.default_rng()
66
64
  X = _convert_to_dataframe(
67
- rng.random(size=1000), sycl_queue=queue, target_df=dataframe, dtype=dtype
65
+ rng.random(size=1000).reshape(1, -1),
66
+ sycl_queue=queue,
67
+ target_df=dataframe,
68
+ dtype=dtype,
68
69
  )
69
70
 
70
- _ = pairwise_distances(X.reshape(1, -1), metric=metric)
71
+ _ = pairwise_distances(X, metric=metric)
71
72
  assert all(
72
73
  [
73
74
  "running accelerated version" in i.message
@@ -80,12 +81,13 @@ def test_pairwise_distances_patching(caplog, dataframe, queue, dtype, metric):
80
81
  @pytest.mark.parametrize(
81
82
  "dtype", [i for i in DTYPES if "32" in i.__name__ or "64" in i.__name__]
82
83
  )
83
- @pytest.mark.parametrize(
84
- "dataframe, queue", get_dataframes_and_queues(dataframe_filter_="numpy")
85
- )
84
+ @pytest.mark.parametrize("dataframe, queue", get_dataframes_and_queues())
86
85
  def test_roc_auc_score_patching(caplog, dataframe, queue, dtype):
87
86
  if dtype in [np.uint32, np.uint64] and sys.platform == "win32":
88
87
  pytest.skip("Windows issue with unsigned ints")
88
+ elif dtype == np.float64 and queue and not queue.sycl_device.has_aspect_fp64:
89
+ pytest.skip("Hardware does not support fp64 SYCL testing")
90
+
89
91
  with caplog.at_level(logging.WARNING, logger="sklearnex"):
90
92
  rng = nprnd.default_rng()
91
93
  X = _convert_to_dataframe(
@@ -112,14 +114,25 @@ def test_roc_auc_score_patching(caplog, dataframe, queue, dtype):
112
114
 
113
115
 
114
116
  @pytest.mark.parametrize("dtype", DTYPES)
115
- @pytest.mark.parametrize(
116
- "dataframe, queue", get_dataframes_and_queues(dataframe_filter_="numpy")
117
- )
117
+ @pytest.mark.parametrize("dataframe, queue", get_dataframes_and_queues())
118
118
  @pytest.mark.parametrize("estimator, method", gen_models_info(PATCHED_MODELS))
119
119
  def test_standard_estimator_patching(caplog, dataframe, queue, dtype, estimator, method):
120
120
  with caplog.at_level(logging.WARNING, logger="sklearnex"):
121
121
  est = PATCHED_MODELS[estimator]()
122
122
 
123
+ if queue:
124
+ if dtype == np.float16 and not queue.sycl_device.has_aspect_fp16:
125
+ pytest.skip("Hardware does not support fp16 SYCL testing")
126
+ elif dtype == np.float64 and not queue.sycl_device.has_aspect_fp64:
127
+ pytest.skip("Hardware does not support fp64 SYCL testing")
128
+ elif queue.sycl_device.is_gpu and estimator in [
129
+ "KMeans",
130
+ "ElasticNet",
131
+ "Lasso",
132
+ "Ridge",
133
+ ]:
134
+ pytest.skip(f"{estimator} does not support GPU queues")
135
+
123
136
  if estimator == "TSNE" and method == "fit_transform":
124
137
  pytest.skip("TSNE.fit_transform is too slow for common testing")
125
138
  elif (
@@ -129,15 +142,17 @@ def test_standard_estimator_patching(caplog, dataframe, queue, dtype, estimator,
129
142
  and dtype in [np.uint32, np.uint64]
130
143
  ):
131
144
  pytest.skip("Windows segmentation fault for Ridge.predict for unsigned ints")
132
- elif not hasattr(est, method):
145
+ elif method and not hasattr(est, method):
133
146
  pytest.skip(f"sklearn available_if prevents testing {estimator}.{method}")
147
+
134
148
  X, y = gen_dataset(est, queue=queue, target_df=dataframe, dtype=dtype)
135
149
  est.fit(X, y)
136
150
 
137
- if method != "score":
138
- getattr(est, method)(X)
139
- else:
140
- est.score(X, y)
151
+ if method:
152
+ if method != "score":
153
+ getattr(est, method)(X)
154
+ else:
155
+ est.score(X, y)
141
156
  assert all(
142
157
  [
143
158
  "running accelerated version" in i.message
@@ -148,9 +163,7 @@ def test_standard_estimator_patching(caplog, dataframe, queue, dtype, estimator,
148
163
 
149
164
 
150
165
  @pytest.mark.parametrize("dtype", DTYPES)
151
- @pytest.mark.parametrize(
152
- "dataframe, queue", get_dataframes_and_queues(dataframe_filter_="numpy")
153
- )
166
+ @pytest.mark.parametrize("dataframe, queue", get_dataframes_and_queues())
154
167
  @pytest.mark.parametrize("estimator, method", gen_models_info(SPECIAL_INSTANCES))
155
168
  def test_special_estimator_patching(caplog, dataframe, queue, dtype, estimator, method):
156
169
  # prepare logging
@@ -158,15 +171,24 @@ def test_special_estimator_patching(caplog, dataframe, queue, dtype, estimator,
158
171
  with caplog.at_level(logging.WARNING, logger="sklearnex"):
159
172
  est = SPECIAL_INSTANCES[estimator]
160
173
 
174
+ # Its not possible to get the dpnp/dpctl arrays to be in the proper dtype
175
+ if dtype == np.float16 and queue and not queue.sycl_device.has_aspect_fp16:
176
+ pytest.skip("Hardware does not support fp16 SYCL testing")
177
+ elif dtype == np.float64 and queue and not queue.sycl_device.has_aspect_fp64:
178
+ pytest.skip("Hardware does not support fp64 SYCL testing")
179
+
161
180
  X, y = gen_dataset(est, queue=queue, target_df=dataframe, dtype=dtype)
162
181
  est.fit(X, y)
163
182
 
164
- if not hasattr(est, method):
183
+ if method and not hasattr(est, method):
165
184
  pytest.skip(f"sklearn available_if prevents testing {estimator}.{method}")
166
- if method != "score":
167
- getattr(est, method)(X)
168
- else:
169
- est.score(X, y)
185
+
186
+ if method:
187
+ if method != "score":
188
+ getattr(est, method)(X)
189
+ else:
190
+ est.score(X, y)
191
+
170
192
  assert all(
171
193
  [
172
194
  "running accelerated version" in i.message
@@ -311,18 +333,6 @@ def test_if_estimator_inherits_sklearn(estimator):
311
333
  ), f"{estimator} does not inherit from the patched sklearn estimator"
312
334
  else:
313
335
  assert issubclass(est, BaseEstimator)
314
- assert any(
315
- [
316
- issubclass(est, i)
317
- for i in [
318
- ClassifierMixin,
319
- ClusterMixin,
320
- OutlierMixin,
321
- RegressorMixin,
322
- TransformerMixin,
323
- ]
324
- ]
325
- ), f"{estimator} does not inherit a sklearn Mixin"
326
336
 
327
337
 
328
338
  @pytest.mark.parametrize("estimator", UNPATCHED_MODELS.keys())
@@ -14,6 +14,7 @@
14
14
  # limitations under the License.
15
15
  # ===============================================================================
16
16
 
17
+ from ._namespace import get_namespace
17
18
  from .validation import _assert_all_finite
18
19
 
19
- __all__ = ["_assert_all_finite"]
20
+ __all__ = ["get_namespace", "_assert_all_finite"]
@@ -0,0 +1,97 @@
1
+ # ==============================================================================
2
+ # Copyright 2024 Intel Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ==============================================================================
16
+
17
+ import numpy as np
18
+
19
+ from daal4py.sklearn._utils import sklearn_check_version
20
+
21
+ from .._device_offload import dpnp_available
22
+
23
+ if sklearn_check_version("1.2"):
24
+ from sklearn.utils._array_api import get_namespace as sklearn_get_namespace
25
+
26
+ if dpnp_available:
27
+ import dpnp
28
+
29
+
30
+ def get_namespace(*arrays):
31
+ """Get namespace of arrays.
32
+
33
+ Introspect `arrays` arguments and return their common Array API
34
+ compatible namespace object, if any. NumPy 1.22 and later can
35
+ construct such containers using the `numpy.array_api` namespace
36
+ for instance.
37
+
38
+ This function will return the namespace of SYCL-related arrays
39
+ which define the __sycl_usm_array_interface__ attribute
40
+ regardless of array_api support, the configuration of
41
+ array_api_dispatch, or scikit-learn version.
42
+
43
+ See: https://numpy.org/neps/nep-0047-array-api-standard.html
44
+
45
+ If `arrays` are regular numpy arrays, an instance of the
46
+ `_NumPyApiWrapper` compatibility wrapper is returned instead.
47
+
48
+ Namespace support is not enabled by default. To enabled it
49
+ call:
50
+
51
+ sklearn.set_config(array_api_dispatch=True)
52
+
53
+ or:
54
+
55
+ with sklearn.config_context(array_api_dispatch=True):
56
+ # your code here
57
+
58
+ Otherwise an instance of the `_NumPyApiWrapper`
59
+ compatibility wrapper is always returned irrespective of
60
+ the fact that arrays implement the `__array_namespace__`
61
+ protocol or not.
62
+
63
+ Parameters
64
+ ----------
65
+ *arrays : array objects
66
+ Array objects.
67
+
68
+ Returns
69
+ -------
70
+ namespace : module
71
+ Namespace shared by array objects.
72
+
73
+ is_array_api : bool
74
+ True of the arrays are containers that implement the Array API spec.
75
+ """
76
+
77
+ # sycl support designed to work regardless of array_api_dispatch sklearn global value
78
+ sycl_type = {type(x): x for x in arrays if hasattr(x, "__sycl_usm_array_interface__")}
79
+
80
+ if len(sycl_type) > 1:
81
+ raise ValueError(f"Multiple SYCL types for array inputs: {sycl_type}")
82
+
83
+ if sycl_type:
84
+
85
+ (X,) = sycl_type.values()
86
+
87
+ if hasattr(X, "__array_namespace__"):
88
+ return X.__array_namespace__(), True
89
+ elif dpnp_available and isinstance(X, dpnp.ndarray):
90
+ return dpnp, False
91
+ else:
92
+ raise ValueError(f"SYCL type not recognized: {sycl_type}")
93
+
94
+ elif sklearn_check_version("1.2"):
95
+ return sklearn_get_namespace(*arrays)
96
+ else:
97
+ return np, True