scm2cpp-lasso 0.16.0__tar.gz → 0.17.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.16.0/src/scm2cpp_lasso.egg-info → scm2cpp_lasso-0.17.0}/PKG-INFO +40 -2
  2. scm2cpp_lasso-0.16.0/PKG-INFO → scm2cpp_lasso-0.17.0/README.md +38 -18
  3. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/pyproject.toml +2 -2
  4. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/__init__.py +166 -2
  5. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader_accel_cublas.py +10 -0
  6. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader_classifiers.py +10 -0
  7. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader_gpu_cuda.py +10 -0
  8. scm2cpp_lasso-0.16.0/src/scm2cpp_lasso/_generated/_loader_gramops_loops.py → scm2cpp_lasso-0.17.0/src/scm2cpp_lasso/_generated/_loader_gramops_blas.py +37 -10
  9. scm2cpp_lasso-0.16.0/src/scm2cpp_lasso/_generated/_loader_gramops_blas.py → scm2cpp_lasso-0.17.0/src/scm2cpp_lasso/_generated/_loader_gramops_loops.py +56 -1
  10. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/accel_cublas/accel.cpp +1 -0
  11. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/accel_cublas/accel.hpp +82 -17
  12. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/accel_cublas/accel_capi.cpp +3 -0
  13. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/classifiers.cpp +1 -0
  14. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/classifiers.hpp +65 -0
  15. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/classifiers_capi.cpp +3 -0
  16. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.cpp +1 -0
  17. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.hpp +78 -0
  18. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu_capi.cpp +10 -0
  19. {scm2cpp_lasso-0.16.0/src/scm2cpp_lasso/_generated/gramops_loops → scm2cpp_lasso-0.17.0/src/scm2cpp_lasso/_generated/gramops_blas}/gramops.cpp +5 -0
  20. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.hpp +276 -16
  21. {scm2cpp_lasso-0.16.0/src/scm2cpp_lasso/_generated/gramops_loops → scm2cpp_lasso-0.17.0/src/scm2cpp_lasso/_generated/gramops_blas}/gramops_capi.cpp +12 -3
  22. {scm2cpp_lasso-0.16.0/src/scm2cpp_lasso/_generated/gramops_blas → scm2cpp_lasso-0.17.0/src/scm2cpp_lasso/_generated/gramops_loops}/gramops.cpp +5 -0
  23. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.hpp +653 -383
  24. {scm2cpp_lasso-0.16.0/src/scm2cpp_lasso/_generated/gramops_blas → scm2cpp_lasso-0.17.0/src/scm2cpp_lasso/_generated/gramops_loops}/gramops_capi.cpp +18 -0
  25. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/scm2cpp-blas.hpp +11 -0
  26. scm2cpp_lasso-0.16.0/README.md → scm2cpp_lasso-0.17.0/src/scm2cpp_lasso.egg-info/PKG-INFO +56 -0
  27. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/setup.cfg +0 -0
  28. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/setup.py +0 -0
  29. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_compat.py +0 -0
  30. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/__init__.py +0 -0
  31. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader.py +0 -0
  32. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader_derived_blas.py +0 -0
  33. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader_derived_cublas.py +0 -0
  34. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader_derived_loops.py +0 -0
  35. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader_nmf_blas.py +0 -0
  36. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader_nmf_cublas.py +0 -0
  37. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/_loader_nmf_loops.py +0 -0
  38. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.cpp +0 -0
  39. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.hpp +0 -0
  40. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design_capi.cpp +0 -0
  41. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.cpp +0 -0
  42. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.hpp +0 -0
  43. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design_capi.cpp +0 -0
  44. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.cpp +0 -0
  45. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.hpp +0 -0
  46. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design_capi.cpp +0 -0
  47. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/lasso_cov.cpp +0 -0
  48. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/lasso_cov.hpp +0 -0
  49. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/lasso_cov_capi.cpp +0 -0
  50. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.cpp +0 -0
  51. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.hpp +0 -0
  52. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd_capi.cpp +0 -0
  53. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.cpp +0 -0
  54. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.hpp +0 -0
  55. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd_capi.cpp +0 -0
  56. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.cpp +0 -0
  57. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.hpp +0 -0
  58. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd_capi.cpp +0 -0
  59. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/scm2cpp-cublas.hpp +0 -0
  60. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/scm2cpp-cuda.hpp +0 -0
  61. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_generated/scm2cpp.hpp +0 -0
  62. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/_libfind.py +0 -0
  63. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso/batch_capi.cu +0 -0
  64. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso.egg-info/SOURCES.txt +0 -0
  65. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso.egg-info/dependency_links.txt +0 -0
  66. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso.egg-info/requires.txt +0 -0
  67. {scm2cpp_lasso-0.16.0 → scm2cpp_lasso-0.17.0}/src/scm2cpp_lasso.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scm2cpp-lasso
3
- Version: 0.16.0
4
- Summary: scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
3
+ Version: 0.17.0
4
+ Summary: scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, 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
7
7
  Project-URL: Homepage, https://github.com/niitsuma/scm2cpp
@@ -248,6 +248,7 @@ package picks the fastest one present.
248
248
  | `ParallelFastICA` | FastICA | `fastica.scm` | loops / BLAS / --cuda | no |
249
249
  | `CovPCA` | PCA(svd_solver='covariance_eigh') | `pca.scm` | loops / BLAS / cuBLAS | PCA |
250
250
  | `GramKernelPCA` | KernelPCA (no inverse_transform) | `kernel-pca.scm` | loops / BLAS | no |
251
+ | `GramLDA` | LinearDiscriminantAnalysis (svd, lsqr, eigen) | `lda.scm` | loops / BLAS | no |
251
252
  | `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
252
253
  | `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
253
254
  | `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
@@ -643,6 +644,43 @@ Eigenvalues, eigenvectors and transforms agree with scikit-learn's to
643
644
  The linear row is the algorithm (an n x n problem against a p x p one),
644
645
  not the code.
645
646
 
647
+ ## Linear discriminant analysis: `GramLDA`
648
+
649
+ `GramLDA` is scikit-learn's `LinearDiscriminantAnalysis` with the n x p
650
+ work moved to the Gram matrix (`examples/kernel-only/lda.scm`): one pass
651
+ gives the class means and X'X (dsyrk), and the within-class covariance
652
+ is Sw = (X'X - sum_k n_k mu_k mu_k') / n. Each solver then runs its own
653
+ steps on p x p matrices:
654
+
655
+ - `"svd"` (the default) takes the SVD of the standardised within-class
656
+ design Xc D^-1 / sqrt(n), n x p. Its right singular vectors and values
657
+ are the eigenvectors and square roots of the eigenvalues of
658
+ D^-1 Sw D^-1, so one p x p eigenproblem (dsyevd) replaces it; the
659
+ second, classes x rank SVD and the coefficients follow as in
660
+ scikit-learn;
661
+ - `"lsqr"` solves Sw W = M' by Cholesky;
662
+ - `"eigen"` solves Sb v = lam Sw v (`sym-eigen-gen`, LAPACK's dsygvd).
663
+
664
+ ```python
665
+ from scm2cpp_lasso import GramLDA
666
+ clf = GramLDA().fit(X, y) # solver="svd"
667
+ clf.predict(X), clf.transform(X)
668
+ ```
669
+
670
+ `shrinkage` takes None or a float (it is linear in Sw, so the Gram route
671
+ keeps it), not "auto"; custom `priors` form a Gram per class. The
672
+ coefficients, intercepts, probabilities and explained variance agree
673
+ with scikit-learn's to 1e-12, the predictions exactly, and `transform`
674
+ up to the sign of each column. Measured (`bench/eigen-compare.py`, the
675
+ MKL build, best of three):
676
+
677
+ | case | scikit-learn | `GramLDA` | ratio, one core | ratio, 20 cores |
678
+ |---|---|---|---|---|
679
+ | svd (default), 200,000 x 100, 5 classes | 4.80 s | 0.092 s | 52x | 35x |
680
+ | svd, 50,000 x 500, 10 classes | 4.07 s | 0.25 s | 16x | 14x |
681
+ | lsqr, 200,000 x 100, 5 classes | 0.42 s | 0.089 s | 4.7x | 8.9x |
682
+ | eigen, 200,000 x 100, 5 classes | 0.56 s | 0.094 s | 6.0x | 12x |
683
+
646
684
  ## Bayesian ridge
647
685
 
648
686
  `CovBayesianRidge` is scikit-learn's `BayesianRidge` -- the same model,
@@ -1,21 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: scm2cpp-lasso
3
- Version: 0.16.0
4
- Summary: scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
5
- Author: Hirotaka Niitsuma
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/niitsuma/scm2cpp
8
- Project-URL: Source, https://github.com/niitsuma/scm2cpp/tree/master/python/scm2cpp-lasso
9
- Keywords: lasso,elastic-net,ridge,svm,logistic-regression,coordinate-descent,cuda,compiler
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: C++
13
- Classifier: Topic :: Scientific/Engineering :: Mathematics
14
- Classifier: Intended Audience :: Science/Research
15
- Requires-Python: >=3.8
16
- Description-Content-Type: text/markdown
17
- Requires-Dist: numpy>=1.17
18
-
19
1
  # scm2cpp-lasso
20
2
 
21
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)
@@ -248,6 +230,7 @@ package picks the fastest one present.
248
230
  | `ParallelFastICA` | FastICA | `fastica.scm` | loops / BLAS / --cuda | no |
249
231
  | `CovPCA` | PCA(svd_solver='covariance_eigh') | `pca.scm` | loops / BLAS / cuBLAS | PCA |
250
232
  | `GramKernelPCA` | KernelPCA (no inverse_transform) | `kernel-pca.scm` | loops / BLAS | no |
233
+ | `GramLDA` | LinearDiscriminantAnalysis (svd, lsqr, eigen) | `lda.scm` | loops / BLAS | no |
251
234
  | `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
252
235
  | `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
253
236
  | `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
@@ -643,6 +626,43 @@ Eigenvalues, eigenvectors and transforms agree with scikit-learn's to
643
626
  The linear row is the algorithm (an n x n problem against a p x p one),
644
627
  not the code.
645
628
 
629
+ ## Linear discriminant analysis: `GramLDA`
630
+
631
+ `GramLDA` is scikit-learn's `LinearDiscriminantAnalysis` with the n x p
632
+ work moved to the Gram matrix (`examples/kernel-only/lda.scm`): one pass
633
+ gives the class means and X'X (dsyrk), and the within-class covariance
634
+ is Sw = (X'X - sum_k n_k mu_k mu_k') / n. Each solver then runs its own
635
+ steps on p x p matrices:
636
+
637
+ - `"svd"` (the default) takes the SVD of the standardised within-class
638
+ design Xc D^-1 / sqrt(n), n x p. Its right singular vectors and values
639
+ are the eigenvectors and square roots of the eigenvalues of
640
+ D^-1 Sw D^-1, so one p x p eigenproblem (dsyevd) replaces it; the
641
+ second, classes x rank SVD and the coefficients follow as in
642
+ scikit-learn;
643
+ - `"lsqr"` solves Sw W = M' by Cholesky;
644
+ - `"eigen"` solves Sb v = lam Sw v (`sym-eigen-gen`, LAPACK's dsygvd).
645
+
646
+ ```python
647
+ from scm2cpp_lasso import GramLDA
648
+ clf = GramLDA().fit(X, y) # solver="svd"
649
+ clf.predict(X), clf.transform(X)
650
+ ```
651
+
652
+ `shrinkage` takes None or a float (it is linear in Sw, so the Gram route
653
+ keeps it), not "auto"; custom `priors` form a Gram per class. The
654
+ coefficients, intercepts, probabilities and explained variance agree
655
+ with scikit-learn's to 1e-12, the predictions exactly, and `transform`
656
+ up to the sign of each column. Measured (`bench/eigen-compare.py`, the
657
+ MKL build, best of three):
658
+
659
+ | case | scikit-learn | `GramLDA` | ratio, one core | ratio, 20 cores |
660
+ |---|---|---|---|---|
661
+ | svd (default), 200,000 x 100, 5 classes | 4.80 s | 0.092 s | 52x | 35x |
662
+ | svd, 50,000 x 500, 10 classes | 4.07 s | 0.25 s | 16x | 14x |
663
+ | lsqr, 200,000 x 100, 5 classes | 0.42 s | 0.089 s | 4.7x | 8.9x |
664
+ | eigen, 200,000 x 100, 5 classes | 0.56 s | 0.094 s | 6.0x | 12x |
665
+
646
666
  ## Bayesian ridge
647
667
 
648
668
  `CovBayesianRidge` is scikit-learn's `BayesianRidge` -- the same model,
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "scm2cpp-lasso"
7
- version = "0.16.0"
8
- description = "scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included"
7
+ version = "0.17.0"
8
+ description = "scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, 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"
11
11
  license = {text = "MIT"}
@@ -23,6 +23,7 @@ to build the Gram matrix of a moving-average design in O(n p) time and
23
23
  no design matrix at all.
24
24
  """
25
25
  import ctypes
26
+ import warnings
26
27
 
27
28
  import numpy as np
28
29
 
@@ -49,14 +50,14 @@ __all__ = ["GramLasso", "GramElasticNet", "GramRidge", "GramRidgeCV", "CovLasso"
49
50
  "LBFGSLogisticRegression", "LBFGSHuberRegressor", "LBFGSLogisticRegressionCV",
50
51
  "LBFGSPoissonRegressor", "LBFGSGammaRegressor", "LBFGSTweedieRegressor",
51
52
  "GramLarsCV", "GramLassoLarsCV", "GramOMPCV",
52
- "EMGaussianMixture", "CovPCA", "GramKernelPCA", "ParallelFastICA", "CovARDRegression",
53
+ "EMGaussianMixture", "CovPCA", "GramKernelPCA", "GramLDA", "ParallelFastICA", "CovARDRegression",
53
54
  "L1LinearSVM", "WeiszfeldTheilSen", "f_regression", "f_classif", "SelectKBest",
54
55
  "SelectPercentile", "GramRFE",
55
56
  "CovMultiTaskLasso", "CovMultiTaskLassoCV", "DerivedLasso",
56
57
  "GramLogisticRegression", "GramGroupLasso", "GramMultiTaskLasso",
57
58
  "GramMultiTaskElasticNet", "DesignLasso",
58
59
  "cuda_available", "derived_backend", "kernel"]
59
- __version__ = "0.16.0"
60
+ __version__ = "0.17.0"
60
61
 
61
62
  _BATCH = load_batch_lib()
62
63
  _DP = ctypes.POINTER(ctypes.c_double)
@@ -2244,6 +2245,169 @@ class GramKernelPCA(Tagged, TransformerMixin, BaseEstimator):
2244
2245
  return K @ scaled
2245
2246
 
2246
2247
 
2248
+ class GramLDA(Tagged, ClassifierMixin, TransformerMixin, BaseEstimator):
2249
+ """scikit-learn's ``LinearDiscriminantAnalysis`` over the Gram matrix
2250
+ (``examples/kernel-only/lda.scm``): X'X by dsyrk and the class means
2251
+ in one pass, then the three solvers' own steps on p x p matrices --
2252
+ ``"svd"`` (the default) takes its first SVD, of the n x p
2253
+ standardised within-class design, as the eigenproblem of
2254
+ D^-1 Sw D^-1 (dsyevd); ``"lsqr"`` solves Sw W = M' by Cholesky;
2255
+ ``"eigen"`` is Sb v = lam Sw v (dsygvd). ``shrinkage`` takes None or a
2256
+ float (not "auto"); no ``covariance_estimator``.
2257
+
2258
+ Attributes after fit: classes_, coef_, intercept_, means_, priors_,
2259
+ covariance_ (lsqr, eigen, or store_covariance), scalings_ and
2260
+ explained_variance_ratio_ (svd, eigen), xbar_ (svd), n_features_in_.
2261
+ """
2262
+
2263
+ def __init__(self, solver="svd", shrinkage=None, priors=None, n_components=None,
2264
+ store_covariance=False, tol=1e-4):
2265
+ self.solver, self.shrinkage, self.priors = solver, shrinkage, priors
2266
+ self.n_components, self.store_covariance, self.tol = n_components, store_covariance, tol
2267
+
2268
+ @staticmethod
2269
+ def _shrunk(C, s):
2270
+ # shrunk_covariance: (1 - s) C + s tr(C) / p I
2271
+ if s is None:
2272
+ return C
2273
+ p = C.shape[0]
2274
+ out = (1.0 - s) * C
2275
+ out.flat[::p + 1] += s * np.trace(C) / p
2276
+ return out
2277
+
2278
+ def fit(self, X, y):
2279
+ if self.solver not in ("svd", "lsqr", "eigen"):
2280
+ raise ValueError(f"solver={self.solver!r}: expected 'svd', 'lsqr' or 'eigen'")
2281
+ s = self.shrinkage
2282
+ if s is not None and (isinstance(s, str) or not 0.0 <= float(s) <= 1.0):
2283
+ raise ValueError(f"shrinkage={s!r}: GramLDA takes None or a float in [0, 1]")
2284
+ if self.solver == "svd" and s is not None:
2285
+ raise NotImplementedError("shrinkage not supported with 'svd' solver.")
2286
+ s = None if s is None else float(s)
2287
+ X, y = fit_xy(self, X, y, classifier=True)
2288
+ n, p = X.shape
2289
+ if n < 2:
2290
+ raise ValueError(f"Found array with {n} sample(s) (shape={X.shape}) while a "
2291
+ "minimum of 2 is required.")
2292
+ self.classes_, yi = classes_of(y)
2293
+ K = len(self.classes_)
2294
+ if n == K:
2295
+ raise ValueError("The number of samples must be more than the number of classes.")
2296
+ if K < 2:
2297
+ raise ValueError("The number of classes has to be greater than one; got 1 class")
2298
+ k = _gramops_kernels()
2299
+ lab = np.ascontiguousarray(yi, dtype=np.int32)
2300
+ G, means, counts = np.zeros((p, p)), np.zeros((K, p)), np.zeros(K)
2301
+ k.lda_moments(X, lab, G, means, counts, n, p, K)
2302
+ if self.priors is None:
2303
+ priors = counts / n
2304
+ else:
2305
+ priors = np.asarray(self.priors, dtype=np.float64)
2306
+ if np.any(priors < 0):
2307
+ raise ValueError("priors must be non-negative")
2308
+ if abs(priors.sum() - 1.0) > 1e-5:
2309
+ warnings.warn("The priors do not sum to 1. Renormalizing", UserWarning)
2310
+ priors = priors / priors.sum()
2311
+ self.priors_, self.means_ = priors, means
2312
+ top = min(K - 1, p)
2313
+ if self.n_components is not None and int(self.n_components) > top:
2314
+ raise ValueError("n_components cannot be larger than min(n_features, n_classes - 1).")
2315
+ self._max_components = top if self.n_components is None else int(self.n_components)
2316
+ xx = np.diagonal(G).copy()
2317
+ k.lda_within(G, means, counts, n, p, K) # G is now Sw, empirical priors
2318
+ if not np.all(np.diagonal(G) > 1e-8 * xx / n):
2319
+ # a column whose class means dwarf its spread: the correction
2320
+ # cancelled its digits, so take the centred rows instead
2321
+ Xc = np.ascontiguousarray(X - means[yi])
2322
+ G = _gram(Xc) / n
2323
+ Sw_emp = G
2324
+
2325
+ def class_cov():
2326
+ # scikit-learn's _class_cov: sum_k prior_k (shrunk) C_k; with
2327
+ # the empirical priors that is the shrunk Sw, else per class
2328
+ if self.priors is None or np.allclose(priors, counts / n):
2329
+ return self._shrunk(Sw_emp, s)
2330
+ C = np.zeros((p, p))
2331
+ for c in range(K):
2332
+ Xk = np.ascontiguousarray(X[yi == c] - means[c])
2333
+ C += priors[c] * self._shrunk(_gram(Xk) / max(Xk.shape[0], 1), s)
2334
+ return C
2335
+
2336
+ if self.solver == "svd":
2337
+ if self.store_covariance:
2338
+ self.covariance_ = class_cov()
2339
+ self.xbar_ = priors @ means
2340
+ std, V, S = np.zeros(p), np.zeros((p, p)), np.zeros(p)
2341
+ k.lda_svd_first(np.ascontiguousarray(Sw_emp), std, V, S, p)
2342
+ rank = int(np.sum(S > self.tol))
2343
+ scal = (V[:, :rank] / std[:, None]) / S[:rank]
2344
+ fac = 1.0 if K == 1 else 1.0 / (K - 1)
2345
+ Z = (np.sqrt(n * priors * fac) * (means - self.xbar_).T).T @ scal
2346
+ _, S2, Vt2 = np.linalg.svd(Z, full_matrices=False)
2347
+ self.explained_variance_ratio_ = (S2 ** 2 / np.sum(S2 ** 2))[:self._max_components] \
2348
+ if self._max_components else np.empty((0,))
2349
+ rank2 = int(np.sum(S2 > self.tol * S2[0]))
2350
+ self.scalings_ = scal @ Vt2.T[:, :rank2]
2351
+ coef = (means - self.xbar_) @ self.scalings_
2352
+ self.intercept_ = -0.5 * np.sum(coef ** 2, axis=1) + np.log(priors)
2353
+ self.coef_ = coef @ self.scalings_.T
2354
+ self.intercept_ -= self.xbar_ @ self.coef_.T
2355
+ else:
2356
+ Sw = class_cov()
2357
+ self.covariance_ = Sw
2358
+ if self.solver == "lsqr":
2359
+ coef = _ridge_solve(Sw, np.ascontiguousarray(means.T), 0.0)
2360
+ if coef is None:
2361
+ coef = np.linalg.lstsq(Sw, means.T, rcond=None)[0]
2362
+ self.coef_ = coef.T
2363
+ self.intercept_ = -0.5 * np.diag(means @ self.coef_.T) + np.log(priors)
2364
+ else:
2365
+ xbar = counts @ means / n
2366
+ St = self._shrunk(Sw_emp + (means - xbar).T @ ((counts / n)[:, None] * (means - xbar)), s)
2367
+ V, ev = np.zeros((p, p)), np.zeros(p)
2368
+ k.lda_eigen(np.ascontiguousarray(St - Sw), np.ascontiguousarray(Sw.copy()), V, ev, p)
2369
+ self.explained_variance_ratio_ = (ev / np.sum(ev))[:self._max_components]
2370
+ self.scalings_ = V
2371
+ self.coef_ = means @ V @ V.T
2372
+ self.intercept_ = -0.5 * np.diag(means @ self.coef_.T) + np.log(priors)
2373
+ if K == 2:
2374
+ self.coef_ = (self.coef_[1, :] - self.coef_[0, :]).reshape(1, -1)
2375
+ self.intercept_ = np.asarray(self.intercept_[1] - self.intercept_[0]).reshape(1)
2376
+ return self
2377
+
2378
+ def decision_function(self, X):
2379
+ check_is_fitted(self)
2380
+ d = pred_x(self, X) @ self.coef_.T + self.intercept_
2381
+ return d.ravel() if d.shape[1] == 1 else d
2382
+
2383
+ def predict(self, X):
2384
+ d = self.decision_function(X)
2385
+ idx = (d > 0).astype(int) if d.ndim == 1 else d.argmax(axis=1)
2386
+ return self.classes_[idx]
2387
+
2388
+ def predict_proba(self, X):
2389
+ d = self.decision_function(X)
2390
+ if d.ndim == 1:
2391
+ p1 = 1.0 / (1.0 + np.exp(-d))
2392
+ return np.stack([1 - p1, p1], axis=1)
2393
+ e = np.exp(d - d.max(axis=1, keepdims=True))
2394
+ return e / e.sum(axis=1, keepdims=True)
2395
+
2396
+ def predict_log_proba(self, X):
2397
+ P = self.predict_proba(X)
2398
+ with np.errstate(divide="ignore"):
2399
+ return np.log(P)
2400
+
2401
+ def transform(self, X):
2402
+ if self.solver == "lsqr":
2403
+ raise NotImplementedError(
2404
+ "transform not implemented for 'lsqr' solver (use 'svd' or 'eigen').")
2405
+ check_is_fitted(self)
2406
+ X = pred_x(self, X)
2407
+ Xn = (X - self.xbar_) @ self.scalings_ if self.solver == "svd" else X @ self.scalings_
2408
+ return Xn[:, :self._max_components]
2409
+
2410
+
2247
2411
  class ParallelFastICA(Tagged, TransformerMixin, BaseEstimator):
2248
2412
  """FastICA, scikit-learn's ``FastICA`` at its defaults translated
2249
2413
  whole (``examples/kernel-only/fastica.scm``: algorithm="parallel",
@@ -122,6 +122,16 @@ def sym_eigen_top(a, v, ev, e, m, k):
122
122
  e = np.ascontiguousarray(e, dtype=np.float64)
123
123
  return _lib.scm2cpp_sym_eigen_top(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), e.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m, k)
124
124
 
125
+ _lib.scm2cpp_sym_eigen_gen.restype = ctypes.c_int
126
+ _lib.scm2cpp_sym_eigen_gen.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
127
+ def sym_eigen_gen(a, b, v, ev, e, m):
128
+ a = np.ascontiguousarray(a, dtype=np.float64)
129
+ b = np.ascontiguousarray(b, dtype=np.float64)
130
+ v = np.ascontiguousarray(v, dtype=np.float64)
131
+ ev = np.ascontiguousarray(ev, dtype=np.float64)
132
+ e = np.ascontiguousarray(e, dtype=np.float64)
133
+ return _lib.scm2cpp_sym_eigen_gen(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), b.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), e.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m)
134
+
125
135
  _lib.scm2cpp_pca.restype = ctypes.c_int
126
136
  _lib.scm2cpp_pca.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int]
127
137
  def pca(x, comps, ev, sv, mean, n, p):
@@ -251,6 +251,16 @@ def sym_eigen_top(a, v, ev, e, m, k):
251
251
  e = np.ascontiguousarray(e, dtype=np.float64)
252
252
  return _lib.scm2cpp_sym_eigen_top(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), e.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m, k)
253
253
 
254
+ _lib.scm2cpp_sym_eigen_gen.restype = ctypes.c_int
255
+ _lib.scm2cpp_sym_eigen_gen.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
256
+ def sym_eigen_gen(a, b, v, ev, e, m):
257
+ a = np.ascontiguousarray(a, dtype=np.float64)
258
+ b = np.ascontiguousarray(b, dtype=np.float64)
259
+ v = np.ascontiguousarray(v, dtype=np.float64)
260
+ ev = np.ascontiguousarray(ev, dtype=np.float64)
261
+ e = np.ascontiguousarray(e, dtype=np.float64)
262
+ return _lib.scm2cpp_sym_eigen_gen(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), b.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), e.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m)
263
+
254
264
  _lib.scm2cpp_ts_minnorm.restype = ctypes.c_int
255
265
  _lib.scm2cpp_ts_minnorm.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int]
256
266
  def ts_minnorm(x, y, idx, w, aa, v, ev, e, ab, s, ns, fitint, p, d):
@@ -45,6 +45,16 @@ def sym_eigen_top(a, v, ev, e, m, k):
45
45
  e = np.ascontiguousarray(e, dtype=np.float64)
46
46
  return _lib.scm2cpp_sym_eigen_top(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), a.size, v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.size, ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.size, e.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), e.size, m, k)
47
47
 
48
+ _lib.scm2cpp_sym_eigen_gen.restype = ctypes.c_int
49
+ _lib.scm2cpp_sym_eigen_gen.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int]
50
+ def sym_eigen_gen(a, b, v, ev, e, m):
51
+ a = np.ascontiguousarray(a, dtype=np.float64)
52
+ b = np.ascontiguousarray(b, dtype=np.float64)
53
+ v = np.ascontiguousarray(v, dtype=np.float64)
54
+ ev = np.ascontiguousarray(ev, dtype=np.float64)
55
+ e = np.ascontiguousarray(e, dtype=np.float64)
56
+ return _lib.scm2cpp_sym_eigen_gen(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), a.size, b.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), b.size, v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.size, ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.size, e.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), e.size, m)
57
+
48
58
  _lib.scm2cpp_ica_tanh.restype = ctypes.c_double
49
59
  _lib.scm2cpp_ica_tanh.argtypes = [ctypes.c_double]
50
60
  def ica_tanh(x):
@@ -8,7 +8,7 @@ from pathlib import Path
8
8
 
9
9
  from .._libfind import load_gramops_lib as _load_gramops_lib
10
10
 
11
- _lib = _load_gramops_lib("loops")
11
+ _lib = _load_gramops_lib("blas")
12
12
 
13
13
  _lib.scm2cpp_spd_inverse.restype = ctypes.c_int
14
14
  _lib.scm2cpp_spd_inverse.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
@@ -329,15 +329,6 @@ def eig_order(ev, ord, m):
329
329
  ord = np.ascontiguousarray(ord, dtype=np.int32)
330
330
  return _lib.scm2cpp_eig_order(ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ord.ctypes.data_as(ctypes.POINTER(ctypes.c_int)), m)
331
331
 
332
- _lib.scm2cpp_sym_eigen_top.restype = ctypes.c_int
333
- _lib.scm2cpp_sym_eigen_top.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int]
334
- def sym_eigen_top(a, v, ev, e, m, k):
335
- a = np.ascontiguousarray(a, dtype=np.float64)
336
- v = np.ascontiguousarray(v, dtype=np.float64)
337
- ev = np.ascontiguousarray(ev, dtype=np.float64)
338
- e = np.ascontiguousarray(e, dtype=np.float64)
339
- return _lib.scm2cpp_sym_eigen_top(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), e.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m, k)
340
-
341
332
  _lib.scm2cpp_ica_tanh.restype = ctypes.c_double
342
333
  _lib.scm2cpp_ica_tanh.argtypes = [ctypes.c_double]
343
334
  def ica_tanh(x):
@@ -624,3 +615,39 @@ def kpca_linear(x, xm, g, vecs, vals, n, p, c):
624
615
  vals = np.ascontiguousarray(vals, dtype=np.float64)
625
616
  return _lib.scm2cpp_kpca_linear(x.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), xm.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), g.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), vecs.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), vals.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), n, p, c)
626
617
 
618
+ _lib.scm2cpp_lda_moments.restype = ctypes.c_int
619
+ _lib.scm2cpp_lda_moments.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int, ctypes.c_int]
620
+ def lda_moments(x, lab, g, means, counts, n, p, k):
621
+ x = np.ascontiguousarray(x, dtype=np.float64)
622
+ lab = np.ascontiguousarray(lab, dtype=np.int32)
623
+ g = np.ascontiguousarray(g, dtype=np.float64)
624
+ means = np.ascontiguousarray(means, dtype=np.float64)
625
+ counts = np.ascontiguousarray(counts, dtype=np.float64)
626
+ return _lib.scm2cpp_lda_moments(x.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), lab.ctypes.data_as(ctypes.POINTER(ctypes.c_int)), g.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), means.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), counts.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), n, p, k)
627
+
628
+ _lib.scm2cpp_lda_within.restype = ctypes.c_int
629
+ _lib.scm2cpp_lda_within.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_double, ctypes.c_int, ctypes.c_int]
630
+ def lda_within(g, means, counts, n, p, k):
631
+ g = np.ascontiguousarray(g, dtype=np.float64)
632
+ means = np.ascontiguousarray(means, dtype=np.float64)
633
+ counts = np.ascontiguousarray(counts, dtype=np.float64)
634
+ return _lib.scm2cpp_lda_within(g.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), means.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), counts.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), n, p, k)
635
+
636
+ _lib.scm2cpp_lda_svd_first.restype = ctypes.c_int
637
+ _lib.scm2cpp_lda_svd_first.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
638
+ def lda_svd_first(sw, std, v, s, p):
639
+ sw = np.ascontiguousarray(sw, dtype=np.float64)
640
+ std = np.ascontiguousarray(std, dtype=np.float64)
641
+ v = np.ascontiguousarray(v, dtype=np.float64)
642
+ s = np.ascontiguousarray(s, dtype=np.float64)
643
+ return _lib.scm2cpp_lda_svd_first(sw.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), std.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), s.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), p)
644
+
645
+ _lib.scm2cpp_lda_eigen.restype = ctypes.c_int
646
+ _lib.scm2cpp_lda_eigen.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
647
+ def lda_eigen(sb, sw, v, ev, p):
648
+ sb = np.ascontiguousarray(sb, dtype=np.float64)
649
+ sw = np.ascontiguousarray(sw, dtype=np.float64)
650
+ v = np.ascontiguousarray(v, dtype=np.float64)
651
+ ev = np.ascontiguousarray(ev, dtype=np.float64)
652
+ return _lib.scm2cpp_lda_eigen(sb.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), sw.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), p)
653
+
@@ -8,7 +8,7 @@ from pathlib import Path
8
8
 
9
9
  from .._libfind import load_gramops_lib as _load_gramops_lib
10
10
 
11
- _lib = _load_gramops_lib("blas")
11
+ _lib = _load_gramops_lib("loops")
12
12
 
13
13
  _lib.scm2cpp_spd_inverse.restype = ctypes.c_int
14
14
  _lib.scm2cpp_spd_inverse.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
@@ -329,6 +329,25 @@ def eig_order(ev, ord, m):
329
329
  ord = np.ascontiguousarray(ord, dtype=np.int32)
330
330
  return _lib.scm2cpp_eig_order(ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ord.ctypes.data_as(ctypes.POINTER(ctypes.c_int)), m)
331
331
 
332
+ _lib.scm2cpp_sym_eigen_top.restype = ctypes.c_int
333
+ _lib.scm2cpp_sym_eigen_top.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int]
334
+ def sym_eigen_top(a, v, ev, e, m, k):
335
+ a = np.ascontiguousarray(a, dtype=np.float64)
336
+ v = np.ascontiguousarray(v, dtype=np.float64)
337
+ ev = np.ascontiguousarray(ev, dtype=np.float64)
338
+ e = np.ascontiguousarray(e, dtype=np.float64)
339
+ return _lib.scm2cpp_sym_eigen_top(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), e.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m, k)
340
+
341
+ _lib.scm2cpp_sym_eigen_gen.restype = ctypes.c_int
342
+ _lib.scm2cpp_sym_eigen_gen.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
343
+ def sym_eigen_gen(a, b, v, ev, e, m):
344
+ a = np.ascontiguousarray(a, dtype=np.float64)
345
+ b = np.ascontiguousarray(b, dtype=np.float64)
346
+ v = np.ascontiguousarray(v, dtype=np.float64)
347
+ ev = np.ascontiguousarray(ev, dtype=np.float64)
348
+ e = np.ascontiguousarray(e, dtype=np.float64)
349
+ return _lib.scm2cpp_sym_eigen_gen(a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), b.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), e.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), m)
350
+
332
351
  _lib.scm2cpp_ica_tanh.restype = ctypes.c_double
333
352
  _lib.scm2cpp_ica_tanh.argtypes = [ctypes.c_double]
334
353
  def ica_tanh(x):
@@ -615,3 +634,39 @@ def kpca_linear(x, xm, g, vecs, vals, n, p, c):
615
634
  vals = np.ascontiguousarray(vals, dtype=np.float64)
616
635
  return _lib.scm2cpp_kpca_linear(x.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), xm.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), g.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), vecs.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), vals.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), n, p, c)
617
636
 
637
+ _lib.scm2cpp_lda_moments.restype = ctypes.c_int
638
+ _lib.scm2cpp_lda_moments.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int, ctypes.c_int]
639
+ def lda_moments(x, lab, g, means, counts, n, p, k):
640
+ x = np.ascontiguousarray(x, dtype=np.float64)
641
+ lab = np.ascontiguousarray(lab, dtype=np.int32)
642
+ g = np.ascontiguousarray(g, dtype=np.float64)
643
+ means = np.ascontiguousarray(means, dtype=np.float64)
644
+ counts = np.ascontiguousarray(counts, dtype=np.float64)
645
+ return _lib.scm2cpp_lda_moments(x.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), lab.ctypes.data_as(ctypes.POINTER(ctypes.c_int)), g.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), means.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), counts.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), n, p, k)
646
+
647
+ _lib.scm2cpp_lda_within.restype = ctypes.c_int
648
+ _lib.scm2cpp_lda_within.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_double, ctypes.c_int, ctypes.c_int]
649
+ def lda_within(g, means, counts, n, p, k):
650
+ g = np.ascontiguousarray(g, dtype=np.float64)
651
+ means = np.ascontiguousarray(means, dtype=np.float64)
652
+ counts = np.ascontiguousarray(counts, dtype=np.float64)
653
+ return _lib.scm2cpp_lda_within(g.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), means.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), counts.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), n, p, k)
654
+
655
+ _lib.scm2cpp_lda_svd_first.restype = ctypes.c_int
656
+ _lib.scm2cpp_lda_svd_first.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
657
+ def lda_svd_first(sw, std, v, s, p):
658
+ sw = np.ascontiguousarray(sw, dtype=np.float64)
659
+ std = np.ascontiguousarray(std, dtype=np.float64)
660
+ v = np.ascontiguousarray(v, dtype=np.float64)
661
+ s = np.ascontiguousarray(s, dtype=np.float64)
662
+ return _lib.scm2cpp_lda_svd_first(sw.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), std.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), s.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), p)
663
+
664
+ _lib.scm2cpp_lda_eigen.restype = ctypes.c_int
665
+ _lib.scm2cpp_lda_eigen.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), ctypes.c_int]
666
+ def lda_eigen(sb, sw, v, ev, p):
667
+ sb = np.ascontiguousarray(sb, dtype=np.float64)
668
+ sw = np.ascontiguousarray(sw, dtype=np.float64)
669
+ v = np.ascontiguousarray(v, dtype=np.float64)
670
+ ev = np.ascontiguousarray(ev, dtype=np.float64)
671
+ return _lib.scm2cpp_lda_eigen(sb.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), sw.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), v.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), ev.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), p)
672
+