scm2cpp-lasso 0.13.2__tar.gz → 0.15.0__tar.gz

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.
Files changed (67) hide show
  1. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/PKG-INFO +87 -4
  2. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/README.md +86 -3
  3. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/pyproject.toml +1 -1
  4. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/__init__.py +679 -248
  5. scm2cpp_lasso-0.15.0/src/scm2cpp_lasso/_compat.py +284 -0
  6. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso.egg-info/PKG-INFO +87 -4
  7. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso.egg-info/SOURCES.txt +1 -0
  8. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/setup.cfg +0 -0
  9. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/setup.py +0 -0
  10. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/__init__.py +0 -0
  11. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader.py +0 -0
  12. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_accel_cublas.py +0 -0
  13. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_classifiers.py +0 -0
  14. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_derived_blas.py +0 -0
  15. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_derived_cublas.py +0 -0
  16. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_derived_loops.py +0 -0
  17. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_gpu_cuda.py +0 -0
  18. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_gramops_blas.py +0 -0
  19. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_gramops_loops.py +0 -0
  20. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_nmf_blas.py +0 -0
  21. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_nmf_cublas.py +0 -0
  22. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/_loader_nmf_loops.py +0 -0
  23. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/accel_cublas/accel.cpp +0 -0
  24. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/accel_cublas/accel.hpp +0 -0
  25. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/accel_cublas/accel_capi.cpp +0 -0
  26. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/classifiers.cpp +0 -0
  27. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/classifiers.hpp +0 -0
  28. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/classifiers_capi.cpp +0 -0
  29. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.cpp +0 -0
  30. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.hpp +0 -0
  31. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design_capi.cpp +0 -0
  32. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.cpp +0 -0
  33. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.hpp +0 -0
  34. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design_capi.cpp +0 -0
  35. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.cpp +0 -0
  36. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.hpp +0 -0
  37. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design_capi.cpp +0 -0
  38. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.cpp +0 -0
  39. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.hpp +0 -0
  40. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu_capi.cpp +0 -0
  41. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.cpp +0 -0
  42. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.hpp +0 -0
  43. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/gramops_blas/gramops_capi.cpp +0 -0
  44. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.cpp +0 -0
  45. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.hpp +0 -0
  46. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/gramops_loops/gramops_capi.cpp +0 -0
  47. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/lasso_cov.cpp +0 -0
  48. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/lasso_cov.hpp +0 -0
  49. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/lasso_cov_capi.cpp +0 -0
  50. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.cpp +0 -0
  51. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.hpp +0 -0
  52. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd_capi.cpp +0 -0
  53. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.cpp +0 -0
  54. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.hpp +0 -0
  55. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd_capi.cpp +0 -0
  56. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.cpp +0 -0
  57. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.hpp +0 -0
  58. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd_capi.cpp +0 -0
  59. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/scm2cpp-blas.hpp +0 -0
  60. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/scm2cpp-cublas.hpp +0 -0
  61. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/scm2cpp-cuda.hpp +0 -0
  62. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_generated/scm2cpp.hpp +0 -0
  63. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/_libfind.py +0 -0
  64. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso/batch_capi.cu +0 -0
  65. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso.egg-info/dependency_links.txt +0 -0
  66. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso.egg-info/requires.txt +0 -0
  67. {scm2cpp_lasso-0.13.2 → scm2cpp_lasso-0.15.0}/src/scm2cpp_lasso.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scm2cpp-lasso
3
- Version: 0.13.2
3
+ Version: 0.15.0
4
4
  Summary: scikit-learn estimators (lasso, elastic net, ridge, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
5
5
  Author: Hirotaka Niitsuma
6
6
  License: MIT
@@ -102,6 +102,83 @@ at zero, and `lambda_grid()` walks down from it -- the construction
102
102
  scikit-learn uses. If your columns differ wildly in scale, standardize
103
103
  them first; this solver does not do it for you.
104
104
 
105
+ ## scikit-learn compatibility
106
+
107
+ From 0.14.0 every estimator with a `fit(X, y)` (or `fit(X)`) derives
108
+ from scikit-learn's `BaseEstimator` and the matching mixin, so `clone`,
109
+ `get_params` / `set_params`, `GridSearchCV`, `Pipeline` and
110
+ `cross_val_score` take them, and all 44 pass
111
+ `sklearn.utils.estimator_checks.check_estimator` (`check-sklearn.py`
112
+ runs it; the expected failures are `DesignLasso`'s missing `n_iter_`,
113
+ since the derived kernel does not count its sweeps, and
114
+ `LBFGSLogisticRegressionCV`'s
115
+ `n_iter_` of 0 for a C whose warm start is already converged, which
116
+ scikit-learn's own `LogisticRegressionCV` reports on the same data).
117
+ scikit-learn stays optional: without it a numpy-only stand-in gives
118
+ `get_params`, `set_params`, `score` and the same input checks.
119
+
120
+ ```python
121
+ from sklearn.model_selection import GridSearchCV
122
+ from scm2cpp_lasso import GramLasso
123
+
124
+ GridSearchCV(GramLasso(), {"alpha": [0.01, 0.1, 1.0]}, cv=5).fit(X, y)
125
+ ```
126
+
127
+ `CovLasso`, `CovRidge`, `DerivedLasso`, `CovLogistic`,
128
+ `CovGroupLasso` and `CovMultiTaskLasso` keep their
129
+ data-in-the-constructor interface, which solves a whole path at once;
130
+ each has a `fit(X, y)` form with the intercept beside it (0.15.0):
131
+
132
+ | data in the constructor | `fit(X, y)` | scikit-learn |
133
+ |---|---|---|
134
+ | `CovLasso` | `GramLasso`, `GramElasticNet` | Lasso, ElasticNet |
135
+ | `CovRidge` | `GramRidge` | Ridge |
136
+ | `DerivedLasso` | `DesignLasso` | Lasso |
137
+ | `CovLogistic` | `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver="liblinear") |
138
+ | `CovGroupLasso` | `GramGroupLasso` (`groups=None`: the lasso) | (none) |
139
+ | `CovMultiTaskLasso` | `GramMultiTaskLasso`, `GramMultiTaskElasticNet` | MultiTaskLasso, MultiTaskElasticNet |
140
+
141
+ Against scikit-learn on 400 x 30 with an intercept: `DesignLasso` and
142
+ `GramGroupLasso(groups=None)` agree with `Lasso` to 1.5e-10, the
143
+ multi-task pair with `MultiTaskLasso` / `MultiTaskElasticNet` to
144
+ 5e-14, and `GramLogisticRegression` reaches liblinear's objective to
145
+ eight digits with the same predictions.
146
+
147
+ Against the class each one wraps (one alpha, one core), which fits no
148
+ intercept and is unchanged: with `fit_intercept=False` the input checks
149
+ add 15 to 30 us a call (up to +50% on a 0.06 ms fit) and the finiteness
150
+ sum 8 to 14% on 20000 x 200 (none under `assume_finite`); with the
151
+ intercept, the column means add 20 to 30% on 20000 x 200 for the
152
+ Gram-matrix ones, which correct X'X
153
+ for the means rather than copy X to centre it, and about 55% for
154
+ `DesignLasso`, whose kernel needs the centred X itself.
155
+ `GramLogisticRegression` is slower than liblinear by its algorithm, 2.5x
156
+ at 20000 x 200 and more on small problems; `L1LogisticRegression` is
157
+ the fast one for that problem.
158
+
159
+ What it costs is the input checks: X must be a finite 2-D float64
160
+ array with the feature count of the fit. A plain C-ordered float64
161
+ ndarray is checked directly (one sum for finiteness); anything else (a
162
+ list, a DataFrame, another dtype) goes through scikit-learn's
163
+ `validate_data`, which raises the errors scikit-learn raises. The
164
+ checks alone, per call (`bench/sklearn-compat-overhead.py --checks`):
165
+
166
+ | X | fit | predict | predict, 50 rows | validate_data |
167
+ |---|---|---|---|---|
168
+ | 200 x 10 | 13 us | 7 us | 9 us | 173 us |
169
+ | 2000 x 50 | 47 us | 36 us | 9 us | 224 us |
170
+ | 20000 x 200 | 2.7 ms | 3.2 ms | 13 us | 3.2 ms |
171
+
172
+ The finiteness sum is the size-dependent part; under
173
+ `sklearn.set_config(assume_finite=True)` every row is about 3 us.
174
+ Whole calls, before and after (`bench/sklearn-compat-overhead.py`, 30
175
+ estimators, three shapes, the two packages alternating on one core of
176
+ a loaded machine): fits of a millisecond or more are unchanged within
177
+ the run-to-run spread (about 10%); fits of about 0.1 ms take 10 to
178
+ 30% (10 to 40 us) longer; predict on 20000 x 200 takes about twice as
179
+ long (3 ms to 6 ms, the finiteness sum costing as much as the product
180
+ itself), and on small inputs 5 to 10 us longer.
181
+
105
182
  ## Estimators at a glance
106
183
 
107
184
  Every estimator, the scikit-learn estimator it reproduces, the Scheme
@@ -110,12 +187,18 @@ it runs on, and whether Intel's sklearnex accelerates the scikit-learn
110
187
  side. Builds: *loops* is the plain translation, *BLAS* / *cuBLAS* the
111
188
  products handed to (cu)BLAS, *--cuda* the translator's GPU kernels
112
189
  (`gpu_cuda/`), *GPU batch* the hand-written CUDA batch solver; the
113
- package picks the fastest one present. None of the classes derives
114
- from scikit-learn's `BaseEstimator` yet, so `clone`, `GridSearchCV`
115
- and `check_estimator` do not apply to them.
190
+ package picks the fastest one present.
116
191
 
117
192
  | class | scikit-learn | Scheme kernel | builds | sklearnex accelerates |
118
193
  |---|---|---|---|---|
194
+ | `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
195
+ | `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
196
+ | `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets | numpy (Cholesky) | CPU | Ridge |
197
+ | `GramMultiTaskLasso` | MultiTaskLasso, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
198
+ | `GramMultiTaskElasticNet` | MultiTaskElasticNet, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
199
+ | `GramGroupLasso` | (none; skglm GroupLasso), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | - |
200
+ | `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver='liblinear'), by majorization | `lasso-cov.scm` | CPU | no |
201
+ | `DesignLasso` | Lasso, fit(X, y) with the intercept, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
119
202
  | `CovLasso` | Lasso, ElasticNet, lasso_path(precompute=True) | `lasso-cov.scm` | CPU; GPU batch (fit_path_batch, bootstrap) | no |
120
203
  | `CovLassoCV` | LassoCV, ElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
121
204
  | `DerivedLasso` | lasso_path, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
@@ -84,6 +84,83 @@ at zero, and `lambda_grid()` walks down from it -- the construction
84
84
  scikit-learn uses. If your columns differ wildly in scale, standardize
85
85
  them first; this solver does not do it for you.
86
86
 
87
+ ## scikit-learn compatibility
88
+
89
+ From 0.14.0 every estimator with a `fit(X, y)` (or `fit(X)`) derives
90
+ from scikit-learn's `BaseEstimator` and the matching mixin, so `clone`,
91
+ `get_params` / `set_params`, `GridSearchCV`, `Pipeline` and
92
+ `cross_val_score` take them, and all 44 pass
93
+ `sklearn.utils.estimator_checks.check_estimator` (`check-sklearn.py`
94
+ runs it; the expected failures are `DesignLasso`'s missing `n_iter_`,
95
+ since the derived kernel does not count its sweeps, and
96
+ `LBFGSLogisticRegressionCV`'s
97
+ `n_iter_` of 0 for a C whose warm start is already converged, which
98
+ scikit-learn's own `LogisticRegressionCV` reports on the same data).
99
+ scikit-learn stays optional: without it a numpy-only stand-in gives
100
+ `get_params`, `set_params`, `score` and the same input checks.
101
+
102
+ ```python
103
+ from sklearn.model_selection import GridSearchCV
104
+ from scm2cpp_lasso import GramLasso
105
+
106
+ GridSearchCV(GramLasso(), {"alpha": [0.01, 0.1, 1.0]}, cv=5).fit(X, y)
107
+ ```
108
+
109
+ `CovLasso`, `CovRidge`, `DerivedLasso`, `CovLogistic`,
110
+ `CovGroupLasso` and `CovMultiTaskLasso` keep their
111
+ data-in-the-constructor interface, which solves a whole path at once;
112
+ each has a `fit(X, y)` form with the intercept beside it (0.15.0):
113
+
114
+ | data in the constructor | `fit(X, y)` | scikit-learn |
115
+ |---|---|---|
116
+ | `CovLasso` | `GramLasso`, `GramElasticNet` | Lasso, ElasticNet |
117
+ | `CovRidge` | `GramRidge` | Ridge |
118
+ | `DerivedLasso` | `DesignLasso` | Lasso |
119
+ | `CovLogistic` | `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver="liblinear") |
120
+ | `CovGroupLasso` | `GramGroupLasso` (`groups=None`: the lasso) | (none) |
121
+ | `CovMultiTaskLasso` | `GramMultiTaskLasso`, `GramMultiTaskElasticNet` | MultiTaskLasso, MultiTaskElasticNet |
122
+
123
+ Against scikit-learn on 400 x 30 with an intercept: `DesignLasso` and
124
+ `GramGroupLasso(groups=None)` agree with `Lasso` to 1.5e-10, the
125
+ multi-task pair with `MultiTaskLasso` / `MultiTaskElasticNet` to
126
+ 5e-14, and `GramLogisticRegression` reaches liblinear's objective to
127
+ eight digits with the same predictions.
128
+
129
+ Against the class each one wraps (one alpha, one core), which fits no
130
+ intercept and is unchanged: with `fit_intercept=False` the input checks
131
+ add 15 to 30 us a call (up to +50% on a 0.06 ms fit) and the finiteness
132
+ sum 8 to 14% on 20000 x 200 (none under `assume_finite`); with the
133
+ intercept, the column means add 20 to 30% on 20000 x 200 for the
134
+ Gram-matrix ones, which correct X'X
135
+ for the means rather than copy X to centre it, and about 55% for
136
+ `DesignLasso`, whose kernel needs the centred X itself.
137
+ `GramLogisticRegression` is slower than liblinear by its algorithm, 2.5x
138
+ at 20000 x 200 and more on small problems; `L1LogisticRegression` is
139
+ the fast one for that problem.
140
+
141
+ What it costs is the input checks: X must be a finite 2-D float64
142
+ array with the feature count of the fit. A plain C-ordered float64
143
+ ndarray is checked directly (one sum for finiteness); anything else (a
144
+ list, a DataFrame, another dtype) goes through scikit-learn's
145
+ `validate_data`, which raises the errors scikit-learn raises. The
146
+ checks alone, per call (`bench/sklearn-compat-overhead.py --checks`):
147
+
148
+ | X | fit | predict | predict, 50 rows | validate_data |
149
+ |---|---|---|---|---|
150
+ | 200 x 10 | 13 us | 7 us | 9 us | 173 us |
151
+ | 2000 x 50 | 47 us | 36 us | 9 us | 224 us |
152
+ | 20000 x 200 | 2.7 ms | 3.2 ms | 13 us | 3.2 ms |
153
+
154
+ The finiteness sum is the size-dependent part; under
155
+ `sklearn.set_config(assume_finite=True)` every row is about 3 us.
156
+ Whole calls, before and after (`bench/sklearn-compat-overhead.py`, 30
157
+ estimators, three shapes, the two packages alternating on one core of
158
+ a loaded machine): fits of a millisecond or more are unchanged within
159
+ the run-to-run spread (about 10%); fits of about 0.1 ms take 10 to
160
+ 30% (10 to 40 us) longer; predict on 20000 x 200 takes about twice as
161
+ long (3 ms to 6 ms, the finiteness sum costing as much as the product
162
+ itself), and on small inputs 5 to 10 us longer.
163
+
87
164
  ## Estimators at a glance
88
165
 
89
166
  Every estimator, the scikit-learn estimator it reproduces, the Scheme
@@ -92,12 +169,18 @@ it runs on, and whether Intel's sklearnex accelerates the scikit-learn
92
169
  side. Builds: *loops* is the plain translation, *BLAS* / *cuBLAS* the
93
170
  products handed to (cu)BLAS, *--cuda* the translator's GPU kernels
94
171
  (`gpu_cuda/`), *GPU batch* the hand-written CUDA batch solver; the
95
- package picks the fastest one present. None of the classes derives
96
- from scikit-learn's `BaseEstimator` yet, so `clone`, `GridSearchCV`
97
- and `check_estimator` do not apply to them.
172
+ package picks the fastest one present.
98
173
 
99
174
  | class | scikit-learn | Scheme kernel | builds | sklearnex accelerates |
100
175
  |---|---|---|---|---|
176
+ | `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
177
+ | `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
178
+ | `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets | numpy (Cholesky) | CPU | Ridge |
179
+ | `GramMultiTaskLasso` | MultiTaskLasso, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
180
+ | `GramMultiTaskElasticNet` | MultiTaskElasticNet, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
181
+ | `GramGroupLasso` | (none; skglm GroupLasso), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | - |
182
+ | `GramLogisticRegression` | LogisticRegression(l1_ratio=1, solver='liblinear'), by majorization | `lasso-cov.scm` | CPU | no |
183
+ | `DesignLasso` | Lasso, fit(X, y) with the intercept, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
101
184
  | `CovLasso` | Lasso, ElasticNet, lasso_path(precompute=True) | `lasso-cov.scm` | CPU; GPU batch (fit_path_batch, bootstrap) | no |
102
185
  | `CovLassoCV` | LassoCV, ElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
103
186
  | `DerivedLasso` | lasso_path, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "scm2cpp-lasso"
7
- version = "0.13.2"
7
+ version = "0.15.0"
8
8
  description = "scikit-learn estimators (lasso, elastic net, ridge, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"