36 #ifndef GMM_DENSE_QR_H
37 #define GMM_DENSE_QR_H
47 template <
typename MAT>
49 MAT &A =
const_cast<MAT &
>(A_);
50 typedef typename linalg_traits<MAT>::value_type T;
51 typedef typename number_traits<T>::magnitude_type R;
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);
69 if (Vnorm2 > R(1) || gmm::imag(A(j, j)) != R(0)) {
70 auto subA = sub_matrix(A, SUBI, SUBJ);
72 scaled(V, T(R(-2)/Vnorm2)), W);
73 rank_one_update(subA, V, W);
74 for (size_type i = j+1; i < m; ++i) A(i, j) = V[i-j];
83 template <
typename MAT1,
typename MAT2>
84 void apply_house_right(
const MAT1 &QR,
const MAT2 &A_) {
85 MAT2 &A =
const_cast<MAT2 &
>(A_);
86 typedef typename linalg_traits<MAT1>::value_type T;
87 typedef typename number_traits<T>::magnitude_type R;
89 const size_type m = mat_nrows(QR), n = mat_ncols(QR);
90 GMM_ASSERT2(m == mat_ncols(A),
"dimensions mismatch");
92 std::vector<T> V(m), W(mat_nrows(A));
95 const size_type jmax = (m==n && !is_complex(T())) ? m-1
101 R Vnorm2 = vect_norm2_sqr(V);
102 if (Vnorm2 > R(1) || gmm::imag(QR(j, j)) != R(0)) {
103 auto subA = sub_matrix(A, sub_interval(0, mat_nrows(A)),
104 sub_interval(j, m-j));
105 gmm::mult(subA, scaled(V, T(R(-2)/Vnorm2)), W);
106 rank_one_update(subA, W, V);
114 template <
typename MAT1,
typename MAT2>
115 void apply_house_left(
const MAT1 &QR,
const MAT2 &A_) {
116 MAT2 &A =
const_cast<MAT2 &
>(A_);
117 typedef typename linalg_traits<MAT1>::value_type T;
118 typedef typename number_traits<T>::magnitude_type R;
120 const size_type m = mat_nrows(QR), n = mat_ncols(QR);
121 GMM_ASSERT2(m == mat_nrows(A),
"dimensions mismatch");
123 std::vector<T> V(m), W(mat_ncols(A));
126 const size_type jmax = (m==n && !is_complex(T())) ? m-1
133 if (Vnorm2 > R(1) || gmm::imag(QR(j, j)) != R(0)) {
134 auto subA = sub_matrix(A, sub_interval(j, m-j),
135 sub_interval(0, mat_ncols(A)));
137 scaled(V, T(R(-2)/Vnorm2)), W);
138 rank_one_update(subA, V, W);
144 template <
typename MAT1,
typename MAT2,
typename MAT3>
145 void qr_factor(
const MAT1 &A,
const MAT2 &QQ,
const MAT3 &RR) {
146 MAT2 &Q =
const_cast<MAT2 &
>(QQ); MAT3 &R =
const_cast<MAT3 &
>(RR);
147 typedef typename linalg_traits<MAT1>::value_type T;
149 const size_type m = mat_nrows(A), n = mat_ncols(A);
150 GMM_ASSERT2(m >= n,
"dimensions mismatch");
154 dense_matrix<T> VV(m, n);
157 const size_type jmax = (m==n && !is_complex(T())) ? m-1
159 for (size_type j = 0; j < jmax; ++j) {
160 sub_interval SUBI(j, m-j), SUBJ(j, n-j);
162 for (size_type i = j; i < m; ++i) VV(i,j) = Q(i, j);
163 house_vector(sub_vector(mat_col(VV,j), SUBI));
165 row_house_update(sub_matrix(Q, SUBI, SUBJ),
166 sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
169 gmm::copy(sub_matrix(Q, sub_interval(0, n), sub_interval(0, n)), R);
172 const size_type jstart = (m==n && !is_complex(T())) ? m-2
174 for (size_type j = jstart; j !=
size_type(-1); --j) {
175 sub_interval SUBI(j, m-j), SUBJ(j, n-j);
176 row_house_update(sub_matrix(Q, SUBI, SUBJ),
177 sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
182 template <
typename TA,
typename TV,
typename Ttol,
183 typename MAT,
typename VECT>
184 void extract_eig(
const MAT &A, VECT &V, Ttol tol, TA, TV) {
188 Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
191 tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
192 tol_cplx = std::max(tol_cplx, tol_i);
194 if ((i < n-1) && gmm::abs(A(i+1,i)) >= tol_i) {
195 TA tr = A(i,i) + A(i+1, i+1);
196 TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
197 TA delta = tr*tr - TA(4) * det;
198 if (delta < -tol_cplx) {
199 GMM_WARNING1(
"A complex eigenvalue has been detected : "
200 << std::complex<TA>(tr/TA(2), gmm::sqrt(-delta)/TA(2)));
201 V[i] = V[i+1] = tr / TA(2);
204 delta = std::max(TA(0), delta);
205 V[i ] = TA(tr + gmm::sqrt(delta))/ TA(2);
206 V[i+1] = TA(tr - gmm::sqrt(delta))/ TA(2);
215 template <
typename TA,
typename TV,
typename Ttol,
216 typename MAT,
typename VECT>
217 void extract_eig(
const MAT &A, VECT &V, Ttol tol, TA, std::complex<TV>) {
222 gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
223 V[i] = std::complex<TV>(A(i,i));
225 TA tr = A(i,i) + A(i+1, i+1);
226 TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
227 TA delta = tr*tr - TA(4) * det;
229 V[i] = std::complex<TV>(tr / TA(2), gmm::sqrt(-delta) / TA(2));
230 V[i+1] = std::complex<TV>(tr / TA(2), -gmm::sqrt(-delta)/ TA(2));
233 V[i ] = TA(tr + gmm::sqrt(delta)) / TA(2);
234 V[i+1] = TA(tr - gmm::sqrt(delta)) / TA(2);
240 template <
typename TA,
typename TV,
typename Ttol,
241 typename MAT,
typename VECT>
242 void extract_eig(
const MAT &A, VECT &V, Ttol tol, std::complex<TA>, TV) {
243 typedef std::complex<TA> T;
247 Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
250 tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
251 tol_cplx = std::max(tol_cplx, tol_i);
253 if ((i == n-1) || gmm::abs(A(i+1,i)) < tol_i) {
254 if (gmm::abs(std::imag(A(i,i))) > tol_cplx)
255 GMM_WARNING1(
"A complex eigenvalue has been detected : "
256 << T(A(i,i)) <<
" : " << gmm::abs(std::imag(A(i,i)))
257 / gmm::abs(std::real(A(i,i))) <<
" : " << tol_cplx);
258 V[i] = std::real(A(i,i));
261 T tr = A(i,i) + A(i+1, i+1);
262 T det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
263 T delta = tr*tr - TA(4) * det;
264 T a1 = (tr + gmm::sqrt(delta)) / TA(2);
265 T a2 = (tr - gmm::sqrt(delta)) / TA(2);
266 if (gmm::abs(std::imag(a1)) > tol_cplx)
267 GMM_WARNING1(
"A complex eigenvalue has been detected : " << a1);
268 if (gmm::abs(std::imag(a2)) > tol_cplx)
269 GMM_WARNING1(
"A complex eigenvalue has been detected : " << a2);
271 V[i] = std::real(a1); V[i+1] = std::real(a2);
277 template <
typename TA,
typename TV,
typename Ttol,
278 typename MAT,
typename VECT>
280 std::complex<TA>, std::complex<TV>) {
285 gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
286 V[i] = std::complex<TV>(A(i,i));
288 std::complex<TA> tr = A(i,i) + A(i+1, i+1);
289 std::complex<TA> det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
290 std::complex<TA> delta = tr*tr - TA(4) * det;
291 V[i] = (tr + gmm::sqrt(delta)) / TA(2);
292 V[i+1] = (tr - gmm::sqrt(delta)) / TA(2);
301 template <
typename MAT,
typename Ttol,
typename VECT>
inline
304 typename linalg_traits<MAT>::value_type(),
305 typename linalg_traits<VECT>::value_type());
312 template <
typename MAT,
typename Ttol>
314 typedef typename linalg_traits<MAT>::value_type T;
315 typedef typename number_traits<T>::magnitude_type R;
316 R rmin = default_min(R()) * R(2);
318 if (n <= 2) { q = n; p = 0; }
321 if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
322 || gmm::abs(A(i,i-1)) < rmin)
325 while ((q < n-1 && A(n-1-q, n-2-q) == T(0)) ||
326 (q < n-2 && A(n-2-q, n-3-q) == T(0))) ++q;
328 p = n-q;
if (p) --p;
if (p) --p;
329 while (p > 0 && A(p,p-1) != T(0)) --p;
333 template <
typename MAT,
typename Ttol>
inline
336 typedef typename linalg_traits<MAT>::value_type T;
337 typedef typename number_traits<T>::magnitude_type R;
338 R rmin = default_min(R()) * R(2);
339 MAT& A =
const_cast<MAT&
>(AA);
341 if (n <= 1) { q = n; p = 0; }
344 if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
345 || gmm::abs(A(i,i-1)) < rmin)
348 while (q < n-1 && A(n-1-q, n-2-q) == T(0)) ++q;
350 p = n-q;
if (p) --p;
if (p) --p;
351 while (p > 0 && A(p,p-1) != T(0)) --p;
355 template <
typename VECT1,
typename VECT2,
typename Ttol>
inline
356 void symmetric_qr_stop_criterion(
const VECT1 &diag,
const VECT2 &sdiag_,
358 typedef typename linalg_traits<VECT2>::value_type T;
359 typedef typename number_traits<T>::magnitude_type R;
360 R rmin = default_min(R()) * R(2);
361 VECT2 &sdiag =
const_cast<VECT2 &
>(sdiag_);
363 if (n <= 1) { q = n; p = 0;
return; }
365 if (gmm::abs(sdiag[i-1]) < (gmm::abs(diag[i])+ gmm::abs(diag[i-1]))*tol
366 || gmm::abs(sdiag[i-1]) < rmin)
368 while (q < n-1 && sdiag[n-2-q] == T(0)) ++q;
370 p = n-q;
if (p) --p;
if (p) --p;
371 while (p > 0 && sdiag[p-1] != T(0)) --p;
378 template <
typename MATH,
typename MATQ,
typename Ttol>
379 void block2x2_reduction(MATH &H, MATQ &Q, Ttol tol) {
380 typedef typename linalg_traits<MATH>::value_type T;
381 typedef typename number_traits<T>::magnitude_type R;
383 size_type n = mat_nrows(H), nq = mat_nrows(Q);
385 sub_interval SUBQ(0, nq), SUBL(0, 2);
386 std::vector<T> v(2), w(std::max(n, nq)); v[0] = T(1);
388 Ttol tol_i = tol * gmm::abs(H(0,0)), tol_cplx = tol_i;
390 tol_i = (gmm::abs(H(i,i))+gmm::abs(H(i+1,i+1)))*tol;
391 tol_cplx = std::max(tol_cplx, tol_i);
393 if (gmm::abs(H(i+1,i)) > tol_i) {
394 T tr = (H(i+1, i+1) - H(i,i)) / T(2);
395 T delta = tr*tr + H(i,i+1)*H(i+1, i);
397 if (is_complex(T()) || gmm::real(delta) >= R(0)) {
398 sub_interval SUBI(i, 2);
399 T theta = (tr - gmm::sqrt(delta)) / H(i+1,i);
400 R a = gmm::abs(theta);
401 v[1] = (a == R(0)) ? T(-1)
402 : gmm::conj(theta) * (R(1) - gmm::sqrt(a*a + R(1)) / a);
403 row_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
404 col_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
405 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
416 #define tol_type_for_qr typename number_traits<typename \
417 linalg_traits<MAT1>::value_type>::magnitude_type
418 #define default_tol_for_qr \
419 (gmm::default_tol(tol_type_for_qr()) * tol_type_for_qr(3))
424 template <
typename MAT1,
typename VECT,
typename MAT2>
425 void rudimentary_qr_algorithm(
const MAT1 &A,
const VECT &eigval_,
426 const MAT2 &eigvect_,
427 tol_type_for_qr tol = default_tol_for_qr,
428 bool compvect =
true) {
429 VECT &eigval =
const_cast<VECT &
>(eigval_);
430 MAT2 &eigvect =
const_cast<MAT2 &
>(eigvect_);
432 typedef typename linalg_traits<MAT1>::value_type value_type;
434 size_type n = mat_nrows(A), p, q = 0, ite = 0;
435 dense_matrix<value_type> Q(n, n), R(n,n), A1(n,n);
438 Hessenberg_reduction(A1, eigvect, compvect);
439 qr_stop_criterion(A1, p, q, tol);
446 qr_stop_criterion(A1, p, q, tol);
448 GMM_ASSERT1(ite < n*1000,
"QR algorithm failed");
450 if (compvect) block2x2_reduction(A1, Q, tol);
454 template <
typename MAT1,
typename VECT>
455 void rudimentary_qr_algorithm(
const MAT1 &a, VECT &eigval,
456 tol_type_for_qr tol = default_tol_for_qr) {
457 dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
458 rudimentary_qr_algorithm(a, eigval, m, tol,
false);
465 template <
typename MAT1,
typename MAT2>
466 void Francis_qr_step(
const MAT1& HH,
const MAT2 &QQ,
bool compute_Q) {
467 MAT1& H =
const_cast<MAT1&
>(HH); MAT2& Q =
const_cast<MAT2&
>(QQ);
468 typedef typename linalg_traits<MAT1>::value_type value_type;
469 size_type n = mat_nrows(H), nq = mat_nrows(Q);
471 std::vector<value_type> v(3), w(std::max(n, nq));
473 value_type s = H(n-2, n-2) + H(n-1, n-1);
474 value_type t = H(n-2, n-2) * H(n-1, n-1) - H(n-2, n-1) * H(n-1, n-2);
475 value_type x = H(0, 0) * H(0, 0) + H(0,1) * H(1, 0) - s * H(0,0) + t;
476 value_type y = H(1, 0) * (H(0,0) + H(1,1) - s);
477 value_type z = H(1, 0) * H(2, 1);
479 sub_interval SUBQ(0, nq);
482 v[0] = x; v[1] = y; v[2] = z;
484 size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
485 sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
487 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
488 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
491 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
493 x = H(k+1, k); y = H(k+2, k);
494 if (k < n-3) z = H(k+3, k);
496 sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
500 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
501 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
503 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
510 template <
typename MAT1,
typename MAT2,
typename Ttol>
511 void Wilkinson_double_shift_qr_step(
const MAT1& HH,
const MAT2 &QQ,
512 Ttol tol,
bool exc,
bool compute_Q) {
513 MAT1& H =
const_cast<MAT1&
>(HH); MAT2& Q =
const_cast<MAT2&
>(QQ);
514 typedef typename linalg_traits<MAT1>::value_type T;
515 typedef typename number_traits<T>::magnitude_type R;
517 size_type n = mat_nrows(H), nq = mat_nrows(Q), m;
518 std::vector<T> v(3), w(std::max(n, nq));
519 const R dat1(0.75), dat2(-0.4375);
520 T h33, h44, h43h34, v1(0), v2(0), v3(0);
523 R s = gmm::abs(H(n-1, n-2)) + gmm::abs(H(n-2, n-3));
524 h33 = h44 = dat1 * s;
528 h44 = H(n-1,n-1); h33 = H(n-2, n-2);
529 h43h34 = H(n-1, n-2) * H(n-2, n-1);
535 for (m = n-2; m != 0; --m) {
536 T h11 = H(m-1, m-1), h22 = H(m, m);
537 T h21 = H(m, m-1), h12 = H(m-1, m);
538 T h44s = h44 - h11, h33s = h33 - h11;
539 v1 = (h33s*h44s-h43h34) / h21 + h12;
540 v2 = h22 - h11 - h33s - h44s;
542 R s = gmm::abs(v1) + gmm::abs(v2) + gmm::abs(v3);
543 v1 /= s; v2 /= s; v3 /= s;
547 R tst1 = gmm::abs(v1)*(gmm::abs(h00)+gmm::abs(h11)+gmm::abs(h22));
548 if (gmm::abs(h10)*(gmm::abs(v2)+gmm::abs(v3)) <= tol * tst1)
break;
552 sub_interval SUBQ(0, nq);
553 for (
size_type k = (m == 0) ? 0 : m-1; k < n-2; ++k) {
554 v[0] = v1; v[1] = v2; v[2] = v3;
556 size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
557 sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
559 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
560 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
561 if (k > m-1) { H(k+1, k-1) = T(0);
if (k < n-3) H(k+2, k-1) = T(0); }
564 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
566 v1 = H(k+1, k); v2 = H(k+2, k);
567 if (k < n-3) v3 = H(k+3, k);
569 sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
570 v.resize(2); v[0] = v1; v[1] = v2;
572 row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
573 col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
575 col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
586 template <
typename MAT1,
typename VECT,
typename MAT2>
587 void implicit_qr_algorithm(
const MAT1 &A,
const VECT &eigval_,
589 tol_type_for_qr tol = default_tol_for_qr,
590 bool compvect =
true) {
591 VECT &eigval =
const_cast<VECT &
>(eigval_);
592 MAT2 &Q =
const_cast<MAT2 &
>(Q_);
593 typedef typename linalg_traits<MAT1>::value_type T;
594 typedef typename number_traits<T>::magnitude_type R;
597 dense_matrix<T> H(n,n);
600 Hessenberg_reduction(H, Q, compvect);
601 qr_stop_criterion(H, p, q, tol);
604 sub_interval SUBK(0,0);
606 sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(Q));
607 if (compvect) SUBK = SUBI;
610 Wilkinson_double_shift_qr_step(sub_matrix(H, SUBI),
611 sub_matrix(Q, SUBJ, SUBK),
612 tol, (its == 10 || its == 20), compvect);
614 qr_stop_criterion(H, p, q, tol*R(2));
615 if (q != q_old) its = 0;
617 GMM_ASSERT1(ite < n*100,
"QR algorithm failed");
619 if (compvect) block2x2_reduction(H, Q, tol);
623 template <
typename MAT1,
typename VECT>
624 void implicit_qr_algorithm(
const MAT1 &a, VECT &eigval,
625 tol_type_for_qr tol = default_tol_for_qr) {
626 dense_matrix<typename linalg_traits<MAT1>::value_type> m(1,1);
627 implicit_qr_algorithm(a, eigval, m, tol,
false);
634 template <
typename MAT1,
typename MAT2>
635 void symmetric_Wilkinson_qr_step(
const MAT1& MM,
const MAT2 &ZZ,
637 MAT1& M =
const_cast<MAT1&
>(MM); MAT2& Z =
const_cast<MAT2&
>(ZZ);
638 typedef typename linalg_traits<MAT1>::value_type T;
639 typedef typename number_traits<T>::magnitude_type R;
643 M(i, i) = T(gmm::real(M(i, i)));
645 T a = (M(i, i-1) + gmm::conj(M(i-1, i)))/R(2);
646 M(i, i-1) = a; M(i-1, i) = gmm::conj(a);
650 R d = gmm::real(M(n-2, n-2) - M(n-1, n-1)) / R(2);
651 R e = gmm::abs_sqr(M(n-1, n-2));
652 R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
653 if (nu == R(0)) { M(n-1, n-2) = T(0);
return; }
654 R mu = gmm::real(M(n-1, n-1)) - e / nu;
655 T x = M(0,0) - T(mu), z = M(1, 0), c, s;
658 Givens_rotation(x, z, c, s);
660 if (k > 1) Apply_Givens_rotation_left(M(k-1,k-2), M(k,k-2), c, s);
661 Apply_Givens_rotation_left(M(k-1,k-1), M(k,k-1), c, s);
662 Apply_Givens_rotation_left(M(k-1,k ), M(k,k ), c, s);
663 if (k < n-1) Apply_Givens_rotation_left(M(k-1,k+1), M(k,k+1), c, s);
664 if (k > 1) Apply_Givens_rotation_right(M(k-2,k-1), M(k-2,k), c, s);
665 Apply_Givens_rotation_right(M(k-1,k-1), M(k-1,k), c, s);
666 Apply_Givens_rotation_right(M(k ,k-1), M(k,k) , c, s);
667 if (k < n-1) Apply_Givens_rotation_right(M(k+1,k-1), M(k+1,k), c, s);
669 if (compute_z) col_rot(Z, c, s, k-1, k);
670 if (k < n-1) { x = M(k, k-1); z = M(k+1, k-1); }
674 template <
typename VECT1,
typename VECT2,
typename MAT>
675 void symmetric_Wilkinson_qr_step(
const VECT1& diag_,
const VECT2& sdiag_,
676 const MAT &ZZ,
bool compute_z) {
677 VECT1& diag =
const_cast<VECT1&
>(diag_);
678 VECT2& sdiag =
const_cast<VECT2&
>(sdiag_);
679 MAT& Z =
const_cast<MAT&
>(ZZ);
680 typedef typename linalg_traits<VECT2>::value_type T;
681 typedef typename number_traits<T>::magnitude_type R;
684 R d = (diag[n-2] - diag[n-1]) / R(2);
685 R e = gmm::abs_sqr(sdiag[n-2]);
686 R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
687 if (nu == R(0)) { sdiag[n-2] = T(0);
return; }
688 R mu = diag[n-1] - e / nu;
689 T x = diag[0] - T(mu), z = sdiag[0], c, s;
692 T a10(0), a11(diag[0]), a12(gmm::conj(sdiag[0])), a13(0);
693 T a20(0), a21(sdiag[0]), a22(diag[1]), a23(gmm::conj(sdiag[1]));
694 T a31(0), a32(sdiag[1]);
697 Givens_rotation(x, z, c, s);
699 if (k > 1) Apply_Givens_rotation_left(a10, a20, c, s);
700 Apply_Givens_rotation_left(a11, a21, c, s);
701 Apply_Givens_rotation_left(a12, a22, c, s);
702 if (k < n-1) Apply_Givens_rotation_left(a13, a23, c, s);
704 if (k > 1) Apply_Givens_rotation_right(a01, a02, c, s);
705 Apply_Givens_rotation_right(a11, a12, c, s);
706 Apply_Givens_rotation_right(a21, a22, c, s);
707 if (k < n-1) Apply_Givens_rotation_right(a31, a32, c, s);
709 if (compute_z) col_rot(Z, c, s, k-1, k);
711 diag[k-1] = gmm::real(a11);
712 diag[k] = gmm::real(a22);
713 if (k > 1) sdiag[k-2] = (gmm::conj(a01) + a10) / R(2);
714 sdiag[k-1] = (gmm::conj(a12) + a21) / R(2);
716 x = sdiag[k-1]; z = (gmm::conj(a13) + a31) / R(2);
718 a01 = a12; a02 = a13;
719 a10 = a21; a11 = a22; a12 = a23; a13 = T(0);
720 a20 = a31; a21 = a32; a31 = T(0);
723 sdiag[k] = (gmm::conj(a23) + a32) / R(2);
724 a22 = T(diag[k+1]); a32 = sdiag[k+1]; a23 = gmm::conj(a32);
737 template <
typename MAT1,
typename VECT,
typename MAT2>
738 void symmetric_qr_algorithm_old(
const MAT1 &A,
const VECT &eigval_,
739 const MAT2 &eigvect_,
740 tol_type_for_qr tol = default_tol_for_qr,
741 bool compvect =
true) {
742 VECT &eigval =
const_cast<VECT &
>(eigval_);
743 MAT2 &eigvect =
const_cast<MAT2 &
>(eigvect_);
744 typedef typename linalg_traits<MAT1>::value_type T;
745 typedef typename number_traits<T>::magnitude_type R;
747 size_type n(mat_nrows(A)), q(0), p(0), ite(0);
748 dense_matrix<T> Tri(n, n);
751 if (compvect)
gmm::copy(identity_matrix(), eigvect);
752 Householder_tridiagonalization(Tri, eigvect, compvect);
753 symmetric_qr_stop_criterion(Tri, p, q, tol);
756 sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
757 if (!compvect) SUBK = sub_interval(0,0);
758 symmetric_Wilkinson_qr_step(sub_matrix(Tri, SUBI),
759 sub_matrix(eigvect, SUBJ, SUBK), compvect);
761 symmetric_qr_stop_criterion(Tri, p, q, tol*R(2));
763 GMM_ASSERT1(ite < n*100,
"QR algorithm failed. Probably, your matrix"
764 " is not real symmetric or complex hermitian");
770 template <
typename MAT1,
typename VECT,
typename MAT2>
771 void symmetric_qr_algorithm(
const MAT1 &A,
const VECT &eigval_,
772 const MAT2 &eigvect_,
773 tol_type_for_qr tol = default_tol_for_qr,
774 bool compvect =
true) {
775 VECT &eigval =
const_cast<VECT &
>(eigval_);
776 MAT2 &eigvect =
const_cast<MAT2 &
>(eigvect_);
777 typedef typename linalg_traits<MAT1>::value_type T;
778 typedef typename number_traits<T>::magnitude_type R;
780 size_type n = mat_nrows(A), q = 0, p, ite = 0;
781 if (compvect)
gmm::copy(identity_matrix(), eigvect);
783 if (n == 1) { eigval[0]=gmm::real(A(0,0));
return; }
784 dense_matrix<T> Tri(n, n);
787 Householder_tridiagonalization(Tri, eigvect, compvect);
789 std::vector<R> diag(n);
790 std::vector<T> sdiag(n);
792 { diag[i] = gmm::real(Tri(i, i));
if (i+1 < n) sdiag[i] = Tri(i+1, i); }
794 symmetric_qr_stop_criterion(diag, sdiag, p, q, tol);
797 sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
798 if (!compvect) SUBK = sub_interval(0,0);
800 symmetric_Wilkinson_qr_step(sub_vector(diag, SUBI),
801 sub_vector(sdiag, SUBI),
802 sub_matrix(eigvect, SUBJ, SUBK), compvect);
804 symmetric_qr_stop_criterion(diag, sdiag, p, q, tol*R(3));
806 GMM_ASSERT1(ite < n*100,
"QR algorithm failed.");
813 template <
typename MAT1,
typename VECT>
814 void symmetric_qr_algorithm(
const MAT1 &a, VECT &eigval,
815 tol_type_for_qr tol = default_tol_for_qr) {
816 dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
817 symmetric_qr_algorithm(a, eigval, m, tol,
false);
void copy(const L1 &l1, L2 &l2)
*/
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2_sqr(const V &v)
squared Euclidean norm of a vector.
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
conjugated_return< L >::return_type conjugated(const L &v)
return a conjugated view of the input matrix or vector.
Householder for dense matrices.
void qr_factor(const MAT &A_)
QR factorization using Householder method (complex and real version).
void extract_eig(const MAT &A, const VECT &V, Ttol tol)
Compute eigenvalue vector.
size_t size_type
used as the common size type in the library