37 #ifndef GMM_DENSE_QR_H 38 #define GMM_DENSE_QR_H 48 template <
typename MAT1>
50 MAT1 &A =
const_cast<MAT1 &
>(A_);
51 typedef typename linalg_traits<MAT1>::value_type value_type;
53 size_type m = mat_nrows(A), n = mat_ncols(A);
54 GMM_ASSERT2(m >= n,
"dimensions mismatch");
56 std::vector<value_type> W(m), V(m);
58 for (size_type j = 0; j < n; ++j) {
59 sub_interval SUBI(j, m-j), SUBJ(j, n-j);
60 V.resize(m-j); W.resize(n-j);
62 for (size_type i = j; i < m; ++i) V[i-j] = A(i, j);
65 row_house_update(sub_matrix(A, SUBI, SUBJ), V, W);
66 for (size_type i = j+1; i < m; ++i) A(i, j) = V[i-j];
74 template <
typename MAT1,
typename MAT2>
75 void apply_house_right(
const MAT1 &QR,
const MAT2 &A_) {
76 MAT2 &A =
const_cast<MAT2 &
>(A_);
77 typedef typename linalg_traits<MAT1>::value_type T;
78 size_type m = mat_nrows(QR), n = mat_ncols(QR);
79 GMM_ASSERT2(m == mat_ncols(A),
"dimensions mismatch");
81 std::vector<T> V(m), W(mat_nrows(A));
83 for (size_type j = 0; j < n; ++j) {
85 for (size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
86 col_house_update(sub_matrix(A, sub_interval(0, mat_nrows(A)),
87 sub_interval(j, m-j)), V, W);
94 template <
typename MAT1,
typename MAT2>
95 void apply_house_left(
const MAT1 &QR,
const MAT2 &A_) {
96 MAT2 &A =
const_cast<MAT2 &
>(A_);
97 typedef typename linalg_traits<MAT1>::value_type T;
98 size_type m = mat_nrows(QR), n = mat_ncols(QR);
99 GMM_ASSERT2(m == mat_nrows(A),
"dimensions mismatch");
101 std::vector<T> V(m), W(mat_ncols(A));
103 for (size_type j = 0; j < n; ++j) {
105 for (size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
106 row_house_update(sub_matrix(A, sub_interval(j, m-j),
107 sub_interval(0, mat_ncols(A))), V, W);
112 template <
typename MAT1,
typename MAT2,
typename MAT3>
113 void qr_factor(
const MAT1 &A,
const MAT2 &QQ,
const MAT3 &RR) {
114 MAT2 &Q =
const_cast<MAT2 &
>(QQ); MAT3 &R =
const_cast<MAT3 &
>(RR);
115 typedef typename linalg_traits<MAT1>::value_type value_type;
117 size_type m = mat_nrows(A), n = mat_ncols(A);
118 GMM_ASSERT2(m >= n,
"dimensions mismatch");
121 std::vector<value_type> W(m);
122 dense_matrix<value_type> VV(m, n);
124 for (size_type j = 0; j < n; ++j) {
125 sub_interval SUBI(j, m-j), SUBJ(j, n-j);
127 for (size_type i = j; i < m; ++i) VV(i,j) = Q(i, j);
128 house_vector(sub_vector(mat_col(VV,j), SUBI));
130 row_house_update(sub_matrix(Q, SUBI, SUBJ),
131 sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
134 gmm::copy(sub_matrix(Q, sub_interval(0, n), sub_interval(0, n)), R);
135 gmm::copy(identity_matrix(), Q);
137 for (size_type j = n-1; j !=
size_type(-1); --j) {
138 sub_interval SUBI(j, m-j), SUBJ(j, n-j);
139 row_house_update(sub_matrix(Q, SUBI, SUBJ),
140 sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
145 template <
typename TA,
typename TV,
typename Ttol,
146 typename MAT,
typename VECT>
147 void extract_eig(
const MAT &A, VECT &V, Ttol tol, TA, TV) {
148 size_type n = mat_nrows(A);
151 Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
152 for (size_type i = 0; i < n; ++i) {
154 tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
155 tol_cplx = std::max(tol_cplx, tol_i);
157 if ((i < n-1) && gmm::abs(A(i+1,i)) >= tol_i) {
158 TA tr = A(i,i) + A(i+1, i+1);
159 TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
160 TA delta = tr*tr - TA(4) * det;
161 if (delta < -tol_cplx) {
162 GMM_WARNING1(
"A complex eigenvalue has been detected : " 163 << std::complex<TA>(tr/TA(2), gmm::sqrt(-delta)/TA(2)));
164 V[i] = V[i+1] = tr / TA(2);
167 delta = std::max(TA(0), delta);
168 V[i ] = TA(tr + gmm::sqrt(delta))/ TA(2);
169 V[i+1] = TA(tr - gmm::sqrt(delta))/ TA(2);
178 template <
typename TA,
typename TV,
typename Ttol,
179 typename MAT,
typename VECT>
180 void extract_eig(
const MAT &A, VECT &V, Ttol tol, TA, std::complex<TV>) {
181 size_type n = mat_nrows(A);
183 for (size_type i = 0; i < n; ++i)
185 gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
186 V[i] = std::complex<TV>(A(i,i));
188 TA tr = A(i,i) + A(i+1, i+1);
189 TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
190 TA delta = tr*tr - TA(4) * det;
192 V[i] = std::complex<TV>(tr / TA(2), gmm::sqrt(-delta) / TA(2));
193 V[i+1] = std::complex<TV>(tr / TA(2), -gmm::sqrt(-delta)/ TA(2));
196 V[i ] = TA(tr + gmm::sqrt(delta)) / TA(2);
197 V[i+1] = TA(tr - gmm::sqrt(delta)) / TA(2);
203 template <
typename TA,
typename TV,
typename Ttol,
204 typename MAT,
typename VECT>
205 void extract_eig(
const MAT &A, VECT &V, Ttol tol, std::complex<TA>, TV) {
206 typedef std::complex<TA> T;
207 size_type n = mat_nrows(A);
210 Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
211 for (size_type i = 0; i < n; ++i) {
213 tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
214 tol_cplx = std::max(tol_cplx, tol_i);
216 if ((i == n-1) || gmm::abs(A(i+1,i)) < tol_i) {
217 if (gmm::abs(std::imag(A(i,i))) > tol_cplx)
218 GMM_WARNING1(
"A complex eigenvalue has been detected : " 219 << T(A(i,i)) <<
" : " << gmm::abs(std::imag(A(i,i)))
220 / gmm::abs(std::real(A(i,i))) <<
" : " << tol_cplx);
221 V[i] = std::real(A(i,i));
224 T tr = A(i,i) + A(i+1, i+1);
225 T det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
226 T delta = tr*tr - TA(4) * det;
227 T a1 = (tr + gmm::sqrt(delta)) / TA(2);
228 T a2 = (tr - gmm::sqrt(delta)) / TA(2);
229 if (gmm::abs(std::imag(a1)) > tol_cplx)
230 GMM_WARNING1(
"A complex eigenvalue has been detected : " << a1);
231 if (gmm::abs(std::imag(a2)) > tol_cplx)
232 GMM_WARNING1(
"A complex eigenvalue has been detected : " << a2);
234 V[i] = std::real(a1); V[i+1] = std::real(a2);
240 template <
typename TA,
typename TV,
typename Ttol,
241 typename MAT,
typename VECT>
243 std::complex<TA>, std::complex<TV>) {
244 size_type n = mat_nrows(A);
246 for (size_type i = 0; i < n; ++i)
248 gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
249 V[i] = std::complex<TV>(A(i,i));
251 std::complex<TA> tr = A(i,i) + A(i+1, i+1);
252 std::complex<TA> det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
253 std::complex<TA> delta = tr*tr - TA(4) * det;
254 V[i] = (tr + gmm::sqrt(delta)) / TA(2);
255 V[i+1] = (tr - gmm::sqrt(delta)) / TA(2);
264 template <
typename MAT,
typename Ttol,
typename VECT>
inline 267 typename linalg_traits<MAT>::value_type(),
268 typename linalg_traits<VECT>::value_type());
275 template <
typename MAT,
typename Ttol>
276 void qr_stop_criterion(MAT &A, size_type &p, size_type &q, Ttol tol) {
277 typedef typename linalg_traits<MAT>::value_type T;
278 typedef typename number_traits<T>::magnitude_type R;
279 R rmin = default_min(R()) * R(2);
280 size_type n = mat_nrows(A);
281 if (n <= 2) { q = n; p = 0; }
283 for (size_type i = 1; i < n-q; ++i)
284 if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
285 || gmm::abs(A(i,i-1)) < rmin)
288 while ((q < n-1 && A(n-1-q, n-2-q) == T(0)) ||
289 (q < n-2 && A(n-2-q, n-3-q) == T(0))) ++q;
291 p = n-q;
if (p) --p;
if (p) --p;
292 while (p > 0 && A(p,p-1) != T(0)) --p;
296 template <
typename MAT,
typename Ttol>
inline 297 void symmetric_qr_stop_criterion(
const MAT &AA, size_type &p, size_type &q,
299 typedef typename linalg_traits<MAT>::value_type T;
300 typedef typename number_traits<T>::magnitude_type R;
301 R rmin = default_min(R()) * R(2);
302 MAT& A =
const_cast<MAT&
>(AA);
303 size_type n = mat_nrows(A);
304 if (n <= 1) { q = n; p = 0; }
306 for (size_type i = 1; i < n-q; ++i)
307 if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
308 || gmm::abs(A(i,i-1)) < rmin)
311 while (q < n-1 && A(n-1-q, n-2-q) == T(0)) ++q;
313 p = n-q;
if (p) --p;
if (p) --p;
314 while (p > 0 && A(p,p-1) != T(0)) --p;
318 template <
typename VECT1,
typename VECT2,
typename Ttol>
inline 319 void symmetric_qr_stop_criterion(
const VECT1 &diag,
const VECT2 &sdiag_,
320 size_type &p, size_type &q, Ttol tol) {
321 typedef typename linalg_traits<VECT2>::value_type T;
322 typedef typename number_traits<T>::magnitude_type R;
323 R rmin = default_min(R()) * R(2);
324 VECT2 &sdiag =
const_cast<VECT2 &
>(sdiag_);
325 size_type n = vect_size(diag);
326 if (n <= 1) { q = n; p = 0;
return; }
327 for (size_type i = 1; i < n-q; ++i)
328 if (gmm::abs(sdiag[i-1]) < (gmm::abs(diag[i])+ gmm::abs(diag[i-1]))*tol
329 || gmm::abs(sdiag[i-1]) < rmin)
331 while (q < n-1 && sdiag[n-2-q] == T(0)) ++q;
333 p = n-q;
if (p) --p;
if (p) --p;
334 while (p > 0 && sdiag[p-1] != T(0)) --p;
341 template <
typename MATH,
typename MATQ,
typename Ttol>
342 void block2x2_reduction(MATH &H, MATQ &Q, Ttol tol) {
343 typedef typename linalg_traits<MATH>::value_type T;
344 typedef typename number_traits<T>::magnitude_type R;
346 size_type n = mat_nrows(H), nq = mat_nrows(Q);
348 sub_interval SUBQ(0, nq), SUBL(0, 2);
349 std::vector<T> v(2), w(std::max(n, nq)); v[0] = T(1);
351 Ttol tol_i = tol * gmm::abs(H(0,0)), tol_cplx = tol_i;
352 for (size_type i = 0; i < n-1; ++i) {
353 tol_i = (gmm::abs(H(i,i))+gmm::abs(H(i+1,i+1)))*tol;
354 tol_cplx = std::max(tol_cplx, tol_i);
356 if (gmm::abs(H(i+1,i)) > tol_i) {
357 T tr = (H(i+1, i+1) - H(i,i)) / T(2);
358 T delta = tr*tr + H(i,i+1)*H(i+1, i);
360 if (is_complex(T()) || gmm::real(delta) >= R(0)) {
361 sub_interval SUBI(i, 2);
362 T theta = (tr - gmm::sqrt(delta)) / H(i+1,i);
363 R a = gmm::abs(theta);
364 v[1] = (a == R(0)) ? T(-1)
365 : gmm::conj(theta) * (R(1) - gmm::sqrt(a*a + R(1)) / a);
366 row_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
367 col_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
368 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
379 #define tol_type_for_qr typename number_traits<typename \ 380 linalg_traits<MAT1>::value_type>::magnitude_type 381 #define default_tol_for_qr \ 382 (gmm::default_tol(tol_type_for_qr()) * tol_type_for_qr(3)) 387 template <
typename MAT1,
typename VECT,
typename MAT2>
388 void rudimentary_qr_algorithm(
const MAT1 &A,
const VECT &eigval_,
389 const MAT2 &eigvect_,
390 tol_type_for_qr tol = default_tol_for_qr,
391 bool compvect =
true) {
392 VECT &eigval =
const_cast<VECT &
>(eigval_);
393 MAT2 &eigvect =
const_cast<MAT2 &
>(eigvect_);
395 typedef typename linalg_traits<MAT1>::value_type value_type;
397 size_type n = mat_nrows(A), p, q = 0, ite = 0;
398 dense_matrix<value_type> Q(n, n), R(n,n), A1(n,n);
401 Hessenberg_reduction(A1, eigvect, compvect);
402 qr_stop_criterion(A1, p, q, tol);
407 if (compvect) { gmm::mult(eigvect, Q, R); gmm::copy(R, eigvect); }
409 qr_stop_criterion(A1, p, q, tol);
411 GMM_ASSERT1(ite < n*1000,
"QR algorithm failed");
413 if (compvect) block2x2_reduction(A1, Q, tol);
417 template <
typename MAT1,
typename VECT>
418 void rudimentary_qr_algorithm(
const MAT1 &a, VECT &eigval,
419 tol_type_for_qr tol = default_tol_for_qr) {
420 dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
421 rudimentary_qr_algorithm(a, eigval, m, tol,
false);
428 template <
typename MAT1,
typename MAT2>
429 void Francis_qr_step(
const MAT1& HH,
const MAT2 &QQ,
bool compute_Q) {
430 MAT1& H =
const_cast<MAT1&
>(HH); MAT2& Q =
const_cast<MAT2&
>(QQ);
431 typedef typename linalg_traits<MAT1>::value_type value_type;
432 size_type n = mat_nrows(H), nq = mat_nrows(Q);
434 std::vector<value_type> v(3), w(std::max(n, nq));
436 value_type s = H(n-2, n-2) + H(n-1, n-1);
437 value_type t = H(n-2, n-2) * H(n-1, n-1) - H(n-2, n-1) * H(n-1, n-2);
438 value_type x = H(0, 0) * H(0, 0) + H(0,1) * H(1, 0) - s * H(0,0) + t;
439 value_type y = H(1, 0) * (H(0,0) + H(1,1) - s);
440 value_type z = H(1, 0) * H(2, 1);
442 sub_interval SUBQ(0, nq);
444 for (size_type k = 0; k < n - 2; ++k) {
445 v[0] = x; v[1] = y; v[2] = z;
447 size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
448 sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
450 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
451 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
454 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
456 x = H(k+1, k); y = H(k+2, k);
457 if (k < n-3) z = H(k+3, k);
459 sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
463 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
464 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
466 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
473 template <
typename MAT1,
typename MAT2,
typename Ttol>
474 void Wilkinson_double_shift_qr_step(
const MAT1& HH,
const MAT2 &QQ,
475 Ttol tol,
bool exc,
bool compute_Q) {
476 MAT1& H =
const_cast<MAT1&
>(HH); MAT2& Q =
const_cast<MAT2&
>(QQ);
477 typedef typename linalg_traits<MAT1>::value_type T;
478 typedef typename number_traits<T>::magnitude_type R;
480 size_type n = mat_nrows(H), nq = mat_nrows(Q), m;
481 std::vector<T> v(3), w(std::max(n, nq));
482 const R dat1(0.75), dat2(-0.4375);
483 T h33, h44, h43h34, v1(0), v2(0), v3(0);
486 R s = gmm::abs(H(n-1, n-2)) + gmm::abs(H(n-2, n-3));
487 h33 = h44 = dat1 * s;
491 h44 = H(n-1,n-1); h33 = H(n-2, n-2);
492 h43h34 = H(n-1, n-2) * H(n-2, n-1);
498 for (m = n-2; m != 0; --m) {
499 T h11 = H(m-1, m-1), h22 = H(m, m);
500 T h21 = H(m, m-1), h12 = H(m-1, m);
501 T h44s = h44 - h11, h33s = h33 - h11;
502 v1 = (h33s*h44s-h43h34) / h21 + h12;
503 v2 = h22 - h11 - h33s - h44s;
505 R s = gmm::abs(v1) + gmm::abs(v2) + gmm::abs(v3);
506 v1 /= s; v2 /= s; v3 /= s;
510 R tst1 = gmm::abs(v1)*(gmm::abs(h00)+gmm::abs(h11)+gmm::abs(h22));
511 if (gmm::abs(h10)*(gmm::abs(v2)+gmm::abs(v3)) <= tol * tst1)
break;
515 sub_interval SUBQ(0, nq);
516 for (size_type k = (m == 0) ? 0 : m-1; k < n-2; ++k) {
517 v[0] = v1; v[1] = v2; v[2] = v3;
519 size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
520 sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
522 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
523 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
524 if (k > m-1) { H(k+1, k-1) = T(0);
if (k < n-3) H(k+2, k-1) = T(0); }
527 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
529 v1 = H(k+1, k); v2 = H(k+2, k);
530 if (k < n-3) v3 = H(k+3, k);
532 sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
533 v.resize(2); v[0] = v1; v[1] = v2;
535 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
536 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
538 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
549 template <
typename MAT1,
typename VECT,
typename MAT2>
550 void implicit_qr_algorithm(
const MAT1 &A,
const VECT &eigval_,
552 tol_type_for_qr tol = default_tol_for_qr,
553 bool compvect =
true) {
554 VECT &eigval =
const_cast<VECT &
>(eigval_);
555 MAT2 &Q =
const_cast<MAT2 &
>(Q_);
556 typedef typename linalg_traits<MAT1>::value_type value_type;
558 size_type n(mat_nrows(A)), q(0), q_old, p(0), ite(0), its(0);
559 dense_matrix<value_type> H(n,n);
560 sub_interval SUBK(0,0);
563 Hessenberg_reduction(H, Q, compvect);
564 qr_stop_criterion(H, p, q, tol);
567 sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(Q));
568 if (compvect) SUBK = SUBI;
571 Wilkinson_double_shift_qr_step(sub_matrix(H, SUBI),
572 sub_matrix(Q, SUBJ, SUBK),
573 tol, (its == 10 || its == 20), compvect);
575 qr_stop_criterion(H, p, q, tol*2);
576 if (q != q_old) its = 0;
578 GMM_ASSERT1(ite < n*100,
"QR algorithm failed");
580 if (compvect) block2x2_reduction(H, Q, tol);
585 template <
typename MAT1,
typename VECT>
586 void implicit_qr_algorithm(
const MAT1 &a, VECT &eigval,
587 tol_type_for_qr tol = default_tol_for_qr) {
588 dense_matrix<typename linalg_traits<MAT1>::value_type> m(1,1);
589 implicit_qr_algorithm(a, eigval, m, tol,
false);
596 template <
typename MAT1,
typename MAT2>
597 void symmetric_Wilkinson_qr_step(
const MAT1& MM,
const MAT2 &ZZ,
599 MAT1& M =
const_cast<MAT1&
>(MM); MAT2& Z =
const_cast<MAT2&
>(ZZ);
600 typedef typename linalg_traits<MAT1>::value_type T;
601 typedef typename number_traits<T>::magnitude_type R;
602 size_type n = mat_nrows(M);
604 for (size_type i = 0; i < n; ++i) {
605 M(i, i) = T(gmm::real(M(i, i)));
607 T a = (M(i, i-1) + gmm::conj(M(i-1, i)))/R(2);
608 M(i, i-1) = a; M(i-1, i) = gmm::conj(a);
612 R d = gmm::real(M(n-2, n-2) - M(n-1, n-1)) / R(2);
613 R e = gmm::abs_sqr(M(n-1, n-2));
614 R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
615 if (nu == R(0)) { M(n-1, n-2) = T(0);
return; }
616 R mu = gmm::real(M(n-1, n-1)) - e / nu;
617 T x = M(0,0) - T(mu), z = M(1, 0), c, s;
619 for (size_type k = 1; k < n; ++k) {
620 Givens_rotation(x, z, c, s);
622 if (k > 1) Apply_Givens_rotation_left(M(k-1,k-2), M(k,k-2), c, s);
623 Apply_Givens_rotation_left(M(k-1,k-1), M(k,k-1), c, s);
624 Apply_Givens_rotation_left(M(k-1,k ), M(k,k ), c, s);
625 if (k < n-1) Apply_Givens_rotation_left(M(k-1,k+1), M(k,k+1), c, s);
626 if (k > 1) Apply_Givens_rotation_right(M(k-2,k-1), M(k-2,k), c, s);
627 Apply_Givens_rotation_right(M(k-1,k-1), M(k-1,k), c, s);
628 Apply_Givens_rotation_right(M(k ,k-1), M(k,k) , c, s);
629 if (k < n-1) Apply_Givens_rotation_right(M(k+1,k-1), M(k+1,k), c, s);
631 if (compute_z) col_rot(Z, c, s, k-1, k);
632 if (k < n-1) { x = M(k, k-1); z = M(k+1, k-1); }
637 template <
typename VECT1,
typename VECT2,
typename MAT>
638 void symmetric_Wilkinson_qr_step(
const VECT1& diag_,
const VECT2& sdiag_,
639 const MAT &ZZ,
bool compute_z) {
640 VECT1& diag =
const_cast<VECT1&
>(diag_);
641 VECT2& sdiag =
const_cast<VECT2&
>(sdiag_);
642 MAT& Z =
const_cast<MAT&
>(ZZ);
643 typedef typename linalg_traits<VECT2>::value_type T;
644 typedef typename number_traits<T>::magnitude_type R;
646 size_type n = vect_size(diag);
647 R d = (diag[n-2] - diag[n-1]) / R(2);
648 R e = gmm::abs_sqr(sdiag[n-2]);
649 R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
650 if (nu == R(0)) { sdiag[n-2] = T(0);
return; }
651 R mu = diag[n-1] - e / nu;
652 T x = diag[0] - T(mu), z = sdiag[0], c, s;
655 T a10(0), a11(diag[0]), a12(gmm::conj(sdiag[0])), a13(0);
656 T a20(0), a21(sdiag[0]), a22(diag[1]), a23(gmm::conj(sdiag[1]));
657 T a31(0), a32(sdiag[1]);
659 for (size_type k = 1; k < n; ++k) {
660 Givens_rotation(x, z, c, s);
662 if (k > 1) Apply_Givens_rotation_left(a10, a20, c, s);
663 Apply_Givens_rotation_left(a11, a21, c, s);
664 Apply_Givens_rotation_left(a12, a22, c, s);
665 if (k < n-1) Apply_Givens_rotation_left(a13, a23, c, s);
667 if (k > 1) Apply_Givens_rotation_right(a01, a02, c, s);
668 Apply_Givens_rotation_right(a11, a12, c, s);
669 Apply_Givens_rotation_right(a21, a22, c, s);
670 if (k < n-1) Apply_Givens_rotation_right(a31, a32, c, s);
672 if (compute_z) col_rot(Z, c, s, k-1, k);
674 diag[k-1] = gmm::real(a11);
675 diag[k] = gmm::real(a22);
676 if (k > 1) sdiag[k-2] = (gmm::conj(a01) + a10) / R(2);
677 sdiag[k-1] = (gmm::conj(a12) + a21) / R(2);
679 x = sdiag[k-1]; z = (gmm::conj(a13) + a31) / R(2);
681 a01 = a12; a02 = a13;
682 a10 = a21; a11 = a22; a12 = a23; a13 = T(0);
683 a20 = a31; a21 = a32; a31 = T(0);
686 sdiag[k] = (gmm::conj(a23) + a32) / R(2);
687 a22 = T(diag[k+1]); a32 = sdiag[k+1]; a23 = gmm::conj(a32);
700 template <
typename MAT1,
typename VECT,
typename MAT2>
701 void symmetric_qr_algorithm_old(
const MAT1 &A,
const VECT &eigval_,
702 const MAT2 &eigvect_,
703 tol_type_for_qr tol = default_tol_for_qr,
704 bool compvect =
true) {
705 VECT &eigval =
const_cast<VECT &
>(eigval_);
706 MAT2 &eigvect =
const_cast<MAT2 &
>(eigvect_);
707 typedef typename linalg_traits<MAT1>::value_type T;
708 typedef typename number_traits<T>::magnitude_type R;
710 if (compvect) gmm::copy(identity_matrix(), eigvect);
711 size_type n = mat_nrows(A), q = 0, p, ite = 0;
712 dense_matrix<T> Tri(n, n);
715 Householder_tridiagonalization(Tri, eigvect, compvect);
717 symmetric_qr_stop_criterion(Tri, p, q, tol);
721 sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
722 if (!compvect) SUBK = sub_interval(0,0);
723 symmetric_Wilkinson_qr_step(sub_matrix(Tri, SUBI),
724 sub_matrix(eigvect, SUBJ, SUBK), compvect);
726 symmetric_qr_stop_criterion(Tri, p, q, tol*R(2));
728 GMM_ASSERT1(ite < n*100,
"QR algorithm failed. Probably, your matrix" 729 " is not real symmetric or complex hermitian");
735 template <
typename MAT1,
typename VECT,
typename MAT2>
736 void symmetric_qr_algorithm(
const MAT1 &A,
const VECT &eigval_,
737 const MAT2 &eigvect_,
738 tol_type_for_qr tol = default_tol_for_qr,
739 bool compvect =
true) {
740 VECT &eigval =
const_cast<VECT &
>(eigval_);
741 MAT2 &eigvect =
const_cast<MAT2 &
>(eigvect_);
742 typedef typename linalg_traits<MAT1>::value_type T;
743 typedef typename number_traits<T>::magnitude_type R;
745 size_type n = mat_nrows(A), q = 0, p, ite = 0;
746 if (compvect) gmm::copy(identity_matrix(), eigvect);
748 if (n == 1) { eigval[0]=gmm::real(A(0,0));
return; }
749 dense_matrix<T> Tri(n, n);
752 Householder_tridiagonalization(Tri, eigvect, compvect);
754 std::vector<R> diag(n);
755 std::vector<T> sdiag(n);
756 for (size_type i = 0; i < n; ++i)
757 { diag[i] = gmm::real(Tri(i, i));
if (i+1 < n) sdiag[i] = Tri(i+1, i); }
759 symmetric_qr_stop_criterion(diag, sdiag, p, q, tol);
762 sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
763 if (!compvect) SUBK = sub_interval(0,0);
765 symmetric_Wilkinson_qr_step(sub_vector(diag, SUBI),
766 sub_vector(sdiag, SUBI),
767 sub_matrix(eigvect, SUBJ, SUBK), compvect);
769 symmetric_qr_stop_criterion(diag, sdiag, p, q, tol*R(3));
771 GMM_ASSERT1(ite < n*100,
"QR algorithm failed.");
774 gmm::copy(diag, eigval);
778 template <
typename MAT1,
typename VECT>
779 void symmetric_qr_algorithm(
const MAT1 &a, VECT &eigval,
780 tol_type_for_qr tol = default_tol_for_qr) {
781 dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
782 symmetric_qr_algorithm(a, eigval, m, tol,
false);
void extract_eig(const MAT &A, const VECT &V, Ttol tol)
Compute eigenvalue vector.
Householder for dense matrices.
void qr_factor(const MAT1 &A_)
QR factorization using Householder method (complex and real version).
size_t size_type
used as the common size type in the library