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 T;
53 const size_type m = mat_nrows(A), n = mat_ncols(A);
54 GMM_ASSERT2(m >= n,
"dimensions mismatch");
56 std::vector<T> W(m), V(m);
59 const size_type jmax = (m==n && !is_complex(T())) ? m-1
61 for (size_type j = 0; j < jmax; ++j) {
62 sub_interval SUBI(j, m-j), SUBJ(j, n-j);
63 V.resize(m-j); W.resize(n-j);
65 for (size_type i = j; i < m; ++i) V[i-j] = A(i, j);
68 row_house_update(sub_matrix(A, SUBI, SUBJ), V, W);
69 for (size_type i = j+1; i < m; ++i) A(i, j) = V[i-j];
77 template <
typename MAT1,
typename MAT2>
78 void apply_house_right(
const MAT1 &QR,
const MAT2 &A_) {
79 MAT2 &A =
const_cast<MAT2 &
>(A_);
80 typedef typename linalg_traits<MAT1>::value_type T;
81 const size_type m = mat_nrows(QR), n = mat_ncols(QR);
82 GMM_ASSERT2(m == mat_ncols(A),
"dimensions mismatch");
84 std::vector<T> V(m), W(mat_nrows(A));
87 const size_type jmax = (m==n && !is_complex(T())) ? m-1
93 col_house_update(sub_matrix(A, sub_interval(0, mat_nrows(A)),
94 sub_interval(j, m-j)),
102 template <
typename MAT1,
typename MAT2>
103 void apply_house_left(
const MAT1 &QR,
const MAT2 &A_) {
104 MAT2 &A =
const_cast<MAT2 &
>(A_);
105 typedef typename linalg_traits<MAT1>::value_type T;
106 const size_type m = mat_nrows(QR), n = mat_ncols(QR);
107 GMM_ASSERT2(m == mat_nrows(A),
"dimensions mismatch");
109 std::vector<T> V(m), W(mat_ncols(A));
112 const size_type jmax = (m==n && !is_complex(T())) ? m-1
116 for (
size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
117 row_house_update(sub_matrix(A, sub_interval(j, m-j),
118 sub_interval(0, mat_ncols(A))),
124 template <
typename MAT1,
typename MAT2,
typename MAT3>
125 void qr_factor(
const MAT1 &A,
const MAT2 &QQ,
const MAT3 &RR) {
126 MAT2 &Q =
const_cast<MAT2 &
>(QQ); MAT3 &R =
const_cast<MAT3 &
>(RR);
127 typedef typename linalg_traits<MAT1>::value_type T;
129 const size_type m = mat_nrows(A), n = mat_ncols(A);
130 GMM_ASSERT2(m >= n,
"dimensions mismatch");
134 dense_matrix<T> VV(m, n);
137 const size_type jmax = (m==n && !is_complex(T())) ? m-1
139 for (size_type j = 0; j < jmax; ++j) {
140 sub_interval SUBI(j, m-j), SUBJ(j, n-j);
142 for (size_type i = j; i < m; ++i) VV(i,j) = Q(i, j);
143 house_vector(sub_vector(mat_col(VV,j), SUBI));
145 row_house_update(sub_matrix(Q, SUBI, SUBJ),
146 sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
149 gmm::copy(sub_matrix(Q, sub_interval(0, n), sub_interval(0, n)), R);
152 const size_type jstart = (m==n && !is_complex(T())) ? m-2
154 for (size_type j = jstart; j !=
size_type(-1); --j) {
155 sub_interval SUBI(j, m-j), SUBJ(j, n-j);
156 row_house_update(sub_matrix(Q, SUBI, SUBJ),
157 sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
162 template <
typename TA,
typename TV,
typename Ttol,
163 typename MAT,
typename VECT>
164 void extract_eig(
const MAT &A, VECT &V, Ttol tol, TA, TV) {
168 Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
171 tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
172 tol_cplx = std::max(tol_cplx, tol_i);
174 if ((i < n-1) && gmm::abs(A(i+1,i)) >= tol_i) {
175 TA tr = A(i,i) + A(i+1, i+1);
176 TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
177 TA delta = tr*tr - TA(4) * det;
178 if (delta < -tol_cplx) {
179 GMM_WARNING1(
"A complex eigenvalue has been detected : "
180 << std::complex<TA>(tr/TA(2), gmm::sqrt(-delta)/TA(2)));
181 V[i] = V[i+1] = tr / TA(2);
184 delta = std::max(TA(0), delta);
185 V[i ] = TA(tr + gmm::sqrt(delta))/ TA(2);
186 V[i+1] = TA(tr - gmm::sqrt(delta))/ TA(2);
195 template <
typename TA,
typename TV,
typename Ttol,
196 typename MAT,
typename VECT>
197 void extract_eig(
const MAT &A, VECT &V, Ttol tol, TA, std::complex<TV>) {
202 gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
203 V[i] = std::complex<TV>(A(i,i));
205 TA tr = A(i,i) + A(i+1, i+1);
206 TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
207 TA delta = tr*tr - TA(4) * det;
209 V[i] = std::complex<TV>(tr / TA(2), gmm::sqrt(-delta) / TA(2));
210 V[i+1] = std::complex<TV>(tr / TA(2), -gmm::sqrt(-delta)/ TA(2));
213 V[i ] = TA(tr + gmm::sqrt(delta)) / TA(2);
214 V[i+1] = TA(tr - gmm::sqrt(delta)) / TA(2);
220 template <
typename TA,
typename TV,
typename Ttol,
221 typename MAT,
typename VECT>
222 void extract_eig(
const MAT &A, VECT &V, Ttol tol, std::complex<TA>, TV) {
223 typedef std::complex<TA> T;
227 Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
230 tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
231 tol_cplx = std::max(tol_cplx, tol_i);
233 if ((i == n-1) || gmm::abs(A(i+1,i)) < tol_i) {
234 if (gmm::abs(std::imag(A(i,i))) > tol_cplx)
235 GMM_WARNING1(
"A complex eigenvalue has been detected : "
236 << T(A(i,i)) <<
" : " << gmm::abs(std::imag(A(i,i)))
237 / gmm::abs(std::real(A(i,i))) <<
" : " << tol_cplx);
238 V[i] = std::real(A(i,i));
241 T tr = A(i,i) + A(i+1, i+1);
242 T det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
243 T delta = tr*tr - TA(4) * det;
244 T a1 = (tr + gmm::sqrt(delta)) / TA(2);
245 T a2 = (tr - gmm::sqrt(delta)) / TA(2);
246 if (gmm::abs(std::imag(a1)) > tol_cplx)
247 GMM_WARNING1(
"A complex eigenvalue has been detected : " << a1);
248 if (gmm::abs(std::imag(a2)) > tol_cplx)
249 GMM_WARNING1(
"A complex eigenvalue has been detected : " << a2);
251 V[i] = std::real(a1); V[i+1] = std::real(a2);
257 template <
typename TA,
typename TV,
typename Ttol,
258 typename MAT,
typename VECT>
260 std::complex<TA>, std::complex<TV>) {
265 gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
266 V[i] = std::complex<TV>(A(i,i));
268 std::complex<TA> tr = A(i,i) + A(i+1, i+1);
269 std::complex<TA> det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
270 std::complex<TA> delta = tr*tr - TA(4) * det;
271 V[i] = (tr + gmm::sqrt(delta)) / TA(2);
272 V[i+1] = (tr - gmm::sqrt(delta)) / TA(2);
281 template <
typename MAT,
typename Ttol,
typename VECT>
inline
284 typename linalg_traits<MAT>::value_type(),
285 typename linalg_traits<VECT>::value_type());
292 template <
typename MAT,
typename Ttol>
294 typedef typename linalg_traits<MAT>::value_type T;
295 typedef typename number_traits<T>::magnitude_type R;
296 R rmin = default_min(R()) * R(2);
298 if (n <= 2) { q = n; p = 0; }
301 if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
302 || gmm::abs(A(i,i-1)) < rmin)
305 while ((q < n-1 && A(n-1-q, n-2-q) == T(0)) ||
306 (q < n-2 && A(n-2-q, n-3-q) == T(0))) ++q;
308 p = n-q;
if (p) --p;
if (p) --p;
309 while (p > 0 && A(p,p-1) != T(0)) --p;
313 template <
typename MAT,
typename Ttol>
inline
316 typedef typename linalg_traits<MAT>::value_type T;
317 typedef typename number_traits<T>::magnitude_type R;
318 R rmin = default_min(R()) * R(2);
319 MAT& A =
const_cast<MAT&
>(AA);
321 if (n <= 1) { q = n; p = 0; }
324 if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
325 || gmm::abs(A(i,i-1)) < rmin)
328 while (q < n-1 && A(n-1-q, n-2-q) == T(0)) ++q;
330 p = n-q;
if (p) --p;
if (p) --p;
331 while (p > 0 && A(p,p-1) != T(0)) --p;
335 template <
typename VECT1,
typename VECT2,
typename Ttol>
inline
336 void symmetric_qr_stop_criterion(
const VECT1 &diag,
const VECT2 &sdiag_,
338 typedef typename linalg_traits<VECT2>::value_type T;
339 typedef typename number_traits<T>::magnitude_type R;
340 R rmin = default_min(R()) * R(2);
341 VECT2 &sdiag =
const_cast<VECT2 &
>(sdiag_);
343 if (n <= 1) { q = n; p = 0;
return; }
345 if (gmm::abs(sdiag[i-1]) < (gmm::abs(diag[i])+ gmm::abs(diag[i-1]))*tol
346 || gmm::abs(sdiag[i-1]) < rmin)
348 while (q < n-1 && sdiag[n-2-q] == T(0)) ++q;
350 p = n-q;
if (p) --p;
if (p) --p;
351 while (p > 0 && sdiag[p-1] != T(0)) --p;
358 template <
typename MATH,
typename MATQ,
typename Ttol>
359 void block2x2_reduction(MATH &H, MATQ &Q, Ttol tol) {
360 typedef typename linalg_traits<MATH>::value_type T;
361 typedef typename number_traits<T>::magnitude_type R;
363 size_type n = mat_nrows(H), nq = mat_nrows(Q);
365 sub_interval SUBQ(0, nq), SUBL(0, 2);
366 std::vector<T> v(2), w(std::max(n, nq)); v[0] = T(1);
368 Ttol tol_i = tol * gmm::abs(H(0,0)), tol_cplx = tol_i;
370 tol_i = (gmm::abs(H(i,i))+gmm::abs(H(i+1,i+1)))*tol;
371 tol_cplx = std::max(tol_cplx, tol_i);
373 if (gmm::abs(H(i+1,i)) > tol_i) {
374 T tr = (H(i+1, i+1) - H(i,i)) / T(2);
375 T delta = tr*tr + H(i,i+1)*H(i+1, i);
377 if (is_complex(T()) || gmm::real(delta) >= R(0)) {
378 sub_interval SUBI(i, 2);
379 T theta = (tr - gmm::sqrt(delta)) / H(i+1,i);
380 R a = gmm::abs(theta);
381 v[1] = (a == R(0)) ? T(-1)
382 : gmm::conj(theta) * (R(1) - gmm::sqrt(a*a + R(1)) / a);
383 row_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
384 col_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
385 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
396 #define tol_type_for_qr typename number_traits<typename \
397 linalg_traits<MAT1>::value_type>::magnitude_type
398 #define default_tol_for_qr \
399 (gmm::default_tol(tol_type_for_qr()) * tol_type_for_qr(3))
404 template <
typename MAT1,
typename VECT,
typename MAT2>
405 void rudimentary_qr_algorithm(
const MAT1 &A,
const VECT &eigval_,
406 const MAT2 &eigvect_,
407 tol_type_for_qr tol = default_tol_for_qr,
408 bool compvect =
true) {
409 VECT &eigval =
const_cast<VECT &
>(eigval_);
410 MAT2 &eigvect =
const_cast<MAT2 &
>(eigvect_);
412 typedef typename linalg_traits<MAT1>::value_type value_type;
414 size_type n = mat_nrows(A), p, q = 0, ite = 0;
415 dense_matrix<value_type> Q(n, n), R(n,n), A1(n,n);
418 Hessenberg_reduction(A1, eigvect, compvect);
419 qr_stop_criterion(A1, p, q, tol);
426 qr_stop_criterion(A1, p, q, tol);
428 GMM_ASSERT1(ite < n*1000,
"QR algorithm failed");
430 if (compvect) block2x2_reduction(A1, Q, tol);
434 template <
typename MAT1,
typename VECT>
435 void rudimentary_qr_algorithm(
const MAT1 &a, VECT &eigval,
436 tol_type_for_qr tol = default_tol_for_qr) {
437 dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
438 rudimentary_qr_algorithm(a, eigval, m, tol,
false);
445 template <
typename MAT1,
typename MAT2>
446 void Francis_qr_step(
const MAT1& HH,
const MAT2 &QQ,
bool compute_Q) {
447 MAT1& H =
const_cast<MAT1&
>(HH); MAT2& Q =
const_cast<MAT2&
>(QQ);
448 typedef typename linalg_traits<MAT1>::value_type value_type;
449 size_type n = mat_nrows(H), nq = mat_nrows(Q);
451 std::vector<value_type> v(3), w(std::max(n, nq));
453 value_type s = H(n-2, n-2) + H(n-1, n-1);
454 value_type t = H(n-2, n-2) * H(n-1, n-1) - H(n-2, n-1) * H(n-1, n-2);
455 value_type x = H(0, 0) * H(0, 0) + H(0,1) * H(1, 0) - s * H(0,0) + t;
456 value_type y = H(1, 0) * (H(0,0) + H(1,1) - s);
457 value_type z = H(1, 0) * H(2, 1);
459 sub_interval SUBQ(0, nq);
462 v[0] = x; v[1] = y; v[2] = z;
464 size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
465 sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
467 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
468 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
471 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
473 x = H(k+1, k); y = H(k+2, k);
474 if (k < n-3) z = H(k+3, k);
476 sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
480 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
481 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
483 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
490 template <
typename MAT1,
typename MAT2,
typename Ttol>
491 void Wilkinson_double_shift_qr_step(
const MAT1& HH,
const MAT2 &QQ,
492 Ttol tol,
bool exc,
bool compute_Q) {
493 MAT1& H =
const_cast<MAT1&
>(HH); MAT2& Q =
const_cast<MAT2&
>(QQ);
494 typedef typename linalg_traits<MAT1>::value_type T;
495 typedef typename number_traits<T>::magnitude_type R;
497 size_type n = mat_nrows(H), nq = mat_nrows(Q), m;
498 std::vector<T> v(3), w(std::max(n, nq));
499 const R dat1(0.75), dat2(-0.4375);
500 T h33, h44, h43h34, v1(0), v2(0), v3(0);
503 R s = gmm::abs(H(n-1, n-2)) + gmm::abs(H(n-2, n-3));
504 h33 = h44 = dat1 * s;
508 h44 = H(n-1,n-1); h33 = H(n-2, n-2);
509 h43h34 = H(n-1, n-2) * H(n-2, n-1);
515 for (m = n-2; m != 0; --m) {
516 T h11 = H(m-1, m-1), h22 = H(m, m);
517 T h21 = H(m, m-1), h12 = H(m-1, m);
518 T h44s = h44 - h11, h33s = h33 - h11;
519 v1 = (h33s*h44s-h43h34) / h21 + h12;
520 v2 = h22 - h11 - h33s - h44s;
522 R s = gmm::abs(v1) + gmm::abs(v2) + gmm::abs(v3);
523 v1 /= s; v2 /= s; v3 /= s;
527 R tst1 = gmm::abs(v1)*(gmm::abs(h00)+gmm::abs(h11)+gmm::abs(h22));
528 if (gmm::abs(h10)*(gmm::abs(v2)+gmm::abs(v3)) <= tol * tst1)
break;
532 sub_interval SUBQ(0, nq);
533 for (
size_type k = (m == 0) ? 0 : m-1; k < n-2; ++k) {
534 v[0] = v1; v[1] = v2; v[2] = v3;
536 size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
537 sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
539 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
540 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
541 if (k > m-1) { H(k+1, k-1) = T(0);
if (k < n-3) H(k+2, k-1) = T(0); }
544 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
546 v1 = H(k+1, k); v2 = H(k+2, k);
547 if (k < n-3) v3 = H(k+3, k);
549 sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
550 v.resize(2); v[0] = v1; v[1] = v2;
552 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
553 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
555 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
566 template <
typename MAT1,
typename VECT,
typename MAT2>
567 void implicit_qr_algorithm(
const MAT1 &A,
const VECT &eigval_,
569 tol_type_for_qr tol = default_tol_for_qr,
570 bool compvect =
true) {
571 VECT &eigval =
const_cast<VECT &
>(eigval_);
572 MAT2 &Q =
const_cast<MAT2 &
>(Q_);
573 typedef typename linalg_traits<MAT1>::value_type T;
574 typedef typename number_traits<T>::magnitude_type R;
577 dense_matrix<T> H(n,n);
580 Hessenberg_reduction(H, Q, compvect);
581 qr_stop_criterion(H, p, q, tol);
584 sub_interval SUBK(0,0);
586 sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(Q));
587 if (compvect) SUBK = SUBI;
590 Wilkinson_double_shift_qr_step(sub_matrix(H, SUBI),
591 sub_matrix(Q, SUBJ, SUBK),
592 tol, (its == 10 || its == 20), compvect);
594 qr_stop_criterion(H, p, q, tol*R(2));
595 if (q != q_old) its = 0;
597 GMM_ASSERT1(ite < n*100,
"QR algorithm failed");
599 if (compvect) block2x2_reduction(H, Q, tol);
603 template <
typename MAT1,
typename VECT>
604 void implicit_qr_algorithm(
const MAT1 &a, VECT &eigval,
605 tol_type_for_qr tol = default_tol_for_qr) {
606 dense_matrix<typename linalg_traits<MAT1>::value_type> m(1,1);
607 implicit_qr_algorithm(a, eigval, m, tol,
false);
614 template <
typename MAT1,
typename MAT2>
615 void symmetric_Wilkinson_qr_step(
const MAT1& MM,
const MAT2 &ZZ,
617 MAT1& M =
const_cast<MAT1&
>(MM); MAT2& Z =
const_cast<MAT2&
>(ZZ);
618 typedef typename linalg_traits<MAT1>::value_type T;
619 typedef typename number_traits<T>::magnitude_type R;
623 M(i, i) = T(gmm::real(M(i, i)));
625 T a = (M(i, i-1) + gmm::conj(M(i-1, i)))/R(2);
626 M(i, i-1) = a; M(i-1, i) = gmm::conj(a);
630 R d = gmm::real(M(n-2, n-2) - M(n-1, n-1)) / R(2);
631 R e = gmm::abs_sqr(M(n-1, n-2));
632 R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
633 if (nu == R(0)) { M(n-1, n-2) = T(0);
return; }
634 R mu = gmm::real(M(n-1, n-1)) - e / nu;
635 T x = M(0,0) - T(mu), z = M(1, 0), c, s;
638 Givens_rotation(x, z, c, s);
640 if (k > 1) Apply_Givens_rotation_left(M(k-1,k-2), M(k,k-2), c, s);
641 Apply_Givens_rotation_left(M(k-1,k-1), M(k,k-1), c, s);
642 Apply_Givens_rotation_left(M(k-1,k ), M(k,k ), c, s);
643 if (k < n-1) Apply_Givens_rotation_left(M(k-1,k+1), M(k,k+1), c, s);
644 if (k > 1) Apply_Givens_rotation_right(M(k-2,k-1), M(k-2,k), c, s);
645 Apply_Givens_rotation_right(M(k-1,k-1), M(k-1,k), c, s);
646 Apply_Givens_rotation_right(M(k ,k-1), M(k,k) , c, s);
647 if (k < n-1) Apply_Givens_rotation_right(M(k+1,k-1), M(k+1,k), c, s);
649 if (compute_z) col_rot(Z, c, s, k-1, k);
650 if (k < n-1) { x = M(k, k-1); z = M(k+1, k-1); }
654 template <
typename VECT1,
typename VECT2,
typename MAT>
655 void symmetric_Wilkinson_qr_step(
const VECT1& diag_,
const VECT2& sdiag_,
656 const MAT &ZZ,
bool compute_z) {
657 VECT1& diag =
const_cast<VECT1&
>(diag_);
658 VECT2& sdiag =
const_cast<VECT2&
>(sdiag_);
659 MAT& Z =
const_cast<MAT&
>(ZZ);
660 typedef typename linalg_traits<VECT2>::value_type T;
661 typedef typename number_traits<T>::magnitude_type R;
664 R d = (diag[n-2] - diag[n-1]) / R(2);
665 R e = gmm::abs_sqr(sdiag[n-2]);
666 R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
667 if (nu == R(0)) { sdiag[n-2] = T(0);
return; }
668 R mu = diag[n-1] - e / nu;
669 T x = diag[0] - T(mu), z = sdiag[0], c, s;
672 T a10(0), a11(diag[0]), a12(gmm::conj(sdiag[0])), a13(0);
673 T a20(0), a21(sdiag[0]), a22(diag[1]), a23(gmm::conj(sdiag[1]));
674 T a31(0), a32(sdiag[1]);
677 Givens_rotation(x, z, c, s);
679 if (k > 1) Apply_Givens_rotation_left(a10, a20, c, s);
680 Apply_Givens_rotation_left(a11, a21, c, s);
681 Apply_Givens_rotation_left(a12, a22, c, s);
682 if (k < n-1) Apply_Givens_rotation_left(a13, a23, c, s);
684 if (k > 1) Apply_Givens_rotation_right(a01, a02, c, s);
685 Apply_Givens_rotation_right(a11, a12, c, s);
686 Apply_Givens_rotation_right(a21, a22, c, s);
687 if (k < n-1) Apply_Givens_rotation_right(a31, a32, c, s);
689 if (compute_z) col_rot(Z, c, s, k-1, k);
691 diag[k-1] = gmm::real(a11);
692 diag[k] = gmm::real(a22);
693 if (k > 1) sdiag[k-2] = (gmm::conj(a01) + a10) / R(2);
694 sdiag[k-1] = (gmm::conj(a12) + a21) / R(2);
696 x = sdiag[k-1]; z = (gmm::conj(a13) + a31) / R(2);
698 a01 = a12; a02 = a13;
699 a10 = a21; a11 = a22; a12 = a23; a13 = T(0);
700 a20 = a31; a21 = a32; a31 = T(0);
703 sdiag[k] = (gmm::conj(a23) + a32) / R(2);
704 a22 = T(diag[k+1]); a32 = sdiag[k+1]; a23 = gmm::conj(a32);
717 template <
typename MAT1,
typename VECT,
typename MAT2>
718 void symmetric_qr_algorithm_old(
const MAT1 &A,
const VECT &eigval_,
719 const MAT2 &eigvect_,
720 tol_type_for_qr tol = default_tol_for_qr,
721 bool compvect =
true) {
722 VECT &eigval =
const_cast<VECT &
>(eigval_);
723 MAT2 &eigvect =
const_cast<MAT2 &
>(eigvect_);
724 typedef typename linalg_traits<MAT1>::value_type T;
725 typedef typename number_traits<T>::magnitude_type R;
727 size_type n(mat_nrows(A)), q(0), p(0), ite(0);
728 dense_matrix<T> Tri(n, n);
731 if (compvect)
gmm::copy(identity_matrix(), eigvect);
732 Householder_tridiagonalization(Tri, eigvect, compvect);
733 symmetric_qr_stop_criterion(Tri, p, q, tol);
736 sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
737 if (!compvect) SUBK = sub_interval(0,0);
738 symmetric_Wilkinson_qr_step(sub_matrix(Tri, SUBI),
739 sub_matrix(eigvect, SUBJ, SUBK), compvect);
741 symmetric_qr_stop_criterion(Tri, p, q, tol*R(2));
743 GMM_ASSERT1(ite < n*100,
"QR algorithm failed. Probably, your matrix"
744 " is not real symmetric or complex hermitian");
750 template <
typename MAT1,
typename VECT,
typename MAT2>
751 void symmetric_qr_algorithm(
const MAT1 &A,
const VECT &eigval_,
752 const MAT2 &eigvect_,
753 tol_type_for_qr tol = default_tol_for_qr,
754 bool compvect =
true) {
755 VECT &eigval =
const_cast<VECT &
>(eigval_);
756 MAT2 &eigvect =
const_cast<MAT2 &
>(eigvect_);
757 typedef typename linalg_traits<MAT1>::value_type T;
758 typedef typename number_traits<T>::magnitude_type R;
760 size_type n = mat_nrows(A), q = 0, p, ite = 0;
761 if (compvect)
gmm::copy(identity_matrix(), eigvect);
763 if (n == 1) { eigval[0]=gmm::real(A(0,0));
return; }
764 dense_matrix<T> Tri(n, n);
767 Householder_tridiagonalization(Tri, eigvect, compvect);
769 std::vector<R> diag(n);
770 std::vector<T> sdiag(n);
772 { diag[i] = gmm::real(Tri(i, i));
if (i+1 < n) sdiag[i] = Tri(i+1, i); }
774 symmetric_qr_stop_criterion(diag, sdiag, p, q, tol);
777 sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
778 if (!compvect) SUBK = sub_interval(0,0);
780 symmetric_Wilkinson_qr_step(sub_vector(diag, SUBI),
781 sub_vector(sdiag, SUBI),
782 sub_matrix(eigvect, SUBJ, SUBK), compvect);
784 symmetric_qr_stop_criterion(diag, sdiag, p, q, tol*R(3));
786 GMM_ASSERT1(ite < n*100,
"QR algorithm failed.");
793 template <
typename MAT1,
typename VECT>
794 void symmetric_qr_algorithm(
const MAT1 &a, VECT &eigval,
795 tol_type_for_qr tol = default_tol_for_qr) {
796 dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
797 symmetric_qr_algorithm(a, eigval, m, tol,
false);
void copy(const L1 &l1, L2 &l2)
*/
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
Householder for dense matrices.
void extract_eig(const MAT &A, const VECT &V, Ttol tol)
Compute eigenvalue vector.
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