-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathkernel.cpp
More file actions
85 lines (71 loc) · 4.01 KB
/
kernel.cpp
File metadata and controls
85 lines (71 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <kernel.hpp>
#include <algorithm>
#include <numeric>
#include <vector>
#include <array>
#include <random>
#include <Eigen/Dense>
#include <Eigen/SVD>
DenseZMat::DenseZMat(long long M, long long N) : Accessor(M, N), A(nullptr) {
if (0 < M && 0 < N) {
A = (std::complex<double>*)malloc(M * N * sizeof(std::complex<double>));
std::fill(A, &A[M * N], 0.);
}
}
DenseZMat::~DenseZMat() {
if (A)
free(A);
}
void DenseZMat::op_Aij_mulB(char opA, long long mC, long long nC, long long k, long long iA, long long jA, const std::complex<double>* B_in, long long strideB, std::complex<double>* C_out, long long strideC) const {
Eigen::Stride<Eigen::Dynamic, 1> lda(M, 1), ldb(strideB, 1), ldc(strideC, 1);
Eigen::Map<Eigen::MatrixXcd, Eigen::Unaligned, Eigen::Stride<Eigen::Dynamic, 1>> matC(C_out, mC, nC, ldc);
Eigen::Map<const Eigen::MatrixXcd, Eigen::Unaligned, Eigen::Stride<Eigen::Dynamic, 1>> matB(B_in, k, nC, ldb);
if (opA == 'T' || opA == 't')
matC.noalias() = Eigen::Map<const Eigen::MatrixXcd, Eigen::Unaligned, Eigen::Stride<Eigen::Dynamic, 1>>(&A[iA + jA * M], k, mC, lda).transpose() * matB;
else if (opA == 'C' || opA == 'c')
matC.noalias() = Eigen::Map<const Eigen::MatrixXcd, Eigen::Unaligned, Eigen::Stride<Eigen::Dynamic, 1>>(&A[iA + jA * M], k, mC, lda).adjoint() * matB;
else
matC.noalias() = Eigen::Map<const Eigen::MatrixXcd, Eigen::Unaligned, Eigen::Stride<Eigen::Dynamic, 1>>(&A[iA + jA * M], mC, k, lda) * matB;
}
void Zrsvd(double epi, long long m, long long n, long long* k, long long p, long long niters, const Accessor& A, long long iA, long long jA, double* S, std::complex<double>* U, long long ldu, std::complex<double>* V, long long ldv) {
long long rank = std::min(*k, std::min(m, n));
p = std::min(rank + p, std::min(m, n));
Eigen::MatrixXcd R(n, p), Q(m, p);
std::mt19937_64 gen;
std::normal_distribution<double> norm_dist(0., 1.);
std::generate(R.reshaped().begin(), R.reshaped().end(), [&]() { return std::complex<double>(norm_dist(gen), norm_dist(gen)); });
A.op_Aij_mulB('N', m, p, n, iA, jA, R.data(), n, Q.data(), m);
while (0 < --niters) {
Eigen::HouseholderQR<Eigen::MatrixXcd> qr(Q);
Q = qr.householderQ() * Eigen::MatrixXcd::Identity(m, p);
A.op_Aij_mulB('C', n, p, m, iA, jA, Q.data(), m, R.data(), n);
A.op_Aij_mulB('N', m, p, n, iA, jA, R.data(), n, Q.data(), m);
}
Eigen::HouseholderQR<Eigen::MatrixXcd> qr(Q);
Q = qr.householderQ() * Eigen::MatrixXcd::Identity(m, p);
A.op_Aij_mulB('C', n, p, m, iA, jA, Q.data(), m, R.data(), n);
Eigen::JacobiSVD<Eigen::MatrixXcd> svd(R, Eigen::ComputeThinU | Eigen::ComputeThinV);
if (0. < epi && epi < 1.)
{ svd.setThreshold(epi); *k = rank = std::min(rank, (long long)svd.rank()); }
Eigen::Stride<Eigen::Dynamic, 1> ldU(ldu, 1), ldV(ldv, 1);
Eigen::Map<Eigen::MatrixXcd, Eigen::Unaligned, Eigen::Stride<Eigen::Dynamic, 1>> matU(U, m, rank, ldU);
Eigen::Map<Eigen::MatrixXcd, Eigen::Unaligned, Eigen::Stride<Eigen::Dynamic, 1>> matV(V, n, rank, ldV);
Eigen::Map<Eigen::VectorXd> vecS(S, rank);
vecS = svd.singularValues().topRows(rank);
matV = svd.matrixU().leftCols(rank);
matU.noalias() = Q * svd.matrixV().leftCols(rank);
}
void gen_matrix(const MatrixAccessor& eval, long long m, long long n, const double* bi, const double* bj, std::complex<double> Aij[]) {
const std::array<double, 3>* bi3 = reinterpret_cast<const std::array<double, 3>*>(bi);
const std::array<double, 3>* bi3_end = reinterpret_cast<const std::array<double, 3>*>(&bi[3 * m]);
const std::array<double, 3>* bj3 = reinterpret_cast<const std::array<double, 3>*>(bj);
const std::array<double, 3>* bj3_end = reinterpret_cast<const std::array<double, 3>*>(&bj[3 * n]);
std::for_each(bj3, bj3_end, [&](const std::array<double, 3>& j) -> void {
long long ix = std::distance(bj3, &j);
std::for_each(bi3, bi3_end, [&](const std::array<double, 3>& i) -> void {
long long iy = std::distance(bi3, &i);
double d = std::hypot(i[0] - j[0], i[1] - j[1], i[2] - j[2]);
Aij[iy + ix * m] = eval(d);
});
});
}