scikit-learn-intelex 2024.1.0__py311-none-manylinux1_x86_64.whl → 2024.2.0__py311-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 (40) hide show
  1. {scikit_learn_intelex-2024.1.0.dist-info → scikit_learn_intelex-2024.2.0.dist-info}/METADATA +2 -2
  2. {scikit_learn_intelex-2024.1.0.dist-info → scikit_learn_intelex-2024.2.0.dist-info}/RECORD +38 -34
  3. sklearnex/cluster/dbscan.py +3 -3
  4. sklearnex/{preview/linear_model → covariance}/__init__.py +3 -3
  5. sklearnex/covariance/incremental_covariance.py +130 -0
  6. sklearnex/covariance/tests/test_incremental_covariance.py +143 -0
  7. sklearnex/dispatcher.py +19 -18
  8. sklearnex/ensemble/_forest.py +5 -10
  9. sklearnex/linear_model/__init__.py +1 -2
  10. sklearnex/linear_model/linear.py +3 -10
  11. sklearnex/{preview/linear_model → linear_model}/logistic_regression.py +19 -38
  12. sklearnex/linear_model/tests/test_logreg.py +70 -5
  13. sklearnex/neighbors/__init__.py +1 -1
  14. sklearnex/neighbors/_lof.py +167 -0
  15. sklearnex/neighbors/knn_classification.py +6 -9
  16. sklearnex/neighbors/knn_regression.py +6 -8
  17. sklearnex/neighbors/knn_unsupervised.py +5 -7
  18. sklearnex/neighbors/tests/test_neighbors.py +12 -11
  19. sklearnex/preview/__init__.py +1 -1
  20. sklearnex/preview/cluster/k_means.py +3 -8
  21. sklearnex/preview/covariance/covariance.py +46 -12
  22. sklearnex/preview/decomposition/pca.py +3 -5
  23. sklearnex/spmd/__init__.py +1 -0
  24. sklearnex/spmd/covariance/__init__.py +19 -0
  25. sklearnex/spmd/covariance/covariance.py +21 -0
  26. sklearnex/spmd/linear_model/__init__.py +2 -1
  27. sklearnex/spmd/linear_model/logistic_regression.py +21 -0
  28. sklearnex/svm/nusvc.py +5 -6
  29. sklearnex/svm/nusvr.py +3 -4
  30. sklearnex/svm/svc.py +5 -6
  31. sklearnex/svm/svr.py +3 -4
  32. sklearnex/tests/test_memory_usage.py +1 -4
  33. sklearnex/tests/test_monkeypatch.py +33 -20
  34. sklearnex/tests/test_n_jobs_support.py +71 -9
  35. sklearnex/tests/test_patching.py +19 -5
  36. sklearnex/neighbors/lof.py +0 -436
  37. sklearnex/preview/linear_model/tests/test_preview_logistic_regression.py +0 -59
  38. {scikit_learn_intelex-2024.1.0.dist-info → scikit_learn_intelex-2024.2.0.dist-info}/LICENSE.txt +0 -0
  39. {scikit_learn_intelex-2024.1.0.dist-info → scikit_learn_intelex-2024.2.0.dist-info}/WHEEL +0 -0
  40. {scikit_learn_intelex-2024.1.0.dist-info → scikit_learn_intelex-2024.2.0.dist-info}/top_level.txt +0 -0
@@ -29,18 +29,15 @@ if daal_check_version((2023, "P", 200)):
29
29
  check_is_fitted,
30
30
  )
31
31
 
32
- from daal4py.sklearn._utils import (
33
- control_n_jobs,
34
- run_with_n_jobs,
35
- sklearn_check_version,
36
- )
32
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
33
+ from daal4py.sklearn._utils import sklearn_check_version
37
34
  from onedal.cluster import KMeans as onedal_KMeans
38
35
 
39
36
  from ..._device_offload import dispatch, wrap_output_data
40
37
  from ..._utils import PatchingConditionsChain
41
38
  from ._common import BaseKMeans
42
39
 
43
- @control_n_jobs
40
+ @control_n_jobs(decorated_methods=["fit", "predict"])
44
41
  class KMeans(sklearn_KMeans, BaseKMeans):
45
42
  __doc__ = sklearn_KMeans.__doc__
46
43
  n_iter_, inertia_ = None, None
@@ -212,7 +209,6 @@ if daal_check_version((2023, "P", 200)):
212
209
 
213
210
  return self
214
211
 
215
- @run_with_n_jobs
216
212
  def _onedal_fit(self, X, _, sample_weight, queue=None):
217
213
  assert sample_weight is None
218
214
 
@@ -294,7 +290,6 @@ if daal_check_version((2023, "P", 200)):
294
290
  X,
295
291
  )
296
292
 
297
- @run_with_n_jobs
298
293
  def _onedal_predict(self, X, queue=None):
299
294
  X = self._validate_data(
300
295
  X, accept_sparse=False, reset=False, dtype=[np.float64, np.float32]
@@ -14,32 +14,47 @@
14
14
  # limitations under the License.
15
15
  # ===============================================================================
16
16
 
17
+ import warnings
18
+
19
+ import numpy as np
17
20
  from scipy import sparse as sp
18
21
  from sklearn.covariance import EmpiricalCovariance as sklearn_EmpiricalCovariance
19
22
  from sklearn.utils import check_array
20
23
 
21
- from daal4py.sklearn._utils import control_n_jobs, run_with_n_jobs, sklearn_check_version
24
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
25
+ from daal4py.sklearn._utils import sklearn_check_version
22
26
  from onedal.common.hyperparameters import get_hyperparameters
23
27
  from onedal.covariance import EmpiricalCovariance as onedal_EmpiricalCovariance
28
+ from sklearnex import config_context
29
+ from sklearnex.metrics import pairwise_distances
24
30
 
25
- from ..._device_offload import dispatch
31
+ from ..._device_offload import dispatch, wrap_output_data
26
32
  from ..._utils import PatchingConditionsChain, register_hyperparameters
27
33
 
28
34
 
29
35
  @register_hyperparameters({"fit": get_hyperparameters("covariance", "compute")})
30
- @control_n_jobs
36
+ @control_n_jobs(decorated_methods=["fit", "mahalanobis"])
31
37
  class EmpiricalCovariance(sklearn_EmpiricalCovariance):
32
38
  __doc__ = sklearn_EmpiricalCovariance.__doc__
33
39
 
40
+ if sklearn_check_version("1.2"):
41
+ _parameter_constraints: dict = {
42
+ **sklearn_EmpiricalCovariance._parameter_constraints,
43
+ }
44
+
34
45
  def _save_attributes(self):
35
46
  assert hasattr(self, "_onedal_estimator")
36
- self.covariance_ = self._onedal_estimator.covariance_
47
+ self._set_covariance(self._onedal_estimator.covariance_)
37
48
  self.location_ = self._onedal_estimator.location_
38
49
 
39
50
  _onedal_covariance = staticmethod(onedal_EmpiricalCovariance)
40
51
 
41
- @run_with_n_jobs
42
52
  def _onedal_fit(self, X, queue=None):
53
+ if X.shape[0] == 1:
54
+ warnings.warn(
55
+ "Only one sample available. You may want to reshape your data array"
56
+ )
57
+
43
58
  onedal_params = {
44
59
  "method": "dense",
45
60
  "bias": True,
@@ -54,7 +69,7 @@ class EmpiricalCovariance(sklearn_EmpiricalCovariance):
54
69
  patching_status = PatchingConditionsChain(
55
70
  f"sklearn.covariance.{class_name}.{method_name}"
56
71
  )
57
- if method_name == "fit":
72
+ if method_name in ["fit", "mahalanobis"]:
58
73
  (X,) = data
59
74
  patching_status.and_conditions(
60
75
  [
@@ -62,10 +77,6 @@ class EmpiricalCovariance(sklearn_EmpiricalCovariance):
62
77
  self.assume_centered == False,
63
78
  "assume_centered parameter is not supported on oneDAL side",
64
79
  ),
65
- (
66
- self.store_precision == False,
67
- "precision matrix calculation is not supported on oneDAL side",
68
- ),
69
80
  (not sp.issparse(X), "X is sparse. Sparse input is not supported."),
70
81
  ]
71
82
  )
@@ -79,9 +90,9 @@ class EmpiricalCovariance(sklearn_EmpiricalCovariance):
79
90
  if sklearn_check_version("1.2"):
80
91
  self._validate_params()
81
92
  if sklearn_check_version("0.23"):
82
- self._validate_data(X)
93
+ X = self._validate_data(X, force_all_finite=False)
83
94
  else:
84
- check_array(X)
95
+ X = check_array(X, force_all_finite=False)
85
96
 
86
97
  dispatch(
87
98
  self,
@@ -95,4 +106,27 @@ class EmpiricalCovariance(sklearn_EmpiricalCovariance):
95
106
 
96
107
  return self
97
108
 
109
+ # expose sklearnex pairwise_distances if mahalanobis distance eventually supported
110
+ @wrap_output_data
111
+ def mahalanobis(self, X):
112
+ if sklearn_check_version("1.0"):
113
+ X = self._validate_data(X, reset=False)
114
+ else:
115
+ X = check_array(X)
116
+
117
+ precision = self.get_precision()
118
+ with config_context(assume_finite=True):
119
+ # compute mahalanobis distances
120
+ dist = pairwise_distances(
121
+ X, self.location_[np.newaxis, :], metric="mahalanobis", VI=precision
122
+ )
123
+
124
+ return np.reshape(dist, (len(X),)) ** 2
125
+
126
+ error_norm = wrap_output_data(sklearn_EmpiricalCovariance.error_norm)
127
+ score = wrap_output_data(sklearn_EmpiricalCovariance.score)
128
+
98
129
  fit.__doc__ = sklearn_EmpiricalCovariance.fit.__doc__
130
+ mahalanobis.__doc__ = sklearn_EmpiricalCovariance.mahalanobis
131
+ error_norm.__doc__ = sklearn_EmpiricalCovariance.error_norm.__doc__
132
+ score.__doc__ = sklearn_EmpiricalCovariance.score.__doc__
@@ -23,7 +23,8 @@ from sklearn.base import BaseEstimator
23
23
  from sklearn.utils.extmath import stable_cumsum
24
24
  from sklearn.utils.validation import check_array, check_is_fitted
25
25
 
26
- from daal4py.sklearn._utils import control_n_jobs, run_with_n_jobs, sklearn_check_version
26
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
27
+ from daal4py.sklearn._utils import sklearn_check_version
27
28
  from onedal.utils import _check_array
28
29
 
29
30
  from ..._device_offload import dispatch
@@ -43,7 +44,7 @@ from onedal.decomposition import PCA as onedal_PCA
43
44
 
44
45
 
45
46
  @register_hyperparameters({"fit": get_hyperparameters("covariance", "compute")})
46
- @control_n_jobs
47
+ @control_n_jobs(decorated_methods=["fit", "transform"])
47
48
  class PCA(sklearn_PCA):
48
49
  __doc__ = sklearn_PCA.__doc__
49
50
 
@@ -220,7 +221,6 @@ class PCA(sklearn_PCA):
220
221
  def _onedal_gpu_supported(self, method_name, *data):
221
222
  return self._onedal_supported(method_name, *data)
222
223
 
223
- @run_with_n_jobs
224
224
  def _onedal_fit(self, X, y=None, queue=None):
225
225
  if self.n_components == "mle" or self.n_components is None:
226
226
  onedal_n_components = min(X.shape)
@@ -244,11 +244,9 @@ class PCA(sklearn_PCA):
244
244
 
245
245
  return U, S, V
246
246
 
247
- @run_with_n_jobs
248
247
  def _onedal_predict(self, X, queue=None):
249
248
  return self._onedal_estimator.predict(X, queue)
250
249
 
251
- @run_with_n_jobs
252
250
  def _onedal_transform(self, X):
253
251
  X = _check_array(X, dtype=[np.float64, np.float32], ensure_2d=True, copy=False)
254
252
 
@@ -17,6 +17,7 @@
17
17
  __all__ = [
18
18
  "basic_statistics",
19
19
  "cluster",
20
+ "covariance",
20
21
  "decomposition",
21
22
  "ensemble",
22
23
  "linear_model",
@@ -0,0 +1,19 @@
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
+ from .covariance import EmpiricalCovariance
18
+
19
+ __all__ = ["EmpiricalCovariance"]
@@ -0,0 +1,21 @@
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
+ from onedal.spmd.covariance import EmpiricalCovariance
18
+
19
+ # TODO:
20
+ # Currently it uses `onedal` module interface.
21
+ # Add sklearnex dispatching.
@@ -15,5 +15,6 @@
15
15
  # ==============================================================================
16
16
 
17
17
  from .linear_model import LinearRegression
18
+ from .logistic_regression import LogisticRegression
18
19
 
19
- __all__ = ["LinearRegression"]
20
+ __all__ = ["LinearRegression", "LogisticRegression"]
@@ -0,0 +1,21 @@
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
+ from onedal.spmd.linear_model import LogisticRegression
18
+
19
+ # TODO:
20
+ # Currently it uses `onedal` module interface.
21
+ # Add sklearnex dispatching.
sklearnex/svm/nusvc.py CHANGED
@@ -18,7 +18,8 @@ from sklearn.exceptions import NotFittedError
18
18
  from sklearn.svm import NuSVC as sklearn_NuSVC
19
19
  from sklearn.utils.validation import _deprecate_positional_args
20
20
 
21
- from daal4py.sklearn._utils import control_n_jobs, run_with_n_jobs, sklearn_check_version
21
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
22
+ from daal4py.sklearn._utils import sklearn_check_version
22
23
 
23
24
  from .._device_offload import dispatch, wrap_output_data
24
25
  from ._common import BaseSVC
@@ -29,7 +30,9 @@ if sklearn_check_version("1.0"):
29
30
  from onedal.svm import NuSVC as onedal_NuSVC
30
31
 
31
32
 
32
- @control_n_jobs
33
+ @control_n_jobs(
34
+ decorated_methods=["fit", "predict", "_predict_proba", "decision_function"]
35
+ )
33
36
  class NuSVC(sklearn_NuSVC, BaseSVC):
34
37
  __doc__ = sklearn_NuSVC.__doc__
35
38
 
@@ -229,7 +232,6 @@ class NuSVC(sklearn_NuSVC, BaseSVC):
229
232
  X,
230
233
  )
231
234
 
232
- @run_with_n_jobs
233
235
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
234
236
  onedal_params = {
235
237
  "nu": self.nu,
@@ -253,11 +255,9 @@ class NuSVC(sklearn_NuSVC, BaseSVC):
253
255
  self._fit_proba(X, y, sample_weight, queue=queue)
254
256
  self._save_attributes()
255
257
 
256
- @run_with_n_jobs
257
258
  def _onedal_predict(self, X, queue=None):
258
259
  return self._onedal_estimator.predict(X, queue=queue)
259
260
 
260
- @run_with_n_jobs
261
261
  def _onedal_predict_proba(self, X, queue=None):
262
262
  if getattr(self, "clf_prob", None) is None:
263
263
  raise NotFittedError(
@@ -272,6 +272,5 @@ class NuSVC(sklearn_NuSVC, BaseSVC):
272
272
  with config_context(**cfg):
273
273
  return self.clf_prob.predict_proba(X)
274
274
 
275
- @run_with_n_jobs
276
275
  def _onedal_decision_function(self, X, queue=None):
277
276
  return self._onedal_estimator.decision_function(X, queue=queue)
sklearnex/svm/nusvr.py CHANGED
@@ -17,14 +17,15 @@
17
17
  from sklearn.svm import NuSVR as sklearn_NuSVR
18
18
  from sklearn.utils.validation import _deprecate_positional_args
19
19
 
20
- from daal4py.sklearn._utils import control_n_jobs, run_with_n_jobs, sklearn_check_version
20
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
21
+ from daal4py.sklearn._utils import sklearn_check_version
21
22
  from onedal.svm import NuSVR as onedal_NuSVR
22
23
 
23
24
  from .._device_offload import dispatch, wrap_output_data
24
25
  from ._common import BaseSVR
25
26
 
26
27
 
27
- @control_n_jobs
28
+ @control_n_jobs(decorated_methods=["fit", "predict"])
28
29
  class NuSVR(sklearn_NuSVR, BaseSVR):
29
30
  __doc__ = sklearn_NuSVR.__doc__
30
31
 
@@ -142,7 +143,6 @@ class NuSVR(sklearn_NuSVR, BaseSVR):
142
143
  X,
143
144
  )
144
145
 
145
- @run_with_n_jobs
146
146
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
147
147
  onedal_params = {
148
148
  "C": self.C,
@@ -161,6 +161,5 @@ class NuSVR(sklearn_NuSVR, BaseSVR):
161
161
  self._onedal_estimator.fit(X, y, sample_weight, queue=queue)
162
162
  self._save_attributes()
163
163
 
164
- @run_with_n_jobs
165
164
  def _onedal_predict(self, X, queue=None):
166
165
  return self._onedal_estimator.predict(X, queue=queue)
sklearnex/svm/svc.py CHANGED
@@ -20,7 +20,8 @@ from sklearn.exceptions import NotFittedError
20
20
  from sklearn.svm import SVC as sklearn_SVC
21
21
  from sklearn.utils.validation import _deprecate_positional_args
22
22
 
23
- from daal4py.sklearn._utils import control_n_jobs, run_with_n_jobs, sklearn_check_version
23
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
24
+ from daal4py.sklearn._utils import sklearn_check_version
24
25
 
25
26
  from .._device_offload import dispatch, wrap_output_data
26
27
  from .._utils import PatchingConditionsChain
@@ -32,7 +33,9 @@ if sklearn_check_version("1.0"):
32
33
  from onedal.svm import SVC as onedal_SVC
33
34
 
34
35
 
35
- @control_n_jobs
36
+ @control_n_jobs(
37
+ decorated_methods=["fit", "predict", "_predict_proba", "decision_function"]
38
+ )
36
39
  class SVC(sklearn_SVC, BaseSVC):
37
40
  __doc__ = sklearn_SVC.__doc__
38
41
 
@@ -258,7 +261,6 @@ class SVC(sklearn_SVC, BaseSVC):
258
261
  return patching_status
259
262
  raise RuntimeError(f"Unknown method {method_name} in {class_name}")
260
263
 
261
- @run_with_n_jobs
262
264
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
263
265
  onedal_params = {
264
266
  "C": self.C,
@@ -282,11 +284,9 @@ class SVC(sklearn_SVC, BaseSVC):
282
284
  self._fit_proba(X, y, sample_weight, queue=queue)
283
285
  self._save_attributes()
284
286
 
285
- @run_with_n_jobs
286
287
  def _onedal_predict(self, X, queue=None):
287
288
  return self._onedal_estimator.predict(X, queue=queue)
288
289
 
289
- @run_with_n_jobs
290
290
  def _onedal_predict_proba(self, X, queue=None):
291
291
  if getattr(self, "clf_prob", None) is None:
292
292
  raise NotFittedError(
@@ -301,6 +301,5 @@ class SVC(sklearn_SVC, BaseSVC):
301
301
  with config_context(**cfg):
302
302
  return self.clf_prob.predict_proba(X)
303
303
 
304
- @run_with_n_jobs
305
304
  def _onedal_decision_function(self, X, queue=None):
306
305
  return self._onedal_estimator.decision_function(X, queue=queue)
sklearnex/svm/svr.py CHANGED
@@ -17,14 +17,15 @@
17
17
  from sklearn.svm import SVR as sklearn_SVR
18
18
  from sklearn.utils.validation import _deprecate_positional_args
19
19
 
20
- from daal4py.sklearn._utils import control_n_jobs, run_with_n_jobs, sklearn_check_version
20
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
21
+ from daal4py.sklearn._utils import sklearn_check_version
21
22
  from onedal.svm import SVR as onedal_SVR
22
23
 
23
24
  from .._device_offload import dispatch, wrap_output_data
24
25
  from ._common import BaseSVR
25
26
 
26
27
 
27
- @control_n_jobs
28
+ @control_n_jobs(decorated_methods=["fit", "predict"])
28
29
  class SVR(sklearn_SVR, BaseSVR):
29
30
  __doc__ = sklearn_SVR.__doc__
30
31
 
@@ -143,7 +144,6 @@ class SVR(sklearn_SVR, BaseSVR):
143
144
  X,
144
145
  )
145
146
 
146
- @run_with_n_jobs
147
147
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
148
148
  onedal_params = {
149
149
  "C": self.C,
@@ -162,6 +162,5 @@ class SVR(sklearn_SVR, BaseSVR):
162
162
  self._onedal_estimator.fit(X, y, sample_weight, queue=queue)
163
163
  self._save_attributes()
164
164
 
165
- @run_with_n_jobs
166
165
  def _onedal_predict(self, X, queue=None):
167
166
  return self._onedal_estimator.predict(X, queue=queue)
@@ -94,10 +94,7 @@ def remove_duplicated_estimators(estimators_list):
94
94
  return estimators_map.values()
95
95
 
96
96
 
97
- BANNED_ESTIMATORS = (
98
- "LocalOutlierFactor", # fails on ndarray_c for sklearn > 1.0
99
- "TSNE", # too slow for using in testing on common data size
100
- )
97
+ BANNED_ESTIMATORS = ("TSNE",) # too slow for using in testing on common data size
101
98
  estimators = [
102
99
  PreviewPCA,
103
100
  TrainTestSplitEstimator,
@@ -45,8 +45,12 @@ def test_monkey_patching():
45
45
  n = _classes[i][1]
46
46
 
47
47
  sklearnex.unpatch_sklearn(t)
48
- class_module = getattr(p, n).__module__
49
- assert class_module.startswith("sklearn"), "Unpatching has completed with error."
48
+ sklearn_class = getattr(p, n, None)
49
+ if sklearn_class is not None:
50
+ sklearn_class = sklearn_class.__module__
51
+ assert sklearn_class is None or sklearn_class.startswith(
52
+ "sklearn"
53
+ ), "Unpatching has completed with error."
50
54
 
51
55
  sklearnex.unpatch_sklearn()
52
56
 
@@ -55,8 +59,12 @@ def test_monkey_patching():
55
59
  p = _classes[i][0]
56
60
  n = _classes[i][1]
57
61
 
58
- class_module = getattr(p, n).__module__
59
- assert class_module.startswith("sklearn"), "Unpatching has completed with error."
62
+ sklearn_class = getattr(p, n, None)
63
+ if sklearn_class is not None:
64
+ sklearn_class = sklearn_class.__module__
65
+ assert sklearn_class is None or sklearn_class.startswith(
66
+ "sklearn"
67
+ ), "Unpatching has completed with error."
60
68
 
61
69
  sklearnex.unpatch_sklearn()
62
70
 
@@ -85,7 +93,10 @@ def test_patch_by_list_simple():
85
93
 
86
94
  assert RandomForestRegressor.__module__.startswith("sklearn")
87
95
  assert KNeighborsRegressor.__module__.startswith("sklearn")
88
- assert LogisticRegression.__module__.startswith("daal4py")
96
+ if daal_check_version((2024, "P", 1)):
97
+ assert LogisticRegression.__module__.startswith("sklearnex")
98
+ else:
99
+ assert LogisticRegression.__module__.startswith("daal4py")
89
100
  assert SVC.__module__.startswith("sklearn")
90
101
 
91
102
  sklearnex.unpatch_sklearn()
@@ -101,7 +112,10 @@ def test_patch_by_list_many_estimators():
101
112
 
102
113
  assert RandomForestRegressor.__module__.startswith("sklearn")
103
114
  assert KNeighborsRegressor.__module__.startswith("sklearn")
104
- assert LogisticRegression.__module__.startswith("daal4py")
115
+ if daal_check_version((2024, "P", 1)):
116
+ assert LogisticRegression.__module__.startswith("sklearnex")
117
+ else:
118
+ assert LogisticRegression.__module__.startswith("daal4py")
105
119
  assert SVC.__module__.startswith("daal4py") or SVC.__module__.startswith("sklearnex")
106
120
 
107
121
  sklearnex.unpatch_sklearn()
@@ -119,7 +133,10 @@ def test_unpatch_by_list_many_estimators():
119
133
  assert KNeighborsRegressor.__module__.startswith(
120
134
  "daal4py"
121
135
  ) or KNeighborsRegressor.__module__.startswith("sklearnex")
122
- assert LogisticRegression.__module__.startswith("daal4py")
136
+ if daal_check_version((2024, "P", 1)):
137
+ assert LogisticRegression.__module__.startswith("sklearnex")
138
+ else:
139
+ assert LogisticRegression.__module__.startswith("daal4py")
123
140
  assert SVC.__module__.startswith("daal4py") or SVC.__module__.startswith("sklearnex")
124
141
 
125
142
  sklearnex.unpatch_sklearn(["KNeighborsRegressor", "RandomForestRegressor"])
@@ -131,7 +148,11 @@ def test_unpatch_by_list_many_estimators():
131
148
 
132
149
  assert RandomForestRegressor.__module__.startswith("sklearn")
133
150
  assert KNeighborsRegressor.__module__.startswith("sklearn")
134
- assert LogisticRegression.__module__.startswith("daal4py")
151
+ if daal_check_version((2024, "P", 1)):
152
+ assert LogisticRegression.__module__.startswith("sklearnex")
153
+ else:
154
+ assert LogisticRegression.__module__.startswith("daal4py")
155
+
135
156
  assert SVC.__module__.startswith("daal4py") or SVC.__module__.startswith("sklearnex")
136
157
 
137
158
 
@@ -161,12 +182,11 @@ def test_preview_namespace():
161
182
  from sklearn.cluster import DBSCAN
162
183
  from sklearn.decomposition import PCA
163
184
  from sklearn.ensemble import RandomForestClassifier
164
- from sklearn.linear_model import LinearRegression, LogisticRegression
185
+ from sklearn.linear_model import LinearRegression
165
186
  from sklearn.svm import SVC
166
187
 
167
188
  return (
168
189
  LinearRegression(),
169
- LogisticRegression(),
170
190
  PCA(),
171
191
  DBSCAN(),
172
192
  SVC(),
@@ -182,7 +202,7 @@ def test_preview_namespace():
182
202
 
183
203
  assert _is_preview_enabled()
184
204
 
185
- lr, log_reg, pca, dbscan, svc, rfc = get_estimators()
205
+ lr, pca, dbscan, svc, rfc = get_estimators()
186
206
  assert "sklearnex" in rfc.__module__
187
207
 
188
208
  if daal_check_version((2023, "P", 100)):
@@ -190,20 +210,14 @@ def test_preview_namespace():
190
210
  else:
191
211
  assert "daal4py" in lr.__module__
192
212
 
193
- if daal_check_version((2024, "P", 1)):
194
- assert "sklearnex" in log_reg.__module__
195
- else:
196
- assert "daal4py" in log_reg.__module__
197
-
198
213
  assert "sklearnex.preview" in pca.__module__
199
214
  assert "sklearnex" in dbscan.__module__
200
215
  assert "sklearnex" in svc.__module__
201
216
  sklearnex.unpatch_sklearn()
202
217
 
203
218
  # no patching behavior
204
- lr, log_reg, pca, dbscan, svc, rfc = get_estimators()
219
+ lr, pca, dbscan, svc, rfc = get_estimators()
205
220
  assert "sklearn." in lr.__module__ and "daal4py" not in lr.__module__
206
- assert "sklearn." in log_reg.__module__ and "daal4py" not in log_reg.__module__
207
221
  assert "sklearn." in pca.__module__ and "daal4py" not in pca.__module__
208
222
  assert "sklearn." in dbscan.__module__ and "daal4py" not in dbscan.__module__
209
223
  assert "sklearn." in svc.__module__ and "daal4py" not in svc.__module__
@@ -213,13 +227,12 @@ def test_preview_namespace():
213
227
  sklearnex.patch_sklearn()
214
228
  assert not _is_preview_enabled()
215
229
 
216
- lr, log_reg, pca, dbscan, svc, rfc = get_estimators()
230
+ lr, pca, dbscan, svc, rfc = get_estimators()
217
231
  if daal_check_version((2023, "P", 100)):
218
232
  assert "sklearnex" in lr.__module__
219
233
  else:
220
234
  assert "daal4py" in lr.__module__
221
235
 
222
- assert "daal4py" in log_reg.__module__
223
236
  assert "daal4py" in pca.__module__
224
237
  assert "sklearnex" in rfc.__module__
225
238
  assert "sklearnex" in dbscan.__module__
@@ -14,18 +14,80 @@
14
14
  # limitations under the License.
15
15
  # ==============================================================================
16
16
 
17
+ import inspect
18
+ import logging
19
+ from multiprocessing import cpu_count
20
+
17
21
  import pytest
22
+ from sklearn.base import BaseEstimator
23
+ from sklearn.datasets import make_classification
24
+
25
+ from sklearnex.dispatcher import get_patch_map
26
+ from sklearnex.svm import SVC, NuSVC
27
+
28
+ ESTIMATORS = set(
29
+ filter(
30
+ lambda x: inspect.isclass(x) and issubclass(x, BaseEstimator),
31
+ [value[0][0][2] for value in get_patch_map().values()],
32
+ )
33
+ )
34
+
35
+ X, Y = make_classification(n_samples=40, n_features=4, random_state=42)
36
+
37
+
38
+ @pytest.mark.parametrize("estimator_class", ESTIMATORS)
39
+ @pytest.mark.parametrize("n_jobs", [None, -1, 1, 2])
40
+ def test_n_jobs_support(caplog, estimator_class, n_jobs):
41
+ def check_estimator_doc(estimator):
42
+ if estimator.__doc__ is not None:
43
+ assert "n_jobs" in estimator.__doc__
44
+
45
+ def check_n_jobs_entry_in_logs(caplog, function_name, n_jobs):
46
+ for rec in caplog.records:
47
+ if function_name in rec.message and "threads" in rec.message:
48
+ expected_n_jobs = n_jobs if n_jobs > 0 else cpu_count() + 1 + n_jobs
49
+ logging.info(f"{function_name}: setting {expected_n_jobs} threads")
50
+ if f"{function_name}: setting {expected_n_jobs} threads" in rec.message:
51
+ return True
52
+ # False if n_jobs is set and not found in logs
53
+ return n_jobs is None
18
54
 
19
- from sklearnex.cluster import KMeans
20
- from sklearnex.linear_model import ElasticNet, Lasso, Ridge
21
- from sklearnex.svm import SVC, SVR, NuSVC, NuSVR
55
+ def check_method(*args, method, caplog):
56
+ method(*args)
57
+ assert check_n_jobs_entry_in_logs(caplog, method.__name__, n_jobs)
22
58
 
23
- estimators = [KMeans, SVC, SVR, NuSVC, NuSVR, Lasso, Ridge, ElasticNet]
59
+ def check_methods_decoration(estimator):
60
+ funcs = {
61
+ i: getattr(estimator, i)
62
+ for i in dir(estimator)
63
+ if hasattr(estimator, i) and callable(getattr(estimator, i))
64
+ }
24
65
 
66
+ for func_name, func in funcs.items():
67
+ assert hasattr(func, "__onedal_n_jobs_decorated__") == (
68
+ func_name in estimator._n_jobs_supported_onedal_methods
69
+ ), f"{estimator}.{func_name} n_jobs decoration does not match {estimator} n_jobs supported methods"
25
70
 
26
- @pytest.mark.parametrize("estimator", estimators)
27
- def test_n_jobs_support(estimator):
28
- # use `n_jobs` parameter where original sklearn doesn't expect it
29
- estimator(n_jobs=1)
71
+ caplog.set_level(logging.DEBUG, logger="sklearnex")
72
+ estimator_kwargs = {"n_jobs": n_jobs}
73
+ # by default, [Nu]SVC.predict_proba is restricted by @available_if decorator
74
+ if estimator_class in [SVC, NuSVC]:
75
+ estimator_kwargs["probability"] = True
76
+ estimator_instance = estimator_class(**estimator_kwargs)
30
77
  # check `n_jobs` parameter doc entry
31
- assert "n_jobs" in estimator.__doc__
78
+ check_estimator_doc(estimator_class)
79
+ check_estimator_doc(estimator_instance)
80
+ # check `n_jobs` log entry for supported methods
81
+ # `fit` call is required before other methods
82
+ check_method(X, Y, method=estimator_instance.fit, caplog=caplog)
83
+ for method_name in estimator_instance._n_jobs_supported_onedal_methods:
84
+ if method_name == "fit":
85
+ continue
86
+ method = getattr(estimator_instance, method_name)
87
+ if len(inspect.signature(method).parameters) == 0:
88
+ check_method(method=method, caplog=caplog)
89
+ else:
90
+ check_method(X, method=method, caplog=caplog)
91
+ # check if correct methods were decorated
92
+ check_methods_decoration(estimator_class)
93
+ check_methods_decoration(estimator_instance)