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.
- scm2cpp_learn/__init__.py +3836 -0
- scm2cpp_learn/_classifiers.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/_compat.py +284 -0
- scm2cpp_learn/_generated/__init__.py +0 -0
- scm2cpp_learn/_generated/_loader.py +41 -0
- scm2cpp_learn/_generated/_loader_accel_cublas.py +173 -0
- scm2cpp_learn/_generated/_loader_classifiers.py +308 -0
- scm2cpp_learn/_generated/_loader_derived_blas.py +29 -0
- scm2cpp_learn/_generated/_loader_derived_cublas.py +29 -0
- scm2cpp_learn/_generated/_loader_derived_loops.py +29 -0
- scm2cpp_learn/_generated/_loader_gpu_cuda.py +313 -0
- scm2cpp_learn/_generated/_loader_gramops_blas.py +692 -0
- scm2cpp_learn/_generated/_loader_gramops_loops.py +711 -0
- scm2cpp_learn/_generated/_loader_nmf_blas.py +29 -0
- scm2cpp_learn/_generated/_loader_nmf_cublas.py +29 -0
- scm2cpp_learn/_generated/_loader_nmf_loops.py +29 -0
- scm2cpp_learn/_generated/accel_cublas/accel.cpp +24 -0
- scm2cpp_learn/_generated/accel_cublas/accel.hpp +1178 -0
- scm2cpp_learn/_generated/accel_cublas/accel_capi.cpp +76 -0
- scm2cpp_learn/_generated/classifiers.cpp +37 -0
- scm2cpp_learn/_generated/classifiers.hpp +3745 -0
- scm2cpp_learn/_generated/classifiers_capi.cpp +115 -0
- scm2cpp_learn/_generated/derived_blas/lasso_design.cpp +5 -0
- scm2cpp_learn/_generated/derived_blas/lasso_design.hpp +156 -0
- scm2cpp_learn/_generated/derived_blas/lasso_design_capi.cpp +19 -0
- scm2cpp_learn/_generated/derived_cublas/lasso_design.cpp +5 -0
- scm2cpp_learn/_generated/derived_cublas/lasso_design.hpp +158 -0
- scm2cpp_learn/_generated/derived_cublas/lasso_design_capi.cpp +19 -0
- scm2cpp_learn/_generated/derived_loops/lasso_design.cpp +5 -0
- scm2cpp_learn/_generated/derived_loops/lasso_design.hpp +179 -0
- scm2cpp_learn/_generated/derived_loops/lasso_design_capi.cpp +19 -0
- scm2cpp_learn/_generated/gpu_cuda/gpu.cpp +37 -0
- scm2cpp_learn/_generated/gpu_cuda/gpu.hpp +3846 -0
- scm2cpp_learn/_generated/gpu_cuda/gpu_capi.cpp +308 -0
- scm2cpp_learn/_generated/gramops_blas/gramops.cpp +82 -0
- scm2cpp_learn/_generated/gramops_blas/gramops.hpp +5411 -0
- scm2cpp_learn/_generated/gramops_blas/gramops_capi.cpp +244 -0
- scm2cpp_learn/_generated/gramops_loops/gramops.cpp +82 -0
- scm2cpp_learn/_generated/gramops_loops/gramops.hpp +6395 -0
- scm2cpp_learn/_generated/gramops_loops/gramops_capi.cpp +250 -0
- scm2cpp_learn/_generated/lasso_cov.cpp +7 -0
- scm2cpp_learn/_generated/lasso_cov.hpp +152 -0
- scm2cpp_learn/_generated/lasso_cov_capi.cpp +25 -0
- scm2cpp_learn/_generated/nmf_blas/nmf_cd.cpp +5 -0
- scm2cpp_learn/_generated/nmf_blas/nmf_cd.hpp +132 -0
- scm2cpp_learn/_generated/nmf_blas/nmf_cd_capi.cpp +19 -0
- scm2cpp_learn/_generated/nmf_cublas/nmf_cd.cpp +5 -0
- scm2cpp_learn/_generated/nmf_cublas/nmf_cd.hpp +136 -0
- scm2cpp_learn/_generated/nmf_cublas/nmf_cd_capi.cpp +19 -0
- scm2cpp_learn/_generated/nmf_loops/nmf_cd.cpp +5 -0
- scm2cpp_learn/_generated/nmf_loops/nmf_cd.hpp +167 -0
- scm2cpp_learn/_generated/nmf_loops/nmf_cd_capi.cpp +19 -0
- scm2cpp_learn/_generated/scm2cpp-blas.hpp +158 -0
- scm2cpp_learn/_generated/scm2cpp-cublas.hpp +155 -0
- scm2cpp_learn/_generated/scm2cpp-cuda.hpp +285 -0
- scm2cpp_learn/_generated/scm2cpp.hpp +1627 -0
- scm2cpp_learn/_gramops_blas.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/_lasso_cov.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/_lasso_derived_blas.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/_libfind.py +153 -0
- scm2cpp_learn/_nmf_blas.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/batch_capi.cu +428 -0
- scm2cpp_learn-0.18.0.dist-info/DELVEWHEEL +2 -0
- scm2cpp_learn-0.18.0.dist-info/METADATA +1171 -0
- scm2cpp_learn-0.18.0.dist-info/RECORD +72 -0
- scm2cpp_learn-0.18.0.dist-info/WHEEL +5 -0
- scm2cpp_learn-0.18.0.dist-info/top_level.txt +1 -0
- scm2cpp_learn.libs/.load-order-scm2cpp_learn-0.18.0 +4 -0
- scm2cpp_learn.libs/libopenblas-0486735c359a67419d8832e3c40e2837.dll +4 -0
- scm2cpp_learn.libs/msvcp140-73438573e87f9a2fd944b01def13566d.dll +0 -0
- scm2cpp_learn.libs/vcruntime140-052ad6a20d375957e82aa6a3c441ea54.dll +0 -0
- 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,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
|