-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathRandomSVD.hh
98 lines (84 loc) · 2.1 KB
/
RandomSVD.hh
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
86
87
88
89
90
91
92
93
94
95
96
97
98
// Randomised SVD implementation
// Copyright (c) 2016 Illumina, Inc.
// Auther: Jared O'Connell <[email protected]>
//
//This is an implementation of the algorithm described in Halko 2011:
//http://arxiv.org/pdf/0909.4061.pdf
#pragma once
#include "math.h"
#include <stdlib.h>
#include "Eigen/Dense"
#include "Eigen/Eigenvalues"
template<typename MatrixType>
class RandomSVD {
typedef typename MatrixType::Scalar Scalar;
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> VectorType;
public:
//N:nsample L:nsnp e: desired number of PCs
//mat is an N x L
RandomSVD(const MatrixType & mat,int e,int q=3) {
int r = e;
if(r>mat.rows())
{
r=mat.rows();
}
if(q<1)
{
q=1;
}
MatrixType R;
rnorm(R,mat.cols(),r);//L x e
MatrixType Y = mat * R;//N x e
orthonormalize(Y);
MatrixType Ystar;
for(int i=0;i<q;i++)
{
Ystar=mat.transpose() * Y; // L x e
orthonormalize(Ystar);
Y=mat * Ystar;
orthonormalize(Y);
}
MatrixType B = Y.transpose() * mat;//e x L
Eigen::JacobiSVD<MatrixType > svd(B, Eigen::ComputeThinU | Eigen::ComputeThinV);
_U = Y * svd.matrixU(); //N x e matrix
_S = svd.singularValues(); //diagonal e x e matrix
_V = svd.matrixV(); //L x e matrix.
}
MatrixType matrixU() const{
return _U;
}
VectorType singularValues() const {
return _S;
}
MatrixType matrixV() const {
return _V;
}
private:
MatrixType _U;
VectorType _S;
MatrixType _V;
inline void rnorm(MatrixType & X,int nrow, int ncol) {
X.resize(nrow,ncol);
float pi = 3.141592653589793238462643383279502884;
float rmax = (float)RAND_MAX;
for(int i=0;i<nrow;i++)
{
for(int j=0;j<ncol;j+=2)
{
float v = ((float)std::rand() + 1.) / (rmax+2.);
float u = ((float)std::rand() + 2.) / (rmax+2.);
float c = sqrt(-2. * log(v));
X(i,j) = c * cos(2. * pi * u);
if(j<ncol-1)
{
X(i,j+1) = c * sin(2. * pi * u);
}
}
}
}
inline void orthonormalize(MatrixType & mat) {
MatrixType thinQ;
thinQ.setIdentity(mat.rows(), mat.cols());
mat = mat.householderQr().householderQ()*thinQ;
}
};