scm2cpp-lasso 0.13.1__tar.gz → 0.14.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.1 → scm2cpp_lasso-0.14.0}/PKG-INFO +59 -6
  2. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/README.md +58 -5
  3. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/pyproject.toml +1 -1
  4. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/setup.py +19 -4
  5. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/__init__.py +472 -248
  6. scm2cpp_lasso-0.14.0/src/scm2cpp_lasso/_compat.py +283 -0
  7. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso.egg-info/PKG-INFO +59 -6
  8. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso.egg-info/SOURCES.txt +1 -0
  9. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/setup.cfg +0 -0
  10. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/__init__.py +0 -0
  11. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader.py +0 -0
  12. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_accel_cublas.py +0 -0
  13. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_classifiers.py +0 -0
  14. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_derived_blas.py +0 -0
  15. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_derived_cublas.py +0 -0
  16. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_derived_loops.py +0 -0
  17. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_gpu_cuda.py +0 -0
  18. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_gramops_blas.py +0 -0
  19. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_gramops_loops.py +0 -0
  20. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_nmf_blas.py +0 -0
  21. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_nmf_cublas.py +0 -0
  22. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/_loader_nmf_loops.py +0 -0
  23. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/accel_cublas/accel.cpp +0 -0
  24. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/accel_cublas/accel.hpp +0 -0
  25. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/accel_cublas/accel_capi.cpp +0 -0
  26. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/classifiers.cpp +0 -0
  27. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/classifiers.hpp +0 -0
  28. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/classifiers_capi.cpp +0 -0
  29. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.cpp +0 -0
  30. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.hpp +0 -0
  31. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design_capi.cpp +0 -0
  32. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.cpp +0 -0
  33. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.hpp +0 -0
  34. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design_capi.cpp +0 -0
  35. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.cpp +0 -0
  36. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.hpp +0 -0
  37. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design_capi.cpp +0 -0
  38. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.cpp +0 -0
  39. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.hpp +0 -0
  40. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu_capi.cpp +0 -0
  41. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.cpp +0 -0
  42. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.hpp +0 -0
  43. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/gramops_blas/gramops_capi.cpp +0 -0
  44. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.cpp +0 -0
  45. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.hpp +0 -0
  46. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/gramops_loops/gramops_capi.cpp +0 -0
  47. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/lasso_cov.cpp +0 -0
  48. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/lasso_cov.hpp +0 -0
  49. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/lasso_cov_capi.cpp +0 -0
  50. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.cpp +0 -0
  51. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.hpp +0 -0
  52. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd_capi.cpp +0 -0
  53. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.cpp +0 -0
  54. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.hpp +0 -0
  55. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd_capi.cpp +0 -0
  56. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.cpp +0 -0
  57. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.hpp +0 -0
  58. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd_capi.cpp +0 -0
  59. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/scm2cpp-blas.hpp +0 -0
  60. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/scm2cpp-cublas.hpp +0 -0
  61. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/scm2cpp-cuda.hpp +0 -0
  62. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_generated/scm2cpp.hpp +0 -0
  63. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/_libfind.py +0 -0
  64. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso/batch_capi.cu +0 -0
  65. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso.egg-info/dependency_links.txt +0 -0
  66. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.0}/src/scm2cpp_lasso.egg-info/requires.txt +0 -0
  67. {scm2cpp_lasso-0.13.1 → scm2cpp_lasso-0.14.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.1
3
+ Version: 0.14.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
@@ -18,6 +18,8 @@ Requires-Dist: numpy>=1.17
18
18
 
19
19
  # scm2cpp-lasso
20
20
 
21
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/niitsuma/scm2cpp/blob/master/notebooks/compare-sklearn.ipynb)
22
+
21
23
  *[Japanese (README.ja.md)](README.ja.md)*
22
24
 
23
25
  Lasso by coordinate descent over a Gram matrix, with an optional GPU
@@ -28,8 +30,9 @@ path. The solver is Scheme, translated to C++ by
28
30
  $ pip install scm2cpp-lasso
29
31
  ```
30
32
 
31
- On Linux x86_64 and macOS arm64 (macOS 14 or later) this installs a wheel: compiled, with
32
- OpenBLAS inside, nothing to build. Elsewhere pip builds the sdist,
33
+ On Linux x86_64, macOS arm64 (macOS 14 or later) and Windows AMD64
34
+ this installs a wheel: compiled, nothing to build (with OpenBLAS
35
+ inside on Linux and macOS; Windows has the loop variants). Elsewhere pip builds the sdist,
33
36
  which needs a C++17 compiler and nothing else. The wheels carry no
34
37
  GPU code (a wheel cannot know the device); for the GPU builds, install
35
38
  from the sdist on a machine with `nvcc` on the path:
@@ -99,6 +102,55 @@ at zero, and `lambda_grid()` walks down from it -- the construction
99
102
  scikit-learn uses. If your columns differ wildly in scale, standardize
100
103
  them first; this solver does not do it for you.
101
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 39 pass
111
+ `sklearn.utils.estimator_checks.check_estimator` (`check-sklearn.py`
112
+ runs it; the one expected failure is `LBFGSLogisticRegressionCV`'s
113
+ `n_iter_` of 0 for a C whose warm start is already converged, which
114
+ scikit-learn's own `LogisticRegressionCV` reports on the same data).
115
+ scikit-learn stays optional: without it a numpy-only stand-in gives
116
+ `get_params`, `set_params`, `score` and the same input checks.
117
+
118
+ ```python
119
+ from sklearn.model_selection import GridSearchCV
120
+ from scm2cpp_lasso import GramLasso
121
+
122
+ GridSearchCV(GramLasso(), {"alpha": [0.01, 0.1, 1.0]}, cv=5).fit(X, y)
123
+ ```
124
+
125
+ `GramLasso`, `GramElasticNet` and `GramRidge` are the `fit(X, y)`
126
+ forms, with the intercept, over the Gram-matrix solvers; `CovLasso`,
127
+ `CovRidge`, `DerivedLasso`, `CovLogistic`, `CovGroupLasso` and
128
+ `CovMultiTaskLasso` keep their data-in-the-constructor interface,
129
+ which solves a whole path at once.
130
+
131
+ What it costs is the input checks: X must be a finite 2-D float64
132
+ array with the feature count of the fit. A plain C-ordered float64
133
+ ndarray is checked directly (one sum for finiteness); anything else (a
134
+ list, a DataFrame, another dtype) goes through scikit-learn's
135
+ `validate_data`, which raises the errors scikit-learn raises. The
136
+ checks alone, per call (`bench/sklearn-compat-overhead.py --checks`):
137
+
138
+ | X | fit | predict | predict, 50 rows | validate_data |
139
+ |---|---|---|---|---|
140
+ | 200 x 10 | 13 us | 7 us | 9 us | 173 us |
141
+ | 2000 x 50 | 47 us | 36 us | 9 us | 224 us |
142
+ | 20000 x 200 | 2.7 ms | 3.2 ms | 13 us | 3.2 ms |
143
+
144
+ The finiteness sum is the size-dependent part; under
145
+ `sklearn.set_config(assume_finite=True)` every row is about 3 us.
146
+ Whole calls, before and after (`bench/sklearn-compat-overhead.py`, 30
147
+ estimators, three shapes, the two packages alternating on one core of
148
+ a loaded machine): fits of a millisecond or more are unchanged within
149
+ the run-to-run spread (about 10%); fits of about 0.1 ms take 10 to
150
+ 30% (10 to 40 us) longer; predict on 20000 x 200 takes about twice as
151
+ long (3 ms to 6 ms, the finiteness sum costing as much as the product
152
+ itself), and on small inputs 5 to 10 us longer.
153
+
102
154
  ## Estimators at a glance
103
155
 
104
156
  Every estimator, the scikit-learn estimator it reproduces, the Scheme
@@ -107,12 +159,13 @@ it runs on, and whether Intel's sklearnex accelerates the scikit-learn
107
159
  side. Builds: *loops* is the plain translation, *BLAS* / *cuBLAS* the
108
160
  products handed to (cu)BLAS, *--cuda* the translator's GPU kernels
109
161
  (`gpu_cuda/`), *GPU batch* the hand-written CUDA batch solver; the
110
- package picks the fastest one present. None of the classes derives
111
- from scikit-learn's `BaseEstimator` yet, so `clone`, `GridSearchCV`
112
- and `check_estimator` do not apply to them.
162
+ package picks the fastest one present.
113
163
 
114
164
  | class | scikit-learn | Scheme kernel | builds | sklearnex accelerates |
115
165
  |---|---|---|---|---|
166
+ | `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
167
+ | `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
168
+ | `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets | numpy (Cholesky) | CPU | Ridge |
116
169
  | `CovLasso` | Lasso, ElasticNet, lasso_path(precompute=True) | `lasso-cov.scm` | CPU; GPU batch (fit_path_batch, bootstrap) | no |
117
170
  | `CovLassoCV` | LassoCV, ElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
118
171
  | `DerivedLasso` | lasso_path, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
@@ -1,5 +1,7 @@
1
1
  # scm2cpp-lasso
2
2
 
3
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/niitsuma/scm2cpp/blob/master/notebooks/compare-sklearn.ipynb)
4
+
3
5
  *[Japanese (README.ja.md)](README.ja.md)*
4
6
 
5
7
  Lasso by coordinate descent over a Gram matrix, with an optional GPU
@@ -10,8 +12,9 @@ path. The solver is Scheme, translated to C++ by
10
12
  $ pip install scm2cpp-lasso
11
13
  ```
12
14
 
13
- On Linux x86_64 and macOS arm64 (macOS 14 or later) this installs a wheel: compiled, with
14
- OpenBLAS inside, nothing to build. Elsewhere pip builds the sdist,
15
+ On Linux x86_64, macOS arm64 (macOS 14 or later) and Windows AMD64
16
+ this installs a wheel: compiled, nothing to build (with OpenBLAS
17
+ inside on Linux and macOS; Windows has the loop variants). Elsewhere pip builds the sdist,
15
18
  which needs a C++17 compiler and nothing else. The wheels carry no
16
19
  GPU code (a wheel cannot know the device); for the GPU builds, install
17
20
  from the sdist on a machine with `nvcc` on the path:
@@ -81,6 +84,55 @@ at zero, and `lambda_grid()` walks down from it -- the construction
81
84
  scikit-learn uses. If your columns differ wildly in scale, standardize
82
85
  them first; this solver does not do it for you.
83
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 39 pass
93
+ `sklearn.utils.estimator_checks.check_estimator` (`check-sklearn.py`
94
+ runs it; the one expected failure is `LBFGSLogisticRegressionCV`'s
95
+ `n_iter_` of 0 for a C whose warm start is already converged, which
96
+ scikit-learn's own `LogisticRegressionCV` reports on the same data).
97
+ scikit-learn stays optional: without it a numpy-only stand-in gives
98
+ `get_params`, `set_params`, `score` and the same input checks.
99
+
100
+ ```python
101
+ from sklearn.model_selection import GridSearchCV
102
+ from scm2cpp_lasso import GramLasso
103
+
104
+ GridSearchCV(GramLasso(), {"alpha": [0.01, 0.1, 1.0]}, cv=5).fit(X, y)
105
+ ```
106
+
107
+ `GramLasso`, `GramElasticNet` and `GramRidge` are the `fit(X, y)`
108
+ forms, with the intercept, over the Gram-matrix solvers; `CovLasso`,
109
+ `CovRidge`, `DerivedLasso`, `CovLogistic`, `CovGroupLasso` and
110
+ `CovMultiTaskLasso` keep their data-in-the-constructor interface,
111
+ which solves a whole path at once.
112
+
113
+ What it costs is the input checks: X must be a finite 2-D float64
114
+ array with the feature count of the fit. A plain C-ordered float64
115
+ ndarray is checked directly (one sum for finiteness); anything else (a
116
+ list, a DataFrame, another dtype) goes through scikit-learn's
117
+ `validate_data`, which raises the errors scikit-learn raises. The
118
+ checks alone, per call (`bench/sklearn-compat-overhead.py --checks`):
119
+
120
+ | X | fit | predict | predict, 50 rows | validate_data |
121
+ |---|---|---|---|---|
122
+ | 200 x 10 | 13 us | 7 us | 9 us | 173 us |
123
+ | 2000 x 50 | 47 us | 36 us | 9 us | 224 us |
124
+ | 20000 x 200 | 2.7 ms | 3.2 ms | 13 us | 3.2 ms |
125
+
126
+ The finiteness sum is the size-dependent part; under
127
+ `sklearn.set_config(assume_finite=True)` every row is about 3 us.
128
+ Whole calls, before and after (`bench/sklearn-compat-overhead.py`, 30
129
+ estimators, three shapes, the two packages alternating on one core of
130
+ a loaded machine): fits of a millisecond or more are unchanged within
131
+ the run-to-run spread (about 10%); fits of about 0.1 ms take 10 to
132
+ 30% (10 to 40 us) longer; predict on 20000 x 200 takes about twice as
133
+ long (3 ms to 6 ms, the finiteness sum costing as much as the product
134
+ itself), and on small inputs 5 to 10 us longer.
135
+
84
136
  ## Estimators at a glance
85
137
 
86
138
  Every estimator, the scikit-learn estimator it reproduces, the Scheme
@@ -89,12 +141,13 @@ it runs on, and whether Intel's sklearnex accelerates the scikit-learn
89
141
  side. Builds: *loops* is the plain translation, *BLAS* / *cuBLAS* the
90
142
  products handed to (cu)BLAS, *--cuda* the translator's GPU kernels
91
143
  (`gpu_cuda/`), *GPU batch* the hand-written CUDA batch solver; the
92
- package picks the fastest one present. None of the classes derives
93
- from scikit-learn's `BaseEstimator` yet, so `clone`, `GridSearchCV`
94
- and `check_estimator` do not apply to them.
144
+ package picks the fastest one present.
95
145
 
96
146
  | class | scikit-learn | Scheme kernel | builds | sklearnex accelerates |
97
147
  |---|---|---|---|---|
148
+ | `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
149
+ | `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
150
+ | `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets | numpy (Cholesky) | CPU | Ridge |
98
151
  | `CovLasso` | Lasso, ElasticNet, lasso_path(precompute=True) | `lasso-cov.scm` | CPU; GPU batch (fit_path_batch, bootstrap) | no |
99
152
  | `CovLassoCV` | LassoCV, ElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
100
153
  | `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.1"
7
+ version = "0.14.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"
@@ -12,6 +12,7 @@ device, or a failed nvcc all leave a working CPU package behind, and
12
12
  the batch path notices at import and falls back.
13
13
  """
14
14
  import os
15
+ import re
15
16
  import shutil
16
17
  import subprocess
17
18
  import sys
@@ -28,7 +29,9 @@ GEN_REL = PKG_REL + "/_generated"
28
29
  PKG = HERE / "src" / "scm2cpp_lasso"
29
30
  GEN = PKG / "_generated"
30
31
 
31
- CXXFLAGS = ["-O2", "-std=c++17"] if os.name != "nt" else ["/O2", "/std:c++17"]
32
+ # MSVC: /EHsc for C++ exceptions, /bigobj for the large generated files
33
+ MSVC = ["/O2", "/std:c++17", "/EHsc", "/bigobj"]
34
+ CXXFLAGS = ["-O2", "-std=c++17"] if os.name != "nt" else MSVC
32
35
 
33
36
  kernel = Extension(
34
37
  "scm2cpp_lasso._lasso_cov",
@@ -92,12 +95,24 @@ else:
92
95
  "scm2cpp_lasso._lasso_derived_loops",
93
96
  sources=[GEN_REL + "/derived_loops/lasso_design_capi.cpp"],
94
97
  include_dirs=[GEN_REL + "/derived_loops", GEN_REL],
95
- extra_compile_args=(["-O3", "-std=c++17"] if os.name != "nt"
96
- else ["/O2", "/std:c++17"]),
98
+ extra_compile_args=(["-O3", "-std=c++17"] if os.name != "nt" else MSVC),
97
99
  )
98
100
 
99
101
 
100
102
  class BuildWithCuda(build_ext):
103
+ def get_export_symbols(self, ext):
104
+ # The extensions are plain shared libraries the package loads
105
+ # through ctypes, not Python modules: no PyInit_ entry point,
106
+ # and on Windows a DLL shows ctypes only what it exports, so the
107
+ # exports are the extern "C" wrappers of the -M C API. (Unix
108
+ # linkers export everything and ignore this list.)
109
+ names = []
110
+ for src in ext.sources:
111
+ if src.endswith("_capi.cpp"):
112
+ text = (HERE / src).read_text()
113
+ names += re.findall(r'extern "C"[^(\n]*?\b(scm2cpp_\w+)\(', text)
114
+ return names
115
+
101
116
  def build_extensions(self):
102
117
  # the kernel is C++ compiled through the usual machinery, so
103
118
  # wheels and cross-compilation behave as they always do
@@ -165,7 +180,7 @@ def cuda_home():
165
180
  # flags carry: with signed overflow defined the compiler cannot treat
166
181
  # the flat index i*p + j as an induction variable, and the linear SVM's
167
182
  # sweep runs 25% slower.
168
- _cls_flags = ["-O3", "-std=c++17", "-fstrict-overflow"] if os.name != "nt" else ["/O2", "/std:c++17"]
183
+ _cls_flags = ["-O3", "-std=c++17", "-fstrict-overflow"] if os.name != "nt" else MSVC
169
184
  classifiers = Extension(
170
185
  "scm2cpp_lasso._classifiers",
171
186
  sources=[GEN_REL + "/classifiers_capi.cpp"],