ViennaCL - The Vienna Computing Library  1.6.2
Free open-source GPU-accelerated linear algebra and solver library.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
qr_method.cpp
Go to the documentation of this file.
1 /* =========================================================================
2  Copyright (c) 2010-2014, Institute for Microelectronics,
3  Institute for Analysis and Scientific Computing,
4  TU Wien.
5  Portions of this software are copyright by UChicago Argonne, LLC.
6 
7  -----------------
8  ViennaCL - The Vienna Computing Library
9  -----------------
10 
11  Project Head: Karl Rupp rupp@iue.tuwien.ac.at
12 
13  (A list of authors and contributors can be found in the PDF manual)
14 
15  License: MIT (X11), see file LICENSE in the base directory
16 ============================================================================= */
17 
18 
23 /*
24 Solutions for testdata were generated with Scilab line:
25 
26 M=fscanfMat('nsm1.example');e=spec(M);e=gsort(e);rr=real(e);ii=imag(e);e=cat(1, rr, ii); s=strcat(string(e), ' ');write('tmp', s);
27 */
28 
29 #ifndef NDEBUG
30  #define NDEBUG
31 #endif
32 
33 //#define VIENNACL_DEBUG_ALL
34 #include <iostream>
35 #include <fstream>
36 #include <stdexcept>
37 #include <vector>
38 
39 #include "viennacl/linalg/prod.hpp"
41 
43 
44 #include <boost/numeric/ublas/vector.hpp>
45 #include <boost/numeric/ublas/matrix.hpp>
46 
47 namespace ublas = boost::numeric::ublas;
48 
49 typedef float ScalarType;
50 
51 const ScalarType EPS = 0.0001f;
52 
53 void read_matrix_size(std::fstream& f, std::size_t& sz);
54 
55 void read_matrix_size(std::fstream& f, std::size_t& sz)
56 {
57  if(!f.is_open())
58  {
59  throw std::invalid_argument("File is not opened");
60  }
61 
62  f >> sz;
63 }
64 
65 template <typename MatrixLayout>
67 {
68  if(!f.is_open())
69  {
70  throw std::invalid_argument("File is not opened");
71  }
72 
73  boost::numeric::ublas::matrix<ScalarType> h_A(A.size1(), A.size2());
74 
75  for(std::size_t i = 0; i < h_A.size1(); i++) {
76  for(std::size_t j = 0; j < h_A.size2(); j++) {
77  ScalarType val = 0.0;
78  f >> val;
79  h_A(i, j) = val;
80  }
81  }
82 
83  viennacl::copy(h_A, A);
84 }
85 
86 void read_vector_body(std::fstream& f, std::vector<ScalarType>& v);
87 
88 void read_vector_body(std::fstream& f, std::vector<ScalarType>& v) {
89  if(!f.is_open())
90  throw std::invalid_argument("File is not opened");
91 
92  for(std::size_t i = 0; i < v.size(); i++)
93  {
94  ScalarType val = 0.0;
95  f >> val;
96  v[i] = val;
97  }
98 }
99 
100 template <typename MatrixLayout>
102 {
103  ublas::matrix<ScalarType> A(A_orig.size1(), A_orig.size2());
104  viennacl::copy(A_orig, A);
105 
106  for (unsigned int i = 0; i < A.size1(); i++) {
107  for (unsigned int j = 0; j < A.size2(); j++) {
108  if ((std::abs(A(i, j)) > EPS) && ((i - 1) != j) && (i != j) && ((i + 1) != j))
109  {
110  // std::cout << "Failed at " << i << " " << j << " " << A(i, j) << "\n";
111  return false;
112  }
113  }
114  }
115  return true;
116 }
117 
118 template <typename MatrixLayout>
120 {
121  ublas::matrix<ScalarType> A(A_orig.size1(), A_orig.size2());
122  viennacl::copy(A_orig, A);
123 
124  for (std::size_t i = 0; i < A.size1(); i++) {
125  for (std::size_t j = 0; j < A.size2(); j++) {
126  if ((std::abs(A(i, j)) > EPS) && (i > (j + 1)))
127  {
128  // std::cout << "Failed at " << i << " " << j << " " << A(i, j) << "\n";
129  return false;
130  }
131  }
132  }
133  return true;
134 }
135 
136 ScalarType matrix_compare(ublas::matrix<ScalarType>& res,
137  ublas::matrix<ScalarType>& ref);
138 
139 ScalarType matrix_compare(ublas::matrix<ScalarType>& res,
140  ublas::matrix<ScalarType>& ref)
141 {
142  ScalarType diff = 0.0;
143  ScalarType mx = 0.0;
144 
145  for(std::size_t i = 0; i < res.size1(); i++)
146  {
147  for(std::size_t j = 0; j < res.size2(); j++)
148  {
149  diff = std::max(diff, std::abs(res(i, j) - ref(i, j)));
150  mx = std::max(mx, res(i, j));
151  }
152  }
153 
154  return diff / mx;
155 }
156 
157 ScalarType vector_compare(std::vector<ScalarType> & res,
158  std::vector<ScalarType> & ref);
159 
160 ScalarType vector_compare(std::vector<ScalarType> & res,
161  std::vector<ScalarType> & ref)
162 {
163  std::sort(ref.begin(), ref.end());
164  std::sort(res.begin(), res.end());
165 
166  ScalarType diff = 0.0;
167  ScalarType mx = 0.0;
168  for(size_t i = 0; i < res.size(); i++)
169  {
170  diff = std::max(diff, std::abs(res[i] - ref[i]));
171  mx = std::max(mx, res[i]);
172  }
173 
174  return diff / mx;
175 }
176 
177 template <typename MatrixLayout>
179 {
180  for (unsigned int i = 0; i < A.size1(); i++) {
181  for (unsigned int j = 0; j < A.size2(); j++)
182  std::cout << std::fixed << A(i, j) << "\t";
183  std::cout << "\n";
184  }
185 }
186 
187 template <typename MatrixLayout>
188 void test_eigen(const std::string& fn, bool is_symm)
189 {
190  std::cout << "Reading..." << "\n";
191  std::size_t sz;
192  // read file
193  std::fstream f(fn.c_str(), std::fstream::in);
194  //read size of input matrix
195  read_matrix_size(f, sz);
196 
198  if (is_row)
199  std::cout << "Testing row-major matrix of size " << sz << "-by-" << sz << std::endl;
200  else
201  std::cout << "Testing column-major matrix of size " << sz << "-by-" << sz << std::endl;
202 
203  viennacl::matrix<ScalarType> A_input(sz, sz), A_ref(sz, sz), Q(sz, sz);
204  // reference vector with reference values from file
205  std::vector<ScalarType> eigen_ref_re(sz);
206  // calculated real eigenvalues
207  std::vector<ScalarType> eigen_re(sz);
208  // calculated im. eigenvalues
209  std::vector<ScalarType> eigen_im(sz);
210 
211  // read input matrix from file
212  read_matrix_body(f, A_input);
213  // read reference eigenvalues from file
214  read_vector_body(f, eigen_ref_re);
215 
216 
217  f.close();
218 
219  A_ref = A_input;
220 
221  std::cout << "Calculation..." << "\n";
222 
223  Timer timer;
224  timer.start();
225  // Start the calculation
226  if(is_symm)
227  viennacl::linalg::qr_method_sym(A_input, Q, eigen_re);
228  else
229  viennacl::linalg::qr_method_nsm(A_input, Q, eigen_re, eigen_im);
230 /*
231 
232  std::cout << "\n\n Matrix A: \n\n";
233  matrix_print(A_input);
234  std::cout << "\n\n";
235 
236  std::cout << "\n\n Matrix Q: \n\n";
237  matrix_print(Q);
238  std::cout << "\n\n";
239 */
240 
241  double time_spend = timer.get();
242 
243  std::cout << "Verification..." << "\n";
244 
245  bool is_hessenberg = check_hessenberg(A_input);
246  bool is_tridiag = check_tridiag(A_input);
247 
248  ublas::matrix<ScalarType> A_ref_ublas(sz, sz), A_input_ublas(sz, sz), Q_ublas(sz, sz), result1(sz, sz), result2(sz, sz);
249  viennacl::copy(A_ref, A_ref_ublas);
250  viennacl::copy(A_input, A_input_ublas);
251  viennacl::copy(Q, Q_ublas);
252 
253  // compute result1 = ublas::prod(Q_ublas, A_input_ublas); (terribly slow when using ublas directly)
254  for (std::size_t i=0; i<result1.size1(); ++i)
255  for (std::size_t j=0; j<result1.size2(); ++j)
256  {
257  ScalarType value = 0;
258  for (std::size_t k=0; k<Q_ublas.size2(); ++k)
259  value += Q_ublas(i, k) * A_input_ublas(k, j);
260  result1(i,j) = value;
261  }
262  // compute result2 = ublas::prod(A_ref_ublas, Q_ublas); (terribly slow when using ublas directly)
263  for (std::size_t i=0; i<result2.size1(); ++i)
264  for (std::size_t j=0; j<result2.size2(); ++j)
265  {
266  ScalarType value = 0;
267  for (std::size_t k=0; k<A_ref_ublas.size2(); ++k)
268  value += A_ref_ublas(i, k) * Q_ublas(k, j);
269  result2(i,j) = value;
270  }
271 
272 
273  ScalarType prods_diff = matrix_compare(result1, result2);
274  ScalarType eigen_diff = vector_compare(eigen_re, eigen_ref_re);
275 
276 
277  bool is_ok = is_hessenberg;
278 
279  if(is_symm)
280  is_ok = is_ok && is_tridiag;
281 
282  is_ok = is_ok && (eigen_diff < EPS);
283  is_ok = is_ok && (prods_diff < EPS);
284 
285  // std::cout << A_ref << "\n";
286  // std::cout << A_input << "\n";
287  // std::cout << Q << "\n";
288  // std::cout << eigen_re << "\n";
289  // std::cout << eigen_im << "\n";
290  // std::cout << eigen_ref_re << "\n";
291  // std::cout << eigen_ref_im << "\n";
292 
293  // std::cout << result1 << "\n";
294  // std::cout << result2 << "\n";
295  // std::cout << eigen_ref << "\n";
296  // std::cout << eigen << "\n";
297 
298  printf("%6s [%dx%d] %40s time = %.4f\n", is_ok?"[[OK]]":"[FAIL]", (int)A_ref.size1(), (int)A_ref.size2(), fn.c_str(), time_spend);
299  printf("tridiagonal = %d, hessenberg = %d prod-diff = %f eigen-diff = %f\n", is_tridiag, is_hessenberg, prods_diff, eigen_diff);
300  std::cout << std::endl << std::endl;
301 
302  if (!is_ok)
303  exit(EXIT_FAILURE);
304 
305 }
306 
307 int main()
308 {
309 
310  test_eigen<viennacl::row_major>("../examples/testdata/eigen/symm5.example", true);
311  // test_eigen<viennacl::row_major>("../../examples/testdata/eigen/symm3.example", true); // Computation of this matrix takes very long
312 
313  test_eigen<viennacl::column_major>("../examples/testdata/eigen/symm5.example", true);
314 // test_eigen<viennacl::column_major>("../../examples/testdata/eigen/symm3.example", true);
315 
316  //test_eigen<viennacl::row_major>("../examples/testdata/eigen/nsm2.example", false);
317  //test_eigen<viennacl::row_major>("../../examples/testdata/eigen/nsm2.example", false);
318  //test_eigen("../../examples/testdata/eigen/nsm3.example", false);
319  //test_eigen("../../examples/testdata/eigen/nsm4.example", false); //Note: This test suffers from round-off errors in single precision, hence disabled
320 
321  std::cout << std::endl;
322  std::cout << "------- Test completed --------" << std::endl;
323  std::cout << std::endl;
324 
325  return EXIT_SUCCESS;
326 }
Helper class for checking whether a matrix has a row-major layout.
Definition: forwards.h:483
Generic interface for matrix-vector and matrix-matrix products. See viennacl/linalg/vector_operations...
void matrix_print(viennacl::matrix< ScalarType, MatrixLayout > &A)
Definition: qr_method.cpp:178
bool check_hessenberg(viennacl::matrix< ScalarType, MatrixLayout > &A_orig)
Definition: qr_method.cpp:119
void read_vector_body(std::fstream &f, std::vector< ScalarType > &v)
Definition: qr_method.cpp:88
void start()
A dense matrix class.
Definition: forwards.h:374
double get() const
T max(const T &lhs, const T &rhs)
Maximum.
Definition: util.hpp:59
float ScalarType
Definition: qr_method.cpp:49
void test_eigen(const std::string &fn, bool is_symm)
Definition: qr_method.cpp:188
void read_matrix_size(std::fstream &f, std::size_t &sz)
Definition: qr_method.cpp:55
void qr_method_nsm(viennacl::matrix< SCALARTYPE > &A, viennacl::matrix< SCALARTYPE > &Q, std::vector< SCALARTYPE > &D, std::vector< SCALARTYPE > &E)
Definition: qr-method.hpp:796
size_type size2() const
Returns the number of columns.
Definition: matrix_def.hpp:217
size_type size1() const
Returns the number of rows.
Definition: matrix_def.hpp:215
int main()
Definition: qr_method.cpp:307
ScalarType matrix_compare(ublas::matrix< ScalarType > &res, ublas::matrix< ScalarType > &ref)
Definition: qr_method.cpp:139
bool check_tridiag(viennacl::matrix< ScalarType, MatrixLayout > &A_orig)
Definition: qr_method.cpp:101
Implementation of the QR method for eigenvalue computations. Experimental.
void copy(std::vector< NumericT > &cpu_vec, circulant_matrix< NumericT, AlignmentV > &gpu_mat)
Copies a circulant matrix from the std::vector to the OpenCL device (either GPU or multi-core CPU) ...
float ScalarType
Definition: fft_1d.cpp:42
const ScalarType EPS
Definition: qr_method.cpp:51
ScalarType vector_compare(std::vector< ScalarType > &res, std::vector< ScalarType > &ref)
Definition: qr_method.cpp:160
ScalarType diff(ScalarType &s1, viennacl::scalar< ScalarType > &s2)
Definition: blas3_solve.cpp:69
void read_matrix_body(std::fstream &f, viennacl::matrix< ScalarType, MatrixLayout > &A)
Definition: qr_method.cpp:66
void qr_method_sym(viennacl::matrix< SCALARTYPE > &A, viennacl::matrix< SCALARTYPE > &Q, std::vector< SCALARTYPE > &D)
Definition: qr-method.hpp:806