scm2cpp-learn 0.18.0__py3-none-win_amd64.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.
Files changed (72) hide show
  1. scm2cpp_learn/__init__.py +3836 -0
  2. scm2cpp_learn/_classifiers.cp312-win_amd64.pyd +0 -0
  3. scm2cpp_learn/_compat.py +284 -0
  4. scm2cpp_learn/_generated/__init__.py +0 -0
  5. scm2cpp_learn/_generated/_loader.py +41 -0
  6. scm2cpp_learn/_generated/_loader_accel_cublas.py +173 -0
  7. scm2cpp_learn/_generated/_loader_classifiers.py +308 -0
  8. scm2cpp_learn/_generated/_loader_derived_blas.py +29 -0
  9. scm2cpp_learn/_generated/_loader_derived_cublas.py +29 -0
  10. scm2cpp_learn/_generated/_loader_derived_loops.py +29 -0
  11. scm2cpp_learn/_generated/_loader_gpu_cuda.py +313 -0
  12. scm2cpp_learn/_generated/_loader_gramops_blas.py +692 -0
  13. scm2cpp_learn/_generated/_loader_gramops_loops.py +711 -0
  14. scm2cpp_learn/_generated/_loader_nmf_blas.py +29 -0
  15. scm2cpp_learn/_generated/_loader_nmf_cublas.py +29 -0
  16. scm2cpp_learn/_generated/_loader_nmf_loops.py +29 -0
  17. scm2cpp_learn/_generated/accel_cublas/accel.cpp +24 -0
  18. scm2cpp_learn/_generated/accel_cublas/accel.hpp +1178 -0
  19. scm2cpp_learn/_generated/accel_cublas/accel_capi.cpp +76 -0
  20. scm2cpp_learn/_generated/classifiers.cpp +37 -0
  21. scm2cpp_learn/_generated/classifiers.hpp +3745 -0
  22. scm2cpp_learn/_generated/classifiers_capi.cpp +115 -0
  23. scm2cpp_learn/_generated/derived_blas/lasso_design.cpp +5 -0
  24. scm2cpp_learn/_generated/derived_blas/lasso_design.hpp +156 -0
  25. scm2cpp_learn/_generated/derived_blas/lasso_design_capi.cpp +19 -0
  26. scm2cpp_learn/_generated/derived_cublas/lasso_design.cpp +5 -0
  27. scm2cpp_learn/_generated/derived_cublas/lasso_design.hpp +158 -0
  28. scm2cpp_learn/_generated/derived_cublas/lasso_design_capi.cpp +19 -0
  29. scm2cpp_learn/_generated/derived_loops/lasso_design.cpp +5 -0
  30. scm2cpp_learn/_generated/derived_loops/lasso_design.hpp +179 -0
  31. scm2cpp_learn/_generated/derived_loops/lasso_design_capi.cpp +19 -0
  32. scm2cpp_learn/_generated/gpu_cuda/gpu.cpp +37 -0
  33. scm2cpp_learn/_generated/gpu_cuda/gpu.hpp +3846 -0
  34. scm2cpp_learn/_generated/gpu_cuda/gpu_capi.cpp +308 -0
  35. scm2cpp_learn/_generated/gramops_blas/gramops.cpp +82 -0
  36. scm2cpp_learn/_generated/gramops_blas/gramops.hpp +5411 -0
  37. scm2cpp_learn/_generated/gramops_blas/gramops_capi.cpp +244 -0
  38. scm2cpp_learn/_generated/gramops_loops/gramops.cpp +82 -0
  39. scm2cpp_learn/_generated/gramops_loops/gramops.hpp +6395 -0
  40. scm2cpp_learn/_generated/gramops_loops/gramops_capi.cpp +250 -0
  41. scm2cpp_learn/_generated/lasso_cov.cpp +7 -0
  42. scm2cpp_learn/_generated/lasso_cov.hpp +152 -0
  43. scm2cpp_learn/_generated/lasso_cov_capi.cpp +25 -0
  44. scm2cpp_learn/_generated/nmf_blas/nmf_cd.cpp +5 -0
  45. scm2cpp_learn/_generated/nmf_blas/nmf_cd.hpp +132 -0
  46. scm2cpp_learn/_generated/nmf_blas/nmf_cd_capi.cpp +19 -0
  47. scm2cpp_learn/_generated/nmf_cublas/nmf_cd.cpp +5 -0
  48. scm2cpp_learn/_generated/nmf_cublas/nmf_cd.hpp +136 -0
  49. scm2cpp_learn/_generated/nmf_cublas/nmf_cd_capi.cpp +19 -0
  50. scm2cpp_learn/_generated/nmf_loops/nmf_cd.cpp +5 -0
  51. scm2cpp_learn/_generated/nmf_loops/nmf_cd.hpp +167 -0
  52. scm2cpp_learn/_generated/nmf_loops/nmf_cd_capi.cpp +19 -0
  53. scm2cpp_learn/_generated/scm2cpp-blas.hpp +158 -0
  54. scm2cpp_learn/_generated/scm2cpp-cublas.hpp +155 -0
  55. scm2cpp_learn/_generated/scm2cpp-cuda.hpp +285 -0
  56. scm2cpp_learn/_generated/scm2cpp.hpp +1627 -0
  57. scm2cpp_learn/_gramops_blas.cp312-win_amd64.pyd +0 -0
  58. scm2cpp_learn/_lasso_cov.cp312-win_amd64.pyd +0 -0
  59. scm2cpp_learn/_lasso_derived_blas.cp312-win_amd64.pyd +0 -0
  60. scm2cpp_learn/_libfind.py +153 -0
  61. scm2cpp_learn/_nmf_blas.cp312-win_amd64.pyd +0 -0
  62. scm2cpp_learn/batch_capi.cu +428 -0
  63. scm2cpp_learn-0.18.0.dist-info/DELVEWHEEL +2 -0
  64. scm2cpp_learn-0.18.0.dist-info/METADATA +1171 -0
  65. scm2cpp_learn-0.18.0.dist-info/RECORD +72 -0
  66. scm2cpp_learn-0.18.0.dist-info/WHEEL +5 -0
  67. scm2cpp_learn-0.18.0.dist-info/top_level.txt +1 -0
  68. scm2cpp_learn.libs/.load-order-scm2cpp_learn-0.18.0 +4 -0
  69. scm2cpp_learn.libs/libopenblas-0486735c359a67419d8832e3c40e2837.dll +4 -0
  70. scm2cpp_learn.libs/msvcp140-73438573e87f9a2fd944b01def13566d.dll +0 -0
  71. scm2cpp_learn.libs/vcruntime140-052ad6a20d375957e82aa6a3c441ea54.dll +0 -0
  72. scm2cpp_learn.libs/vcruntime140_1-a198370e11c6e7469d1cf0ef5b3f433d.dll +0 -0
@@ -0,0 +1,136 @@
1
+
2
+ #ifndef NMF_CD_HPP
3
+ #define NMF_CD_HPP
4
+ #define SCM2CPP_MINIMAL
5
+ #include "scm2cpp-cublas.hpp"
6
+ #include <vector>
7
+ #include "scm2cpp.hpp"
8
+
9
+ double
10
+ nmf_half( scm2cpp::cspan<double> x, scm2cpp::span<double> w, scm2cpp::cspan<double> ht, int n, int p, int k );
11
+ SCM2CPP_FN int
12
+ nmf( scm2cpp::cspan<double> x, scm2cpp::cspan<double> xt, scm2cpp::span<double> w, scm2cpp::span<double> ht, int iters, double tol, int n, int p, int k );
13
+
14
+
15
+
16
+ inline double
17
+ nmf_half( scm2cpp::cspan<double> x, scm2cpp::span<double> w, scm2cpp::cspan<double> ht, int n, int p, int k )
18
+ { scm2cpp::device_matrix d24299 = scm2cpp::dmat_upload(ht, (p*k), 1);
19
+ if( k < p ) {
20
+ double violation = 0.0;
21
+ std::vector<double> b024287(k,0.0);
22
+ std::vector<double> g24286((k*k),0.0);
23
+ std::vector<double> c24285((n*k),0.0);
24
+ scm2cpp::device_matrix d24297 = scm2cpp::dmat_upload(ht, (p*k), 1);
25
+ scm2cpp::device_matrix d24298 = scm2cpp::dmat_upload(x, (n*p), 1);
26
+ scm2cpp::blas_syrk(g24286, d24297, 1.0, 0.0, 1, k, p) ;
27
+ scm2cpp::blas_gemm(c24285, d24298, d24297, 1.0, 0.0, 0, 0, n, k, p) ;
28
+ scm2cpp::blas_gemm(c24285, scm2cpp::dmat_upload(w, (n*k), 1), scm2cpp::dmat_upload(g24286, (k*k), 1), -1.0, 1.0, 0, 0, n, k, k) ;
29
+ for( int t = 0 ; !(t == k) ; t = (t+1) ) {
30
+ double hess = ([&]() -> double { int i2053 = 0; double r2054 = 0.0; while (!(i2053 == p)) {
31
+ int i2053_next24303 = (i2053+1);
32
+ double r2054_next24304 = (r2054+(ht[((i2053*k)+t)]*ht[((i2053*k)+t)]));
33
+ i2053 = i2053_next24303;
34
+ r2054 = r2054_next24304;
35
+ } return r2054; })();
36
+ for( int i = 0 ; !(i == n) ; i = (i+1) ) {
37
+ double grad = 0.0;
38
+ double old = w[((i*k)+t)];
39
+ grad = (grad-c24285[((i*k)+t)]) ;
40
+ double pg = ( ( old == 0.0 ) ? (( ( grad < 0.0 ) ? (grad) : (0.0) )) : (grad) );
41
+ violation = (violation+( ( pg < 0.0 ) ? ((0.0-pg)) : (pg) )) ;
42
+ ;
43
+ if( !(hess == 0.0) ) {
44
+ double wnew = (old-(grad/hess));
45
+ double wc = ( ( wnew < 0.0 ) ? (0.0) : (wnew) );
46
+ w[ ((i*k)+t) ] = wc ;
47
+ if( !(wc == old) ) {
48
+ for( int k24289 = 0 ; !(k24289 == k) ; k24289 = (k24289+1) ) {
49
+ c24285[ ((i*k)+k24289) ] = (c24285[((i*k)+k24289)]-(g24286[((t*k)+k24289)]*(wc-old))) ;
50
+ } ;
51
+ } else {
52
+ false ;
53
+ } ;
54
+ ;
55
+ ;
56
+ } else {
57
+ false ;
58
+ } ;
59
+ ;
60
+ } ;
61
+ ;
62
+ } ;
63
+ 0 ;
64
+ ;
65
+ ;
66
+ return violation ;
67
+ }
68
+ else {
69
+ std::vector<double> r((n*p),0.0);
70
+ for( int i2052 = 0 ; !(i2052 == (n*p)) ; i2052 = (i2052+1) ) {
71
+ r[ i2052 ] = x[i2052] ;
72
+ } ;
73
+ scm2cpp::blas_gemm(r, scm2cpp::dmat_upload(w, (n*k), 1), d24299, -1.0, 1.0, 0, 1, n, p, k) ;
74
+ double violation = 0.0;
75
+ for( int t = 0 ; !(t == k) ; t = (t+1) ) {
76
+ double hess = 0.0;
77
+ for( int j = 0 ; !(j == p) ; j = (j+1) ) {
78
+ hess = (hess+(ht[((j*k)+t)]*ht[((j*k)+t)])) ;
79
+ } ;
80
+ for( int i = 0 ; !(i == n) ; i = (i+1) ) {
81
+ double grad = 0.0;
82
+ double old = w[((i*k)+t)];
83
+ for( int j = 0 ; !(j == p) ; j = (j+1) ) {
84
+ grad = (grad-(r[((i*p)+j)]*ht[((j*k)+t)])) ;
85
+ } ;
86
+ double pg = ( ( old == 0.0 ) ? (( ( grad < 0.0 ) ? (grad) : (0.0) )) : (grad) );
87
+ violation = (violation+( ( pg < 0.0 ) ? ((0.0-pg)) : (pg) )) ;
88
+ ;
89
+ if( !(hess == 0.0) ) {
90
+ double wnew = (old-(grad/hess));
91
+ double wc = ( ( wnew < 0.0 ) ? (0.0) : (wnew) );
92
+ w[ ((i*k)+t) ] = wc ;
93
+ if( !(wc == old) ) {
94
+ for( int j = 0 ; !(j == p) ; j = (j+1) ) {
95
+ r[ ((i*p)+j) ] = (r[((i*p)+j)]-(ht[((j*k)+t)]*(wc-old))) ;
96
+ } ;
97
+ } else {
98
+ false ;
99
+ } ;
100
+ ;
101
+ ;
102
+ } else {
103
+ false ;
104
+ } ;
105
+ ;
106
+ } ;
107
+ ;
108
+ } ;
109
+ return violation ;
110
+ }
111
+ }
112
+
113
+
114
+ SCM2CPP_FN inline int
115
+ nmf( scm2cpp::cspan<double> x, scm2cpp::cspan<double> xt, scm2cpp::span<double> w, scm2cpp::span<double> ht, int iters, double tol, int n, int p, int k )
116
+ { double vinit = 0.0;
117
+ int stop = 0;
118
+ int it = 0;
119
+ for( ; !((stop == 1 || it >= iters)) ; ) {
120
+ it = (it+1) ;
121
+ double v = (nmf_half(x,w,ht,n,p,k)+nmf_half(xt,ht,w,p,n,k));
122
+ if( it == 1 ) {
123
+ vinit = v ;
124
+ } else {
125
+ 0 ;
126
+ } ;
127
+ if( (vinit == 0.0 || (v/vinit) <= tol) ) {
128
+ stop = 1 ;
129
+ } else {
130
+ 0 ;
131
+ } ;
132
+ ;
133
+ } ;
134
+ return it ;
135
+ }
136
+ #endif // NMF_CD_HPP
@@ -0,0 +1,19 @@
1
+ // extern "C" wrappers over the translated functions, for Python and
2
+ // any other caller that speaks the C ABI. Array parameters arrive as
3
+ // element pointers: a view parameter takes the pointer as it is, so
4
+ // the caller's buffer is read and written in place with no copy; a
5
+ // fixed-extent one is reinterpreted as the std::array the function
6
+ // expects. The caller guarantees the length either way.
7
+ // Build (boost includes only if the generated header asks for them,
8
+ // which a numeric kernel's does not):
9
+ // g++ -O2 -std=c++17 -shared -fPIC -I. -o libnmf_cd.so nmf_cd_capi.cpp
10
+ #include "nmf_cd.hpp"
11
+ #include <vector>
12
+ #include <algorithm>
13
+
14
+ extern "C" double scm2cpp_nmf_half(double* x, double* w, double* ht, int n, int p, int k) {
15
+ return nmf_half(x, w, ht, n, p, k);
16
+ }
17
+ extern "C" int scm2cpp_nmf(double* x, double* xt, double* w, double* ht, int iters, double tol, int n, int p, int k) {
18
+ return nmf(x, xt, w, ht, iters, tol, n, p, k);
19
+ }
@@ -0,0 +1,5 @@
1
+
2
+ #include "nmf_cd.hpp"
3
+ // #include "scm2cpp.hpp"
4
+
5
+
@@ -0,0 +1,167 @@
1
+
2
+ #ifndef NMF_CD_HPP
3
+ #define NMF_CD_HPP
4
+ #define SCM2CPP_MINIMAL
5
+ #include <vector>
6
+ #include "scm2cpp.hpp"
7
+
8
+ double
9
+ nmf_half( scm2cpp::cspan<double> x, scm2cpp::span<double> w, scm2cpp::cspan<double> ht, int n, int p, int k );
10
+ SCM2CPP_FN int
11
+ nmf( scm2cpp::cspan<double> x, scm2cpp::cspan<double> xt, scm2cpp::span<double> w, scm2cpp::span<double> ht, int iters, double tol, int n, int p, int k );
12
+
13
+
14
+
15
+ inline double
16
+ nmf_half( scm2cpp::cspan<double> x, scm2cpp::span<double> w, scm2cpp::cspan<double> ht, int n, int p, int k )
17
+ { if( k < p ) {
18
+ double violation = 0.0;
19
+ std::vector<double> b024287(k,0.0);
20
+ std::vector<double> g24286((k*k),0.0);
21
+ std::vector<double> c24285((n*k),0.0);
22
+ for( int y2059 = 0 ; !(y2059 == k) ; y2059 = (y2059+1) ) {
23
+ for( int y2060 = 0 ; !(y2060 == k) ; y2060 = (y2060+1) ) {
24
+ g24286[ ((y2059*k)+y2060) ] = ([&]() -> double { int k2061 = 0; double sum2071 = 0.0; while (!(k2061 == p)) {
25
+ int k2061_next24297 = (k2061+1);
26
+ double sum2071_next24298 = (sum2071+(ht[((k2061*k)+y2060)]*ht[((k2061*k)+y2059)]));
27
+ k2061 = k2061_next24297;
28
+ sum2071 = sum2071_next24298;
29
+ } return sum2071; })() ;
30
+ } ;
31
+ } ;
32
+ for( int y2062 = 0 ; !(y2062 == n) ; y2062 = (y2062+1) ) {
33
+ for( int y2063 = 0 ; !(y2063 == k) ; y2063 = (y2063+1) ) {
34
+ c24285[ ((y2062*k)+y2063) ] = ([&]() -> double { int k2064 = 0; double sum2073 = 0.0; while (!(k2064 == p)) {
35
+ int k2064_next24299 = (k2064+1);
36
+ double sum2073_next24300 = (sum2073+(x[((y2062*p)+k2064)]*ht[((k2064*k)+y2063)]));
37
+ k2064 = k2064_next24299;
38
+ sum2073 = sum2073_next24300;
39
+ } return sum2073; })() ;
40
+ } ;
41
+ } ;
42
+ for( int y2065 = 0 ; !(y2065 == n) ; y2065 = (y2065+1) ) {
43
+ for( int y2066 = 0 ; !(y2066 == k) ; y2066 = (y2066+1) ) {
44
+ c24285[ ((y2065*k)+y2066) ] = (c24285[((y2065*k)+y2066)]-([&]() -> double { int k2067 = 0; double sum2075 = 0.0; while (!(k2067 == k)) {
45
+ int k2067_next24301 = (k2067+1);
46
+ double sum2075_next24302 = (sum2075+(w[((y2065*k)+k2067)]*g24286[((k2067*k)+y2066)]));
47
+ k2067 = k2067_next24301;
48
+ sum2075 = sum2075_next24302;
49
+ } return sum2075; })()) ;
50
+ } ;
51
+ } ;
52
+ for( int t = 0 ; !(t == k) ; t = (t+1) ) {
53
+ double hess = ([&]() -> double { int i2068 = 0; double r2069 = 0.0; while (!(i2068 == p)) {
54
+ int i2068_next24303 = (i2068+1);
55
+ double r2069_next24304 = (r2069+(ht[((i2068*k)+t)]*ht[((i2068*k)+t)]));
56
+ i2068 = i2068_next24303;
57
+ r2069 = r2069_next24304;
58
+ } return r2069; })();
59
+ for( int i = 0 ; !(i == n) ; i = (i+1) ) {
60
+ double grad = 0.0;
61
+ double old = w[((i*k)+t)];
62
+ grad = (grad-c24285[((i*k)+t)]) ;
63
+ double pg = ( ( old == 0.0 ) ? (( ( grad < 0.0 ) ? (grad) : (0.0) )) : (grad) );
64
+ violation = (violation+( ( pg < 0.0 ) ? ((0.0-pg)) : (pg) )) ;
65
+ ;
66
+ if( !(hess == 0.0) ) {
67
+ double wnew = (old-(grad/hess));
68
+ double wc = ( ( wnew < 0.0 ) ? (0.0) : (wnew) );
69
+ w[ ((i*k)+t) ] = wc ;
70
+ if( !(wc == old) ) {
71
+ for( int k24289 = 0 ; !(k24289 == k) ; k24289 = (k24289+1) ) {
72
+ c24285[ ((i*k)+k24289) ] = (c24285[((i*k)+k24289)]-(g24286[((t*k)+k24289)]*(wc-old))) ;
73
+ } ;
74
+ } else {
75
+ false ;
76
+ } ;
77
+ ;
78
+ ;
79
+ } else {
80
+ false ;
81
+ } ;
82
+ ;
83
+ } ;
84
+ ;
85
+ } ;
86
+ 0 ;
87
+ ;
88
+ return violation ;
89
+ }
90
+ else {
91
+ std::vector<double> r((n*p),0.0);
92
+ for( int i2052 = 0 ; !(i2052 == (n*p)) ; i2052 = (i2052+1) ) {
93
+ r[ i2052 ] = x[i2052] ;
94
+ } ;
95
+ for( int k2053 = 0 ; !(k2053 == n) ; k2053 = (k2053+1) ) {
96
+ for( int k2054 = 0 ; !(k2054 == p) ; k2054 = (k2054+1) ) {
97
+ r[ ((k2053*p)+k2054) ] = (r[((k2053*p)+k2054)]-([&]() -> double { int i2056 = 0; double r2057 = 0.0; while (!(i2056 == k)) {
98
+ int i2056_next24305 = (i2056+1);
99
+ double r2057_next24306 = (r2057+(w[((k2053*k)+i2056)]*ht[((k2054*k)+i2056)]));
100
+ i2056 = i2056_next24305;
101
+ r2057 = r2057_next24306;
102
+ } return r2057; })()) ;
103
+ } ;
104
+ } ;
105
+ double violation = 0.0;
106
+ for( int t = 0 ; !(t == k) ; t = (t+1) ) {
107
+ double hess = 0.0;
108
+ for( int j = 0 ; !(j == p) ; j = (j+1) ) {
109
+ hess = (hess+(ht[((j*k)+t)]*ht[((j*k)+t)])) ;
110
+ } ;
111
+ for( int i = 0 ; !(i == n) ; i = (i+1) ) {
112
+ double grad = 0.0;
113
+ double old = w[((i*k)+t)];
114
+ for( int j = 0 ; !(j == p) ; j = (j+1) ) {
115
+ grad = (grad-(r[((i*p)+j)]*ht[((j*k)+t)])) ;
116
+ } ;
117
+ double pg = ( ( old == 0.0 ) ? (( ( grad < 0.0 ) ? (grad) : (0.0) )) : (grad) );
118
+ violation = (violation+( ( pg < 0.0 ) ? ((0.0-pg)) : (pg) )) ;
119
+ ;
120
+ if( !(hess == 0.0) ) {
121
+ double wnew = (old-(grad/hess));
122
+ double wc = ( ( wnew < 0.0 ) ? (0.0) : (wnew) );
123
+ w[ ((i*k)+t) ] = wc ;
124
+ if( !(wc == old) ) {
125
+ for( int j = 0 ; !(j == p) ; j = (j+1) ) {
126
+ r[ ((i*p)+j) ] = (r[((i*p)+j)]-(ht[((j*k)+t)]*(wc-old))) ;
127
+ } ;
128
+ } else {
129
+ false ;
130
+ } ;
131
+ ;
132
+ ;
133
+ } else {
134
+ false ;
135
+ } ;
136
+ ;
137
+ } ;
138
+ ;
139
+ } ;
140
+ return violation ;
141
+ }
142
+ }
143
+
144
+
145
+ SCM2CPP_FN inline int
146
+ nmf( scm2cpp::cspan<double> x, scm2cpp::cspan<double> xt, scm2cpp::span<double> w, scm2cpp::span<double> ht, int iters, double tol, int n, int p, int k )
147
+ { double vinit = 0.0;
148
+ int stop = 0;
149
+ int it = 0;
150
+ for( ; !((stop == 1 || it >= iters)) ; ) {
151
+ it = (it+1) ;
152
+ double v = (nmf_half(x,w,ht,n,p,k)+nmf_half(xt,ht,w,p,n,k));
153
+ if( it == 1 ) {
154
+ vinit = v ;
155
+ } else {
156
+ 0 ;
157
+ } ;
158
+ if( (vinit == 0.0 || (v/vinit) <= tol) ) {
159
+ stop = 1 ;
160
+ } else {
161
+ 0 ;
162
+ } ;
163
+ ;
164
+ } ;
165
+ return it ;
166
+ }
167
+ #endif // NMF_CD_HPP
@@ -0,0 +1,19 @@
1
+ // extern "C" wrappers over the translated functions, for Python and
2
+ // any other caller that speaks the C ABI. Array parameters arrive as
3
+ // element pointers: a view parameter takes the pointer as it is, so
4
+ // the caller's buffer is read and written in place with no copy; a
5
+ // fixed-extent one is reinterpreted as the std::array the function
6
+ // expects. The caller guarantees the length either way.
7
+ // Build (boost includes only if the generated header asks for them,
8
+ // which a numeric kernel's does not):
9
+ // g++ -O2 -std=c++17 -shared -fPIC -I. -o libnmf_cd.so nmf_cd_capi.cpp
10
+ #include "nmf_cd.hpp"
11
+ #include <vector>
12
+ #include <algorithm>
13
+
14
+ extern "C" double scm2cpp_nmf_half(double* x, double* w, double* ht, int n, int p, int k) {
15
+ return nmf_half(x, w, ht, n, p, k);
16
+ }
17
+ extern "C" int scm2cpp_nmf(double* x, double* xt, double* w, double* ht, int iters, double tol, int n, int p, int k) {
18
+ return nmf(x, xt, w, ht, iters, tol, n, p, k);
19
+ }
@@ -0,0 +1,158 @@
1
+ // The contractions of the array algebra as cblas calls: what the ops
2
+ // of bindings/cblas-binding.scm expand to under --blas.
3
+ //
4
+ // Every array is a flat row-major container of doubles (std::vector,
5
+ // boost::array, anything with operator[] over contiguous storage).
6
+ // A contraction whose summed axes sit at the front or the back of
7
+ // each operand is one dgemm over the matrices the other axes flatten
8
+ // to: ta says the left operand is stored k x m (op(a) = a^T) rather
9
+ // than m x k, tb that the right one is stored n x k rather than k x n.
10
+ // Link with -lopenblas or another cblas.
11
+ #ifndef SCM2CPP_BLAS_HPP
12
+ #define SCM2CPP_BLAS_HPP
13
+
14
+ // SCM2CPP_MKL: Intel MKL's names for the same two interfaces (the
15
+ // package's setup.py defines it when it links MKL)
16
+ // MSVC's C++ has no C99 _Complex, which lapack.h falls back to; it
17
+ // takes std::complex when lapack_complex_* are defined first (nothing
18
+ // here calls a complex routine, so their layout never matters)
19
+ #if defined(_MSC_VER) && !defined(lapack_complex_float)
20
+ #include <complex>
21
+ #define lapack_complex_float std::complex<float>
22
+ #define lapack_complex_double std::complex<double>
23
+ #endif
24
+ #ifdef SCM2CPP_MKL
25
+ #include <mkl_cblas.h>
26
+ #include <mkl_lapacke.h>
27
+ #else
28
+ #include <cblas.h>
29
+ #include <lapacke.h>
30
+ #endif
31
+ #include <cstddef>
32
+ #include <vector>
33
+
34
+ namespace scm2cpp {
35
+
36
+ // y (m x n) = alpha op(a) op(b) + beta y. A product whose m or n is 1
37
+ // at run time (one class of a logistic regression, say) is a dgemv: the
38
+ // vector operand is contiguous either way, and OpenBLAS's dgemm with a
39
+ // unit dimension costs a third more than its dgemv.
40
+ template <class Y, class A, class B>
41
+ inline void blas_gemm(Y& y, const A& a, const B& b, double alpha, double beta,
42
+ int ta, int tb, int m, int n, int k) {
43
+ if (n == 1)
44
+ cblas_dgemv(CblasRowMajor, ta ? CblasTrans : CblasNoTrans, ta ? k : m, ta ? m : k,
45
+ alpha, &a[0], ta ? m : k, &b[0], 1, beta, &y[0], 1);
46
+ else if (m == 1)
47
+ cblas_dgemv(CblasRowMajor, tb ? CblasNoTrans : CblasTrans, tb ? n : k, tb ? k : n,
48
+ alpha, &b[0], tb ? k : n, &a[0], 1, beta, &y[0], 1);
49
+ else
50
+ cblas_dgemm(CblasRowMajor, ta ? CblasTrans : CblasNoTrans,
51
+ tb ? CblasTrans : CblasNoTrans, m, n, k,
52
+ alpha, &a[0], ta ? m : k, &b[0], tb ? k : n, beta, &y[0], n);
53
+ }
54
+
55
+ // y (m) = alpha op(a) v + beta y (v k)
56
+ template <class Y, class A, class V>
57
+ inline void blas_gemv(Y& y, const A& a, const V& v, double alpha, double beta,
58
+ int ta, int m, int k) {
59
+ if (ta)
60
+ cblas_dgemv(CblasRowMajor, CblasTrans, k, m, alpha, &a[0], m, &v[0], 1,
61
+ beta, &y[0], 1);
62
+ else
63
+ cblas_dgemv(CblasRowMajor, CblasNoTrans, m, k, alpha, &a[0], k, &v[0], 1,
64
+ beta, &y[0], 1);
65
+ }
66
+
67
+ // batch slabs of the same: y[l] (m x n) = alpha op(a[l]) op(b[l]) +
68
+ // beta y[l] for l below batch, the slabs contiguous (strides m*k,
69
+ // k*n, m*n): a contraction whose leading labels are shared by both
70
+ // operands and the result
71
+ template <class Y, class A, class B>
72
+ inline void blas_gemm_batched(Y& y, const A& a, const B& b, double alpha, double beta,
73
+ int ta, int tb, int m, int n, int k, int batch) {
74
+ for (int l = 0; l < batch; ++l)
75
+ cblas_dgemm(CblasRowMajor, ta ? CblasTrans : CblasNoTrans,
76
+ tb ? CblasTrans : CblasNoTrans, m, n, k,
77
+ alpha, &a[(size_t)l * m * k], ta ? m : k,
78
+ &b[(size_t)l * k * n], tb ? k : n, beta, &y[(size_t)l * m * n], n);
79
+ }
80
+
81
+ // y (m x m) = alpha op(a) op(a)^T + beta y: the Gram matrix, one
82
+ // triangle by dsyrk and the other mirrored
83
+ template <class Y, class A>
84
+ inline void blas_syrk(Y& y, const A& a, double alpha, double beta, int ta,
85
+ int m, int k) {
86
+ cblas_dsyrk(CblasRowMajor, CblasUpper, ta ? CblasTrans : CblasNoTrans, m, k,
87
+ alpha, &a[0], ta ? m : k, beta, &y[0], m);
88
+ for (int i = 1; i < m; ++i)
89
+ for (int j = 0; j < i; ++j)
90
+ y[i * m + j] = y[j * m + i];
91
+ }
92
+
93
+ // The symmetric eigenproblem as sym-eigen.scm states it: A (m x m,
94
+ // symmetric, row-major) is destroyed, V gets the eigenvectors as
95
+ // columns (V[j m + c] is entry j of vector c), EV the eigenvalues
96
+ // (ascending here; the callers order them themselves). dsyevd, the
97
+ // divide and conquer that numpy's eigh runs, leaves the vectors in A
98
+ // in exactly that layout. Returns 0, or LAPACK's info.
99
+ template <class A, class V, class E>
100
+ inline int lapack_syevd(A& a, V& v, E& ev, int m) {
101
+ int info = LAPACKE_dsyevd(LAPACK_ROW_MAJOR, 'V', 'U', m, &a[0], m, &ev[0]);
102
+ for (std::size_t t = 0; t < (std::size_t)m * m; ++t) v[t] = a[t];
103
+ return info;
104
+ }
105
+
106
+ // The K largest eigenpairs as sym-eigen.scm's sym-eigen-top states
107
+ // them: A (m x m) destroyed, EV the values in decreasing order, V (m x
108
+ // K) the vectors as columns. dsyevr over the index range m-K+1..m (what
109
+ // scipy's eigh with subset_by_index runs), which gives them increasing;
110
+ // reversed here. Returns LAPACK's info.
111
+ template <class A, class V, class E>
112
+ inline int lapack_syevr_top(A& a, V& v, E& ev, int m, int k) {
113
+ if (k <= 0) return 0;
114
+ std::vector<double> w(m), z((std::size_t)m * k);
115
+ std::vector<lapack_int> isuppz(2 * (std::size_t)k);
116
+ lapack_int found = 0;
117
+ int info = LAPACKE_dsyevr(LAPACK_ROW_MAJOR, 'V', 'I', 'U', m, &a[0], m, 0.0, 0.0,
118
+ m - k + 1, m, 0.0, &found, w.data(), z.data(), k, isuppz.data());
119
+ for (int c = 0; c < k; ++c) {
120
+ ev[c] = w[k - 1 - c];
121
+ for (int j = 0; j < m; ++j) v[(std::size_t)j * k + c] = z[(std::size_t)j * k + (k - 1 - c)];
122
+ }
123
+ return info;
124
+ }
125
+
126
+ // A v = lam B v as sym-eigen.scm's sym-eigen-gen states it: A and B
127
+ // (m x m) destroyed, V the vectors as columns with V'BV = I, EV the
128
+ // values (increasing). dsygvd, itype 1, what scipy's eigh(a, b) runs.
129
+ // Returns LAPACK's info.
130
+ template <class A, class B, class V, class E>
131
+ inline int lapack_sygvd(A& a, B& b, V& v, E& ev, int m) {
132
+ int info = LAPACKE_dsygvd(LAPACK_ROW_MAJOR, 1, 'V', 'U', m, &a[0], m, &b[0], m, &ev[0]);
133
+ for (std::size_t t = 0; t < (std::size_t)m * m; ++t) v[t] = a[t];
134
+ return info;
135
+ }
136
+
137
+ // A W = B as gram.scm's spd-solve states it: A (m x m, positive
138
+ // definite) destroyed, B (m x q, row-major) overwritten by W. dposv,
139
+ // what numpy's solve on a positive definite matrix and scipy's
140
+ // cho_solve reach. Returns LAPACK's info (> 0: not positive definite).
141
+ template <class A, class B>
142
+ inline int lapack_posv(A& a, B& b, int m, int q) {
143
+ return LAPACKE_dposv(LAPACK_ROW_MAJOR, 'U', m, q, &a[0], m, &b[0], q);
144
+ }
145
+
146
+ // The thin SVD as sym-svd.scm states it: A (m x n, row-major) is
147
+ // destroyed, S gets the k = min(m, n) values in decreasing order, U the
148
+ // m x k left vectors, VT the k x n right ones. dgesdd, the divide and
149
+ // conquer that numpy's svd runs, with jobz 'S'. Returns LAPACK's info.
150
+ template <class A, class U, class S, class VT>
151
+ inline int lapack_gesdd(A& a, U& u, S& s, VT& vt, int m, int n) {
152
+ int k = m < n ? m : n;
153
+ return LAPACKE_dgesdd(LAPACK_ROW_MAJOR, 'S', m, n, &a[0], n, &s[0], &u[0], k, &vt[0], n);
154
+ }
155
+
156
+ } // namespace scm2cpp
157
+
158
+ #endif
@@ -0,0 +1,155 @@
1
+ // The contractions of the array algebra as cuBLAS calls: what the
2
+ // ops of bindings/cublas-binding.scm expand to under --cublas.
3
+ //
4
+ // The matrix operand of every product is a device_matrix, the copy
5
+ // of a row-major p x n host matrix that dmat_upload takes once at the
6
+ // entry of the scope using it; the vector operands are host
7
+ // containers, copied over per call and the result copied back. A
8
+ // row-major p x n host matrix is the column-major n x p matrix cuBLAS
9
+ // reads (leading dimension n), so nothing is ever transposed in
10
+ // memory. The one cuBLAS handle is created on first use.
11
+ // Compile with -I<cuda>/include, link with -lcublas -lcudart.
12
+ #ifndef SCM2CPP_CUBLAS_HPP
13
+ #define SCM2CPP_CUBLAS_HPP
14
+
15
+ #include <cublas_v2.h>
16
+ #include <cuda_runtime.h>
17
+ #include <cstdio>
18
+ #include <cstdlib>
19
+ #include <memory>
20
+
21
+ namespace scm2cpp {
22
+
23
+ inline void cuda_check(cudaError_t e, const char* what) {
24
+ if (e != cudaSuccess) {
25
+ std::fprintf(stderr, "scm2cpp-cublas: %s: %s\n", what, cudaGetErrorString(e));
26
+ std::abort();
27
+ }
28
+ }
29
+ inline void cublas_check(cublasStatus_t s, const char* what) {
30
+ if (s != CUBLAS_STATUS_SUCCESS) {
31
+ std::fprintf(stderr, "scm2cpp-cublas: %s: status %d\n", what, (int)s);
32
+ std::abort();
33
+ }
34
+ }
35
+
36
+ inline cublasHandle_t cublas_handle() {
37
+ static cublasHandle_t h = 0;
38
+ if (!h) cublas_check(cublasCreate(&h), "cublasCreate");
39
+ return h;
40
+ }
41
+
42
+ // A device copy of len doubles, freed with the last handle to it.
43
+ struct device_buffer {
44
+ std::shared_ptr<double> d;
45
+ size_t len;
46
+ device_buffer() : len(0) {}
47
+ explicit device_buffer(size_t n) : len(n) {
48
+ double* p = 0;
49
+ cuda_check(cudaMalloc((void**)&p, n * sizeof(double)), "cudaMalloc");
50
+ d.reset(p, cudaFree);
51
+ }
52
+ double* get() const { return d.get(); }
53
+ template <class V>
54
+ void upload(const V& v) {
55
+ cuda_check(cudaMemcpy(get(), &v[0], len * sizeof(double), cudaMemcpyHostToDevice),
56
+ "cudaMemcpy H2D");
57
+ }
58
+ template <class V>
59
+ void download(V& v) const {
60
+ cuda_check(cudaMemcpy(&v[0], get(), len * sizeof(double), cudaMemcpyDeviceToHost),
61
+ "cudaMemcpy D2H");
62
+ }
63
+ };
64
+
65
+ template <class V>
66
+ inline device_buffer to_device(const V& v, size_t n) {
67
+ device_buffer b(n);
68
+ b.upload(v);
69
+ return b;
70
+ }
71
+
72
+ // A row-major p x n matrix on the device.
73
+ struct device_matrix {
74
+ device_buffer buf;
75
+ int p, n;
76
+ device_matrix() : p(0), n(0) {}
77
+ device_matrix(const device_buffer& b, int p_, int n_) : buf(b), p(p_), n(n_) {}
78
+ double* get() const { return buf.get(); }
79
+ };
80
+
81
+ template <class X>
82
+ inline device_matrix dmat_upload(const X& x, int p, int n) {
83
+ return device_matrix(to_device(x, (size_t)p * n), p, n);
84
+ }
85
+
86
+ // y (m x n host) = alpha op(a) op(b) + beta y, a and b on the device.
87
+ // A row-major m x n array is the column-major n x m array of the same
88
+ // buffer, so the row-major product is the column-major product of the
89
+ // operands swapped: C^T = op(b)^T op(a)^T.
90
+ template <class Y>
91
+ inline void blas_gemm(Y& y, const device_matrix& a, const device_matrix& b,
92
+ double alpha, double beta, int ta, int tb, int m, int n, int k) {
93
+ device_buffer dy = beta != 0.0 ? to_device(y, (size_t)m * n)
94
+ : device_buffer((size_t)m * n);
95
+ cublas_check(cublasDgemm(cublas_handle(), tb ? CUBLAS_OP_T : CUBLAS_OP_N,
96
+ ta ? CUBLAS_OP_T : CUBLAS_OP_N, n, m, k,
97
+ &alpha, b.get(), tb ? k : n, a.get(), ta ? m : k,
98
+ &beta, dy.get(), n),
99
+ "cublasDgemm");
100
+ dy.download(y);
101
+ }
102
+
103
+ // batch slabs of the same in one call: y[l] (m x n) = alpha op(a[l])
104
+ // op(b[l]) + beta y[l], the slabs contiguous (strides m*k, k*n, m*n)
105
+ template <class Y>
106
+ inline void blas_gemm_batched(Y& y, const device_matrix& a, const device_matrix& b,
107
+ double alpha, double beta, int ta, int tb,
108
+ int m, int n, int k, int batch) {
109
+ const size_t total = (size_t)m * n * batch;
110
+ device_buffer dy = beta != 0.0 ? to_device(y, total) : device_buffer(total);
111
+ cublas_check(cublasDgemmStridedBatched(
112
+ cublas_handle(), tb ? CUBLAS_OP_T : CUBLAS_OP_N,
113
+ ta ? CUBLAS_OP_T : CUBLAS_OP_N, n, m, k,
114
+ &alpha, b.get(), tb ? k : n, (long long)k * n,
115
+ a.get(), ta ? m : k, (long long)m * k,
116
+ &beta, dy.get(), n, (long long)m * n, batch),
117
+ "cublasDgemmStridedBatched");
118
+ dy.download(y);
119
+ }
120
+
121
+ // y (m host) = alpha op(a) v + beta y (a device, v k host)
122
+ template <class Y, class V>
123
+ inline void blas_gemv(Y& y, const device_matrix& a, const V& v, double alpha,
124
+ double beta, int ta, int m, int k) {
125
+ device_buffer dv = to_device(v, k);
126
+ device_buffer dy = beta != 0.0 ? to_device(y, m) : device_buffer(m);
127
+ if (ta)
128
+ cublas_check(cublasDgemv(cublas_handle(), CUBLAS_OP_N, m, k, &alpha, a.get(), m,
129
+ dv.get(), 1, &beta, dy.get(), 1), "cublasDgemv");
130
+ else
131
+ cublas_check(cublasDgemv(cublas_handle(), CUBLAS_OP_T, k, m, &alpha, a.get(), k,
132
+ dv.get(), 1, &beta, dy.get(), 1), "cublasDgemv");
133
+ dy.download(y);
134
+ }
135
+
136
+ // y (m x m host) = alpha op(a) op(a)^T + beta y: one triangle by dsyrk
137
+ // over the column-major reading, the other mirrored on the host
138
+ template <class Y>
139
+ inline void blas_syrk(Y& y, const device_matrix& a, double alpha, double beta,
140
+ int ta, int m, int k) {
141
+ device_buffer dy = beta != 0.0 ? to_device(y, (size_t)m * m)
142
+ : device_buffer((size_t)m * m);
143
+ cublas_check(cublasDsyrk(cublas_handle(), CUBLAS_FILL_MODE_UPPER,
144
+ ta ? CUBLAS_OP_N : CUBLAS_OP_T, m, k, &alpha, a.get(),
145
+ ta ? m : k, &beta, dy.get(), m),
146
+ "cublasDsyrk");
147
+ dy.download(y);
148
+ for (int i = 0; i < m; ++i)
149
+ for (int j = i + 1; j < m; ++j)
150
+ y[i * m + j] = y[j * m + i];
151
+ }
152
+
153
+ } // namespace scm2cpp
154
+
155
+ #endif