TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
qr_eigen_values.cpp
Go to the documentation of this file.
1
8#include <cassert>
9#include <cmath>
10#include <cstdlib>
11#include <ctime>
12#include <iostream>
13#ifdef _OPENMP
14#include <omp.h>
15#endif
16
17#include "./qr_decompose.h"
18using qr_algorithm::operator<<;
19
20#define LIMS 9
28void create_matrix(std::valarray<std::valarray<double>> *A) {
29 int i, j, tmp, lim2 = LIMS >> 1;
30 int N = A->size();
31
32#ifdef _OPENMP
33#pragma omp for
34#endif
35 for (i = 0; i < N; i++) {
36 A[0][i][i] = (std::rand() % LIMS) - lim2;
37 for (j = i + 1; j < N; j++) {
38 tmp = (std::rand() % LIMS) - lim2;
39 A[0][i][j] = tmp; // summetrically distribute random values
40 A[0][j][i] = tmp;
41 }
42 }
43}
44
54void mat_mul(const std::valarray<std::valarray<double>> &A,
55 const std::valarray<std::valarray<double>> &B,
56 std::valarray<std::valarray<double>> *OUT) {
57 int R1 = A.size();
58 int C1 = A[0].size();
59 int R2 = B.size();
60 int C2 = B[0].size();
61 if (C1 != R2) {
62 perror("Matrix dimensions mismatch!");
63 return;
64 }
65
66 for (int i = 0; i < R1; i++) {
67 for (int j = 0; j < C2; j++) {
68 OUT[0][i][j] = 0.f;
69 for (int k = 0; k < C1; k++) {
70 OUT[0][i][j] += A[i][k] * B[k][j];
71 }
72 }
73 }
74}
75
76namespace qr_algorithm {
98std::valarray<double> eigen_values(std::valarray<std::valarray<double>> *A,
99 bool print_intermediates = false) {
100 int rows = A->size();
101 int columns = rows;
102 int counter = 0, num_eigs = rows - 1;
103 double last_eig = 0;
104
105 std::valarray<std::valarray<double>> Q(rows);
106 std::valarray<std::valarray<double>> R(columns);
107
108 /* number of eigen values = matrix size */
109 std::valarray<double> eigen_vals(rows);
110 for (int i = 0; i < rows; i++) {
111 Q[i] = std::valarray<double>(columns);
112 R[i] = std::valarray<double>(columns);
113 }
114
115 /* continue till all eigen values are found */
116 while (num_eigs > 0) {
117 /* iterate with QR decomposition */
118 while (std::abs(A[0][num_eigs][num_eigs - 1]) >
119 std::numeric_limits<double>::epsilon()) {
120 // initial approximation = last diagonal element
121 last_eig = A[0][num_eigs][num_eigs];
122 for (int i = 0; i < rows; i++) {
123 A[0][i][i] -= last_eig; /* A - cI */
124 }
125
126 qr_decompose(*A, &Q, &R);
127
128 if (print_intermediates) {
129 std::cout << *A << "\n";
130 std::cout << Q << "\n";
131 std::cout << R << "\n";
132 printf("-------------------- %d ---------------------\n",
133 ++counter);
134 }
135
136 // new approximation A' = R * Q
137 mat_mul(R, Q, A);
138
139 for (int i = 0; i < rows; i++) {
140 A[0][i][i] += last_eig; /* A + cI */
141 }
142 }
143
144 /* store the converged eigen value */
145 eigen_vals[num_eigs] = last_eig;
146 // A[0][num_eigs][num_eigs];
147 if (print_intermediates) {
148 std::cout << "========================\n";
149 std::cout << "Eigen value: " << last_eig << ",\n";
150 std::cout << "========================\n";
151 }
152
153 num_eigs--;
154 rows--;
155 columns--;
156 }
157 eigen_vals[0] = A[0][0][0];
158
159 if (print_intermediates) {
160 std::cout << Q << "\n";
161 std::cout << R << "\n";
162 }
163
164 return eigen_vals;
165}
166
167} // namespace qr_algorithm
168
177void test1() {
178 std::valarray<std::valarray<double>> X = {{5, 7}, {7, 11}};
179 double y[] = {15.56158, 0.384227}; // corresponding y-values
180
181 std::cout << "------- Test 1 -------" << std::endl;
182 std::valarray<double> eig_vals = qr_algorithm::eigen_values(&X);
183
184 for (int i = 0; i < 2; i++) {
185 std::cout << i + 1 << "/2 Checking for " << y[i] << " --> ";
186 bool result = false;
187 for (int j = 0; j < 2 && !result; j++) {
188 if (std::abs(y[i] - eig_vals[j]) < 0.1) {
189 result = true;
190 std::cout << "(" << eig_vals[j] << ") ";
191 }
192 }
193 assert(result); // ensure that i^th expected eigen value was computed
194 std::cout << "found\n";
195 }
196 std::cout << "Test 1 Passed\n\n";
197}
198
210void test2() {
211 std::valarray<std::valarray<double>> X = {{-4, 4, 2, 0, -3},
212 {4, -4, 4, -3, -1},
213 {2, 4, 4, 3, -3},
214 {0, -3, 3, -1, -3},
215 {-3, -1, -3, -3, 0}};
216 double y[] = {9.27648, -9.26948, 2.0181, -1.03516,
217 -5.98994}; // corresponding y-values
218
219 std::cout << "------- Test 2 -------" << std::endl;
220 std::valarray<double> eig_vals = qr_algorithm::eigen_values(&X);
221
222 std::cout << X << "\n"
223 << "Eigen values: " << eig_vals << "\n";
224
225 for (int i = 0; i < 5; i++) {
226 std::cout << i + 1 << "/5 Checking for " << y[i] << " --> ";
227 bool result = false;
228 for (int j = 0; j < 5 && !result; j++) {
229 if (std::abs(y[i] - eig_vals[j]) < 0.1) {
230 result = true;
231 std::cout << "(" << eig_vals[j] << ") ";
232 }
233 }
234 assert(result); // ensure that i^th expected eigen value was computed
235 std::cout << "found\n";
236 }
237 std::cout << "Test 2 Passed\n\n";
238}
239
243int main(int argc, char **argv) {
244 int mat_size = 5;
245 if (argc == 2) {
246 mat_size = atoi(argv[1]);
247 } else { // if invalid input argument is given run tests
248 test1();
249 test2();
250 std::cout << "Usage: ./qr_eigen_values [mat_size]\n";
251 return 0;
252 }
253
254 if (mat_size < 2) {
255 fprintf(stderr, "Matrix size should be > 2\n");
256 return -1;
257 }
258
259 // initialize random number generator
260 std::srand(std::time(nullptr));
261
262 int i, rows = mat_size, columns = mat_size;
263
264 std::valarray<std::valarray<double>> A(rows);
265
266 for (int i = 0; i < rows; i++) {
267 A[i] = std::valarray<double>(columns);
268 }
269
270 /* create a random matrix */
271 create_matrix(&A);
272
273 std::cout << A << "\n";
274
275 clock_t t1 = clock();
276 std::valarray<double> eigen_vals = qr_algorithm::eigen_values(&A);
277 double dtime = static_cast<double>(clock() - t1) / CLOCKS_PER_SEC;
278
279 std::cout << "Eigen vals: ";
280 for (i = 0; i < mat_size; i++) std::cout << eigen_vals[i] << "\t";
281 std::cout << "\nTime taken to compute: " << dtime << " sec\n";
282
283 return 0;
284}
int main()
Main function.
Functions to compute QR decomposition of any rectangular matrix.
std::valarray< double > eigen_values(std::valarray< std::valarray< double > > *A, bool print_intermediates=false)
void qr_decompose(const std::valarray< std::valarray< T > > &A, std::valarray< std::valarray< T > > *Q, std::valarray< std::valarray< T > > *R)
Library functions to compute QR decomposition of a given matrix.
void test2()
void test1()
void create_matrix(std::valarray< std::valarray< double > > *A)
void mat_mul(const std::valarray< std::valarray< double > > &A, const std::valarray< std::valarray< double > > &B, std::valarray< std::valarray< double > > *OUT)
#define LIMS