-
Notifications
You must be signed in to change notification settings - Fork 1
/
arpaca_test.cpp
156 lines (127 loc) · 4.38 KB
/
arpaca_test.cpp
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <vector>
#include <eigen3/Eigen/Dense>
#include <eigen3/Eigen/Sparse>
#include <gtest/gtest.h>
#include "arpaca.hpp"
namespace arpaca {
template<typename T> struct PrecisionThreshold;
template<> struct PrecisionThreshold<float> { static const float value; };
template<> struct PrecisionThreshold<double> { static const double value; };
const float PrecisionThreshold<float>::value = 1e-3f;
const double PrecisionThreshold<double>::value = 1e-10;
std::vector<int> MakeRandomSequence(int n, int k)
{
std::vector<int> seq;
seq.reserve(n);
for (int i = 0; i < n; ++i) seq.push_back(i);
std::random_shuffle(seq.begin(), seq.end());
seq.resize(k);
return seq;
}
double GetRandomValue(double range)
{
return 2 * range * std::rand() / RAND_MAX - range;
}
template<typename Scalar>
Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>
MakeSymmetrixRandomMatrix(int n, int k, Scalar range)
{
Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> X(n, n);
X.setZero();
std::vector<int> idx = MakeRandomSequence(n*n, 2*k);
for (size_t i = 0; i < idx.size(); ++i)
X(idx[i]/n, idx[i]%n) = GetRandomValue(range);
return (X + X.transpose()) / 2;
}
template<typename Scalar>
Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
MakeSparse(const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>& X)
{
Eigen::SparseMatrix<Scalar, Eigen::RowMajor> S(X.rows(), X.cols());
for (int i = 0; i < S.rows(); ++i) {
S.startVec(i);
for (int j = 0; j < S.cols(); ++j)
if (X(i, j) != 0)
S.insertBack(i, j) = X(i, j);
}
S.finalize();
return S;
}
struct RandomMatrixTestParameter {
int n;
int k;
int num_eigenvalues;
int num_lanczos_vectors;
};
RandomMatrixTestParameter MakeParameter(int n, int k, int ne, int nlv)
{
RandomMatrixTestParameter p = { n, k, ne, nlv };
return p;
}
class RandomMatrixTest
: public testing::TestWithParam<RandomMatrixTestParameter> {
protected:
template<typename Scalar>
void TestOfScalar()
{
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> Matrix;
typedef Eigen::SparseMatrix<Scalar, Eigen::RowMajor> SparseMatrix;
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Vector;
RandomMatrixTestParameter p = GetParam();
Matrix X = MakeSymmetrixRandomMatrix(p.n, p.k, Scalar(10.0));
SparseMatrix S = MakeSparse(X);
Eigen::SelfAdjointEigenSolver<Matrix> X_eigen(S);
SymmetricEigenSolver<Scalar> S_eigen =
Solve(S, p.num_eigenvalues, ALGEBRAIC_LARGEST, p.num_lanczos_vectors);
Vector X_eigenvalues = X_eigen.eigenvalues().bottomRows(p.num_eigenvalues);
Matrix X_eigenvectors =
X_eigen.eigenvectors().rightCols(p.num_eigenvalues);
Vector S_eigenvalues = S_eigen.MoveEigenvalues();
Matrix S_eigenvectors = S_eigen.MoveEigenvectors();
{
const Scalar diff_mean =
(X_eigenvalues - S_eigenvalues).cwiseAbs().mean();
EXPECT_TRUE(diff_mean < PrecisionThreshold<Scalar>::value)
<< "eigenvalues diff_mean: " << diff_mean;
}
{
Scalar diff_sum = 0.0;
for (int i = 0; i < p.num_eigenvalues; ++i) {
// Since each eigenvector given by X and S may have different signs,
// we have to check either same or opposite.
const Scalar diff1 =
(X_eigenvectors.col(i) - S_eigenvectors.col(i)).cwiseAbs().mean();
const Scalar diff2 =
(X_eigenvectors.col(i) + S_eigenvectors.col(i)).cwiseAbs().mean();
diff_sum += std::min(diff1, diff2);
}
const Scalar diff_mean = diff_sum / p.num_eigenvalues;
EXPECT_TRUE(diff_mean < PrecisionThreshold<Scalar>::value)
<< "eigenvectors diff_mean: " << diff_mean;
}
std::cout << "info: " << S_eigen.GetInfo() << std::endl;
std::cout << "# actual iterations: "
<< S_eigen.num_actual_iterations() << std::endl;
std::cout << "# converged eigenvalues: "
<< S_eigen.num_converged_eigenvalues() << std::endl;
}
};
TEST_P(RandomMatrixTest, Double)
{
TestOfScalar<double>();
}
TEST_P(RandomMatrixTest, Float)
{
TestOfScalar<float>();
}
INSTANTIATE_TEST_CASE_P(
SizeTest,
RandomMatrixTest,
testing::Values(MakeParameter(100, 1000, 10, 50),
MakeParameter(1000, 10000, 100, 500),
MakeParameter(100, 1000, 50, 0)));
} // namespace arpaca