scm2cpp-lasso 0.13.2__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 (65) hide show
  1. scm2cpp_lasso/__init__.py +2808 -0
  2. scm2cpp_lasso/_classifiers.cp312-win_amd64.pyd +0 -0
  3. scm2cpp_lasso/_generated/__init__.py +0 -0
  4. scm2cpp_lasso/_generated/_loader.py +41 -0
  5. scm2cpp_lasso/_generated/_loader_accel_cublas.py +140 -0
  6. scm2cpp_lasso/_generated/_loader_classifiers.py +281 -0
  7. scm2cpp_lasso/_generated/_loader_derived_blas.py +29 -0
  8. scm2cpp_lasso/_generated/_loader_derived_cublas.py +29 -0
  9. scm2cpp_lasso/_generated/_loader_derived_loops.py +29 -0
  10. scm2cpp_lasso/_generated/_loader_gpu_cuda.py +294 -0
  11. scm2cpp_lasso/_generated/_loader_gramops_blas.py +496 -0
  12. scm2cpp_lasso/_generated/_loader_gramops_loops.py +496 -0
  13. scm2cpp_lasso/_generated/_loader_nmf_blas.py +29 -0
  14. scm2cpp_lasso/_generated/_loader_nmf_cublas.py +29 -0
  15. scm2cpp_lasso/_generated/_loader_nmf_loops.py +29 -0
  16. scm2cpp_lasso/_generated/accel_cublas/accel.cpp +20 -0
  17. scm2cpp_lasso/_generated/accel_cublas/accel.hpp +1023 -0
  18. scm2cpp_lasso/_generated/accel_cublas/accel_capi.cpp +64 -0
  19. scm2cpp_lasso/_generated/classifiers.cpp +34 -0
  20. scm2cpp_lasso/_generated/classifiers.hpp +2825 -0
  21. scm2cpp_lasso/_generated/classifiers_capi.cpp +106 -0
  22. scm2cpp_lasso/_generated/derived_blas/lasso_design.cpp +5 -0
  23. scm2cpp_lasso/_generated/derived_blas/lasso_design.hpp +153 -0
  24. scm2cpp_lasso/_generated/derived_blas/lasso_design_capi.cpp +19 -0
  25. scm2cpp_lasso/_generated/derived_cublas/lasso_design.cpp +5 -0
  26. scm2cpp_lasso/_generated/derived_cublas/lasso_design.hpp +155 -0
  27. scm2cpp_lasso/_generated/derived_cublas/lasso_design_capi.cpp +19 -0
  28. scm2cpp_lasso/_generated/derived_loops/lasso_design.cpp +5 -0
  29. scm2cpp_lasso/_generated/derived_loops/lasso_design.hpp +176 -0
  30. scm2cpp_lasso/_generated/derived_loops/lasso_design_capi.cpp +19 -0
  31. scm2cpp_lasso/_generated/gpu_cuda/gpu.cpp +35 -0
  32. scm2cpp_lasso/_generated/gpu_cuda/gpu.hpp +3715 -0
  33. scm2cpp_lasso/_generated/gpu_cuda/gpu_capi.cpp +289 -0
  34. scm2cpp_lasso/_generated/gramops_blas/gramops.cpp +57 -0
  35. scm2cpp_lasso/_generated/gramops_blas/gramops.hpp +3033 -0
  36. scm2cpp_lasso/_generated/gramops_blas/gramops_capi.cpp +175 -0
  37. scm2cpp_lasso/_generated/gramops_loops/gramops.cpp +57 -0
  38. scm2cpp_lasso/_generated/gramops_loops/gramops.hpp +3302 -0
  39. scm2cpp_lasso/_generated/gramops_loops/gramops_capi.cpp +175 -0
  40. scm2cpp_lasso/_generated/lasso_cov.cpp +7 -0
  41. scm2cpp_lasso/_generated/lasso_cov.hpp +152 -0
  42. scm2cpp_lasso/_generated/lasso_cov_capi.cpp +25 -0
  43. scm2cpp_lasso/_generated/nmf_blas/nmf_cd.cpp +5 -0
  44. scm2cpp_lasso/_generated/nmf_blas/nmf_cd.hpp +132 -0
  45. scm2cpp_lasso/_generated/nmf_blas/nmf_cd_capi.cpp +19 -0
  46. scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.cpp +5 -0
  47. scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.hpp +136 -0
  48. scm2cpp_lasso/_generated/nmf_cublas/nmf_cd_capi.cpp +19 -0
  49. scm2cpp_lasso/_generated/nmf_loops/nmf_cd.cpp +5 -0
  50. scm2cpp_lasso/_generated/nmf_loops/nmf_cd.hpp +167 -0
  51. scm2cpp_lasso/_generated/nmf_loops/nmf_cd_capi.cpp +19 -0
  52. scm2cpp_lasso/_generated/scm2cpp-blas.hpp +77 -0
  53. scm2cpp_lasso/_generated/scm2cpp-cublas.hpp +155 -0
  54. scm2cpp_lasso/_generated/scm2cpp-cuda.hpp +285 -0
  55. scm2cpp_lasso/_generated/scm2cpp.hpp +1627 -0
  56. scm2cpp_lasso/_gramops_loops.cp312-win_amd64.pyd +0 -0
  57. scm2cpp_lasso/_lasso_cov.cp312-win_amd64.pyd +0 -0
  58. scm2cpp_lasso/_lasso_derived_loops.cp312-win_amd64.pyd +0 -0
  59. scm2cpp_lasso/_libfind.py +149 -0
  60. scm2cpp_lasso/_nmf_loops.cp312-win_amd64.pyd +0 -0
  61. scm2cpp_lasso/batch_capi.cu +428 -0
  62. scm2cpp_lasso-0.13.2.dist-info/METADATA +920 -0
  63. scm2cpp_lasso-0.13.2.dist-info/RECORD +65 -0
  64. scm2cpp_lasso-0.13.2.dist-info/WHEEL +5 -0
  65. scm2cpp_lasso-0.13.2.dist-info/top_level.txt +1 -0
@@ -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,77 @@
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
+ #include <cblas.h>
15
+
16
+ namespace scm2cpp {
17
+
18
+ // y (m x n) = alpha op(a) op(b) + beta y. A product whose m or n is 1
19
+ // at run time (one class of a logistic regression, say) is a dgemv: the
20
+ // vector operand is contiguous either way, and OpenBLAS's dgemm with a
21
+ // unit dimension costs a third more than its dgemv.
22
+ template <class Y, class A, class B>
23
+ inline void blas_gemm(Y& y, const A& a, const B& b, double alpha, double beta,
24
+ int ta, int tb, int m, int n, int k) {
25
+ if (n == 1)
26
+ cblas_dgemv(CblasRowMajor, ta ? CblasTrans : CblasNoTrans, ta ? k : m, ta ? m : k,
27
+ alpha, &a[0], ta ? m : k, &b[0], 1, beta, &y[0], 1);
28
+ else if (m == 1)
29
+ cblas_dgemv(CblasRowMajor, tb ? CblasNoTrans : CblasTrans, tb ? n : k, tb ? k : n,
30
+ alpha, &b[0], tb ? k : n, &a[0], 1, beta, &y[0], 1);
31
+ else
32
+ cblas_dgemm(CblasRowMajor, ta ? CblasTrans : CblasNoTrans,
33
+ tb ? CblasTrans : CblasNoTrans, m, n, k,
34
+ alpha, &a[0], ta ? m : k, &b[0], tb ? k : n, beta, &y[0], n);
35
+ }
36
+
37
+ // y (m) = alpha op(a) v + beta y (v k)
38
+ template <class Y, class A, class V>
39
+ inline void blas_gemv(Y& y, const A& a, const V& v, double alpha, double beta,
40
+ int ta, int m, int k) {
41
+ if (ta)
42
+ cblas_dgemv(CblasRowMajor, CblasTrans, k, m, alpha, &a[0], m, &v[0], 1,
43
+ beta, &y[0], 1);
44
+ else
45
+ cblas_dgemv(CblasRowMajor, CblasNoTrans, m, k, alpha, &a[0], k, &v[0], 1,
46
+ beta, &y[0], 1);
47
+ }
48
+
49
+ // batch slabs of the same: y[l] (m x n) = alpha op(a[l]) op(b[l]) +
50
+ // beta y[l] for l below batch, the slabs contiguous (strides m*k,
51
+ // k*n, m*n): a contraction whose leading labels are shared by both
52
+ // operands and the result
53
+ template <class Y, class A, class B>
54
+ inline void blas_gemm_batched(Y& y, const A& a, const B& b, double alpha, double beta,
55
+ int ta, int tb, int m, int n, int k, int batch) {
56
+ for (int l = 0; l < batch; ++l)
57
+ cblas_dgemm(CblasRowMajor, ta ? CblasTrans : CblasNoTrans,
58
+ tb ? CblasTrans : CblasNoTrans, m, n, k,
59
+ alpha, &a[(size_t)l * m * k], ta ? m : k,
60
+ &b[(size_t)l * k * n], tb ? k : n, beta, &y[(size_t)l * m * n], n);
61
+ }
62
+
63
+ // y (m x m) = alpha op(a) op(a)^T + beta y: the Gram matrix, one
64
+ // triangle by dsyrk and the other mirrored
65
+ template <class Y, class A>
66
+ inline void blas_syrk(Y& y, const A& a, double alpha, double beta, int ta,
67
+ int m, int k) {
68
+ cblas_dsyrk(CblasRowMajor, CblasUpper, ta ? CblasTrans : CblasNoTrans, m, k,
69
+ alpha, &a[0], ta ? m : k, beta, &y[0], m);
70
+ for (int i = 1; i < m; ++i)
71
+ for (int j = 0; j < i; ++j)
72
+ y[i * m + j] = y[j * m + i];
73
+ }
74
+
75
+ } // namespace scm2cpp
76
+
77
+ #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