ViennaCL - The Vienna Computing Library  1.7.0
Free open-source GPU-accelerated linear algebra and solver library.
tql2.hpp
Go to the documentation of this file.
1 #ifndef VIENNACL_LINALG_TQL2_HPP
2 #define VIENNACL_LINALG_TQL2_HPP
3 
4 /* =========================================================================
5  Copyright (c) 2010-2015, Institute for Microelectronics,
6  Institute for Analysis and Scientific Computing,
7  TU Wien.
8  Portions of this software are copyright by UChicago Argonne, LLC.
9 
10  -----------------
11  ViennaCL - The Vienna Computing Library
12  -----------------
13 
14  Project Head: Karl Rupp rupp@iue.tuwien.ac.at
15 
16  (A list of authors and contributors can be found in the manual)
17 
18  License: MIT (X11), see file LICENSE in the base directory
19 ============================================================================= */
20 
26 #include "viennacl/vector.hpp"
27 #include "viennacl/matrix.hpp"
28 #include <iomanip>
29 
31 #include "viennacl/linalg/prod.hpp"
32 
33 namespace viennacl
34 {
35 namespace linalg
36 {
37  // Symmetric tridiagonal QL algorithm.
38  // This is derived from the Algol procedures tql1, by Bowdler, Martin, Reinsch, and Wilkinson,
39  // Handbook for Auto. Comp., Vol.ii-Linear Algebra, and the corresponding Fortran subroutine in EISPACK.
40  template <typename SCALARTYPE, typename VectorType>
41  void tql1(vcl_size_t n,
42  VectorType & d,
43  VectorType & e)
44  {
45  for (vcl_size_t i = 1; i < n; i++)
46  e[i - 1] = e[i];
47 
48 
49  e[n - 1] = 0;
50 
51  SCALARTYPE f = 0.;
52  SCALARTYPE tst1 = 0.;
53  SCALARTYPE eps = static_cast<SCALARTYPE>(1e-6);
54 
55 
56  for (vcl_size_t l = 0; l < n; l++)
57  {
58  // Find small subdiagonal element.
59  tst1 = std::max<SCALARTYPE>(tst1, std::fabs(d[l]) + std::fabs(e[l]));
60  vcl_size_t m = l;
61  while (m < n)
62  {
63  if (std::fabs(e[m]) <= eps * tst1)
64  break;
65  m++;
66  }
67 
68  // If m == l, d[l) is an eigenvalue, otherwise, iterate.
69  if (m > l)
70  {
71  vcl_size_t iter = 0;
72  do
73  {
74  iter = iter + 1; // (Could check iteration count here.)
75 
76  // Compute implicit shift
77  SCALARTYPE g = d[l];
78  SCALARTYPE p = (d[l + 1] - g) / (2 * e[l]);
79  SCALARTYPE r = viennacl::linalg::detail::pythag<SCALARTYPE>(p, 1);
80  if (p < 0)
81  {
82  r = -r;
83  }
84 
85  d[l] = e[l] / (p + r);
86  d[l + 1] = e[l] * (p + r);
87  SCALARTYPE h = g - d[l];
88  for (vcl_size_t i = l + 2; i < n; i++)
89  {
90  d[i] -= h;
91  }
92 
93  f = f + h;
94 
95  // Implicit QL transformation.
96  p = d[m];
97  SCALARTYPE c = 1;
98  SCALARTYPE s = 0;
99  for (int i = int(m - 1); i >= int(l); i--)
100  {
101  g = c * e[vcl_size_t(i)];
102  h = c * p;
103  r = viennacl::linalg::detail::pythag<SCALARTYPE>(p, e[vcl_size_t(i)]);
104  e[vcl_size_t(i) + 1] = s * r;
105  s = e[vcl_size_t(i)] / r;
106  c = p / r;
107  p = c * d[vcl_size_t(i)] - s * g;
108  d[vcl_size_t(i) + 1] = h + s * (c * g + s * d[vcl_size_t(i)]);
109  }
110  e[l] = s * p;
111  d[l] = c * p;
112  // Check for convergence.
113  }
114  while (std::fabs(e[l]) > eps * tst1);
115  }
116  d[l] = d[l] + f;
117  e[l] = 0;
118  }
119  }
120 
121 
122 
123 
124 
125 
126 
127 // Symmetric tridiagonal QL algorithm.
128 // This is derived from the Algol procedures tql2, by Bowdler, Martin, Reinsch, and Wilkinson,
129 // Handbook for Auto. Comp., Vol.ii-Linear Algebra, and the corresponding Fortran subroutine in EISPACK.
130 template <typename SCALARTYPE, typename VectorType, typename F>
132  VectorType & d,
133  VectorType & e)
134 {
135  vcl_size_t n = static_cast<vcl_size_t>(viennacl::traits::size1(Q));
136 
137  //boost::numeric::ublas::vector<SCALARTYPE> cs(n), ss(n);
138  std::vector<SCALARTYPE> cs(n), ss(n);
139  viennacl::vector<SCALARTYPE> tmp1(n), tmp2(n);
140 
141  for (vcl_size_t i = 1; i < n; i++)
142  e[i - 1] = e[i];
143 
144  e[n - 1] = 0;
145 
146  SCALARTYPE f = 0;
147  SCALARTYPE tst1 = 0;
148  SCALARTYPE eps = static_cast<SCALARTYPE>(viennacl::linalg::detail::EPS);
149 
150  for (vcl_size_t l = 0; l < n; l++)
151  {
152  // Find small subdiagonal element.
153  tst1 = std::max<SCALARTYPE>(tst1, std::fabs(d[l]) + std::fabs(e[l]));
154  vcl_size_t m = l;
155  while (m < n)
156  {
157  if (std::fabs(e[m]) <= eps * tst1)
158  break;
159  m++;
160  }
161 
162  // If m == l, d[l) is an eigenvalue, otherwise, iterate.
163  if (m > l)
164  {
165  vcl_size_t iter = 0;
166  do
167  {
168  iter = iter + 1; // (Could check iteration count here.)
169 
170  // Compute implicit shift
171  SCALARTYPE g = d[l];
172  SCALARTYPE p = (d[l + 1] - g) / (2 * e[l]);
173  SCALARTYPE r = viennacl::linalg::detail::pythag<SCALARTYPE>(p, 1);
174  if (p < 0)
175  {
176  r = -r;
177  }
178 
179  d[l] = e[l] / (p + r);
180  d[l + 1] = e[l] * (p + r);
181  SCALARTYPE dl1 = d[l + 1];
182  SCALARTYPE h = g - d[l];
183  for (vcl_size_t i = l + 2; i < n; i++)
184  {
185  d[i] -= h;
186  }
187 
188  f = f + h;
189 
190  // Implicit QL transformation.
191  p = d[m];
192  SCALARTYPE c = 1;
193  SCALARTYPE c2 = c;
194  SCALARTYPE c3 = c;
195  SCALARTYPE el1 = e[l + 1];
196  SCALARTYPE s = 0;
197  SCALARTYPE s2 = 0;
198  for (int i = int(m - 1); i >= int(l); i--)
199  {
200  c3 = c2;
201  c2 = c;
202  s2 = s;
203  g = c * e[vcl_size_t(i)];
204  h = c * p;
206  e[vcl_size_t(i) + 1] = s * r;
207  s = e[vcl_size_t(i)] / r;
208  c = p / r;
209  p = c * d[vcl_size_t(i)] - s * g;
210  d[vcl_size_t(i) + 1] = h + s * (c * g + s * d[vcl_size_t(i)]);
211 
212 
213  cs[vcl_size_t(i)] = c;
214  ss[vcl_size_t(i)] = s;
215  }
216 
217 
218  p = -s * s2 * c3 * el1 * e[l] / dl1;
219  e[l] = s * p;
220  d[l] = c * p;
221 
222  viennacl::copy(cs, tmp1);
223  viennacl::copy(ss, tmp2);
224 
225  viennacl::linalg::givens_next(Q, tmp1, tmp2, int(l), int(m));
226 
227  // Check for convergence.
228  }
229  while (std::fabs(e[l]) > eps * tst1);
230  }
231  d[l] = d[l] + f;
232  e[l] = 0;
233  }
234 
235  // Sort eigenvalues and corresponding vectors.
236 /*
237  for (int i = 0; i < n-1; i++) {
238  int k = i;
239  SCALARTYPE p = d[i];
240  for (int j = i+1; j < n; j++) {
241  if (d[j] > p) {
242  k = j;
243  p = d[j);
244  }
245  }
246  if (k != i) {
247  d[k] = d[i];
248  d[i] = p;
249  for (int j = 0; j < n; j++) {
250  p = Q(j, i);
251  Q(j, i) = Q(j, k);
252  Q(j, k) = p;
253  }
254  }
255  }
256 
257 */
258 
259 }
260 } // namespace linalg
261 } // namespace viennacl
262 #endif
Generic interface for matrix-vector and matrix-matrix products. See viennacl/linalg/vector_operations...
Implementation of the dense matrix class.
vcl_size_t size1(MatrixType const &mat)
Generic routine for obtaining the number of rows of a matrix (ViennaCL, uBLAS, etc.)
Definition: size.hpp:163
void tql2(matrix_base< SCALARTYPE, F > &Q, VectorType &d, VectorType &e)
Definition: tql2.hpp:131
viennacl::scalar< int > s2
Main namespace in ViennaCL. Holds all the basic types such as vector, matrix, etc. and defines operations upon them.
Definition: cpu_ram.hpp:34
Common routines used for the QR method and SVD. Experimental.
std::size_t vcl_size_t
Definition: forwards.h:75
SCALARTYPE pythag(SCALARTYPE a, SCALARTYPE b)
The vector type with operator-overloads and proxy classes is defined here. Linear algebra operations ...
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) ...
void tql1(vcl_size_t n, VectorType &d, VectorType &e)
Definition: tql2.hpp:41
void givens_next(matrix_base< NumericT > &Q, vector_base< NumericT > &tmp1, vector_base< NumericT > &tmp2, int l, int m)
This function updates the matrix Q. It is part of the tql2 algorithm.