mat_utils.txx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. #include SCTL_INCLUDE(matrix.hpp)
  2. #if defined(SCTL_HAVE_CUDA)
  3. #include <cuda_runtime_api.h>
  4. #include <cublas_v2.h>
  5. #endif
  6. #if defined(SCTL_HAVE_BLAS)
  7. #include SCTL_INCLUDE(blas.h)
  8. #endif
  9. #if defined(SCTL_HAVE_LAPACK)
  10. #include SCTL_INCLUDE(lapack.h)
  11. #endif
  12. #include <omp.h>
  13. #include <cmath>
  14. #include <cassert>
  15. #include <cstdlib>
  16. #include <algorithm>
  17. #include <iostream>
  18. #include <vector>
  19. namespace SCTL_NAMESPACE {
  20. namespace mat {
  21. template <class ValueType> inline void gemm(char TransA, char TransB, int M, int N, int K, ValueType alpha, Iterator<ValueType> A, int lda, Iterator<ValueType> B, int ldb, ValueType beta, Iterator<ValueType> C, int ldc) {
  22. if ((TransA == 'N' || TransA == 'n') && (TransB == 'N' || TransB == 'n')) {
  23. for (Long n = 0; n < N; n++) { // Columns of C
  24. for (Long m = 0; m < M; m++) { // Rows of C
  25. ValueType AxB = 0;
  26. for (Long k = 0; k < K; k++) {
  27. AxB += A[m + lda * k] * B[k + ldb * n];
  28. }
  29. C[m + ldc * n] = alpha * AxB + (beta == 0 ? 0 : beta * C[m + ldc * n]);
  30. }
  31. }
  32. } else if (TransA == 'N' || TransA == 'n') {
  33. for (Long n = 0; n < N; n++) { // Columns of C
  34. for (Long m = 0; m < M; m++) { // Rows of C
  35. ValueType AxB = 0;
  36. for (Long k = 0; k < K; k++) {
  37. AxB += A[m + lda * k] * B[n + ldb * k];
  38. }
  39. C[m + ldc * n] = alpha * AxB + (beta == 0 ? 0 : beta * C[m + ldc * n]);
  40. }
  41. }
  42. } else if (TransB == 'N' || TransB == 'n') {
  43. for (Long n = 0; n < N; n++) { // Columns of C
  44. for (Long m = 0; m < M; m++) { // Rows of C
  45. ValueType AxB = 0;
  46. for (Long k = 0; k < K; k++) {
  47. AxB += A[k + lda * m] * B[k + ldb * n];
  48. }
  49. C[m + ldc * n] = alpha * AxB + (beta == 0 ? 0 : beta * C[m + ldc * n]);
  50. }
  51. }
  52. } else {
  53. for (Long n = 0; n < N; n++) { // Columns of C
  54. for (Long m = 0; m < M; m++) { // Rows of C
  55. ValueType AxB = 0;
  56. for (Long k = 0; k < K; k++) {
  57. AxB += A[k + lda * m] * B[n + ldb * k];
  58. }
  59. C[m + ldc * n] = alpha * AxB + (beta == 0 ? 0 : beta * C[m + ldc * n]);
  60. }
  61. }
  62. }
  63. }
  64. #if defined(SCTL_HAVE_BLAS)
  65. template <> inline void gemm<float>(char TransA, char TransB, int M, int N, int K, float alpha, Iterator<float> A, int lda, Iterator<float> B, int ldb, float beta, Iterator<float> C, int ldc) { sgemm_(&TransA, &TransB, &M, &N, &K, &alpha, &A[0], &lda, &B[0], &ldb, &beta, &C[0], &ldc); }
  66. template <> inline void gemm<double>(char TransA, char TransB, int M, int N, int K, double alpha, Iterator<double> A, int lda, Iterator<double> B, int ldb, double beta, Iterator<double> C, int ldc) { dgemm_(&TransA, &TransB, &M, &N, &K, &alpha, &A[0], &lda, &B[0], &ldb, &beta, &C[0], &ldc); }
  67. #endif
  68. #if defined(SCTL_HAVE_CUDA)
  69. template <> inline void cublasgemm<float>(char TransA, char TransB, int M, int N, int K, float alpha, Iterator<float> A, int lda, Iterator<float> B, int ldb, float beta, Iterator<float> C, int ldc) {
  70. cublasOperation_t cublasTransA, cublasTransB;
  71. cublasHandle_t *handle = CUDA_Lock::acquire_handle();
  72. if (TransA == 'T' || TransA == 't')
  73. cublasTransA = CUBLAS_OP_T;
  74. else if (TransA == 'N' || TransA == 'n')
  75. cublasTransA = CUBLAS_OP_N;
  76. if (TransB == 'T' || TransB == 't')
  77. cublasTransB = CUBLAS_OP_T;
  78. else if (TransB == 'N' || TransB == 'n')
  79. cublasTransB = CUBLAS_OP_N;
  80. cublasStatus_t status = cublasSgemm(*handle, cublasTransA, cublasTransB, M, N, K, &alpha, A, lda, B, ldb, &beta, C, ldc);
  81. }
  82. template <> inline void cublasgemm<double>(char TransA, char TransB, int M, int N, int K, double alpha, Iterator<double> A, int lda, Iterator<double> B, int ldb, double beta, Iterator<double> C, int ldc) {
  83. cublasOperation_t cublasTransA, cublasTransB;
  84. cublasHandle_t *handle = CUDA_Lock::acquire_handle();
  85. if (TransA == 'T' || TransA == 't')
  86. cublasTransA = CUBLAS_OP_T;
  87. else if (TransA == 'N' || TransA == 'n')
  88. cublasTransA = CUBLAS_OP_N;
  89. if (TransB == 'T' || TransB == 't')
  90. cublasTransB = CUBLAS_OP_T;
  91. else if (TransB == 'N' || TransB == 'n')
  92. cublasTransB = CUBLAS_OP_N;
  93. cublasStatus_t status = cublasDgemm(*handle, cublasTransA, cublasTransB, M, N, K, &alpha, A, lda, B, ldb, &beta, C, ldc);
  94. }
  95. #endif
  96. //#define SCTL_SVD_DEBUG
  97. template <class ValueType> static inline void GivensL(Iterator<ValueType> S_, StaticArray<Long, 2> &dim, Long m, ValueType a, ValueType b) {
  98. auto S = [S_,dim](Long i, Long j){ return S_[(i) * dim[1] + (j)]; };
  99. ValueType r = sqrt<ValueType>(a * a + b * b);
  100. if (r == 0) return;
  101. ValueType c = a / r;
  102. ValueType s = -b / r;
  103. #pragma omp parallel for
  104. for (Long i = 0; i < dim[1]; i++) {
  105. ValueType S0 = S(m + 0, i);
  106. ValueType S1 = S(m + 1, i);
  107. S(m, i) += S0 * (c - 1);
  108. S(m, i) += S1 * (-s);
  109. S(m + 1, i) += S0 * (s);
  110. S(m + 1, i) += S1 * (c - 1);
  111. }
  112. }
  113. template <class ValueType> static inline void GivensR(Iterator<ValueType> S_, StaticArray<Long, 2> &dim, Long m, ValueType a, ValueType b) {
  114. auto S = [S_,dim](Long i, Long j){ return S_[(i) * dim[1] + (j)]; };
  115. ValueType r = sqrt<ValueType>(a * a + b * b);
  116. if (r == 0) return;
  117. ValueType c = a / r;
  118. ValueType s = -b / r;
  119. #pragma omp parallel for
  120. for (Long i = 0; i < dim[0]; i++) {
  121. ValueType S0 = S(i, m + 0);
  122. ValueType S1 = S(i, m + 1);
  123. S(i, m) += S0 * (c - 1);
  124. S(i, m) += S1 * (-s);
  125. S(i, m + 1) += S0 * (s);
  126. S(i, m + 1) += S1 * (c - 1);
  127. }
  128. }
  129. template <class ValueType> static inline void SVD(StaticArray<Long, 2> &dim, Iterator<ValueType> U_, Iterator<ValueType> S_, Iterator<ValueType> V_, ValueType eps = -1) {
  130. auto U = [U_,dim](Long i, Long j){ return U_[(i) * dim[0] + (j)]; };
  131. auto S = [S_,dim](Long i, Long j){ return S_[(i) * dim[1] + (j)]; };
  132. auto V = [V_,dim](Long i, Long j){ return V_[(i) * dim[1] + (j)]; };
  133. assert(dim[0] >= dim[1]);
  134. #ifdef SCTL_SVD_DEBUG
  135. Matrix<ValueType> M0(dim[0], dim[1], S_);
  136. #endif
  137. { // Bi-diagonalization
  138. Long n = std::min(dim[0], dim[1]);
  139. std::vector<ValueType> house_vec(std::max(dim[0], dim[1]));
  140. for (Long i = 0; i < n; i++) {
  141. // Column Householder
  142. {
  143. ValueType x1 = S(i, i);
  144. if (x1 < 0) x1 = -x1;
  145. ValueType x_inv_norm = 0;
  146. for (Long j = i; j < dim[0]; j++) {
  147. x_inv_norm += S(j, i) * S(j, i);
  148. }
  149. if (x_inv_norm > 0) x_inv_norm = 1 / sqrt<ValueType>(x_inv_norm);
  150. ValueType alpha = sqrt<ValueType>(1 + x1 * x_inv_norm);
  151. ValueType beta = x_inv_norm / alpha;
  152. if (x_inv_norm == 0) alpha = 0; // nothing to do
  153. house_vec[i] = -alpha;
  154. for (Long j = i + 1; j < dim[0]; j++) {
  155. house_vec[j] = -beta * S(j, i);
  156. }
  157. if (S(i, i) < 0)
  158. for (Long j = i + 1; j < dim[0]; j++) {
  159. house_vec[j] = -house_vec[j];
  160. }
  161. }
  162. #pragma omp parallel for
  163. for (Long k = i; k < dim[1]; k++) {
  164. ValueType dot_prod = 0;
  165. for (Long j = i; j < dim[0]; j++) {
  166. dot_prod += S(j, k) * house_vec[j];
  167. }
  168. for (Long j = i; j < dim[0]; j++) {
  169. S(j, k) -= dot_prod * house_vec[j];
  170. }
  171. }
  172. #pragma omp parallel for
  173. for (Long k = 0; k < dim[0]; k++) {
  174. ValueType dot_prod = 0;
  175. for (Long j = i; j < dim[0]; j++) {
  176. dot_prod += U(k, j) * house_vec[j];
  177. }
  178. for (Long j = i; j < dim[0]; j++) {
  179. U(k, j) -= dot_prod * house_vec[j];
  180. }
  181. }
  182. // Row Householder
  183. if (i >= n - 1) continue;
  184. {
  185. ValueType x1 = S(i, i + 1);
  186. if (x1 < 0) x1 = -x1;
  187. ValueType x_inv_norm = 0;
  188. for (Long j = i + 1; j < dim[1]; j++) {
  189. x_inv_norm += S(i, j) * S(i, j);
  190. }
  191. if (x_inv_norm > 0) x_inv_norm = 1 / sqrt<ValueType>(x_inv_norm);
  192. ValueType alpha = sqrt<ValueType>(1 + x1 * x_inv_norm);
  193. ValueType beta = x_inv_norm / alpha;
  194. if (x_inv_norm == 0) alpha = 0; // nothing to do
  195. house_vec[i + 1] = -alpha;
  196. for (Long j = i + 2; j < dim[1]; j++) {
  197. house_vec[j] = -beta * S(i, j);
  198. }
  199. if (S(i, i + 1) < 0)
  200. for (Long j = i + 2; j < dim[1]; j++) {
  201. house_vec[j] = -house_vec[j];
  202. }
  203. }
  204. #pragma omp parallel for
  205. for (Long k = i; k < dim[0]; k++) {
  206. ValueType dot_prod = 0;
  207. for (Long j = i + 1; j < dim[1]; j++) {
  208. dot_prod += S(k, j) * house_vec[j];
  209. }
  210. for (Long j = i + 1; j < dim[1]; j++) {
  211. S(k, j) -= dot_prod * house_vec[j];
  212. }
  213. }
  214. #pragma omp parallel for
  215. for (Long k = 0; k < dim[1]; k++) {
  216. ValueType dot_prod = 0;
  217. for (Long j = i + 1; j < dim[1]; j++) {
  218. dot_prod += V(j, k) * house_vec[j];
  219. }
  220. for (Long j = i + 1; j < dim[1]; j++) {
  221. V(j, k) -= dot_prod * house_vec[j];
  222. }
  223. }
  224. }
  225. }
  226. Long k0 = 0;
  227. Long iter = 0;
  228. if (eps < 0) {
  229. eps = 1.0;
  230. while (eps + (ValueType)1.0 > 1.0) eps *= 0.5;
  231. eps *= 64.0;
  232. }
  233. while (k0 < dim[1] - 1) { // Diagonalization
  234. iter++;
  235. ValueType S_max = 0.0;
  236. for (Long i = 0; i < dim[1]; i++) S_max = (S_max > fabs<ValueType>(S(i, i)) ? S_max : fabs<ValueType>(S(i, i)));
  237. for (Long i = 0; i < dim[1] - 1; i++) S_max = (S_max > fabs<ValueType>(S(i, i + 1)) ? S_max : fabs<ValueType>(S(i, i + 1)));
  238. // while(k0<dim[1]-1 && fabs<ValueType>(S(k0,k0+1))<=eps*(fabs<ValueType>(S(k0,k0))+fabs<ValueType>(S(k0+1,k0+1)))) k0++;
  239. while (k0 < dim[1] - 1 && fabs<ValueType>(S(k0, k0 + 1)) <= eps * S_max) k0++;
  240. if (k0 == dim[1] - 1) continue;
  241. Long n = k0 + 2;
  242. // while(n<dim[1] && fabs<ValueType>(S(n-1,n))>eps*(fabs<ValueType>(S(n-1,n-1))+fabs<ValueType>(S(n,n)))) n++;
  243. while (n < dim[1] && fabs<ValueType>(S(n - 1, n)) > eps * S_max) n++;
  244. ValueType alpha = 0;
  245. ValueType beta = 0;
  246. if (n - k0 == 2 && fabs<ValueType>(S(k0, k0)) < eps * S_max && fabs<ValueType>(S(k0 + 1, k0 + 1)) < eps * S_max) { // Compute mu
  247. alpha=0;
  248. beta=1;
  249. } else {
  250. StaticArray<ValueType, 2 * 2> C;
  251. C[0 * 2 + 0] = S(n - 2, n - 2) * S(n - 2, n - 2);
  252. if (n - k0 > 2) C[0 * 2 + 0] += S(n - 3, n - 2) * S(n - 3, n - 2);
  253. C[0 * 2 + 1] = S(n - 2, n - 2) * S(n - 2, n - 1);
  254. C[1 * 2 + 0] = S(n - 2, n - 2) * S(n - 2, n - 1);
  255. C[1 * 2 + 1] = S(n - 1, n - 1) * S(n - 1, n - 1) + S(n - 2, n - 1) * S(n - 2, n - 1);
  256. ValueType b = -(C[0 * 2 + 0] + C[1 * 2 + 1]) / 2;
  257. ValueType c = C[0 * 2 + 0] * C[1 * 2 + 1] - C[0 * 2 + 1] * C[1 * 2 + 0];
  258. ValueType d = 0;
  259. if (b * b - c > 0)
  260. d = sqrt<ValueType>(b * b - c);
  261. else {
  262. ValueType b = (C[0 * 2 + 0] - C[1 * 2 + 1]) / 2;
  263. ValueType c = -C[0 * 2 + 1] * C[1 * 2 + 0];
  264. if (b * b - c > 0) d = sqrt<ValueType>(b * b - c);
  265. }
  266. ValueType lambda1 = -b + d;
  267. ValueType lambda2 = -b - d;
  268. ValueType d1 = lambda1 - C[1 * 2 + 1];
  269. d1 = (d1 < 0 ? -d1 : d1);
  270. ValueType d2 = lambda2 - C[1 * 2 + 1];
  271. d2 = (d2 < 0 ? -d2 : d2);
  272. ValueType mu = (d1 < d2 ? lambda1 : lambda2);
  273. alpha = S(k0, k0) * S(k0, k0) - mu;
  274. beta = S(k0, k0) * S(k0, k0 + 1);
  275. }
  276. for (Long k = k0; k < n - 1; k++) {
  277. StaticArray<Long, 2> dimU;
  278. dimU[0] = dim[0];
  279. dimU[1] = dim[0];
  280. StaticArray<Long, 2> dimV;
  281. dimV[0] = dim[1];
  282. dimV[1] = dim[1];
  283. GivensR(S_, dim, k, alpha, beta);
  284. GivensL(V_, dimV, k, alpha, beta);
  285. alpha = S(k, k);
  286. beta = S(k + 1, k);
  287. GivensL(S_, dim, k, alpha, beta);
  288. GivensR(U_, dimU, k, alpha, beta);
  289. alpha = S(k, k + 1);
  290. beta = S(k, k + 2);
  291. }
  292. { // Make S bi-diagonal again
  293. for (Long i0 = k0; i0 < n - 1; i0++) {
  294. for (Long i1 = 0; i1 < dim[1]; i1++) {
  295. if (i0 > i1 || i0 + 1 < i1) S(i0, i1) = 0;
  296. }
  297. }
  298. for (Long i0 = 0; i0 < dim[0]; i0++) {
  299. for (Long i1 = k0; i1 < n - 1; i1++) {
  300. if (i0 > i1 || i0 + 1 < i1) S(i0, i1) = 0;
  301. }
  302. }
  303. for (Long i = 0; i < dim[1] - 1; i++) {
  304. if (fabs<ValueType>(S(i, i + 1)) <= eps * S_max) {
  305. S(i, i + 1) = 0;
  306. }
  307. }
  308. }
  309. // std::cout<<iter<<' '<<k0<<' '<<n<<'\n';
  310. }
  311. { // Check Error
  312. #ifdef SCTL_SVD_DEBUG
  313. Matrix<ValueType> U0(dim[0], dim[0], U_);
  314. Matrix<ValueType> S0(dim[0], dim[1], S_);
  315. Matrix<ValueType> V0(dim[1], dim[1], V_);
  316. Matrix<ValueType> E = M0 - U0 * S0 * V0;
  317. ValueType max_err = 0;
  318. ValueType max_nondiag0 = 0;
  319. ValueType max_nondiag1 = 0;
  320. for (Long i = 0; i < E.Dim(0); i++)
  321. for (Long j = 0; j < E.Dim(1); j++) {
  322. if (max_err < fabs<ValueType>(E[i][j])) max_err = fabs<ValueType>(E[i][j]);
  323. if ((i > j + 0 || i + 0 < j) && max_nondiag0 < fabs<ValueType>(S0[i][j])) max_nondiag0 = fabs<ValueType>(S0[i][j]);
  324. if ((i > j + 1 || i + 1 < j) && max_nondiag1 < fabs<ValueType>(S0[i][j])) max_nondiag1 = fabs<ValueType>(S0[i][j]);
  325. }
  326. std::cout << max_err << '\n';
  327. std::cout << max_nondiag0 << '\n';
  328. std::cout << max_nondiag1 << '\n';
  329. #endif
  330. }
  331. }
  332. #undef SCTL_SVD_DEBUG
  333. template <class ValueType> inline void svd(char *JOBU, char *JOBVT, int *M, int *N, Iterator<ValueType> A, int *LDA, Iterator<ValueType> S, Iterator<ValueType> U, int *LDU, Iterator<ValueType> VT, int *LDVT, Iterator<ValueType> WORK, int *LWORK, int *INFO) {
  334. StaticArray<Long, 2> dim;
  335. dim[0] = std::max(*N, *M);
  336. dim[1] = std::min(*N, *M);
  337. Iterator<ValueType> U_ = aligned_new<ValueType>(dim[0] * dim[0]);
  338. memset(U_, 0, dim[0] * dim[0]);
  339. Iterator<ValueType> V_ = aligned_new<ValueType>(dim[1] * dim[1]);
  340. memset(V_, 0, dim[1] * dim[1]);
  341. Iterator<ValueType> S_ = aligned_new<ValueType>(dim[0] * dim[1]);
  342. const Long lda = *LDA;
  343. const Long ldu = *LDU;
  344. const Long ldv = *LDVT;
  345. if (dim[1] == *M) {
  346. for (Long i = 0; i < dim[0]; i++)
  347. for (Long j = 0; j < dim[1]; j++) {
  348. S_[i * dim[1] + j] = A[i * lda + j];
  349. }
  350. } else {
  351. for (Long i = 0; i < dim[0]; i++)
  352. for (Long j = 0; j < dim[1]; j++) {
  353. S_[i * dim[1] + j] = A[j * lda + i];
  354. }
  355. }
  356. for (Long i = 0; i < dim[0]; i++) {
  357. U_[i * dim[0] + i] = 1;
  358. }
  359. for (Long i = 0; i < dim[1]; i++) {
  360. V_[i * dim[1] + i] = 1;
  361. }
  362. SVD<ValueType>(dim, U_, S_, V_, (ValueType) - 1);
  363. for (Long i = 0; i < dim[1]; i++) { // Set S
  364. S[i] = S_[i * dim[1] + i];
  365. }
  366. if (dim[1] == *M) { // Set U
  367. for (Long i = 0; i < dim[1]; i++)
  368. for (Long j = 0; j < *M; j++) {
  369. U[j + ldu * i] = V_[j + i * dim[1]] * (S[i] < 0.0 ? -1.0 : 1.0);
  370. }
  371. } else {
  372. for (Long i = 0; i < dim[1]; i++)
  373. for (Long j = 0; j < *M; j++) {
  374. U[j + ldu * i] = U_[i + j * dim[0]] * (S[i] < 0.0 ? -1.0 : 1.0);
  375. }
  376. }
  377. if (dim[0] == *N) { // Set V
  378. for (Long i = 0; i < *N; i++)
  379. for (Long j = 0; j < dim[1]; j++) {
  380. VT[j + ldv * i] = U_[j + i * dim[0]];
  381. }
  382. } else {
  383. for (Long i = 0; i < *N; i++)
  384. for (Long j = 0; j < dim[1]; j++) {
  385. VT[j + ldv * i] = V_[i + j * dim[1]];
  386. }
  387. }
  388. for (Long i = 0; i < dim[1]; i++) {
  389. S[i] = S[i] * (S[i] < 0.0 ? -1.0 : 1.0);
  390. }
  391. aligned_delete<ValueType>(U_);
  392. aligned_delete<ValueType>(S_);
  393. aligned_delete<ValueType>(V_);
  394. if (0) { // Verify
  395. StaticArray<Long, 2> dim;
  396. dim[0] = std::max(*N, *M);
  397. dim[1] = std::min(*N, *M);
  398. const Long lda = *LDA;
  399. const Long ldu = *LDU;
  400. const Long ldv = *LDVT;
  401. Matrix<ValueType> A1(*M, *N);
  402. Matrix<ValueType> S1(dim[1], dim[1]);
  403. Matrix<ValueType> U1(*M, dim[1]);
  404. Matrix<ValueType> V1(dim[1], *N);
  405. for (Long i = 0; i < *N; i++)
  406. for (Long j = 0; j < *M; j++) {
  407. A1[j][i] = A[j + i * lda];
  408. }
  409. S1.SetZero();
  410. for (Long i = 0; i < dim[1]; i++) { // Set S
  411. S1[i][i] = S[i];
  412. }
  413. for (Long i = 0; i < dim[1]; i++)
  414. for (Long j = 0; j < *M; j++) {
  415. U1[j][i] = U[j + ldu * i];
  416. }
  417. for (Long i = 0; i < *N; i++)
  418. for (Long j = 0; j < dim[1]; j++) {
  419. V1[j][i] = VT[j + ldv * i];
  420. }
  421. std::cout << U1 *S1 *V1 - A1 << '\n';
  422. }
  423. }
  424. #if defined(SCTL_HAVE_LAPACK)
  425. template <> inline void svd<float>(char *JOBU, char *JOBVT, int *M, int *N, Iterator<float> A, int *LDA, Iterator<float> S, Iterator<float> U, int *LDU, Iterator<float> VT, int *LDVT, Iterator<float> WORK, int *LWORK, int *INFO) { sgesvd_(JOBU, JOBVT, M, N, &A[0], LDA, &S[0], &U[0], LDU, &VT[0], LDVT, &WORK[0], LWORK, INFO); }
  426. template <> inline void svd<double>(char *JOBU, char *JOBVT, int *M, int *N, Iterator<double> A, int *LDA, Iterator<double> S, Iterator<double> U, int *LDU, Iterator<double> VT, int *LDVT, Iterator<double> WORK, int *LWORK, int *INFO) { dgesvd_(JOBU, JOBVT, M, N, &A[0], LDA, &S[0], &U[0], LDU, &VT[0], LDVT, &WORK[0], LWORK, INFO); }
  427. #endif
  428. /**
  429. * \brief Computes the pseudo inverse of matrix M(n1xn2) (in row major form)
  430. * and returns the output M_(n2xn1). Original contents of M are destroyed.
  431. */
  432. template <class ValueType> inline void pinv(Iterator<ValueType> M, int n1, int n2, ValueType eps, Iterator<ValueType> M_) {
  433. if (n1 * n2 == 0) return;
  434. int m = n2;
  435. int n = n1;
  436. int k = (m < n ? m : n);
  437. Iterator<ValueType> tU = aligned_new<ValueType>(m * k);
  438. Iterator<ValueType> tS = aligned_new<ValueType>(k);
  439. Iterator<ValueType> tVT = aligned_new<ValueType>(k * n);
  440. // SVD
  441. int INFO = 0;
  442. char JOBU = 'S';
  443. char JOBVT = 'S';
  444. // int wssize = max(3*min(m,n)+max(m,n), 5*min(m,n));
  445. int wssize = 3 * (m < n ? m : n) + (m > n ? m : n);
  446. int wssize1 = 5 * (m < n ? m : n);
  447. wssize = (wssize > wssize1 ? wssize : wssize1);
  448. Iterator<ValueType> wsbuf = aligned_new<ValueType>(wssize);
  449. svd(&JOBU, &JOBVT, &m, &n, M, &m, tS, tU, &m, tVT, &k, wsbuf, &wssize, &INFO);
  450. if (INFO != 0) std::cout << INFO << '\n';
  451. assert(INFO == 0);
  452. aligned_delete<ValueType>(wsbuf);
  453. ValueType eps_ = tS[0] * eps;
  454. for (int i = 0; i < k; i++)
  455. if (tS[i] < eps_)
  456. tS[i] = 0;
  457. else
  458. tS[i] = 1.0 / tS[i];
  459. for (int i = 0; i < m; i++) {
  460. for (int j = 0; j < k; j++) {
  461. tU[i + j * m] *= tS[j];
  462. }
  463. }
  464. gemm<ValueType>('T', 'T', n, m, k, 1.0, tVT, k, tU, m, 0.0, M_, n);
  465. aligned_delete<ValueType>(tU);
  466. aligned_delete<ValueType>(tS);
  467. aligned_delete<ValueType>(tVT);
  468. }
  469. } // end namespace mat
  470. } // end namespace SCTL_NAMESPACE